From 0f4df23290003225494048e6dc396b89f19a7bbb Mon Sep 17 00:00:00 2001 From: upstream-mirror Date: Wed, 16 Sep 2026 02:17:34 +0500 Subject: [PATCH] snapshot of https://github.com/sqlc-dev/sqlc.git (main, 2026-09-16; blobs > 131072B omitted) --- .github/ISSUE_TEMPLATE/BUG_REPORT.yml | 88 + .github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml | 30 + .github/dependabot.yml | 20 + .github/workflows/buf.yml | 18 + .github/workflows/build.yml | 19 + .github/workflows/ci-kotlin.yml | 31 + .github/workflows/ci-python.yml | 30 + .github/workflows/ci-typescript.yml | 30 + .github/workflows/ci.yml | 74 + .github/workflows/gen.yml | 192 + .gitignore | 11 + .vscode/settings.json | 3 + CLAUDE.md | 340 ++ Dockerfile | 19 + LICENSE | 21 + Makefile | 60 + NOTICE | 48 + README.md | 59 + buf.gen.yaml | 12 + buf.lock | 2 + buf.work.yaml | 3 + cliff.toml | 56 + cmd/sqlc-gen-json/main.go | 47 + cmd/sqlc-test-setup/main.go | 717 ++++ cmd/sqlc/main.go | 11 + devenv.lock | 100 + devenv.nix | 17 + devenv.yaml | 3 + docker-compose.yml | 39 + docs/.gitignore | 2 + docs/guides/development.md | 61 + .../migrating-off-hosted-managed-databases.md | 71 + docs/guides/migrating-to-sqlc-gen-kotlin.md | 119 + docs/guides/migrating-to-sqlc-gen-python.md | 131 + docs/guides/plugins.md | 104 + docs/guides/privacy.md | 55 + docs/guides/using-go-and-pgx.md | 125 + docs/howto/analyze.md | 129 + docs/howto/ci-cd.md | 159 + docs/howto/ddl.md | 232 + docs/howto/delete.md | 52 + docs/howto/embedding.md | 61 + docs/howto/fmt.md | 74 + docs/howto/generate.md | 76 + docs/howto/insert.md | 238 ++ docs/howto/managed-databases.md | 101 + docs/howto/named_parameters.md | 93 + docs/howto/overrides.md | 184 + docs/howto/parse.md | 111 + docs/howto/prepared_query.md | 89 + docs/howto/push.md | 70 + docs/howto/query_count.md | 83 + docs/howto/rename.md | 122 + docs/howto/select.md | 393 ++ docs/howto/structs.md | 53 + docs/howto/transactions.md | 101 + docs/howto/update.md | 115 + docs/howto/verify.md | 105 + docs/howto/vet.md | 286 ++ docs/index.md | 22 + docs/overview/install.md | 51 + docs/reference/changelog.md | 2936 +++++++++++++ docs/reference/cli.md | 29 + docs/reference/config.md | 501 +++ docs/reference/datatypes.md | 388 ++ docs/reference/environment-variables.md | 190 + docs/reference/language-support.md | 34 + docs/reference/macros.md | 119 + docs/reference/query-annotations.md | 230 + docs/toc.yaml | 72 + docs/tutorials/getting-started-mysql.md | 221 + docs/tutorials/getting-started-postgresql.md | 248 ++ docs/tutorials/getting-started-sqlite.md | 201 + examples/authors/mysql/db.go | 31 + examples/authors/mysql/db_test.go | 53 + examples/authors/mysql/models.go | 15 + examples/authors/mysql/query.sql | 18 + examples/authors/mysql/query.sql.go | 78 + examples/authors/mysql/schema.sql | 5 + examples/authors/postgresql/db.go | 32 + examples/authors/postgresql/db_test.go | 49 + examples/authors/postgresql/models.go | 15 + examples/authors/postgresql/query.sql | 19 + examples/authors/postgresql/query.sql.go | 80 + examples/authors/postgresql/schema.sql | 5 + examples/authors/sqlc.yaml | 52 + examples/authors/sqlite/db.go | 31 + examples/authors/sqlite/db_test.go | 48 + examples/authors/sqlite/models.go | 15 + examples/authors/sqlite/query.sql | 18 + examples/authors/sqlite/query.sql.go | 78 + examples/authors/sqlite/schema.sql | 5 + examples/batch/postgresql/batch.go | 404 ++ examples/batch/postgresql/db.go | 33 + examples/batch/postgresql/db_test.go | 153 + examples/batch/postgresql/models.go | 71 + examples/batch/postgresql/querier.go | 26 + examples/batch/postgresql/query.sql | 56 + examples/batch/postgresql/query.sql.go | 45 + examples/batch/postgresql/schema.sql | 21 + examples/batch/sqlc.json | 28 + examples/booktest/mysql/db.go | 31 + examples/booktest/mysql/db_test.go | 174 + examples/booktest/mysql/models.go | 69 + examples/booktest/mysql/query.sql | 63 + examples/booktest/mysql/query.sql.go | 251 ++ examples/booktest/mysql/schema.sql | 26 + examples/booktest/postgresql/db.go | 32 + examples/booktest/postgresql/db_test.go | 174 + examples/booktest/postgresql/models.go | 70 + examples/booktest/postgresql/query.sql | 63 + examples/booktest/postgresql/query.sql.go | 258 ++ examples/booktest/postgresql/schema.sql | 32 + examples/booktest/sqlc.json | 51 + examples/booktest/sqlite/db.go | 31 + examples/booktest/sqlite/db_test.go | 163 + examples/booktest/sqlite/models.go | 25 + examples/booktest/sqlite/query.sql | 64 + examples/booktest/sqlite/query.sql.go | 279 ++ examples/booktest/sqlite/schema.sql | 20 + examples/jets/README.md | 3 + examples/jets/postgresql/db.go | 32 + examples/jets/postgresql/models.go | 28 + examples/jets/postgresql/query-building.sql | 8 + .../jets/postgresql/query-building.sql.go | 54 + examples/jets/postgresql/schema.sql | 35 + examples/jets/sqlc.json | 25 + examples/ondeck/mysql/city.sql.go | 88 + examples/ondeck/mysql/db.go | 178 + examples/ondeck/mysql/db_test.go | 172 + examples/ondeck/mysql/models.go | 75 + examples/ondeck/mysql/querier.go | 25 + examples/ondeck/mysql/query/city.sql | 23 + examples/ondeck/mysql/query/venue.sql | 48 + examples/ondeck/mysql/schema/0001_city.sql | 4 + examples/ondeck/mysql/schema/0002_venue.sql | 12 + .../ondeck/mysql/schema/0003_add_column.sql | 3 + examples/ondeck/mysql/venue.sql.go | 193 + examples/ondeck/postgresql/city.sql.go | 95 + examples/ondeck/postgresql/db.go | 180 + examples/ondeck/postgresql/db_test.go | 154 + examples/ondeck/postgresql/models.go | 77 + examples/ondeck/postgresql/querier.go | 29 + examples/ondeck/postgresql/query/city.sql | 26 + examples/ondeck/postgresql/query/venue.sql | 49 + .../ondeck/postgresql/schema/0001_city.sql | 4 + .../ondeck/postgresql/schema/0002_venue.sql | 18 + .../postgresql/schema/0003_add_column.sql | 3 + examples/ondeck/postgresql/venue.sql.go | 197 + examples/ondeck/sqlc.json | 61 + examples/ondeck/sqlite/city.sql.go | 88 + examples/ondeck/sqlite/db.go | 178 + examples/ondeck/sqlite/db_test.go | 171 + examples/ondeck/sqlite/models.go | 28 + examples/ondeck/sqlite/querier.go | 25 + examples/ondeck/sqlite/query/city.sql | 23 + examples/ondeck/sqlite/query/venue.sql | 48 + examples/ondeck/sqlite/schema/0001_city.sql | 4 + examples/ondeck/sqlite/schema/0002_venue.sql | 13 + .../ondeck/sqlite/schema/0003_add_column.sql | 3 + examples/ondeck/sqlite/venue.sql.go | 193 + go.mod | 58 + go.sum | 136 + gomod_test.go | 66 + internal/analysis/analysis.pb.go | 546 +++ internal/analysis/analysis_vtproto.pb.go | 2078 +++++++++ internal/analyzer/analyzer.go | 131 + internal/bundler/multipart.go | 40 + internal/bundler/upload.go | 164 + internal/cache/action.go | 209 + internal/cache/cache.go | 103 + internal/cache/cas.go | 138 + internal/cache/digest.go | 100 + internal/cache/tool.go | 95 + internal/cmd/analyze.go | 275 ++ internal/cmd/cmd.go | 277 ++ internal/cmd/createdb.go | 102 + internal/cmd/diff.go | 59 + internal/cmd/fmt.go | 481 +++ internal/cmd/generate.go | 376 ++ internal/cmd/options.go | 29 + internal/cmd/parse.go | 166 + internal/cmd/process.go | 133 + internal/cmd/push.go | 92 + internal/cmd/shim.go | 233 ++ internal/cmd/verify.go | 156 + internal/cmd/vet.go | 709 ++++ internal/cmd/vet_sqlite.go | 7 + internal/codegen/golang/driver.go | 14 + internal/codegen/golang/enum.go | 64 + internal/codegen/golang/field.go | 143 + internal/codegen/golang/gen.go | 426 ++ internal/codegen/golang/go_type.go | 92 + internal/codegen/golang/imports.go | 537 +++ internal/codegen/golang/mysql_type.go | 144 + internal/codegen/golang/opts/enum.go | 64 + internal/codegen/golang/opts/go_type.go | 192 + internal/codegen/golang/opts/options.go | 243 ++ internal/codegen/golang/opts/override.go | 176 + internal/codegen/golang/opts/override_test.go | 117 + internal/codegen/golang/opts/shim.go | 77 + internal/codegen/golang/postgresql_type.go | 619 +++ internal/codegen/golang/qualify.go | 79 + internal/codegen/golang/query.go | 308 ++ internal/codegen/golang/reserved.go | 71 + internal/codegen/golang/result.go | 473 +++ internal/codegen/golang/result_test.go | 78 + internal/codegen/golang/sqlite_type.go | 102 + internal/codegen/golang/struct.go | 53 + internal/codegen/golang/template.go | 7 + .../go-sql-driver-mysql/copyfromCopy.tmpl | 52 + .../golang/templates/pgx/batchCode.tmpl | 134 + .../golang/templates/pgx/copyfromCopy.tmpl | 51 + .../codegen/golang/templates/pgx/dbCode.tmpl | 37 + .../golang/templates/pgx/interfaceCode.tmpl | 73 + .../golang/templates/pgx/queryCode.tmpl | 142 + .../golang/templates/stdlib/dbCode.tmpl | 105 + .../templates/stdlib/interfaceCode.tmpl | 63 + .../golang/templates/stdlib/queryCode.tmpl | 171 + .../codegen/golang/templates/template.tmpl | 254 ++ internal/codegen/json/gen.go | 68 + internal/codegen/json/opts.go | 7 + internal/codegen/sdk/sdk.go | 33 + internal/codegen/sdk/utils.go | 42 + internal/codegen/sdk/utils_test.go | 28 + internal/compiler/analyze.go | 214 + internal/compiler/catalog_core.go | 62 + internal/compiler/compat.go | 137 + internal/compiler/compile.go | 300 ++ internal/compiler/engine.go | 199 + internal/compiler/expand.go | 211 + internal/compiler/expand_core.go | 76 + internal/compiler/find_params.go | 214 + internal/compiler/output_columns.go | 812 ++++ internal/compiler/parse.go | 201 + internal/compiler/parse_core.go | 165 + internal/compiler/query.go | 67 + internal/compiler/query_catalog.go | 109 + internal/compiler/resolve.go | 638 +++ internal/compiler/result.go | 10 + internal/compiler/returning.go | 138 + internal/compiler/selector.go | 48 + internal/compiler/selector_test.go | 35 + internal/compiler/to_column.go | 33 + internal/config/config.go | 239 ++ internal/config/config_test.go | 91 + internal/config/convert/convert.go | 84 + internal/config/convert/convert_test.go | 47 + internal/config/env.go | 17 + internal/config/v_one.go | 196 + internal/config/v_one.json | 361 ++ internal/config/v_two.go | 109 + internal/config/v_two.json | 463 ++ internal/config/validate.go | 12 + internal/constants/query.go | 12 + internal/core/analysis.go | 82 + internal/core/analyzer/analyzer.go | 389 ++ internal/core/analyzer/bench_test.go | 110 + internal/core/analyzer/dml.go | 211 + internal/core/analyzer/expr.go | 1038 +++++ internal/core/analyzer/projection.go | 169 + internal/core/analyzer/scope.go | 243 ++ internal/core/attribute.go | 287 ++ internal/core/cache.go | 161 + internal/core/cast.go | 69 + internal/core/catalog.go | 189 + internal/core/catalogdb/db.go | 31 + internal/core/catalogdb/models.go | 142 + internal/core/catalogdb/query.sql.go | 1445 +++++++ internal/core/catalogdef/embed.go | 6 + internal/core/catalogdef/query.sql | 284 ++ internal/core/catalogdef/schema.sql | 227 + internal/core/class.go | 78 + internal/core/constraint.go | 21 + internal/core/db.go | 171 + internal/core/dialect.go | 210 + internal/core/namespace.go | 39 + internal/core/operator.go | 68 + internal/core/proc.go | 173 + internal/core/rewrite.go | 361 ++ internal/core/schema/schema.go | 570 +++ internal/core/seed/extension.go | 134 + internal/core/seed/seed.go | 965 +++++ internal/core/sqlc.json | 16 + internal/core/typeexpr.go | 324 ++ internal/core/typename.go | 150 + internal/core/types.go | 825 ++++ internal/core/types.md | 769 ++++ internal/dbmanager/client.go | 150 + internal/debug/dump.go | 28 + internal/docs/lint.go | 381 ++ internal/docs/lint_test.go | 116 + internal/endtoend/CLAUDE.md | 117 + internal/endtoend/case_test.go | 143 + internal/endtoend/ddl_test.go | 64 + internal/endtoend/endtoend_test.go | 456 ++ internal/endtoend/fmt_test.go | 194 + internal/endtoend/json_schema_test.go | 82 + .../endtoend/testdata/alias/mysql/go/db.go | 31 + .../testdata/alias/mysql/go/models.go | 9 + .../testdata/alias/mysql/go/query.sql.go | 20 + .../endtoend/testdata/alias/mysql/query.sql | 3 + .../endtoend/testdata/alias/mysql/schema.sql | 2 + .../endtoend/testdata/alias/mysql/sqlc.json | 12 + .../testdata/alias/postgresql/pgx/v4/go/db.go | 32 + .../alias/postgresql/pgx/v4/go/models.go | 9 + .../alias/postgresql/pgx/v4/go/query.sql.go | 20 + .../alias/postgresql/pgx/v4/query.sql | 3 + .../alias/postgresql/pgx/v4/schema.sql | 2 + .../alias/postgresql/pgx/v4/sqlc.json | 13 + .../testdata/alias/postgresql/pgx/v5/go/db.go | 32 + .../alias/postgresql/pgx/v5/go/models.go | 9 + .../alias/postgresql/pgx/v5/go/query.sql.go | 20 + .../alias/postgresql/pgx/v5/query.sql | 3 + .../alias/postgresql/pgx/v5/schema.sql | 2 + .../alias/postgresql/pgx/v5/sqlc.json | 13 + .../testdata/alias/postgresql/stdlib/go/db.go | 31 + .../alias/postgresql/stdlib/go/models.go | 9 + .../alias/postgresql/stdlib/go/query.sql.go | 20 + .../alias/postgresql/stdlib/query.sql | 3 + .../alias/postgresql/stdlib/schema.sql | 1 + .../alias/postgresql/stdlib/sqlc.json | 12 + .../endtoend/testdata/alias/sqlite/go/db.go | 31 + .../testdata/alias/sqlite/go/models.go | 9 + .../testdata/alias/sqlite/go/query.sql.go | 20 + .../endtoend/testdata/alias/sqlite/query.sql | 3 + .../endtoend/testdata/alias/sqlite/schema.sql | 2 + .../endtoend/testdata/alias/sqlite/sqlc.json | 12 + .../testdata/analyze_ast/postgresql/exec.json | 5 + .../testdata/analyze_ast/postgresql/query.sql | 2 + .../analyze_ast/postgresql/schema.sql | 5 + .../analyze_ast/postgresql/stdout.json | 136 + .../analyze_basic/clickhouse/exec.json | 5 + .../analyze_basic/clickhouse/fixture.sql | 1 + .../analyze_basic/clickhouse/query.sql | 2 + .../analyze_basic/clickhouse/schema.sql | 7 + .../analyze_basic/clickhouse/stdout.json | 45 + .../testdata/analyze_basic/duckdb/exec.json | 5 + .../testdata/analyze_basic/duckdb/query.sql | 2 + .../testdata/analyze_basic/duckdb/schema.sql | 7 + .../testdata/analyze_basic/duckdb/stdout.json | 53 + .../analyze_basic/googlesql/exec.json | 5 + .../analyze_basic/googlesql/query.sql | 2 + .../analyze_basic/googlesql/schema.sql | 5 + .../analyze_basic/googlesql/stdout.json | 39 + .../testdata/analyze_basic/mssql/exec.json | 5 + .../testdata/analyze_basic/mssql/query.sql | 2 + .../testdata/analyze_basic/mssql/schema.sql | 7 + .../testdata/analyze_basic/mssql/stdout.json | 68 + .../testdata/analyze_basic/mysql/exec.json | 5 + .../testdata/analyze_basic/mysql/query.sql | 2 + .../testdata/analyze_basic/mysql/schema.sql | 5 + .../testdata/analyze_basic/mysql/stdout.json | 39 + .../analyze_basic/postgresql/exec.json | 5 + .../analyze_basic/postgresql/query.sql | 2 + .../analyze_basic/postgresql/schema.sql | 5 + .../analyze_basic/postgresql/stdout.json | 42 + .../testdata/analyze_basic/sqlite/exec.json | 5 + .../testdata/analyze_basic/sqlite/query.sql | 2 + .../testdata/analyze_basic/sqlite/schema.sql | 5 + .../testdata/analyze_basic/sqlite/stdout.json | 34 + .../testdata/analyze_dml/duckdb/exec.json | 5 + .../testdata/analyze_dml/duckdb/query.sql | 13 + .../testdata/analyze_dml/duckdb/schema.sql | 12 + .../testdata/analyze_dml/duckdb/stdout.json | 144 + .../testdata/analyze_dml/googlesql/exec.json | 5 + .../testdata/analyze_dml/googlesql/query.sql | 17 + .../testdata/analyze_dml/googlesql/schema.sql | 5 + .../analyze_dml/googlesql/stdout.json | 229 + .../testdata/analyze_dml/mssql/exec.json | 5 + .../testdata/analyze_dml/mssql/query.sql | 11 + .../testdata/analyze_dml/mssql/schema.sql | 12 + .../testdata/analyze_dml/mssql/stdout.json | 143 + .../testdata/analyze_dml/mysql/exec.json | 5 + .../testdata/analyze_dml/mysql/query.sql | 11 + .../testdata/analyze_dml/mysql/schema.sql | 12 + .../testdata/analyze_dml/mysql/stdout.json | 112 + .../testdata/analyze_dml/postgresql/exec.json | 5 + .../testdata/analyze_dml/postgresql/query.sql | 14 + .../analyze_dml/postgresql/schema.sql | 12 + .../analyze_dml/postgresql/stdout.json | 165 + .../testdata/analyze_dml/sqlite/exec.json | 5 + .../testdata/analyze_dml/sqlite/query.sql | 8 + .../testdata/analyze_dml/sqlite/schema.sql | 12 + .../testdata/analyze_dml/sqlite/stdout.json | 98 + .../analyze_exec/clickhouse/exec.json | 5 + .../analyze_exec/clickhouse/fixture.sql | 2 + .../analyze_exec/clickhouse/query.sql | 11 + .../analyze_exec/clickhouse/schema.sql | 11 + .../analyze_exec/clickhouse/stdout.json | 130 + .../analyze_expressions/clickhouse/exec.json | 5 + .../clickhouse/fixture.sql | 2 + .../analyze_expressions/clickhouse/query.sql | 29 + .../analyze_expressions/clickhouse/schema.sql | 11 + .../clickhouse/stdout.json | 342 ++ .../analyze_expressions/sqlite/exec.json | 5 + .../analyze_expressions/sqlite/fixture.sql | 4 + .../analyze_expressions/sqlite/query.sql | 23 + .../analyze_expressions/sqlite/schema.sql | 15 + .../analyze_expressions/sqlite/stdout.json | 245 ++ .../analyze_extension/postgresql/exec.json | 5 + .../analyze_extension/postgresql/query.sql | 8 + .../analyze_extension/postgresql/schema.sql | 8 + .../analyze_extension/postgresql/stdout.json | 78 + .../analyze_params/clickhouse/exec.json | 5 + .../analyze_params/clickhouse/fixture.sql | 2 + .../analyze_params/clickhouse/query.sql | 5 + .../analyze_params/clickhouse/schema.sql | 7 + .../analyze_params/clickhouse/stdout.json | 76 + .../testdata/analyze_params/duckdb/exec.json | 5 + .../testdata/analyze_params/duckdb/query.sql | 8 + .../testdata/analyze_params/duckdb/schema.sql | 6 + .../analyze_params/duckdb/stdout.json | 117 + .../testdata/analyze_params/mssql/exec.json | 5 + .../testdata/analyze_params/mssql/query.sql | 5 + .../testdata/analyze_params/mssql/schema.sql | 7 + .../testdata/analyze_params/mssql/stdout.json | 112 + .../testdata/analyze_params/mysql/exec.json | 5 + .../testdata/analyze_params/mysql/query.sql | 8 + .../testdata/analyze_params/mysql/schema.sql | 12 + .../testdata/analyze_params/mysql/stdout.json | 129 + .../analyze_params/postgresql/exec.json | 5 + .../analyze_params/postgresql/query.sql | 11 + .../analyze_params/postgresql/schema.sql | 12 + .../analyze_params/postgresql/stdout.json | 157 + .../testdata/analyze_params/sqlite/exec.json | 5 + .../testdata/analyze_params/sqlite/query.sql | 8 + .../testdata/analyze_params/sqlite/schema.sql | 12 + .../analyze_params/sqlite/stdout.json | 101 + .../testdata/analyze_select/duckdb/exec.json | 5 + .../testdata/analyze_select/duckdb/query.sql | 16 + .../testdata/analyze_select/duckdb/schema.sql | 12 + .../analyze_select/duckdb/stdout.json | 118 + .../analyze_select/googlesql/exec.json | 5 + .../analyze_select/googlesql/query.sql | 8 + .../analyze_select/googlesql/schema.sql | 12 + .../analyze_select/googlesql/stdout.json | 123 + .../testdata/analyze_select/mysql/exec.json | 5 + .../testdata/analyze_select/mysql/query.sql | 17 + .../testdata/analyze_select/mysql/schema.sql | 12 + .../testdata/analyze_select/mysql/stdout.json | 198 + .../analyze_select/postgresql/exec.json | 5 + .../analyze_select/postgresql/query.sql | 17 + .../analyze_select/postgresql/schema.sql | 12 + .../analyze_select/postgresql/stdout.json | 177 + .../testdata/analyze_select/sqlite/exec.json | 5 + .../testdata/analyze_select/sqlite/query.sql | 11 + .../testdata/analyze_select/sqlite/schema.sql | 12 + .../analyze_select/sqlite/stdout.json | 142 + .../analyze_subqueries/clickhouse/exec.json | 5 + .../analyze_subqueries/clickhouse/fixture.sql | 2 + .../analyze_subqueries/clickhouse/query.sql | 27 + .../analyze_subqueries/clickhouse/schema.sql | 11 + .../analyze_subqueries/clickhouse/stdout.json | 159 + .../analyze_system_catalog/mysql/exec.json | 5 + .../analyze_system_catalog/mysql/query.sql | 7 + .../analyze_system_catalog/mysql/schema.sql | 4 + .../analyze_system_catalog/mysql/stdout.json | 93 + .../postgresql/exec.json | 5 + .../postgresql/query.sql | 7 + .../postgresql/schema.sql | 4 + .../postgresql/stdout.json | 69 + .../testdata/analyze_types/bigquery/exec.json | 5 + .../testdata/analyze_types/bigquery/query.sql | 16 + .../analyze_types/bigquery/schema.sql | 21 + .../analyze_types/bigquery/stdout.json | 482 +++ .../analyze_types/clickhouse/exec.json | 5 + .../analyze_types/clickhouse/fixture.sql | 1 + .../analyze_types/clickhouse/query.sql | 19 + .../analyze_types/clickhouse/schema.sql | 28 + .../analyze_types/clickhouse/stdout.json | 881 ++++ .../testdata/analyze_types/duckdb/exec.json | 5 + .../testdata/analyze_types/duckdb/query.sql | 18 + .../testdata/analyze_types/duckdb/schema.sql | 31 + .../testdata/analyze_types/duckdb/stdout.json | 709 ++++ .../analyze_types/googlesql/exec.json | 5 + .../analyze_types/googlesql/query.sql | 14 + .../analyze_types/googlesql/schema.sql | 16 + .../analyze_types/googlesql/stdout.json | 305 ++ .../testdata/analyze_types/mssql/exec.json | 5 + .../testdata/analyze_types/mssql/query.sql | 24 + .../testdata/analyze_types/mssql/schema.sql | 37 + .../testdata/analyze_types/mssql/stdout.json | 600 +++ .../testdata/analyze_types/mysql/exec.json | 5 + .../testdata/analyze_types/mysql/query.sql | 22 + .../testdata/analyze_types/mysql/schema.sql | 29 + .../testdata/analyze_types/mysql/stdout.json | 608 +++ .../analyze_types/postgresql/exec.json | 5 + .../analyze_types/postgresql/query.sql | 25 + .../analyze_types/postgresql/schema.sql | 47 + .../analyze_types/postgresql/stdout.json | 921 ++++ .../testdata/analyze_types/sqlite/exec.json | 5 + .../testdata/analyze_types/sqlite/fixture.sql | 4 + .../testdata/analyze_types/sqlite/query.sql | 18 + .../testdata/analyze_types/sqlite/schema.sql | 24 + .../testdata/analyze_types/sqlite/stdout.json | 333 ++ .../endtoend/testdata/any/pgx/v4/go/db.go | 32 + .../endtoend/testdata/any/pgx/v4/go/models.go | 9 + .../testdata/any/pgx/v4/go/query.sql.go | 36 + .../endtoend/testdata/any/pgx/v4/query.sql | 4 + .../endtoend/testdata/any/pgx/v4/schema.sql | 2 + .../endtoend/testdata/any/pgx/v4/sqlc.json | 13 + .../endtoend/testdata/any/pgx/v5/go/db.go | 32 + .../endtoend/testdata/any/pgx/v5/go/models.go | 9 + .../testdata/any/pgx/v5/go/query.sql.go | 36 + .../endtoend/testdata/any/pgx/v5/query.sql | 4 + .../endtoend/testdata/any/pgx/v5/schema.sql | 2 + .../endtoend/testdata/any/pgx/v5/sqlc.json | 13 + .../endtoend/testdata/any/stdlib/go/db.go | 31 + .../endtoend/testdata/any/stdlib/go/models.go | 9 + .../testdata/any/stdlib/go/query.sql.go | 41 + .../endtoend/testdata/any/stdlib/query.sql | 4 + .../endtoend/testdata/any/stdlib/schema.sql | 2 + .../endtoend/testdata/any/stdlib/sqlc.json | 11 + .../testdata/array_in/pgx/v4/go/db.go | 32 + .../testdata/array_in/pgx/v4/go/models.go | 9 + .../testdata/array_in/pgx/v4/go/query.sql.go | 41 + .../testdata/array_in/pgx/v4/query.sql | 4 + .../testdata/array_in/pgx/v4/schema.sql | 2 + .../testdata/array_in/pgx/v4/sqlc.json | 13 + .../testdata/array_in/pgx/v5/go/db.go | 32 + .../testdata/array_in/pgx/v5/go/models.go | 9 + .../testdata/array_in/pgx/v5/go/query.sql.go | 41 + .../testdata/array_in/pgx/v5/query.sql | 4 + .../testdata/array_in/pgx/v5/schema.sql | 2 + .../testdata/array_in/pgx/v5/sqlc.json | 13 + .../testdata/array_in/stdlib/go/db.go | 31 + .../testdata/array_in/stdlib/go/models.go | 9 + .../testdata/array_in/stdlib/go/query.sql.go | 44 + .../testdata/array_in/stdlib/query.sql | 4 + .../testdata/array_in/stdlib/schema.sql | 2 + .../testdata/array_in/stdlib/sqlc.json | 11 + .../testdata/array_text/pgx/v4/go/db.go | 32 + .../testdata/array_text/pgx/v4/go/models.go | 9 + .../array_text/pgx/v4/go/query.sql.go | 34 + .../testdata/array_text/pgx/v4/query.sql | 2 + .../testdata/array_text/pgx/v4/schema.sql | 2 + .../testdata/array_text/pgx/v4/sqlc.json | 13 + .../testdata/array_text/pgx/v5/go/db.go | 32 + .../testdata/array_text/pgx/v5/go/models.go | 9 + .../array_text/pgx/v5/go/query.sql.go | 34 + .../testdata/array_text/pgx/v5/query.sql | 2 + .../testdata/array_text/pgx/v5/schema.sql | 2 + .../testdata/array_text/pgx/v5/sqlc.json | 13 + .../testdata/array_text/stdlib/go/db.go | 31 + .../testdata/array_text/stdlib/go/models.go | 9 + .../array_text/stdlib/go/query.sql.go | 39 + .../testdata/array_text/stdlib/query.sql | 2 + .../testdata/array_text/stdlib/schema.sql | 2 + .../testdata/array_text/stdlib/sqlc.json | 11 + .../testdata/array_text_join/pgx/v4/go/db.go | 32 + .../array_text_join/pgx/v4/go/models.go | 15 + .../array_text_join/pgx/v4/go/query.sql.go | 36 + .../testdata/array_text_join/pgx/v4/query.sql | 4 + .../array_text_join/pgx/v4/schema.sql | 3 + .../testdata/array_text_join/pgx/v4/sqlc.json | 13 + .../testdata/array_text_join/pgx/v5/go/db.go | 32 + .../array_text_join/pgx/v5/go/models.go | 15 + .../array_text_join/pgx/v5/go/query.sql.go | 36 + .../testdata/array_text_join/pgx/v5/query.sql | 4 + .../array_text_join/pgx/v5/schema.sql | 3 + .../testdata/array_text_join/pgx/v5/sqlc.json | 13 + .../testdata/array_text_join/stdlib/go/db.go | 31 + .../array_text_join/stdlib/go/models.go | 15 + .../array_text_join/stdlib/go/query.sql.go | 41 + .../testdata/array_text_join/stdlib/query.sql | 4 + .../array_text_join/stdlib/schema.sql | 3 + .../testdata/array_text_join/stdlib/sqlc.json | 11 + .../testdata/bad_config/engine/query.sql | 2 + .../testdata/bad_config/engine/sqlc.yaml | 8 + .../testdata/bad_config/engine/stderr.txt | 1 + .../batch/postgresql/pgx/v4/go/batch.go | 180 + .../testdata/batch/postgresql/pgx/v4/go/db.go | 33 + .../batch/postgresql/pgx/v4/go/models.go | 14 + .../batch/postgresql/pgx/v4/go/query.sql.go | 6 + .../batch/postgresql/pgx/v4/query.sql | 12 + .../batch/postgresql/pgx/v4/schema.sql | 3 + .../batch/postgresql/pgx/v4/sqlc.json | 13 + .../batch/postgresql/pgx/v5/go/batch.go | 180 + .../testdata/batch/postgresql/pgx/v5/go/db.go | 33 + .../batch/postgresql/pgx/v5/go/models.go | 14 + .../batch/postgresql/pgx/v5/go/query.sql.go | 6 + .../batch/postgresql/pgx/v5/query.sql | 12 + .../batch/postgresql/pgx/v5/schema.sql | 3 + .../batch/postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/pgx/v4/go/batch.go | 131 + .../batch_imports/postgresql/pgx/v4/go/db.go | 33 + .../postgresql/pgx/v4/go/models.go | 14 + .../postgresql/pgx/v4/go/query.sql.go | 25 + .../batch_imports/postgresql/pgx/v4/query.sql | 12 + .../postgresql/pgx/v4/schema.sql | 3 + .../batch_imports/postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/batch.go | 131 + .../batch_imports/postgresql/pgx/v5/go/db.go | 33 + .../postgresql/pgx/v5/go/models.go | 14 + .../postgresql/pgx/v5/go/query.sql.go | 26 + .../batch_imports/postgresql/pgx/v5/query.sql | 12 + .../postgresql/pgx/v5/schema.sql | 3 + .../batch_imports/postgresql/pgx/v5/sqlc.json | 13 + .../testdata/batch_parameter_limit/issue.md | 1 + .../postgresql/pgx/go/batch.go | 71 + .../postgresql/pgx/go/db.go | 33 + .../postgresql/pgx/go/models.go | 15 + .../postgresql/pgx/go/query.sql.go | 6 + .../postgresql/pgx/query.sql | 6 + .../postgresql/pgx/schema.sql | 5 + .../postgresql/pgx/sqlc.yaml | 11 + .../testdata/batch_parameter_type/issue.md | 1 + .../postgresql/pgx/exec.json | 3 + .../postgresql/pgx/go/batch.go | 101 + .../postgresql/pgx/go/db.go | 33 + .../postgresql/pgx/go/models.go | 18 + .../postgresql/pgx/go/query.sql.go | 6 + .../postgresql/pgx/query.sql | 32 + .../postgresql/pgx/schema.sql | 14 + .../postgresql/pgx/sqlc.yaml | 10 + .../testdata/between_args/mysql/go/db.go | 31 + .../testdata/between_args/mysql/go/models.go | 11 + .../between_args/mysql/go/query.sql.go | 146 + .../testdata/between_args/mysql/query.sql | 19 + .../testdata/between_args/mysql/schema.sql | 7 + .../testdata/between_args/mysql/sqlc.json | 12 + .../testdata/between_args/sqlite/go/db.go | 31 + .../testdata/between_args/sqlite/go/models.go | 10 + .../between_args/sqlite/go/query.sql.go | 112 + .../testdata/between_args/sqlite/query.sql | 14 + .../testdata/between_args/sqlite/schema.sql | 5 + .../testdata/between_args/sqlite/sqlc.json | 12 + .../testdata/bit_string/pgx/v4/go/db.go | 32 + .../testdata/bit_string/pgx/v4/go/models.go | 16 + .../bit_string/pgx/v4/go/query.sql.go | 40 + .../testdata/bit_string/pgx/v4/query.sql | 3 + .../testdata/bit_string/pgx/v4/schema.sql | 8 + .../testdata/bit_string/pgx/v4/sqlc.json | 13 + .../testdata/bit_string/pgx/v5/go/db.go | 32 + .../testdata/bit_string/pgx/v5/go/models.go | 16 + .../bit_string/pgx/v5/go/query.sql.go | 40 + .../testdata/bit_string/pgx/v5/query.sql | 3 + .../testdata/bit_string/pgx/v5/schema.sql | 8 + .../testdata/bit_string/pgx/v5/sqlc.json | 13 + .../build_tags/postgresql/stdlib/go/db.go | 33 + .../build_tags/postgresql/stdlib/go/models.go | 17 + .../postgresql/stdlib/go/querier.go | 20 + .../postgresql/stdlib/go/query.sql.go | 84 + .../build_tags/postgresql/stdlib/query.sql | 19 + .../build_tags/postgresql/stdlib/schema.sql | 5 + .../build_tags/postgresql/stdlib/sqlc.json | 15 + .../testdata/builtins/postgresql/exec.json | 3 + .../testdata/builtins/postgresql/go/db.go | 31 + .../testdata/builtins/postgresql/go/models.go | 5 + .../builtins/postgresql/go/query.sql.go | 274 ++ .../testdata/builtins/postgresql/query.sql | 48 + .../testdata/builtins/postgresql/schema.sql | 2 + .../testdata/builtins/postgresql/sqlc.json | 11 + .../builtins/sqlite/go/aggfunc.sql.go | 165 + .../testdata/builtins/sqlite/go/db.go | 31 + .../builtins/sqlite/go/mathfunc.sql.go | 329 ++ .../testdata/builtins/sqlite/go/models.go | 11 + .../builtins/sqlite/go/scalarfunc.sql.go | 561 +++ .../builtins/sqlite/queries/aggfunc.sql | 41 + .../builtins/sqlite/queries/mathfunc.sql | 86 + .../builtins/sqlite/queries/scalarfunc.sql | 149 + .../testdata/builtins/sqlite/schema.sql | 6 + .../testdata/builtins/sqlite/sqlc.json | 12 + .../testdata/case_named_params/mysql/go/db.go | 31 + .../case_named_params/mysql/go/models.go | 17 + .../case_named_params/mysql/go/query.sql.go | 42 + .../case_named_params/mysql/query.sql | 6 + .../case_named_params/mysql/schema.sql | 12 + .../case_named_params/mysql/sqlc.json | 12 + .../case_named_params/postgresql/go/db.go | 31 + .../case_named_params/postgresql/go/models.go | 17 + .../postgresql/go/query.sql.go | 36 + .../case_named_params/postgresql/query.sql | 6 + .../case_named_params/postgresql/schema.sql | 10 + .../case_named_params/postgresql/sqlc.json | 12 + .../case_named_params/sqlite/go/db.go | 31 + .../case_named_params/sqlite/go/models.go | 17 + .../case_named_params/sqlite/go/query.sql.go | 36 + .../case_named_params/sqlite/query.sql | 6 + .../case_named_params/sqlite/schema.sql | 8 + .../case_named_params/sqlite/sqlc.json | 12 + .../testdata/case_sensitive/sqlite/go/db.go | 31 + .../case_sensitive/sqlite/go/models.go | 14 + .../case_sensitive/sqlite/go/query.sql.go | 29 + .../testdata/case_sensitive/sqlite/query.sql | 6 + .../testdata/case_sensitive/sqlite/schema.sql | 5 + .../testdata/case_sensitive/sqlite/sqlc.json | 1 + .../testdata/case_stmt_bool/pgx/v4/go/db.go | 32 + .../case_stmt_bool/pgx/v4/go/models.go | 9 + .../case_stmt_bool/pgx/v4/go/query.sql.go | 38 + .../testdata/case_stmt_bool/pgx/v4/query.sql | 6 + .../testdata/case_stmt_bool/pgx/v4/schema.sql | 2 + .../testdata/case_stmt_bool/pgx/v4/sqlc.json | 13 + .../testdata/case_stmt_bool/pgx/v5/go/db.go | 32 + .../case_stmt_bool/pgx/v5/go/models.go | 9 + .../case_stmt_bool/pgx/v5/go/query.sql.go | 38 + .../testdata/case_stmt_bool/pgx/v5/query.sql | 6 + .../testdata/case_stmt_bool/pgx/v5/schema.sql | 2 + .../testdata/case_stmt_bool/pgx/v5/sqlc.json | 13 + .../testdata/case_stmt_bool/stdlib/go/db.go | 31 + .../case_stmt_bool/stdlib/go/models.go | 9 + .../case_stmt_bool/stdlib/go/query.sql.go | 41 + .../testdata/case_stmt_bool/stdlib/query.sql | 6 + .../testdata/case_stmt_bool/stdlib/schema.sql | 2 + .../testdata/case_stmt_bool/stdlib/sqlc.json | 11 + .../testdata/case_text/pgx/v4/go/db.go | 32 + .../testdata/case_text/pgx/v4/go/models.go | 9 + .../testdata/case_text/pgx/v4/go/query.sql.go | 38 + .../testdata/case_text/pgx/v4/query.sql | 6 + .../testdata/case_text/pgx/v4/schema.sql | 2 + .../testdata/case_text/pgx/v4/sqlc.json | 13 + .../testdata/case_text/pgx/v5/go/db.go | 32 + .../testdata/case_text/pgx/v5/go/models.go | 9 + .../testdata/case_text/pgx/v5/go/query.sql.go | 38 + .../testdata/case_text/pgx/v5/query.sql | 6 + .../testdata/case_text/pgx/v5/schema.sql | 2 + .../testdata/case_text/pgx/v5/sqlc.json | 13 + .../testdata/case_text/stdlib/go/db.go | 31 + .../testdata/case_text/stdlib/go/models.go | 9 + .../testdata/case_text/stdlib/go/query.sql.go | 41 + .../testdata/case_text/stdlib/query.sql | 6 + .../testdata/case_text/stdlib/schema.sql | 2 + .../testdata/case_text/stdlib/sqlc.json | 11 + .../testdata/case_value_param/issue.md | 1 + .../testdata/case_value_param/mysql/go/db.go | 31 + .../case_value_param/mysql/go/models.go | 14 + .../case_value_param/mysql/go/query.sql.go | 21 + .../testdata/case_value_param/mysql/query.sql | 3 + .../case_value_param/mysql/schema.sql | 4 + .../testdata/case_value_param/mysql/sqlc.yaml | 9 + .../case_value_param/postgresql/exec.json | 3 + .../case_value_param/postgresql/go/db.go | 32 + .../case_value_param/postgresql/go/models.go | 14 + .../postgresql/go/query.sql.go | 22 + .../case_value_param/postgresql/query.sql | 3 + .../case_value_param/postgresql/schema.sql | 4 + .../case_value_param/postgresql/sqlc.yaml | 10 + .../testdata/cast_coalesce/pgx/v4/go/db.go | 32 + .../cast_coalesce/pgx/v4/go/models.go | 13 + .../cast_coalesce/pgx/v4/go/query.sql.go | 35 + .../testdata/cast_coalesce/pgx/v4/query.sql | 3 + .../testdata/cast_coalesce/pgx/v4/schema.sql | 2 + .../testdata/cast_coalesce/pgx/v4/sqlc.json | 13 + .../testdata/cast_coalesce/pgx/v5/go/db.go | 32 + .../cast_coalesce/pgx/v5/go/models.go | 13 + .../cast_coalesce/pgx/v5/go/query.sql.go | 35 + .../testdata/cast_coalesce/pgx/v5/query.sql | 3 + .../testdata/cast_coalesce/pgx/v5/schema.sql | 2 + .../testdata/cast_coalesce/pgx/v5/sqlc.json | 13 + .../testdata/cast_coalesce/stdlib/go/db.go | 31 + .../cast_coalesce/stdlib/go/models.go | 13 + .../cast_coalesce/stdlib/go/query.sql.go | 38 + .../testdata/cast_coalesce/stdlib/query.sql | 3 + .../testdata/cast_coalesce/stdlib/schema.sql | 2 + .../testdata/cast_coalesce/stdlib/sqlc.json | 11 + .../testdata/cast_null/pgx/v4/go/db.go | 32 + .../testdata/cast_null/pgx/v4/go/models.go | 13 + .../testdata/cast_null/pgx/v4/go/query.sql.go | 52 + .../testdata/cast_null/pgx/v4/query.sql | 7 + .../testdata/cast_null/pgx/v4/schema.sql | 2 + .../testdata/cast_null/pgx/v4/sqlc.json | 13 + .../testdata/cast_null/pgx/v5/go/db.go | 32 + .../testdata/cast_null/pgx/v5/go/models.go | 13 + .../testdata/cast_null/pgx/v5/go/query.sql.go | 53 + .../testdata/cast_null/pgx/v5/query.sql | 7 + .../testdata/cast_null/pgx/v5/schema.sql | 2 + .../testdata/cast_null/pgx/v5/sqlc.json | 13 + .../testdata/cast_null/stdlib/go/db.go | 31 + .../testdata/cast_null/stdlib/go/models.go | 13 + .../testdata/cast_null/stdlib/go/query.sql.go | 55 + .../testdata/cast_null/stdlib/query.sql | 7 + .../testdata/cast_null/stdlib/schema.sql | 2 + .../testdata/cast_null/stdlib/sqlc.json | 11 + .../testdata/cast_param/sqlite/go/db.go | 31 + .../testdata/cast_param/sqlite/go/models.go | 14 + .../cast_param/sqlite/go/query.sql.go | 39 + .../testdata/cast_param/sqlite/query.sql | 4 + .../testdata/cast_param/sqlite/schema.sql | 6 + .../testdata/cast_param/sqlite/sqlc.json | 12 + .../testdata/cid_oid_tid_xid/pgx/v4/go/db.go | 32 + .../cid_oid_tid_xid/pgx/v4/go/models.go | 20 + .../cid_oid_tid_xid/pgx/v4/go/query.sql.go | 44 + .../testdata/cid_oid_tid_xid/pgx/v4/query.sql | 3 + .../cid_oid_tid_xid/pgx/v4/schema.sql | 12 + .../testdata/cid_oid_tid_xid/pgx/v4/sqlc.json | 13 + .../testdata/cid_oid_tid_xid/pgx/v5/go/db.go | 32 + .../cid_oid_tid_xid/pgx/v5/go/models.go | 22 + .../cid_oid_tid_xid/pgx/v5/go/query.sql.go | 46 + .../testdata/cid_oid_tid_xid/pgx/v5/query.sql | 3 + .../cid_oid_tid_xid/pgx/v5/schema.sql | 14 + .../testdata/cid_oid_tid_xid/pgx/v5/sqlc.json | 13 + .../endtoend/testdata/citext/pgx/go/db.go | 32 + .../endtoend/testdata/citext/pgx/go/models.go | 14 + .../testdata/citext/pgx/go/query.sql.go | 35 + .../endtoend/testdata/citext/pgx/query.sql | 3 + .../endtoend/testdata/citext/pgx/schema.sql | 7 + .../endtoend/testdata/citext/pgx/sqlc.json | 13 + .../endtoend/testdata/citext/stdlib/go/db.go | 31 + .../testdata/citext/stdlib/go/models.go | 14 + .../testdata/citext/stdlib/go/query.sql.go | 38 + .../endtoend/testdata/citext/stdlib/query.sql | 5 + .../testdata/citext/stdlib/schema.sql | 7 + .../endtoend/testdata/citext/stdlib/sqlc.json | 12 + .../endtoend/testdata/coalesce/mysql/go/db.go | 31 + .../testdata/coalesce/mysql/go/models.go | 14 + .../testdata/coalesce/mysql/go/query.sql.go | 73 + .../testdata/coalesce/mysql/query.sql | 7 + .../testdata/coalesce/mysql/schema.sql | 2 + .../testdata/coalesce/mysql/sqlc.json | 12 + .../coalesce/postgresql/pgx/v4/go/db.go | 32 + .../coalesce/postgresql/pgx/v4/go/models.go | 16 + .../postgresql/pgx/v4/go/query.sql.go | 183 + .../coalesce/postgresql/pgx/v4/query.sql | 23 + .../coalesce/postgresql/pgx/v4/schema.sql | 7 + .../coalesce/postgresql/pgx/v4/sqlc.json | 13 + .../coalesce/postgresql/pgx/v5/go/db.go | 32 + .../coalesce/postgresql/pgx/v5/go/models.go | 16 + .../postgresql/pgx/v5/go/query.sql.go | 184 + .../coalesce/postgresql/pgx/v5/query.sql | 23 + .../coalesce/postgresql/pgx/v5/schema.sql | 7 + .../coalesce/postgresql/pgx/v5/sqlc.json | 13 + .../coalesce/postgresql/stdlib/go/db.go | 31 + .../coalesce/postgresql/stdlib/go/models.go | 16 + .../postgresql/stdlib/go/query.sql.go | 201 + .../coalesce/postgresql/stdlib/query.sql | 23 + .../coalesce/postgresql/stdlib/schema.sql | 7 + .../coalesce/postgresql/stdlib/sqlc.json | 12 + .../testdata/coalesce/sqlite/go/db.go | 31 + .../testdata/coalesce/sqlite/go/models.go | 14 + .../testdata/coalesce/sqlite/go/query.sql.go | 73 + .../testdata/coalesce/sqlite/query.sql | 7 + .../testdata/coalesce/sqlite/schema.sql | 2 + .../testdata/coalesce/sqlite/sqlc.json | 12 + .../testdata/coalesce_as/mysql/go/db.go | 31 + .../testdata/coalesce_as/mysql/go/models.go | 14 + .../coalesce_as/mysql/go/query.sql.go | 45 + .../testdata/coalesce_as/mysql/query.sql | 4 + .../testdata/coalesce_as/mysql/schema.sql | 5 + .../testdata/coalesce_as/mysql/sqlc.json | 12 + .../postgresql/pganalyze/exec.json | 3 + .../coalesce_as/postgresql/pganalyze/go/db.go | 32 + .../postgresql/pganalyze/go/models.go | 14 + .../postgresql/pganalyze/go/query.sql.go | 43 + .../postgresql/pganalyze/query.sql | 4 + .../postgresql/pganalyze/schema.sql | 5 + .../postgresql/pganalyze/sqlc.json | 19 + .../coalesce_as/postgresql/pgx/v4/exec.json | 3 + .../coalesce_as/postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 14 + .../postgresql/pgx/v4/go/query.sql.go | 42 + .../coalesce_as/postgresql/pgx/v4/query.sql | 4 + .../coalesce_as/postgresql/pgx/v4/schema.sql | 5 + .../coalesce_as/postgresql/pgx/v4/sqlc.json | 13 + .../coalesce_as/postgresql/pgx/v5/exec.json | 3 + .../coalesce_as/postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 14 + .../postgresql/pgx/v5/go/query.sql.go | 43 + .../coalesce_as/postgresql/pgx/v5/query.sql | 4 + .../coalesce_as/postgresql/pgx/v5/schema.sql | 5 + .../coalesce_as/postgresql/pgx/v5/sqlc.json | 13 + .../coalesce_as/postgresql/stdlib/exec.json | 3 + .../coalesce_as/postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 14 + .../postgresql/stdlib/go/query.sql.go | 45 + .../coalesce_as/postgresql/stdlib/query.sql | 4 + .../coalesce_as/postgresql/stdlib/schema.sql | 5 + .../coalesce_as/postgresql/stdlib/sqlc.json | 12 + .../testdata/coalesce_as/sqlite/go/db.go | 31 + .../testdata/coalesce_as/sqlite/go/models.go | 14 + .../coalesce_as/sqlite/go/query.sql.go | 45 + .../testdata/coalesce_as/sqlite/query.sql | 4 + .../testdata/coalesce_as/sqlite/schema.sql | 5 + .../testdata/coalesce_as/sqlite/sqlc.json | 12 + .../coalesce_join/postgresql/go/db.go | 31 + .../coalesce_join/postgresql/go/models.go | 13 + .../coalesce_join/postgresql/go/query.sql.go | 44 + .../coalesce_join/postgresql/query.sql | 4 + .../coalesce_join/postgresql/schema.sql | 3 + .../coalesce_join/postgresql/sqlc.json | 12 + .../testdata/coalesce_params/issue.md | 2 + .../testdata/coalesce_params/mysql/exec.json | 6 + .../testdata/coalesce_params/mysql/go/db.go | 31 + .../coalesce_params/mysql/go/models.go | 87 + .../coalesce_params/mysql/go/query.sql.go | 57 + .../testdata/coalesce_params/mysql/query.sql | 17 + .../testdata/coalesce_params/mysql/schema.sql | 43 + .../testdata/coalesce_params/mysql/sqlc.yaml | 9 + .../endtoend/testdata/codegen_json/exec.json | 3 + .../codegen_json/postgresql/query.sql | 19 + .../codegen_json/postgresql/schema.sql | 5 + .../endtoend/testdata/codegen_json/sqlc.json | 17 + .../stdlib/README.md | 1 + .../stdlib/go/db.go | 31 + .../stdlib/go/models.go | 15 + .../stdlib/go/query.sql.go | 21 + .../stdlib/query.sql | 2 + .../stdlib/schema.sql | 5 + .../stdlib/sqlc.json | 11 + .../endtoend/testdata/column_alias/issue.md | 1 + .../testdata/column_alias/stdlib/exec.json | 3 + .../testdata/column_alias/stdlib/go/db.go | 31 + .../testdata/column_alias/stdlib/go/models.go | 18 + .../column_alias/stdlib/go/query.sql.go | 80 + .../testdata/column_alias/stdlib/query.sql | 21 + .../testdata/column_alias/stdlib/schema.sql | 12 + .../testdata/column_alias/stdlib/sqlc.yaml | 10 + .../testdata/column_as/mysql/go/db.go | 31 + .../testdata/column_as/mysql/go/models.go | 5 + .../testdata/column_as/mysql/go/query.sql.go | 42 + .../testdata/column_as/mysql/query.sql | 5 + .../testdata/column_as/mysql/schema.sql | 0 .../testdata/column_as/mysql/sqlc.json | 12 + .../column_as/postgresql/pgx/v4/go/db.go | 32 + .../column_as/postgresql/pgx/v4/go/models.go | 5 + .../postgresql/pgx/v4/go/query.sql.go | 42 + .../column_as/postgresql/pgx/v4/query.sql | 5 + .../column_as/postgresql/pgx/v4/schema.sql | 0 .../column_as/postgresql/pgx/v4/sqlc.json | 13 + .../column_as/postgresql/pgx/v5/go/db.go | 32 + .../column_as/postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 42 + .../column_as/postgresql/pgx/v5/query.sql | 5 + .../column_as/postgresql/pgx/v5/schema.sql | 0 .../column_as/postgresql/pgx/v5/sqlc.json | 13 + .../column_as/postgresql/stdlib/go/db.go | 31 + .../column_as/postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/query.sql.go | 42 + .../column_as/postgresql/stdlib/query.sql | 5 + .../column_as/postgresql/stdlib/schema.sql | 0 .../column_as/postgresql/stdlib/sqlc.json | 12 + .../testdata/column_as/sqlite/go/db.go | 31 + .../testdata/column_as/sqlite/go/models.go | 5 + .../testdata/column_as/sqlite/go/query.sql.go | 42 + .../testdata/column_as/sqlite/query.sql | 5 + .../testdata/column_as/sqlite/schema.sql | 0 .../testdata/column_as/sqlite/sqlc.json | 12 + .../comment_godoc/postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 13 + .../postgresql/pgx/v4/go/query.sql.go | 82 + .../comment_godoc/postgresql/pgx/v4/query.sql | 19 + .../postgresql/pgx/v4/schema.sql | 4 + .../comment_godoc/postgresql/pgx/v4/sqlc.json | 14 + .../comment_godoc/postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 13 + .../postgresql/pgx/v5/go/query.sql.go | 82 + .../comment_godoc/postgresql/pgx/v5/query.sql | 19 + .../postgresql/pgx/v5/schema.sql | 4 + .../comment_godoc/postgresql/pgx/v5/sqlc.json | 14 + .../postgresql/pgx/v4/go/db.go | 25 + .../postgresql/pgx/v4/go/models.go | 13 + .../postgresql/pgx/v4/go/query.sql.go | 82 + .../postgresql/pgx/v4/query.sql | 19 + .../postgresql/pgx/v4/schema.sql | 4 + .../postgresql/pgx/v4/sqlc.json | 14 + .../postgresql/pgx/v5/go/db.go | 25 + .../postgresql/pgx/v5/go/models.go | 13 + .../postgresql/pgx/v5/go/query.sql.go | 82 + .../postgresql/pgx/v5/query.sql | 19 + .../postgresql/pgx/v5/schema.sql | 4 + .../postgresql/pgx/v5/sqlc.json | 14 + .../comment_on/postgresql/pgx/v4/go/db.go | 32 + .../comment_on/postgresql/pgx/v4/go/models.go | 65 + .../postgresql/pgx/v4/go/query.sql.go | 58 + .../comment_on/postgresql/pgx/v4/query.sql | 5 + .../comment_on/postgresql/pgx/v4/schema.sql | 16 + .../comment_on/postgresql/pgx/v4/sqlc.json | 13 + .../comment_on/postgresql/pgx/v5/go/db.go | 32 + .../comment_on/postgresql/pgx/v5/go/models.go | 65 + .../postgresql/pgx/v5/go/query.sql.go | 58 + .../comment_on/postgresql/pgx/v5/query.sql | 5 + .../comment_on/postgresql/pgx/v5/schema.sql | 16 + .../comment_on/postgresql/pgx/v5/sqlc.json | 13 + .../comment_on/postgresql/stdlib/go/db.go | 31 + .../comment_on/postgresql/stdlib/go/models.go | 65 + .../postgresql/stdlib/go/query.sql.go | 64 + .../comment_on/postgresql/stdlib/query.sql | 5 + .../comment_on/postgresql/stdlib/schema.sql | 16 + .../comment_on/postgresql/stdlib/sqlc.json | 12 + .../testdata/comment_syntax/mysql/go/db.go | 31 + .../comment_syntax/mysql/go/models.go | 13 + .../comment_syntax/mysql/go/query.sql.go | 44 + .../testdata/comment_syntax/mysql/query.sql | 8 + .../testdata/comment_syntax/mysql/schema.sql | 2 + .../testdata/comment_syntax/mysql/sqlc.json | 12 + .../comment_syntax/postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 13 + .../postgresql/pgx/v4/go/query.sql.go | 33 + .../postgresql/pgx/v4/query.sql | 5 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../comment_syntax/postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 13 + .../postgresql/pgx/v5/go/query.sql.go | 34 + .../postgresql/pgx/v5/query.sql | 5 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../comment_syntax/postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 13 + .../postgresql/stdlib/go/query.sql.go | 33 + .../postgresql/stdlib/query.sql | 5 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../testdata/comment_syntax/sqlite/go/db.go | 31 + .../comment_syntax/sqlite/go/models.go | 13 + .../comment_syntax/sqlite/go/query.sql.go | 33 + .../testdata/comment_syntax/sqlite/query.sql | 5 + .../testdata/comment_syntax/sqlite/schema.sql | 2 + .../testdata/comment_syntax/sqlite/sqlc.json | 12 + .../testdata/comparisons/mysql/go/db.go | 31 + .../testdata/comparisons/mysql/go/models.go | 9 + .../comparisons/mysql/go/query.sql.go | 253 ++ .../testdata/comparisons/mysql/query.sql | 26 + .../testdata/comparisons/mysql/schema.sql | 5 + .../testdata/comparisons/mysql/sqlc.json | 12 + .../comparisons/postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 9 + .../postgresql/pgx/v4/go/query.sql.go | 178 + .../comparisons/postgresql/pgx/v4/query.sql | 26 + .../comparisons/postgresql/pgx/v4/schema.sql | 5 + .../comparisons/postgresql/pgx/v4/sqlc.json | 13 + .../comparisons/postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 9 + .../postgresql/pgx/v5/go/query.sql.go | 178 + .../comparisons/postgresql/pgx/v5/query.sql | 26 + .../comparisons/postgresql/pgx/v5/schema.sql | 5 + .../comparisons/postgresql/pgx/v5/sqlc.json | 13 + .../comparisons/postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 9 + .../postgresql/stdlib/go/query.sql.go | 199 + .../comparisons/postgresql/stdlib/query.sql | 26 + .../comparisons/postgresql/stdlib/schema.sql | 5 + .../comparisons/postgresql/stdlib/sqlc.json | 12 + .../testdata/comparisons/sqlite/go/db.go | 31 + .../testdata/comparisons/sqlite/go/models.go | 9 + .../comparisons/sqlite/go/query.sql.go | 199 + .../testdata/comparisons/sqlite/query.sql | 20 + .../testdata/comparisons/sqlite/schema.sql | 5 + .../testdata/comparisons/sqlite/sqlc.json | 12 + .../testdata/composite_type/pgx/v4/go/db.go | 32 + .../composite_type/pgx/v4/go/models.go | 14 + .../composite_type/pgx/v4/go/query.sql.go | 34 + .../testdata/composite_type/pgx/v4/query.sql | 2 + .../testdata/composite_type/pgx/v4/schema.sql | 17 + .../testdata/composite_type/pgx/v4/sqlc.json | 13 + .../testdata/composite_type/pgx/v5/go/db.go | 32 + .../composite_type/pgx/v5/go/models.go | 14 + .../composite_type/pgx/v5/go/query.sql.go | 34 + .../testdata/composite_type/pgx/v5/query.sql | 2 + .../testdata/composite_type/pgx/v5/schema.sql | 17 + .../testdata/composite_type/pgx/v5/sqlc.json | 13 + .../testdata/composite_type/stdlib/go/db.go | 31 + .../composite_type/stdlib/go/models.go | 14 + .../composite_type/stdlib/go/query.sql.go | 37 + .../testdata/composite_type/stdlib/query.sql | 2 + .../testdata/composite_type/stdlib/schema.sql | 17 + .../testdata/composite_type/stdlib/sqlc.json | 11 + .../conflicted_arg_name/postgresql/db/db.go | 31 + .../postgresql/db/models.go | 18 + .../postgresql/db/query.sql.go | 35 + .../conflicted_arg_name/postgresql/query.sql | 5 + .../conflicted_arg_name/postgresql/schema.sql | 7 + .../conflicted_arg_name/postgresql/sqlc.json | 11 + .../testdata/copyfrom/mysql/go/copyfrom.go | 88 + .../endtoend/testdata/copyfrom/mysql/go/db.go | 31 + .../testdata/copyfrom/mysql/go/models.go | 16 + .../testdata/copyfrom/mysql/go/query.sql.go | 25 + .../testdata/copyfrom/mysql/query.sql | 5 + .../testdata/copyfrom/mysql/schema.sql | 2 + .../testdata/copyfrom/mysql/sqlc.json | 14 + .../copyfrom/postgresql/pgx/v4/go/copyfrom.go | 78 + .../copyfrom/postgresql/pgx/v4/go/db.go | 33 + .../copyfrom/postgresql/pgx/v4/go/models.go | 14 + .../copyfrom/postgresql/pgx/v4/go/querier.go | 19 + .../postgresql/pgx/v4/go/query.sql.go | 15 + .../copyfrom/postgresql/pgx/v4/query.sql | 7 + .../copyfrom/postgresql/pgx/v4/schema.sql | 3 + .../copyfrom/postgresql/pgx/v4/sqlc.json | 14 + .../copyfrom/postgresql/pgx/v5/go/copyfrom.go | 79 + .../copyfrom/postgresql/pgx/v5/go/db.go | 33 + .../copyfrom/postgresql/pgx/v5/go/models.go | 14 + .../copyfrom/postgresql/pgx/v5/go/querier.go | 20 + .../postgresql/pgx/v5/go/query.sql.go | 15 + .../copyfrom/postgresql/pgx/v5/query.sql | 7 + .../copyfrom/postgresql/pgx/v5/schema.sql | 3 + .../copyfrom/postgresql/pgx/v5/sqlc.json | 14 + .../postgresql/pgx/v4/go/copyfrom.go | 43 + .../postgresql/pgx/v4/go/db.go | 33 + .../postgresql/pgx/v4/go/models.go | 14 + .../postgresql/pgx/v4/go/query.sql.go | 36 + .../postgresql/pgx/v4/query.sql | 9 + .../postgresql/pgx/v4/schema.sql | 3 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/copyfrom.go | 43 + .../postgresql/pgx/v5/go/db.go | 33 + .../postgresql/pgx/v5/go/models.go | 14 + .../postgresql/pgx/v5/go/query.sql.go | 36 + .../postgresql/pgx/v5/query.sql | 9 + .../postgresql/pgx/v5/schema.sql | 3 + .../postgresql/pgx/v5/sqlc.json | 13 + .../mysql/go/copyfrom.go | 51 + .../mysql/go/db.go | 31 + .../mysql/go/models.go | 14 + .../mysql/go/query.sql.go | 19 + .../mysql/query.sql | 2 + .../mysql/schema.sql | 1 + .../mysql/sqlc.json | 15 + .../testdata/copyfrom_named_params/issue.md | 1 + .../postgresql/pgx/go/copyfrom.go | 43 + .../postgresql/pgx/go/db.go | 33 + .../postgresql/pgx/go/models.go | 10 + .../postgresql/pgx/go/query.sql.go | 11 + .../postgresql/pgx/query.sql | 6 + .../postgresql/pgx/schema.sql | 5 + .../postgresql/pgx/sqlc.yaml | 10 + .../postgresql/pgx/v4/go/copyfrom.go | 42 + .../postgresql/pgx/v4/go/db.go | 33 + .../postgresql/pgx/v4/go/models.go | 9 + .../postgresql/pgx/v4/go/querier.go | 15 + .../postgresql/pgx/v4/go/query.sql.go | 6 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 4 + .../postgresql/pgx/v4/sqlc.json | 14 + .../postgresql/pgx/v5/go/copyfrom.go | 42 + .../postgresql/pgx/v5/go/db.go | 33 + .../postgresql/pgx/v5/go/models.go | 9 + .../postgresql/pgx/v5/go/querier.go | 15 + .../postgresql/pgx/v5/go/query.sql.go | 6 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 4 + .../postgresql/pgx/v5/sqlc.json | 14 + .../issue.md | 1 + .../mysql/go/copyfrom.go | 50 + .../mysql/go/db.go | 31 + .../mysql/go/models.go | 13 + .../mysql/go/query.sql.go | 18 + .../mysql/query.sql | 2 + .../mysql/schema.sql | 1 + .../mysql/sqlc.json | 15 + .../testdata/count_star/mysql/go/db.go | 31 + .../testdata/count_star/mysql/go/models.go | 9 + .../testdata/count_star/mysql/go/query.sql.go | 32 + .../testdata/count_star/mysql/query.sql | 5 + .../testdata/count_star/mysql/schema.sql | 2 + .../testdata/count_star/mysql/sqlc.json | 12 + .../count_star/postgresql/pgx/v4/go/db.go | 32 + .../count_star/postgresql/pgx/v4/go/models.go | 9 + .../postgresql/pgx/v4/go/query.sql.go | 32 + .../count_star/postgresql/pgx/v4/query.sql | 5 + .../count_star/postgresql/pgx/v4/schema.sql | 2 + .../count_star/postgresql/pgx/v4/sqlc.json | 13 + .../count_star/postgresql/pgx/v5/go/db.go | 32 + .../count_star/postgresql/pgx/v5/go/models.go | 9 + .../postgresql/pgx/v5/go/query.sql.go | 32 + .../count_star/postgresql/pgx/v5/query.sql | 5 + .../count_star/postgresql/pgx/v5/schema.sql | 2 + .../count_star/postgresql/pgx/v5/sqlc.json | 13 + .../count_star/postgresql/stdlib/go/db.go | 31 + .../count_star/postgresql/stdlib/go/models.go | 9 + .../postgresql/stdlib/go/query.sql.go | 32 + .../count_star/postgresql/stdlib/query.sql | 5 + .../count_star/postgresql/stdlib/schema.sql | 2 + .../count_star/postgresql/stdlib/sqlc.json | 12 + .../testdata/count_star/sqlite/go/db.go | 31 + .../testdata/count_star/sqlite/go/models.go | 9 + .../count_star/sqlite/go/query.sql.go | 32 + .../testdata/count_star/sqlite/query.sql | 5 + .../testdata/count_star/sqlite/schema.sql | 1 + .../testdata/count_star/sqlite/sqlc.json | 12 + .../postgresql/go/db.go | 31 + .../postgresql/go/models.go | 13 + .../postgresql/go/query.sql.go | 37 + .../postgresql/query.sql | 3 + .../postgresql/schema.sql | 3 + .../postgresql/sqlc.json | 12 + .../create_table_as/postgresql/go/db.go | 31 + .../create_table_as/postgresql/go/models.go | 13 + .../postgresql/go/query.sql.go | 37 + .../create_table_as/postgresql/query.sql | 3 + .../create_table_as/postgresql/schema.sql | 3 + .../create_table_as/postgresql/sqlc.json | 12 + .../testdata/create_table_like/mysql/go/db.go | 31 + .../create_table_like/mysql/go/models.go | 22 + .../create_table_like/mysql/go/query.sql.go | 42 + .../create_table_like/mysql/query.sql | 2 + .../create_table_like/mysql/schema.sql | 18 + .../create_table_like/mysql/sqlc.json | 12 + .../create_table_like/postgresql/go/db.go | 31 + .../create_table_like/postgresql/go/models.go | 22 + .../postgresql/go/query.sql.go | 42 + .../create_table_like/postgresql/query.sql | 2 + .../create_table_like/postgresql/schema.sql | 18 + .../create_table_like/postgresql/sqlc.json | 12 + .../testdata/create_view/mysql/go/db.go | 31 + .../testdata/create_view/mysql/go/models.go | 23 + .../create_view/mysql/go/query.sql.go | 64 + .../testdata/create_view/mysql/query.sql | 5 + .../testdata/create_view/mysql/schema.sql | 10 + .../testdata/create_view/mysql/sqlc.json | 12 + .../testdata/create_view/postgresql/go/db.go | 31 + .../create_view/postgresql/go/models.go | 23 + .../create_view/postgresql/go/query.sql.go | 65 + .../testdata/create_view/postgresql/query.sql | 5 + .../create_view/postgresql/schema.sql | 10 + .../testdata/create_view/postgresql/sqlc.json | 12 + .../testdata/create_view/sqlite/go/db.go | 31 + .../testdata/create_view/sqlite/go/models.go | 23 + .../create_view/sqlite/go/query.sql.go | 65 + .../testdata/create_view/sqlite/query.sql | 5 + .../testdata/create_view/sqlite/schema.sql | 11 + .../testdata/create_view/sqlite/sqlc.json | 12 + .../testdata/cte_count/mysql/go/db.go | 31 + .../testdata/cte_count/mysql/go/models.go | 9 + .../testdata/cte_count/mysql/go/query.sql.go | 48 + .../testdata/cte_count/mysql/query.sql | 8 + .../testdata/cte_count/mysql/schema.sql | 2 + .../testdata/cte_count/mysql/sqlc.json | 12 + .../testdata/cte_count/pgx/v4/go/db.go | 32 + .../testdata/cte_count/pgx/v4/go/models.go | 9 + .../testdata/cte_count/pgx/v4/go/query.sql.go | 45 + .../testdata/cte_count/pgx/v4/query.sql | 8 + .../testdata/cte_count/pgx/v4/schema.sql | 2 + .../testdata/cte_count/pgx/v4/sqlc.json | 13 + .../testdata/cte_count/pgx/v5/go/db.go | 32 + .../testdata/cte_count/pgx/v5/go/models.go | 9 + .../testdata/cte_count/pgx/v5/go/query.sql.go | 45 + .../testdata/cte_count/pgx/v5/query.sql | 8 + .../testdata/cte_count/pgx/v5/schema.sql | 2 + .../testdata/cte_count/pgx/v5/sqlc.json | 13 + .../testdata/cte_count/stdlib/go/db.go | 31 + .../testdata/cte_count/stdlib/go/models.go | 9 + .../testdata/cte_count/stdlib/go/query.sql.go | 48 + .../testdata/cte_count/stdlib/query.sql | 8 + .../testdata/cte_count/stdlib/schema.sql | 2 + .../testdata/cte_count/stdlib/sqlc.json | 11 + .../testdata/cte_filter/mysql/go/db.go | 31 + .../testdata/cte_filter/mysql/go/models.go | 9 + .../testdata/cte_filter/mysql/go/query.sql.go | 41 + .../testdata/cte_filter/mysql/query.sql | 6 + .../testdata/cte_filter/mysql/schema.sql | 2 + .../testdata/cte_filter/mysql/sqlc.json | 12 + .../testdata/cte_filter/pgx/v4/go/db.go | 32 + .../testdata/cte_filter/pgx/v4/go/models.go | 9 + .../cte_filter/pgx/v4/go/query.sql.go | 38 + .../testdata/cte_filter/pgx/v4/query.sql | 6 + .../testdata/cte_filter/pgx/v4/schema.sql | 2 + .../testdata/cte_filter/pgx/v4/sqlc.json | 13 + .../testdata/cte_filter/pgx/v5/go/db.go | 32 + .../testdata/cte_filter/pgx/v5/go/models.go | 9 + .../cte_filter/pgx/v5/go/query.sql.go | 38 + .../testdata/cte_filter/pgx/v5/query.sql | 6 + .../testdata/cte_filter/pgx/v5/schema.sql | 2 + .../testdata/cte_filter/pgx/v5/sqlc.json | 13 + .../testdata/cte_filter/stdlib/go/db.go | 31 + .../testdata/cte_filter/stdlib/go/models.go | 9 + .../cte_filter/stdlib/go/query.sql.go | 41 + .../testdata/cte_filter/stdlib/query.sql | 6 + .../testdata/cte_filter/stdlib/schema.sql | 2 + .../testdata/cte_filter/stdlib/sqlc.json | 11 + .../testdata/cte_in_delete/mysql/go/db.go | 31 + .../testdata/cte_in_delete/mysql/go/models.go | 10 + .../cte_in_delete/mysql/go/query.sql.go | 22 + .../testdata/cte_in_delete/mysql/query.sql | 5 + .../testdata/cte_in_delete/mysql/schema.sql | 2 + .../testdata/cte_in_delete/mysql/sqlc.json | 12 + .../testdata/cte_in_delete/pgx/v4/go/db.go | 32 + .../cte_in_delete/pgx/v4/go/models.go | 10 + .../cte_in_delete/pgx/v4/go/query.sql.go | 38 + .../testdata/cte_in_delete/pgx/v4/query.sql | 6 + .../testdata/cte_in_delete/pgx/v4/schema.sql | 2 + .../testdata/cte_in_delete/pgx/v4/sqlc.json | 13 + .../testdata/cte_in_delete/pgx/v5/go/db.go | 32 + .../cte_in_delete/pgx/v5/go/models.go | 10 + .../cte_in_delete/pgx/v5/go/query.sql.go | 38 + .../testdata/cte_in_delete/pgx/v5/query.sql | 6 + .../testdata/cte_in_delete/pgx/v5/schema.sql | 2 + .../testdata/cte_in_delete/pgx/v5/sqlc.json | 13 + .../testdata/cte_in_delete/stdlib/go/db.go | 31 + .../cte_in_delete/stdlib/go/models.go | 10 + .../cte_in_delete/stdlib/go/query.sql.go | 41 + .../testdata/cte_in_delete/stdlib/query.sql | 6 + .../testdata/cte_in_delete/stdlib/schema.sql | 2 + .../testdata/cte_in_delete/stdlib/sqlc.json | 11 + .../endtoend/testdata/cte_join_self/issue.md | 1 + .../cte_join_self/postgresql/pgx/exec.json | 3 + .../cte_join_self/postgresql/pgx/go/db.go | 32 + .../cte_join_self/postgresql/pgx/go/models.go | 5 + .../postgresql/pgx/go/query.sql.go | 34 + .../cte_join_self/postgresql/pgx/query.sql | 10 + .../cte_join_self/postgresql/pgx/schema.sql | 1 + .../cte_join_self/postgresql/pgx/sqlc.yaml | 10 + .../endtoend/testdata/cte_left_join/issue.md | 1 + .../cte_left_join/postgresql/pgx/exec.json | 3 + .../cte_left_join/postgresql/pgx/go/db.go | 32 + .../cte_left_join/postgresql/pgx/go/models.go | 21 + .../postgresql/pgx/go/query.sql.go | 34 + .../cte_left_join/postgresql/pgx/query.sql | 15 + .../cte_left_join/postgresql/pgx/schema.sql | 11 + .../cte_left_join/postgresql/pgx/sqlc.yaml | 10 + .../testdata/cte_multiple_alias/issue.md | 1 + .../postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 21 + .../postgresql/pgx/go/query.sql.go | 48 + .../postgresql/pgx/query.sql | 15 + .../postgresql/pgx/schema.sql | 11 + .../postgresql/pgx/sqlc.yaml | 10 + .../testdata/cte_nested_with/issue.md | 1 + .../cte_nested_with/postgresql/pgx/exec.json | 3 + .../cte_nested_with/postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 15 + .../postgresql/pgx/go/query.sql.go | 38 + .../cte_nested_with/postgresql/pgx/query.sql | 17 + .../cte_nested_with/postgresql/pgx/schema.sql | 5 + .../cte_nested_with/postgresql/pgx/sqlc.yaml | 10 + .../testdata/cte_recursive/mysql/go/db.go | 31 + .../testdata/cte_recursive/mysql/go/models.go | 14 + .../cte_recursive/mysql/go/query.sql.go | 50 + .../testdata/cte_recursive/mysql/query.sql | 9 + .../testdata/cte_recursive/mysql/schema.sql | 2 + .../testdata/cte_recursive/mysql/sqlc.json | 12 + .../testdata/cte_recursive/pgx/v4/go/db.go | 32 + .../cte_recursive/pgx/v4/go/models.go | 14 + .../cte_recursive/pgx/v4/go/query.sql.go | 47 + .../testdata/cte_recursive/pgx/v4/query.sql | 9 + .../testdata/cte_recursive/pgx/v4/schema.sql | 2 + .../testdata/cte_recursive/pgx/v4/sqlc.json | 13 + .../testdata/cte_recursive/pgx/v5/go/db.go | 32 + .../cte_recursive/pgx/v5/go/models.go | 14 + .../cte_recursive/pgx/v5/go/query.sql.go | 48 + .../testdata/cte_recursive/pgx/v5/query.sql | 9 + .../testdata/cte_recursive/pgx/v5/schema.sql | 2 + .../testdata/cte_recursive/pgx/v5/sqlc.json | 13 + .../testdata/cte_recursive/stdlib/go/db.go | 31 + .../cte_recursive/stdlib/go/models.go | 14 + .../cte_recursive/stdlib/go/query.sql.go | 50 + .../testdata/cte_recursive/stdlib/query.sql | 9 + .../testdata/cte_recursive/stdlib/schema.sql | 2 + .../testdata/cte_recursive/stdlib/sqlc.json | 11 + .../testdata/cte_recursive_employees/issue.md | 2 + .../postgresql/pgx/exec.json | 3 + .../postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 15 + .../postgresql/pgx/go/query.sql.go | 56 + .../postgresql/pgx/query.sql | 22 + .../postgresql/pgx/schema.sql | 5 + .../postgresql/pgx/sqlc.yaml | 10 + .../testdata/cte_recursive_star/issue.md | 1 + .../postgresql/pgx/exec.json | 3 + .../postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 27 + .../postgresql/pgx/go/query.sql.go | 59 + .../postgresql/pgx/query.sql | 7 + .../postgresql/pgx/schema.sql | 17 + .../postgresql/pgx/sqlc.yaml | 10 + .../testdata/cte_recursive_subquery/issue.md | 1 + .../postgresql/pgx/exec.json | 3 + .../postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 15 + .../postgresql/pgx/go/query.sql.go | 60 + .../postgresql/pgx/query.sql | 33 + .../postgresql/pgx/schema.sql | 5 + .../postgresql/pgx/sqlc.yaml | 14 + .../testdata/cte_recursive_union/issue.md | 1 + .../postgresql/pgx/exec.json | 3 + .../postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 32 + .../postgresql/pgx/go/query.sql.go | 57 + .../postgresql/pgx/query.sql | 18 + .../postgresql/pgx/schema.sql | 27 + .../postgresql/pgx/sqlc.yaml | 10 + .../endtoend/testdata/cte_select_one/issue.md | 1 + .../cte_select_one/postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 5 + .../postgresql/pgx/go/query.sql.go | 24 + .../cte_select_one/postgresql/pgx/query.sql | 5 + .../cte_select_one/postgresql/pgx/schema.sql | 1 + .../cte_select_one/postgresql/pgx/sqlc.yaml | 10 + .../endtoend/testdata/cte_update/issue.md | 1 + .../cte_update/postgresql/pgx/exec.json | 3 + .../cte_update/postgresql/pgx/go/db.go | 32 + .../cte_update/postgresql/pgx/go/models.go | 16 + .../cte_update/postgresql/pgx/go/query.sql.go | 42 + .../cte_update/postgresql/pgx/query.sql | 9 + .../cte_update/postgresql/pgx/schema.sql | 12 + .../cte_update/postgresql/pgx/sqlc.yaml | 10 + .../testdata/cte_update_multiple/issue.md | 1 + .../postgresql/pgx/exec.json | 3 + .../postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 37 + .../postgresql/pgx/go/query.sql.go | 83 + .../postgresql/pgx/query.sql | 28 + .../postgresql/pgx/schema.sql | 27 + .../postgresql/pgx/sqlc.yaml | 10 + .../endtoend/testdata/cte_with_in/issue.md | 1 + .../postgresql/pganalyze/exec.json | 3 + .../cte_with_in/postgresql/pganalyze/go/db.go | 32 + .../postgresql/pganalyze/go/models.go | 20 + .../postgresql/pganalyze/go/query.sql.go | 164 + .../postgresql/pganalyze/query.sql | 34 + .../postgresql/pganalyze/schema.sql | 12 + .../postgresql/pganalyze/sqlc.json | 14 + .../testdata/data_type_boolean/mysql/db/db.go | 31 + .../data_type_boolean/mysql/db/models.go | 21 + .../data_type_boolean/mysql/db/query.sql.go | 64 + .../data_type_boolean/mysql/query.sql | 5 + .../data_type_boolean/mysql/schema.sql | 13 + .../data_type_boolean/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 19 + .../postgresql/pgx/v4/go/query.sql.go | 58 + .../postgresql/pgx/v4/query.sql | 5 + .../postgresql/pgx/v4/schema.sql | 11 + .../postgresql/pgx/v4/sqlc.json | 14 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 19 + .../postgresql/pgx/v5/go/query.sql.go | 58 + .../postgresql/pgx/v5/query.sql | 5 + .../postgresql/pgx/v5/schema.sql | 11 + .../postgresql/pgx/v5/sqlc.json | 14 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 19 + .../postgresql/stdlib/go/query.sql.go | 64 + .../postgresql/stdlib/query.sql | 5 + .../postgresql/stdlib/schema.sql | 11 + .../postgresql/stdlib/sqlc.json | 13 + .../data_type_boolean/sqlite/db/db.go | 31 + .../data_type_boolean/sqlite/db/models.go | 19 + .../data_type_boolean/sqlite/db/query.sql.go | 64 + .../data_type_boolean/sqlite/query.sql | 5 + .../data_type_boolean/sqlite/schema.sql | 11 + .../data_type_boolean/sqlite/sqlc.json | 11 + .../endtoend/testdata/datatype/mysql/go/db.go | 31 + .../testdata/datatype/mysql/go/models.go | 91 + .../testdata/datatype/mysql/go/query.sql.go | 21 + .../testdata/datatype/mysql/sql/character.sql | 31 + .../testdata/datatype/mysql/sql/datetime.sql | 13 + .../testdata/datatype/mysql/sql/numeric.sql | 40 + .../testdata/datatype/mysql/sql/query.sql | 2 + .../testdata/datatype/mysql/sqlc.json | 12 + .../testdata/datatype/pgx/v4/go/db.go | 32 + .../testdata/datatype/pgx/v4/go/models.go | 112 + .../testdata/datatype/pgx/v4/go/query.sql.go | 21 + .../datatype/pgx/v4/sql/character.sql | 17 + .../testdata/datatype/pgx/v4/sql/datetime.sql | 23 + .../datatype/pgx/v4/sql/net-types.sql | 13 + .../testdata/datatype/pgx/v4/sql/numeric.sql | 36 + .../testdata/datatype/pgx/v4/sql/query.sql | 2 + .../datatype/pgx/v4/sql/rangetypes.sql | 19 + .../testdata/datatype/pgx/v4/sqlc.json | 13 + .../testdata/datatype/pgx/v5/go/db.go | 32 + .../testdata/datatype/pgx/v5/go/models.go | 114 + .../testdata/datatype/pgx/v5/go/query.sql.go | 21 + .../datatype/pgx/v5/sql/character.sql | 17 + .../testdata/datatype/pgx/v5/sql/datetime.sql | 23 + .../datatype/pgx/v5/sql/net-types.sql | 13 + .../testdata/datatype/pgx/v5/sql/numeric.sql | 36 + .../testdata/datatype/pgx/v5/sql/query.sql | 2 + .../datatype/pgx/v5/sql/rangetypes.sql | 19 + .../testdata/datatype/pgx/v5/sqlc.json | 13 + .../testdata/datatype/sqlite/go/db.go | 31 + .../testdata/datatype/sqlite/go/models.go | 80 + .../testdata/datatype/sqlite/go/query.sql.go | 21 + .../datatype/sqlite/sql/character.sql | 23 + .../testdata/datatype/sqlite/sql/datetime.sql | 13 + .../testdata/datatype/sqlite/sql/numeric.sql | 37 + .../testdata/datatype/sqlite/sql/query.sql | 2 + .../testdata/datatype/sqlite/sqlc.json | 12 + .../testdata/datatype/stdlib/go/db.go | 31 + .../testdata/datatype/stdlib/go/models.go | 112 + .../testdata/datatype/stdlib/go/query.sql.go | 21 + .../datatype/stdlib/sql/character.sql | 17 + .../testdata/datatype/stdlib/sql/datetime.sql | 23 + .../datatype/stdlib/sql/net-types.sql | 13 + .../testdata/datatype/stdlib/sql/numeric.sql | 36 + .../testdata/datatype/stdlib/sql/query.sql | 2 + .../datatype/stdlib/sql/rangetypes.sql | 19 + .../testdata/datatype/stdlib/sqlc.json | 11 + .../issue.md | 1 + .../postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 21 + .../postgresql/pgx/go/query.sql.go | 36 + .../postgresql/pgx/query.sql | 2 + .../postgresql/pgx/schema.sql | 13 + .../postgresql/pgx/sqlc.yaml | 10 + .../ddl_alter_table_add_column/mysql/go/db.go | 31 + .../mysql/go/models.go | 15 + .../mysql/go/query.sql.go | 19 + .../mysql/query.sql | 2 + .../mysql/schema.sql | 3 + .../mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 16 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 4 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 16 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 4 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 16 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 4 + .../postgresql/stdlib/sqlc.json | 12 + .../sqlite/go/db.go | 31 + .../sqlite/go/models.go | 15 + .../sqlite/go/query.sql.go | 37 + .../sqlite/query.sql | 2 + .../sqlite/schema.sql | 3 + .../sqlite/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 10 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 10 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 10 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../ddl_alter_table_alter_type/mysql/go/db.go | 31 + .../mysql/go/models.go | 14 + .../mysql/go/query.sql.go | 19 + .../mysql/query.sql | 2 + .../mysql/schema.sql | 3 + .../mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 9 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 9 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 9 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../sqlite/go/db.go | 31 + .../sqlite/go/models.go | 16 + .../sqlite/go/query.sql.go | 60 + .../sqlite/query.sql | 7 + .../sqlite/schema.sql | 10 + .../sqlite/sqlc.json | 12 + .../mysql/go/db.go | 31 + .../mysql/go/models.go | 13 + .../mysql/go/query.sql.go | 19 + .../mysql/query.sql | 2 + .../mysql/schema.sql | 2 + .../mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 9 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 9 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 9 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../mysql/go/db.go | 31 + .../mysql/go/models.go | 14 + .../mysql/go/query.sql.go | 19 + .../mysql/query.sql | 2 + .../mysql/schema.sql | 3 + .../mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 14 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 3 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 14 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 3 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 14 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 3 + .../postgresql/stdlib/sqlc.json | 12 + .../mysql/go/db.go | 31 + .../mysql/go/models.go | 13 + .../mysql/go/query.sql.go | 19 + .../mysql/query.sql | 2 + .../mysql/schema.sql | 2 + .../mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 13 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 13 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 13 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../sqlite/go/db.go | 31 + .../sqlite/go/models.go | 13 + .../sqlite/go/query.sql.go | 19 + .../sqlite/query.sql | 2 + .../sqlite/schema.sql | 2 + .../sqlite/sqlc.json | 12 + .../mysql/exec.json | 6 + .../mysql/go/db.go | 31 + .../mysql/go/models.go | 8 + .../mysql/go/query.sql.go | 19 + .../mysql/query.sql | 2 + .../mysql/schema.sql | 3 + .../mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 8 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 3 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 8 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 3 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 8 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 3 + .../postgresql/stdlib/sqlc.json | 12 + .../mysql/exec.json | 6 + .../mysql/go/db.go | 31 + .../mysql/go/models.go | 9 + .../mysql/go/query.sql.go | 19 + .../mysql/query.sql | 2 + .../mysql/schema.sql | 2 + .../mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 9 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 9 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 9 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 5 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 7 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 7 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 7 + .../postgresql/stdlib/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 24 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 17 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 23 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 17 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 24 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 17 + .../postgresql/stdlib/sqlc.json | 12 + .../ddl_alter_table_rename/mysql/go/db.go | 31 + .../ddl_alter_table_rename/mysql/go/models.go | 17 + .../mysql/go/query.sql.go | 19 + .../ddl_alter_table_rename/mysql/query.sql | 2 + .../ddl_alter_table_rename/mysql/schema.sql | 5 + .../ddl_alter_table_rename/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 13 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 13 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 13 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../ddl_alter_table_rename/sqlite/go/db.go | 31 + .../sqlite/go/models.go | 13 + .../sqlite/go/query.sql.go | 38 + .../ddl_alter_table_rename/sqlite/query.sql | 2 + .../ddl_alter_table_rename/sqlite/schema.sql | 3 + .../ddl_alter_table_rename/sqlite/sqlc.json | 12 + .../mysql/go/db.go | 31 + .../mysql/go/models.go | 13 + .../mysql/go/query.sql.go | 19 + .../mysql/query.sql | 2 + .../mysql/schema.sql | 2 + .../mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 13 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 13 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 13 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../sqlite/go/db.go | 31 + .../sqlite/go/models.go | 13 + .../sqlite/go/query.sql.go | 38 + .../sqlite/query.sql | 2 + .../sqlite/schema.sql | 4 + .../sqlite/sqlc.json | 12 + .../mysql/go/db.go | 31 + .../mysql/go/models.go | 13 + .../mysql/go/query.sql.go | 19 + .../mysql/query.sql | 2 + .../mysql/schema.sql | 2 + .../mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 13 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 13 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 13 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../mysql/go/db.go | 31 + .../mysql/go/models.go | 9 + .../mysql/go/query.sql.go | 19 + .../mysql/query.sql | 2 + .../mysql/schema.sql | 2 + .../mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 9 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 9 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 9 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../mysql/README.md | 1 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 13 + .../postgresql/pgx/v4/go/query.sql.go | 29 + .../postgresql/pgx/v4/query.sql | 5 + .../postgresql/pgx/v4/schema.sql | 3 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 13 + .../postgresql/pgx/v5/go/query.sql.go | 30 + .../postgresql/pgx/v5/query.sql | 5 + .../postgresql/pgx/v5/schema.sql | 3 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 13 + .../postgresql/stdlib/go/query.sql.go | 29 + .../postgresql/stdlib/query.sql | 5 + .../postgresql/stdlib/schema.sql | 3 + .../postgresql/stdlib/sqlc.json | 12 + .../ddl_alter_type_add_value/mysql/README.md | 4 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 53 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 3 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 53 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 3 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 53 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 3 + .../postgresql/stdlib/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 57 + .../postgresql/pgx/v4/go/query.sql.go | 34 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 9 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 57 + .../postgresql/pgx/v5/go/query.sql.go | 34 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 9 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 57 + .../postgresql/stdlib/go/query.sql.go | 37 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 9 + .../postgresql/stdlib/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 57 + .../postgresql/pgx/v4/go/query.sql.go | 34 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 9 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 57 + .../postgresql/pgx/v5/go/query.sql.go | 34 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 9 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 57 + .../postgresql/stdlib/go/query.sql.go | 37 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 9 + .../postgresql/stdlib/sqlc.json | 12 + .../mysql/README.md | 4 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 52 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 52 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 52 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 103 + .../postgresql/pgx/v4/go/query.sql.go | 34 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 15 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 103 + .../postgresql/pgx/v5/go/query.sql.go | 34 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 15 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 103 + .../postgresql/stdlib/go/query.sql.go | 37 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 15 + .../postgresql/stdlib/sqlc.json | 12 + .../testdata/ddl_comment/mysql/README.md | 2 + .../testdata/ddl_comment/mysql/go/db.go | 31 + .../testdata/ddl_comment/mysql/go/models.go | 15 + .../ddl_comment/mysql/go/query.sql.go | 19 + .../testdata/ddl_comment/mysql/query.sql | 2 + .../testdata/ddl_comment/mysql/schema.sql | 3 + .../testdata/ddl_comment/mysql/sqlc.json | 12 + .../ddl_comment/postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 59 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../ddl_comment/postgresql/pgx/v4/query.sql | 2 + .../ddl_comment/postgresql/pgx/v4/schema.sql | 7 + .../ddl_comment/postgresql/pgx/v4/sqlc.json | 13 + .../ddl_comment/postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 60 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../ddl_comment/postgresql/pgx/v5/query.sql | 2 + .../ddl_comment/postgresql/pgx/v5/schema.sql | 7 + .../ddl_comment/postgresql/pgx/v5/sqlc.json | 13 + .../ddl_comment/postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 59 + .../postgresql/stdlib/go/query.sql.go | 19 + .../ddl_comment/postgresql/stdlib/query.sql | 2 + .../ddl_comment/postgresql/stdlib/schema.sql | 7 + .../ddl_comment/postgresql/stdlib/sqlc.json | 12 + .../testdata/ddl_create_enum/mysql/go/db.go | 31 + .../ddl_create_enum/mysql/go/models.go | 114 + .../ddl_create_enum/mysql/go/query.sql.go | 37 + .../testdata/ddl_create_enum/mysql/query.sql | 2 + .../testdata/ddl_create_enum/mysql/schema.sql | 4 + .../testdata/ddl_create_enum/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 113 + .../postgresql/pgx/v4/go/query.sql.go | 34 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 28 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 113 + .../postgresql/pgx/v5/go/query.sql.go | 34 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 28 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 113 + .../postgresql/stdlib/go/query.sql.go | 37 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 28 + .../postgresql/stdlib/sqlc.json | 12 + .../testdata/ddl_create_func_exists/exec.json | 6 + .../ddl_create_func_exists/mysql/README.md | 2 + .../testdata/ddl_create_func_exists/query.sql | 5 + .../testdata/ddl_create_func_exists/sqlc.json | 11 + .../ddl_create_func_exists/stderr.txt | 2 + .../ddl_create_function/mysql/README.md | 2 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 5 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 1 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 1 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 1 + .../postgresql/stdlib/sqlc.json | 12 + .../ddl_create_function_args/mysql/README.md | 2 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 5 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../mysql/README.md | 2 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 5 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 1 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 1 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 1 + .../postgresql/stdlib/sqlc.json | 12 + .../ddl_create_function_types/mysql/README.md | 2 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 5 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../ddl_create_procedure/mysql/go/db.go | 31 + .../ddl_create_procedure/mysql/go/models.go | 13 + .../mysql/go/query.sql.go | 47 + .../ddl_create_procedure/mysql/query.sql | 8 + .../ddl_create_procedure/mysql/schema.sql | 9 + .../ddl_create_procedure/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 13 + .../postgresql/pgx/v4/go/query.sql.go | 61 + .../postgresql/pgx/v4/query.sql | 11 + .../postgresql/pgx/v4/schema.sql | 11 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 13 + .../postgresql/pgx/v5/go/query.sql.go | 61 + .../postgresql/pgx/v5/query.sql | 11 + .../postgresql/pgx/v5/schema.sql | 11 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 13 + .../postgresql/stdlib/go/query.sql.go | 61 + .../postgresql/stdlib/query.sql | 11 + .../postgresql/stdlib/schema.sql | 11 + .../postgresql/stdlib/sqlc.json | 12 + .../testdata/ddl_create_table/mysql/go/db.go | 31 + .../ddl_create_table/mysql/go/models.go | 13 + .../ddl_create_table/mysql/go/query.sql.go | 19 + .../testdata/ddl_create_table/mysql/query.sql | 2 + .../ddl_create_table/mysql/schema.sql | 1 + .../testdata/ddl_create_table/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 13 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 1 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 13 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 1 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 13 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 1 + .../postgresql/stdlib/sqlc.json | 12 + .../testdata/ddl_create_table/sqlite/go/db.go | 31 + .../ddl_create_table/sqlite/go/models.go | 13 + .../ddl_create_table/sqlite/go/query.sql.go | 19 + .../ddl_create_table/sqlite/query.sql | 2 + .../ddl_create_table/sqlite/schema.sql | 1 + .../ddl_create_table/sqlite/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 15 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 6 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 15 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 6 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 15 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 6 + .../postgresql/stdlib/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 36 + .../postgresql/pgx/v4/go/query.sql.go | 87 + .../postgresql/pgx/v4/query.sql | 8 + .../postgresql/pgx/v4/schema.sql | 18 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 34 + .../postgresql/pgx/v5/go/query.sql.go | 87 + .../postgresql/pgx/v5/query.sql | 8 + .../postgresql/pgx/v5/schema.sql | 18 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 36 + .../postgresql/stdlib/go/query.sql.go | 96 + .../postgresql/stdlib/query.sql | 8 + .../postgresql/stdlib/schema.sql | 18 + .../postgresql/stdlib/sqlc.json | 12 + .../postgresql/stdlib/exec.json | 6 + .../postgresql/stdlib/query.sql | 5 + .../postgresql/stdlib/schema.sql | 7 + .../postgresql/stdlib/sqlc.json | 12 + .../postgresql/stdlib/stderr.txt | 2 + .../testdata/ddl_create_table_like/issue.md | 1 + .../postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 15 + .../postgresql/pgx/go/query.sql.go | 34 + .../postgresql/pgx/query.sql | 2 + .../postgresql/pgx/schema.sql | 9 + .../postgresql/pgx/sqlc.yaml | 10 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 19 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 6 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 19 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 6 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 19 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 6 + .../postgresql/stdlib/sqlc.json | 12 + .../ddl_create_table_reserved/mysql/go/db.go | 31 + .../mysql/go/models.go | 13 + .../mysql/go/query.sql.go | 19 + .../ddl_create_table_reserved/mysql/query.sql | 2 + .../mysql/schema.sql | 1 + .../ddl_create_table_reserved/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 13 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 1 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 13 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 1 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 13 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 1 + .../postgresql/stdlib/sqlc.json | 12 + .../ddl_create_table_strict/sqlite/go/db.go | 31 + .../sqlite/go/models.go | 13 + .../sqlite/go/query.sql.go | 19 + .../ddl_create_table_strict/sqlite/query.sql | 2 + .../ddl_create_table_strict/sqlite/schema.sql | 1 + .../ddl_create_table_strict/sqlite/sqlc.json | 12 + .../ddl_create_table_unknown_type/issue.md | 1 + .../postgresql/pgx/exec.json | 6 + .../postgresql/pgx/query.sql | 2 + .../postgresql/pgx/schema.sql | 3 + .../postgresql/pgx/sqlc.yaml | 10 + .../postgresql/pgx/stderr.txt | 5 + .../sqlite/go/db.go | 31 + .../sqlite/go/models.go | 15 + .../sqlite/go/query.sql.go | 19 + .../sqlite/query.sql | 2 + .../sqlite/schema.sql | 1 + .../sqlite/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 19 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 24 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 17 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 24 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 19 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 24 + .../postgresql/stdlib/sqlc.json | 12 + .../ddl_create_trigger/sqlite/go/db.go | 31 + .../ddl_create_trigger/sqlite/go/models.go | 31 + .../ddl_create_trigger/sqlite/go/query.sql.go | 19 + .../ddl_create_trigger/sqlite/query.sql | 2 + .../ddl_create_trigger/sqlite/schema.sql | 32 + .../ddl_create_trigger/sqlite/sqlc.json | 12 + .../ddl_drop_function/mysql/README.md | 2 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 5 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../ddl_drop_function_args/mysql/README.md | 2 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 5 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../mysql/README.md | 2 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 5 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../testdata/ddl_drop_schema/mysql/exec.json | 6 + .../testdata/ddl_drop_schema/mysql/go/db.go | 31 + .../ddl_drop_schema/mysql/go/models.go | 5 + .../ddl_drop_schema/mysql/go/query.sql.go | 19 + .../testdata/ddl_drop_schema/mysql/query.sql | 2 + .../testdata/ddl_drop_schema/mysql/schema.sql | 3 + .../testdata/ddl_drop_schema/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 5 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 3 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 3 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 3 + .../postgresql/stdlib/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 5 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 1 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 1 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 1 + .../postgresql/stdlib/sqlc.json | 12 + .../ddl_drop_table/postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 5 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../ddl_drop_table/postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../ddl_drop_table/postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../testdata/ddl_drop_table/sqlite/go/db.go | 31 + .../ddl_drop_table/sqlite/go/models.go | 5 + .../ddl_drop_table/sqlite/go/query.sql.go | 19 + .../testdata/ddl_drop_table/sqlite/query.sql | 2 + .../testdata/ddl_drop_table/sqlite/schema.sql | 8 + .../testdata/ddl_drop_table/sqlite/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 5 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 3 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 3 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 3 + .../postgresql/stdlib/sqlc.json | 12 + .../ddl_drop_table_if_exists/sqlite/go/db.go | 31 + .../sqlite/go/models.go | 5 + .../sqlite/go/query.sql.go | 19 + .../ddl_drop_table_if_exists/sqlite/query.sql | 2 + .../sqlite/schema.sql | 3 + .../ddl_drop_table_if_exists/sqlite/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 5 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../ddl_drop_type/postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 5 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../ddl_drop_type/postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../ddl_drop_type/postgresql/pgx/v4/sqlc.json | 13 + .../ddl_drop_type/postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../ddl_drop_type/postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../ddl_drop_type/postgresql/pgx/v5/sqlc.json | 13 + .../ddl_drop_type/postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/query.sql.go | 19 + .../ddl_drop_type/postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../ddl_drop_type/postgresql/stdlib/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 5 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 3 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 3 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 3 + .../postgresql/stdlib/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 5 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 14 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 5 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 14 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 5 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 14 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 5 + .../postgresql/stdlib/sqlc.json | 12 + .../ddl_materialized_views_invalid/issue.md | 1 + .../postgresql/pgx/exec.json | 3 + .../postgresql/pgx/query.sql | 4 + .../postgresql/pgx/schema.sql | 9 + .../postgresql/pgx/sqlc.yaml | 10 + .../postgresql/pgx/stderr.txt | 2 + .../ddl_pg_temp/postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 21 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../ddl_pg_temp/postgresql/pgx/v4/query.sql | 2 + .../ddl_pg_temp/postgresql/pgx/v4/schema.sql | 5 + .../ddl_pg_temp/postgresql/pgx/v4/sqlc.json | 13 + .../ddl_pg_temp/postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 21 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../ddl_pg_temp/postgresql/pgx/v5/query.sql | 2 + .../ddl_pg_temp/postgresql/pgx/v5/schema.sql | 5 + .../ddl_pg_temp/postgresql/pgx/v5/sqlc.json | 13 + .../ddl_pg_temp/postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 21 + .../postgresql/stdlib/go/query.sql.go | 19 + .../ddl_pg_temp/postgresql/stdlib/query.sql | 2 + .../ddl_pg_temp/postgresql/stdlib/schema.sql | 5 + .../ddl_pg_temp/postgresql/stdlib/sqlc.json | 12 + .../issue.md | 1 + .../postgresql/pgx/v4/exec.json | 3 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 21 + .../postgresql/pgx/v4/go/query.sql.go | 22 + .../postgresql/pgx/v4/query.sql | 3 + .../postgresql/pgx/v4/schema.sql | 18 + .../postgresql/pgx/v4/sqlc.yaml | 10 + .../postgresql/pgx/v5/exec.json | 3 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 21 + .../postgresql/pgx/v5/go/query.sql.go | 22 + .../postgresql/pgx/v5/query.sql | 3 + .../postgresql/pgx/v5/schema.sql | 18 + .../postgresql/pgx/v5/sqlc.yaml | 10 + .../testdata/delete_from/mysql/go/db.go | 31 + .../testdata/delete_from/mysql/go/models.go | 9 + .../delete_from/mysql/go/query.sql.go | 19 + .../testdata/delete_from/mysql/query.sql | 2 + .../testdata/delete_from/mysql/schema.sql | 2 + .../testdata/delete_from/mysql/sqlc.json | 12 + .../delete_from/postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 9 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../delete_from/postgresql/pgx/v4/query.sql | 2 + .../delete_from/postgresql/pgx/v4/schema.sql | 2 + .../delete_from/postgresql/pgx/v4/sqlc.json | 13 + .../delete_from/postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 9 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../delete_from/postgresql/pgx/v5/query.sql | 2 + .../delete_from/postgresql/pgx/v5/schema.sql | 2 + .../delete_from/postgresql/pgx/v5/sqlc.json | 13 + .../delete_from/postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 9 + .../postgresql/stdlib/go/query.sql.go | 19 + .../delete_from/postgresql/stdlib/query.sql | 2 + .../delete_from/postgresql/stdlib/schema.sql | 2 + .../delete_from/postgresql/stdlib/sqlc.json | 12 + .../testdata/delete_from/sqlite/go/db.go | 31 + .../testdata/delete_from/sqlite/go/models.go | 9 + .../delete_from/sqlite/go/query.sql.go | 19 + .../testdata/delete_from/sqlite/query.sql | 2 + .../testdata/delete_from/sqlite/schema.sql | 1 + .../testdata/delete_from/sqlite/sqlc.json | 12 + .../testdata/delete_inner_join/mysql/go/db.go | 31 + .../delete_inner_join/mysql/go/models.go | 20 + .../delete_inner_join/mysql/go/query.sql.go | 24 + .../delete_inner_join/mysql/query.sql | 7 + .../delete_inner_join/mysql/schema.sql | 18 + .../delete_inner_join/mysql/sqlc.json | 12 + .../testdata/delete_join/mysql/db/db.go | 31 + .../testdata/delete_join/mysql/db/models.go | 17 + .../delete_join/mysql/db/query.sql.go | 84 + .../testdata/delete_join/mysql/query.sql | 34 + .../testdata/delete_join/mysql/schema.sql | 14 + .../testdata/delete_join/mysql/sqlc.json | 11 + .../endtoend/testdata/delete_using/issue.md | 1 + .../delete_using/postgresql/pgx/exec.json | 3 + .../delete_using/postgresql/pgx/go/db.go | 32 + .../delete_using/postgresql/pgx/go/models.go | 18 + .../postgresql/pgx/go/query.sql.go | 39 + .../delete_using/postgresql/pgx/query.sql | 5 + .../delete_using/postgresql/pgx/schema.sql | 9 + .../delete_using/postgresql/pgx/sqlc.yaml | 10 + .../testdata/diff_no_output/exec.json | 3 + .../endtoend/testdata/diff_no_output/go/db.go | 31 + .../testdata/diff_no_output/go/models.go | 20 + .../testdata/diff_no_output/go/query.sql.go | 83 + .../testdata/diff_no_output/query.sql | 18 + .../testdata/diff_no_output/schema.sql | 11 + .../testdata/diff_no_output/sqlc.json | 16 + .../endtoend/testdata/diff_output/exec.json | 3 + .../endtoend/testdata/diff_output/go/db.go | 31 + .../testdata/diff_output/go/models.go | 15 + .../testdata/diff_output/go/query.sql.go | 82 + .../endtoend/testdata/diff_output/query.sql | 18 + .../endtoend/testdata/diff_output/schema.sql | 11 + .../endtoend/testdata/diff_output/sqlc.json | 16 + .../endtoend/testdata/diff_output/stderr.txt | 55 + .../testdata/do/postgresql/pgx/db/db.go | 32 + .../testdata/do/postgresql/pgx/db/models.go | 15 + .../do/postgresql/pgx/db/query.sql.go | 24 + .../testdata/do/postgresql/pgx/query.sql | 7 + .../testdata/do/postgresql/pgx/schema.sql | 5 + .../testdata/do/postgresql/pgx/sqlc.json | 12 + .../testdata/do/postgresql/pq/db/db.go | 31 + .../testdata/do/postgresql/pq/db/models.go | 15 + .../testdata/do/postgresql/pq/db/query.sql.go | 24 + .../testdata/do/postgresql/pq/query.sql | 7 + .../testdata/do/postgresql/pq/schema.sql | 5 + .../testdata/do/postgresql/pq/sqlc.json | 11 + .../duplicate_go_names/enum/query.sql | 2 + .../duplicate_go_names/enum/schema.sql | 3 + .../duplicate_go_names/enum/sqlc.yaml | 8 + .../duplicate_go_names/enum/stderr.txt | 2 + .../duplicate_go_names/null_enum/query.sql | 2 + .../duplicate_go_names/null_enum/schema.sql | 3 + .../duplicate_go_names/null_enum/sqlc.yaml | 8 + .../duplicate_go_names/null_enum/stderr.txt | 2 + .../query_constant/query.sql | 2 + .../query_constant/schema.sql | 1 + .../query_constant/sqlc.yaml | 9 + .../query_constant/stderr.txt | 2 + .../emit_db_and_json_tags/mysql/go/db.go | 31 + .../emit_db_and_json_tags/mysql/go/models.go | 16 + .../mysql/go/query.sql.go | 42 + .../emit_db_and_json_tags/mysql/query.sql | 2 + .../emit_db_and_json_tags/mysql/schema.sql | 6 + .../emit_db_and_json_tags/mysql/sqlc.json | 14 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 16 + .../postgresql/pgx/v4/go/query.sql.go | 39 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 6 + .../postgresql/pgx/v4/sqlc.json | 15 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 16 + .../postgresql/pgx/v5/go/query.sql.go | 39 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 6 + .../postgresql/pgx/v5/sqlc.json | 15 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 16 + .../postgresql/stdlib/go/query.sql.go | 42 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 6 + .../postgresql/stdlib/sqlc.json | 14 + .../emit_db_and_json_tags/sqlite/go/db.go | 31 + .../emit_db_and_json_tags/sqlite/go/models.go | 16 + .../sqlite/go/query.sql.go | 42 + .../emit_db_and_json_tags/sqlite/query.sql | 2 + .../emit_db_and_json_tags/sqlite/schema.sql | 6 + .../emit_db_and_json_tags/sqlite/sqlc.json | 14 + .../testdata/emit_db_tags/mysql/go/db.go | 31 + .../testdata/emit_db_tags/mysql/go/models.go | 16 + .../emit_db_tags/mysql/go/query.sql.go | 42 + .../testdata/emit_db_tags/mysql/query.sql | 2 + .../testdata/emit_db_tags/mysql/schema.sql | 6 + .../testdata/emit_db_tags/mysql/sqlc.json | 13 + .../emit_db_tags/postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 16 + .../postgresql/pgx/v4/go/query.sql.go | 39 + .../emit_db_tags/postgresql/pgx/v4/query.sql | 2 + .../emit_db_tags/postgresql/pgx/v4/schema.sql | 6 + .../emit_db_tags/postgresql/pgx/v4/sqlc.json | 14 + .../emit_db_tags/postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 16 + .../postgresql/pgx/v5/go/query.sql.go | 39 + .../emit_db_tags/postgresql/pgx/v5/query.sql | 2 + .../emit_db_tags/postgresql/pgx/v5/schema.sql | 6 + .../emit_db_tags/postgresql/pgx/v5/sqlc.json | 14 + .../emit_db_tags/postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 16 + .../postgresql/stdlib/go/query.sql.go | 42 + .../emit_db_tags/postgresql/stdlib/query.sql | 2 + .../emit_db_tags/postgresql/stdlib/schema.sql | 6 + .../emit_db_tags/postgresql/stdlib/sqlc.json | 13 + .../testdata/emit_db_tags/sqlite/go/db.go | 31 + .../testdata/emit_db_tags/sqlite/go/models.go | 16 + .../emit_db_tags/sqlite/go/query.sql.go | 42 + .../testdata/emit_db_tags/sqlite/query.sql | 2 + .../testdata/emit_db_tags/sqlite/schema.sql | 6 + .../testdata/emit_db_tags/sqlite/sqlc.json | 13 + .../emit_empty_slices/pgx/v4/go/db.go | 32 + .../emit_empty_slices/pgx/v4/go/models.go | 9 + .../emit_empty_slices/pgx/v4/go/query.sql.go | 34 + .../emit_empty_slices/pgx/v4/query.sql | 2 + .../emit_empty_slices/pgx/v4/schema.sql | 2 + .../emit_empty_slices/pgx/v4/sqlc.json | 14 + .../emit_empty_slices/pgx/v5/go/db.go | 32 + .../emit_empty_slices/pgx/v5/go/models.go | 9 + .../emit_empty_slices/pgx/v5/go/query.sql.go | 34 + .../emit_empty_slices/pgx/v5/query.sql | 2 + .../emit_empty_slices/pgx/v5/schema.sql | 2 + .../emit_empty_slices/pgx/v5/sqlc.json | 14 + .../emit_empty_slices/stdlib/go/db.go | 31 + .../emit_empty_slices/stdlib/go/models.go | 9 + .../emit_empty_slices/stdlib/go/query.sql.go | 37 + .../emit_empty_slices/stdlib/query.sql | 2 + .../emit_empty_slices/stdlib/schema.sql | 2 + .../emit_empty_slices/stdlib/sqlc.json | 12 + .../emit_enum_valid_and_values/go/db.go | 32 + .../emit_enum_valid_and_values/go/models.go | 76 + .../go/query.sql.go | 70 + .../emit_enum_valid_and_values/query.sql | 8 + .../emit_enum_valid_and_values/schema.sql | 4 + .../emit_enum_valid_and_values/sqlc.json | 22 + .../emit_exported_queries/pgx/v4/go/db.go | 32 + .../emit_exported_queries/pgx/v4/go/models.go | 9 + .../pgx/v4/go/query.sql.go | 24 + .../emit_exported_queries/pgx/v4/query.sql | 2 + .../emit_exported_queries/pgx/v4/schema.sql | 2 + .../emit_exported_queries/pgx/v4/sqlc.json | 14 + .../emit_exported_queries/pgx/v5/go/db.go | 32 + .../emit_exported_queries/pgx/v5/go/models.go | 9 + .../pgx/v5/go/query.sql.go | 24 + .../emit_exported_queries/pgx/v5/query.sql | 2 + .../emit_exported_queries/pgx/v5/schema.sql | 2 + .../emit_exported_queries/pgx/v5/sqlc.json | 14 + .../emit_exported_queries/stdlib/go/db.go | 31 + .../emit_exported_queries/stdlib/go/models.go | 9 + .../stdlib/go/query.sql.go | 24 + .../emit_exported_queries/stdlib/query.sql | 2 + .../emit_exported_queries/stdlib/schema.sql | 2 + .../emit_exported_queries/stdlib/sqlc.json | 12 + .../mysql/go/db.go | 24 + .../mysql/go/models.go | 16 + .../mysql/go/query.sql.go | 42 + .../mysql/query.sql | 2 + .../mysql/schema.sql | 6 + .../mysql/sqlc.json | 13 + .../postgresql/pgx/v4/go/db.go | 25 + .../postgresql/pgx/v4/go/models.go | 16 + .../postgresql/pgx/v4/go/query.sql.go | 39 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 6 + .../postgresql/pgx/v4/sqlc.json | 14 + .../postgresql/pgx/v5/go/db.go | 25 + .../postgresql/pgx/v5/go/models.go | 16 + .../postgresql/pgx/v5/go/query.sql.go | 39 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 6 + .../postgresql/pgx/v5/sqlc.json | 14 + .../postgresql/stdlib/go/db.go | 24 + .../postgresql/stdlib/go/models.go | 16 + .../postgresql/stdlib/go/query.sql.go | 42 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 6 + .../postgresql/stdlib/sqlc.json | 13 + .../sqlite/go/db.go | 24 + .../sqlite/go/models.go | 16 + .../sqlite/go/query.sql.go | 42 + .../sqlite/query.sql | 2 + .../sqlite/schema.sql | 6 + .../sqlite/sqlc.json | 13 + .../optin/pgx/v5/go/db.go | 32 + .../optin/pgx/v5/go/models.go | 60 + .../optin/pgx/v5/go/query.sql.go | 34 + .../optin/pgx/v5/query.sql | 2 + .../optin/pgx/v5/schema.sql | 7 + .../optin/pgx/v5/sqlc.json | 14 + .../optout/pgx/v5/go/db.go | 32 + .../optout/pgx/v5/go/models.go | 57 + .../optout/pgx/v5/go/query.sql.go | 34 + .../optout/pgx/v5/query.sql | 2 + .../optout/pgx/v5/schema.sql | 6 + .../optout/pgx/v5/sqlc.json | 15 + .../pgx/v4/go/db.go | 32 + .../pgx/v4/go/models.go | 57 + .../pgx/v4/go/query.sql.go | 34 + .../pgx/v4/query.sql | 2 + .../pgx/v4/schema.sql | 6 + .../pgx/v4/sqlc.json | 14 + .../pgx/v5/go/db.go | 32 + .../pgx/v5/go/models.go | 100 + .../pgx/v5/go/query.sql.go | 49 + .../pgx/v5/query.sql | 5 + .../pgx/v5/schema.sql | 11 + .../pgx/v5/sqlc.json | 14 + .../pgx/v4/go/db.go | 32 + .../pgx/v4/go/models.go | 111 + .../pgx/v4/go/query.sql.go | 21 + .../pgx/v4/sql/character.sql | 17 + .../pgx/v4/sql/datetime.sql | 23 + .../pgx/v4/sql/net-types.sql | 13 + .../pgx/v4/sql/numeric.sql | 36 + .../pgx/v4/sql/query.sql | 2 + .../pgx/v4/sql/rangetypes.sql | 19 + .../pgx/v4/sqlc.json | 14 + .../pgx/v5/go/db.go | 32 + .../pgx/v5/go/models.go | 113 + .../pgx/v5/go/query.sql.go | 21 + .../pgx/v5/sql/character.sql | 17 + .../pgx/v5/sql/datetime.sql | 23 + .../pgx/v5/sql/net-types.sql | 13 + .../pgx/v5/sql/numeric.sql | 36 + .../pgx/v5/sql/query.sql | 2 + .../pgx/v5/sql/rangetypes.sql | 19 + .../pgx/v5/sqlc.json | 14 + .../sqlite/go/db.go | 31 + .../sqlite/go/models.go | 27 + .../sqlite/go/query.sql.go | 21 + .../sqlite/sql/query.sql | 2 + .../sqlite/sql/types.sql | 18 + .../sqlite/sqlc.json | 13 + .../stdlib/go/db.go | 31 + .../stdlib/go/models.go | 112 + .../stdlib/go/query.sql.go | 21 + .../stdlib/sql/character.sql | 17 + .../stdlib/sql/datetime.sql | 23 + .../stdlib/sql/net-types.sql | 13 + .../stdlib/sql/numeric.sql | 36 + .../stdlib/sql/query.sql | 2 + .../stdlib/sql/rangetypes.sql | 19 + .../stdlib/sqlc.json | 12 + .../mysql/go/db.go | 31 + .../mysql/go/models.go | 14 + .../mysql/go/querier.go | 18 + .../mysql/go/query.sql.go | 81 + .../mysql/query.sql | 8 + .../mysql/schema.sql | 2 + .../mysql/sqlc.json | 15 + .../postgresql/pgx/v4/go/batch.go | 72 + .../postgresql/pgx/v4/go/db.go | 33 + .../postgresql/pgx/v4/go/models.go | 14 + .../postgresql/pgx/v4/go/query.sql.go | 75 + .../postgresql/pgx/v4/query.sql | 14 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 19 + .../postgresql/pgx/v5/go/batch.go | 72 + .../postgresql/pgx/v5/go/db.go | 33 + .../postgresql/pgx/v5/go/models.go | 14 + .../postgresql/pgx/v5/go/query.sql.go | 76 + .../postgresql/pgx/v5/query.sql | 14 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 19 + .../emit_sql_as_comment/stdlib/exec.json | 3 + .../emit_sql_as_comment/stdlib/go/db.go | 31 + .../emit_sql_as_comment/stdlib/go/models.go | 9 + .../stdlib/go/query.sql.go | 56 + .../emit_sql_as_comment/stdlib/query.sql | 8 + .../emit_sql_as_comment/stdlib/schema.sql | 1 + .../emit_sql_as_comment/stdlib/sqlc.json | 12 + .../endtoend/testdata/enum/mysql/go/db.go | 24 + .../endtoend/testdata/enum/mysql/go/models.go | 110 + .../testdata/enum/mysql/go/query.sql.go | 110 + .../endtoend/testdata/enum/mysql/query.sql | 22 + .../endtoend/testdata/enum/mysql/schema.sql | 8 + .../endtoend/testdata/enum/mysql/sqlc.json | 13 + .../testdata/enum/postgresql/pgx/v4/go/db.go | 25 + .../enum/postgresql/pgx/v4/go/models.go | 65 + .../enum/postgresql/pgx/v4/go/query.sql.go | 104 + .../testdata/enum/postgresql/pgx/v4/query.sql | 21 + .../enum/postgresql/pgx/v4/schema.sql | 11 + .../testdata/enum/postgresql/pgx/v4/sqlc.json | 14 + .../testdata/enum/postgresql/pgx/v5/go/db.go | 25 + .../enum/postgresql/pgx/v5/go/models.go | 66 + .../enum/postgresql/pgx/v5/go/query.sql.go | 105 + .../testdata/enum/postgresql/pgx/v5/query.sql | 21 + .../enum/postgresql/pgx/v5/schema.sql | 11 + .../testdata/enum/postgresql/pgx/v5/sqlc.json | 14 + .../testdata/enum/postgresql/stdlib/go/db.go | 24 + .../enum/postgresql/stdlib/go/models.go | 65 + .../enum/postgresql/stdlib/go/query.sql.go | 107 + .../testdata/enum/postgresql/stdlib/query.sql | 21 + .../enum/postgresql/stdlib/schema.sql | 10 + .../testdata/enum/postgresql/stdlib/sqlc.json | 13 + .../endtoend/testdata/enum_column/issue.md | 3 + .../testdata/enum_column/mysql/go/db.go | 31 + .../testdata/enum_column/mysql/go/models.go | 271 ++ .../enum_column/mysql/go/query.sql.go | 71 + .../testdata/enum_column/mysql/query.sql | 5 + .../testdata/enum_column/mysql/schema.sql | 39 + .../testdata/enum_column/mysql/sqlc.yaml | 9 + .../enum_ordering/postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 90 + .../postgresql/stdlib/go/querier.go | 15 + .../postgresql/stdlib/go/query.sql.go | 37 + .../enum_ordering/postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 11 + .../enum_ordering/postgresql/stdlib/sqlc.json | 19 + .../testdata/exec_create_table/mysql/db/db.go | 31 + .../exec_create_table/mysql/db/models.go | 5 + .../mysql/db/mysql.query.sql.go | 19 + .../exec_create_table/mysql/mysql.query.sql | 2 + .../exec_create_table/mysql/mysql.schema.sql | 0 .../exec_create_table/mysql/sqlc.yaml | 8 + .../exec_create_table/postgresql/db/db.go | 31 + .../exec_create_table/postgresql/db/models.go | 5 + .../postgresql/db/postgresql.query.sql.go | 19 + .../postgresql/postgresql.query.sql | 2 + .../postgresql/postgresql.schema.sql | 0 .../exec_create_table/postgresql/sqlc.yaml | 9 + .../exec_create_table/sqlite/db/db.go | 31 + .../exec_create_table/sqlite/db/models.go | 5 + .../sqlite/db/sqlite.query.sql.go | 19 + .../exec_create_table/sqlite/sqlc.yaml | 8 + .../exec_create_table/sqlite/sqlite.query.sql | 2 + .../sqlite/sqlite.schema.sql | 0 .../testdata/exec_imports/pgx/v4/go/db.go | 32 + .../testdata/exec_imports/pgx/v4/go/models.go | 14 + .../exec_imports/pgx/v4/go/querier.go | 16 + .../exec_imports/pgx/v4/go/query.sql.go | 30 + .../testdata/exec_imports/pgx/v4/query.sql | 7 + .../testdata/exec_imports/pgx/v4/schema.sql | 2 + .../testdata/exec_imports/pgx/v4/sqlc.json | 14 + .../testdata/exec_imports/pgx/v5/go/db.go | 32 + .../testdata/exec_imports/pgx/v5/go/models.go | 14 + .../exec_imports/pgx/v5/go/querier.go | 16 + .../exec_imports/pgx/v5/go/query.sql.go | 30 + .../testdata/exec_imports/pgx/v5/query.sql | 7 + .../testdata/exec_imports/pgx/v5/schema.sql | 2 + .../testdata/exec_imports/pgx/v5/sqlc.json | 14 + .../testdata/exec_imports/stdlib/go/db.go | 31 + .../testdata/exec_imports/stdlib/go/models.go | 14 + .../exec_imports/stdlib/go/querier.go | 16 + .../exec_imports/stdlib/go/query.sql.go | 30 + .../testdata/exec_imports/stdlib/query.sql | 7 + .../testdata/exec_imports/stdlib/schema.sql | 2 + .../testdata/exec_imports/stdlib/sqlc.json | 12 + .../exec_lastid/go_postgresql_stdlib/go/db.go | 31 + .../go_postgresql_stdlib/go/models.go | 9 + .../go_postgresql_stdlib/go/querier.go | 15 + .../go_postgresql_stdlib/go/query.sql.go | 22 + .../go_postgresql_stdlib/query.sql | 2 + .../go_postgresql_stdlib/schema.sql | 2 + .../go_postgresql_stdlib/sqlc.json | 13 + .../testdata/exec_no_return_struct/issue.md | 1 + .../postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 14 + .../postgresql/pgx/go/query.sql.go | 30 + .../postgresql/pgx/query.sql | 13 + .../postgresql/pgx/schema.sql | 5 + .../postgresql/pgx/sqlc.yaml | 10 + .../exec_result/go_postgresql_pgx/v4/go/db.go | 32 + .../go_postgresql_pgx/v4/go/models.go | 9 + .../go_postgresql_pgx/v4/go/querier.go | 17 + .../go_postgresql_pgx/v4/go/query.sql.go | 20 + .../go_postgresql_pgx/v4/query.sql | 2 + .../go_postgresql_pgx/v4/schema.sql | 2 + .../go_postgresql_pgx/v4/sqlc.json | 14 + .../exec_result/go_postgresql_pgx/v5/go/db.go | 32 + .../go_postgresql_pgx/v5/go/models.go | 9 + .../go_postgresql_pgx/v5/go/querier.go | 17 + .../go_postgresql_pgx/v5/go/query.sql.go | 20 + .../go_postgresql_pgx/v5/query.sql | 2 + .../go_postgresql_pgx/v5/schema.sql | 2 + .../go_postgresql_pgx/v5/sqlc.json | 14 + .../exec_result/go_postgresql_stdlib/go/db.go | 31 + .../go_postgresql_stdlib/go/models.go | 9 + .../go_postgresql_stdlib/go/querier.go | 16 + .../go_postgresql_stdlib/go/query.sql.go | 19 + .../go_postgresql_stdlib/query.sql | 2 + .../go_postgresql_stdlib/schema.sql | 2 + .../go_postgresql_stdlib/sqlc.json | 12 + .../exec_rows/go_postgresql_pgx/v4/go/db.go | 32 + .../go_postgresql_pgx/v4/go/models.go | 9 + .../go_postgresql_pgx/v4/go/querier.go | 15 + .../go_postgresql_pgx/v4/go/query.sql.go | 22 + .../exec_rows/go_postgresql_pgx/v4/query.sql | 2 + .../exec_rows/go_postgresql_pgx/v4/schema.sql | 2 + .../exec_rows/go_postgresql_pgx/v4/sqlc.json | 14 + .../exec_rows/go_postgresql_pgx/v5/go/db.go | 32 + .../go_postgresql_pgx/v5/go/models.go | 9 + .../go_postgresql_pgx/v5/go/querier.go | 15 + .../go_postgresql_pgx/v5/go/query.sql.go | 22 + .../exec_rows/go_postgresql_pgx/v5/query.sql | 2 + .../exec_rows/go_postgresql_pgx/v5/schema.sql | 2 + .../exec_rows/go_postgresql_pgx/v5/sqlc.json | 14 + .../exec_rows/go_postgresql_stdlib/go/db.go | 31 + .../go_postgresql_stdlib/go/models.go | 9 + .../go_postgresql_stdlib/go/querier.go | 15 + .../go_postgresql_stdlib/go/query.sql.go | 22 + .../exec_rows/go_postgresql_stdlib/query.sql | 2 + .../exec_rows/go_postgresql_stdlib/schema.sql | 2 + .../exec_rows/go_postgresql_stdlib/sqlc.json | 12 + .../experiment_coreanalyzer/mysql/exec.json | 6 + .../experiment_coreanalyzer/mysql/go/db.go | 31 + .../mysql/go/models.go | 15 + .../mysql/go/query.sql.go | 81 + .../experiment_coreanalyzer/mysql/query.sql | 15 + .../experiment_coreanalyzer/mysql/schema.sql | 5 + .../experiment_coreanalyzer/mysql/sqlc.json | 12 + .../postgresql/stdlib/exec.json | 6 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 16 + .../postgresql/stdlib/go/query.sql.go | 97 + .../postgresql/stdlib/query.sql | 16 + .../postgresql/stdlib/schema.sql | 6 + .../postgresql/stdlib/sqlc.json | 12 + .../experiment_coreanalyzer/sqlite/exec.json | 6 + .../experiment_coreanalyzer/sqlite/go/db.go | 31 + .../sqlite/go/models.go | 15 + .../sqlite/go/query.sql.go | 87 + .../experiment_coreanalyzer/sqlite/query.sql | 18 + .../experiment_coreanalyzer/sqlite/schema.sql | 5 + .../experiment_coreanalyzer/sqlite/sqlc.json | 12 + .../endtoend/testdata/fmt/mysql/exec.json | 5 + .../endtoend/testdata/fmt/mysql/query.sql | 72 + .../endtoend/testdata/fmt/mysql/schema.sql | 5 + .../endtoend/testdata/fmt/mysql/sqlc.yaml | 9 + .../endtoend/testdata/fmt/mysql/stdout.txt | 73 + .../testdata/fmt/postgresql/exec.json | 5 + .../testdata/fmt/postgresql/query.sql | 33 + .../testdata/fmt/postgresql/schema.sql | 6 + .../testdata/fmt/postgresql/sqlc.yaml | 9 + .../testdata/fmt/postgresql/stdout.txt | 48 + .../endtoend/testdata/fmt/sqlite/exec.json | 5 + .../endtoend/testdata/fmt/sqlite/query.sql | 107 + .../endtoend/testdata/fmt/sqlite/schema.sql | 11 + .../endtoend/testdata/fmt/sqlite/sqlc.yaml | 9 + .../endtoend/testdata/fmt/sqlite/stdout.txt | 84 + .../testdata/full_outer_join/sqlite/go/db.go | 31 + .../full_outer_join/sqlite/go/models.go | 15 + .../full_outer_join/sqlite/go/query.sql.go | 38 + .../testdata/full_outer_join/sqlite/query.sql | 6 + .../full_outer_join/sqlite/schema.sql | 11 + .../testdata/full_outer_join/sqlite/sqlc.json | 1 + .../func_aggregate/pganalyze/exec.json | 3 + .../func_aggregate/pganalyze/go/db.go | 31 + .../func_aggregate/pganalyze/go/models.go | 15 + .../func_aggregate/pganalyze/go/query.sql.go | 22 + .../func_aggregate/pganalyze/query.sql | 3 + .../func_aggregate/pganalyze/schema.sql | 7 + .../func_aggregate/pganalyze/sqlc.json | 11 + .../func_aggregate/postgresql/exec.json | 3 + .../func_aggregate/postgresql/go/db.go | 31 + .../func_aggregate/postgresql/go/models.go | 15 + .../func_aggregate/postgresql/go/query.sql.go | 22 + .../func_aggregate/postgresql/query.sql | 3 + .../func_aggregate/postgresql/schema.sql | 7 + .../func_aggregate/postgresql/sqlc.json | 11 + .../testdata/func_args/pgx/v4/go/db.go | 32 + .../testdata/func_args/pgx/v4/go/models.go | 5 + .../testdata/func_args/pgx/v4/go/query.sql.go | 70 + .../testdata/func_args/pgx/v4/query.sql | 14 + .../testdata/func_args/pgx/v4/schema.sql | 8 + .../testdata/func_args/pgx/v4/sqlc.json | 13 + .../testdata/func_args/pgx/v5/go/db.go | 32 + .../testdata/func_args/pgx/v5/go/models.go | 5 + .../testdata/func_args/pgx/v5/go/query.sql.go | 72 + .../testdata/func_args/pgx/v5/query.sql | 14 + .../testdata/func_args/pgx/v5/schema.sql | 8 + .../testdata/func_args/pgx/v5/sqlc.json | 13 + .../testdata/func_args/stdlib/go/db.go | 31 + .../testdata/func_args/stdlib/go/models.go | 5 + .../testdata/func_args/stdlib/go/query.sql.go | 70 + .../testdata/func_args/stdlib/query.sql | 14 + .../testdata/func_args/stdlib/schema.sql | 8 + .../testdata/func_args/stdlib/sqlc.json | 11 + .../func_args_typecast/pgx/v4/go/db.go | 32 + .../func_args_typecast/pgx/v4/go/models.go | 5 + .../func_args_typecast/pgx/v4/go/query.sql.go | 26 + .../func_args_typecast/pgx/v4/query.sql | 2 + .../func_args_typecast/pgx/v4/schema.sql | 6 + .../func_args_typecast/pgx/v4/sqlc.json | 13 + .../func_args_typecast/pgx/v5/go/db.go | 32 + .../func_args_typecast/pgx/v5/go/models.go | 5 + .../func_args_typecast/pgx/v5/go/query.sql.go | 26 + .../func_args_typecast/pgx/v5/query.sql | 2 + .../func_args_typecast/pgx/v5/schema.sql | 6 + .../func_args_typecast/pgx/v5/sqlc.json | 13 + .../func_args_typecast/stdlib/go/db.go | 31 + .../func_args_typecast/stdlib/go/models.go | 5 + .../func_args_typecast/stdlib/go/query.sql.go | 26 + .../func_args_typecast/stdlib/query.sql | 2 + .../func_args_typecast/stdlib/schema.sql | 6 + .../func_args_typecast/stdlib/sqlc.json | 11 + .../testdata/func_call_cast/mysql/go/db.go | 31 + .../func_call_cast/mysql/go/models.go | 5 + .../func_call_cast/mysql/go/query.sql.go | 21 + .../testdata/func_call_cast/mysql/query.sql | 2 + .../testdata/func_call_cast/mysql/schema.sql | 0 .../testdata/func_call_cast/mysql/sqlc.json | 12 + .../func_call_cast/postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 5 + .../postgresql/pgx/v4/go/query.sql.go | 23 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 1 + .../postgresql/pgx/v4/sqlc.json | 13 + .../func_call_cast/postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 23 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 1 + .../postgresql/pgx/v5/sqlc.json | 13 + .../func_call_cast/postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/query.sql.go | 23 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 1 + .../postgresql/stdlib/sqlc.json | 11 + .../testdata/func_call_cast/sqlite/go/db.go | 31 + .../func_call_cast/sqlite/go/models.go | 5 + .../func_call_cast/sqlite/go/query.sql.go | 21 + .../testdata/func_call_cast/sqlite/query.sql | 2 + .../testdata/func_call_cast/sqlite/schema.sql | 0 .../testdata/func_call_cast/sqlite/sqlc.json | 12 + .../testdata/func_match_types/mysql/go/db.go | 31 + .../func_match_types/mysql/go/models.go | 12 + .../func_match_types/mysql/go/query.sql.go | 45 + .../testdata/func_match_types/mysql/query.sql | 4 + .../func_match_types/mysql/schema.sql | 6 + .../testdata/func_match_types/mysql/sqlc.json | 12 + .../func_match_types/postgresql/go/db.go | 31 + .../func_match_types/postgresql/go/models.go | 12 + .../postgresql/go/query.sql.go | 45 + .../func_match_types/postgresql/query.sql | 4 + .../func_match_types/postgresql/schema.sql | 6 + .../func_match_types/postgresql/sqlc.json | 11 + .../testdata/func_match_types/sqlite/go/db.go | 31 + .../func_match_types/sqlite/go/models.go | 12 + .../func_match_types/sqlite/go/query.sql.go | 46 + .../func_match_types/sqlite/query.sql | 4 + .../func_match_types/sqlite/schema.sql | 6 + .../func_match_types/sqlite/sqlc.json | 12 + .../endtoend/testdata/func_out_param/issue.md | 1 + .../testdata/func_out_param/pgx/go/db.go | 32 + .../testdata/func_out_param/pgx/go/models.go | 15 + .../func_out_param/pgx/go/query.sql.go | 30 + .../testdata/func_out_param/pgx/query.sql | 4 + .../testdata/func_out_param/pgx/schema.sql | 14 + .../testdata/func_out_param/pgx/sqlc.yaml | 10 + .../postgresql/pganalyze/exec.json | 3 + .../postgresql/pganalyze/go/db.go | 32 + .../postgresql/pganalyze/go/models.go | 5 + .../postgresql/pganalyze/go/query.sql.go | 23 + .../postgresql/pganalyze/query.sql | 2 + .../postgresql/pganalyze/schema.sql | 0 .../postgresql/pganalyze/sqlc.json | 13 + .../postgresql/pgx/v5/exec.json | 3 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 24 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 0 .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/exec.json | 3 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/query.sql.go | 24 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 0 .../postgresql/stdlib/sqlc.json | 12 + .../testdata/func_return_record/issue.md | 1 + .../postgresql/pgx/exec.json | 3 + .../postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 9 + .../postgresql/pgx/go/query.sql.go | 30 + .../postgresql/pgx/query.sql | 4 + .../postgresql/pgx/schema.sql | 3 + .../postgresql/pgx/sqlc.yaml | 10 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 5 + .../postgresql/pgx/v4/go/query.sql.go | 41 + .../postgresql/pgx/v4/query.sql | 4 + .../postgresql/pgx/v4/schema.sql | 0 .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 41 + .../postgresql/pgx/v5/query.sql | 4 + .../postgresql/pgx/v5/schema.sql | 0 .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/query.sql.go | 44 + .../postgresql/stdlib/query.sql | 4 + .../postgresql/stdlib/schema.sql | 0 .../postgresql/stdlib/sqlc.json | 12 + .../testdata/func_return_table/issue.md | 1 + .../postgresql/pgx/exec.json | 3 + .../func_return_table/postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 11 + .../postgresql/pgx/go/query.sql.go | 23 + .../postgresql/pgx/query.sql | 2 + .../postgresql/pgx/schema.sql | 27 + .../postgresql/pgx/sqlc.yaml | 10 + .../func_return_table_columns/issue.md | 1 + .../postgresql/pgx/exec.json | 3 + .../postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 10 + .../postgresql/pgx/go/query.sql.go | 41 + .../postgresql/pgx/query.sql | 2 + .../postgresql/pgx/schema.sql | 11 + .../postgresql/pgx/sqlc.yaml | 10 + .../testdata/func_star_expansion/issue.md | 1 + .../postgresql/pgx/exec.json | 3 + .../postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 5 + .../postgresql/pgx/go/query.sql.go | 45 + .../postgresql/pgx/query.sql | 8 + .../postgresql/pgx/schema.sql | 20 + .../postgresql/pgx/sqlc.yaml | 10 + .../func_variadic/postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 15 + .../postgresql/stdlib/go/query.sql.go | 39 + .../func_variadic/postgresql/stdlib/query.sql | 7 + .../postgresql/stdlib/schema.sql | 5 + .../func_variadic/postgresql/stdlib/sqlc.json | 12 + .../testdata/geometric/pgx/v4/go/db.go | 32 + .../testdata/geometric/pgx/v4/go/models.go | 26 + .../testdata/geometric/pgx/v4/go/query.sql.go | 50 + .../testdata/geometric/pgx/v4/query.sql | 3 + .../testdata/geometric/pgx/v4/schema.sql | 18 + .../testdata/geometric/pgx/v4/sqlc.json | 13 + .../testdata/geometric/pgx/v5/go/db.go | 32 + .../testdata/geometric/pgx/v5/go/models.go | 26 + .../testdata/geometric/pgx/v5/go/query.sql.go | 50 + .../testdata/geometric/pgx/v5/query.sql | 3 + .../testdata/geometric/pgx/v5/schema.sql | 18 + .../testdata/geometric/pgx/v5/sqlc.json | 13 + internal/endtoend/testdata/go.mod | 37 + internal/endtoend/testdata/go.sum | 219 + .../golang_initialisms_empty/db/db.go | 31 + .../golang_initialisms_empty/db/models.go | 13 + .../golang_initialisms_empty/db/query.sql.go | 38 + .../golang_initialisms_empty/query.sql | 2 + .../golang_initialisms_empty/schema.sql | 3 + .../golang_initialisms_empty/sqlc.json | 16 + .../testdata/golang_initialisms_url/db/db.go | 31 + .../golang_initialisms_url/db/models.go | 14 + .../golang_initialisms_url/db/query.sql.go | 37 + .../testdata/golang_initialisms_url/query.sql | 2 + .../golang_initialisms_url/schema.sql | 4 + .../testdata/golang_initialisms_url/sqlc.json | 16 + .../golang_invalid_sql_driver/db/db.go | 31 + .../golang_invalid_sql_driver/db/models.go | 13 + .../golang_invalid_sql_driver/db/query.sql.go | 38 + .../golang_invalid_sql_driver/query.sql | 2 + .../golang_invalid_sql_driver/schema.sql | 3 + .../golang_invalid_sql_driver/sqlc.json | 16 + .../golang_invalid_sql_driver/stderr.txt | 2 + .../golang_invalid_sql_package/db/db.go | 31 + .../golang_invalid_sql_package/db/models.go | 13 + .../db/query.sql.go | 38 + .../golang_invalid_sql_package/query.sql | 2 + .../golang_invalid_sql_package/schema.sql | 3 + .../golang_invalid_sql_package/sqlc.json | 16 + .../golang_invalid_sql_package/stderr.txt | 2 + .../endtoend/testdata/having/mysql/go/db.go | 31 + .../testdata/having/mysql/go/models.go | 10 + .../testdata/having/mysql/go/query.sql.go | 40 + .../endtoend/testdata/having/mysql/query.sql | 5 + .../endtoend/testdata/having/mysql/schema.sql | 5 + .../endtoend/testdata/having/mysql/sqlc.json | 12 + .../testdata/having/postgresql/go/db.go | 31 + .../testdata/having/postgresql/go/models.go | 10 + .../having/postgresql/go/query.sql.go | 40 + .../testdata/having/postgresql/query.sql | 5 + .../testdata/having/postgresql/schema.sql | 5 + .../testdata/having/postgresql/sqlc.json | 12 + .../endtoend/testdata/hstore/pgx/v4/go/db.go | 32 + .../testdata/hstore/pgx/v4/go/hstore.sql.go | 60 + .../testdata/hstore/pgx/v4/go/models.go | 14 + .../testdata/hstore/pgx/v4/hstore.sql | 14 + .../endtoend/testdata/hstore/pgx/v4/sqlc.json | 13 + .../endtoend/testdata/hstore/pgx/v5/go/db.go | 32 + .../testdata/hstore/pgx/v5/go/hstore.sql.go | 60 + .../testdata/hstore/pgx/v5/go/models.go | 14 + .../testdata/hstore/pgx/v5/hstore.sql | 14 + .../endtoend/testdata/hstore/pgx/v5/sqlc.json | 13 + .../endtoend/testdata/hstore/stdlib/go/db.go | 31 + .../testdata/hstore/stdlib/go/hstore.sql.go | 64 + .../testdata/hstore/stdlib/go/models.go | 10 + .../testdata/hstore/stdlib/hstore.sql | 14 + .../endtoend/testdata/hstore/stdlib/sqlc.json | 11 + .../testdata/identical_tables/mysql/go/db.go | 31 + .../identical_tables/mysql/go/models.go | 13 + .../identical_tables/mysql/go/query.sql.go | 37 + .../testdata/identical_tables/mysql/query.sql | 2 + .../identical_tables/mysql/schema.sql | 3 + .../testdata/identical_tables/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 13 + .../postgresql/pgx/v4/go/query.sql.go | 34 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 3 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 13 + .../postgresql/pgx/v5/go/query.sql.go | 34 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 3 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 13 + .../postgresql/stdlib/go/query.sql.go | 37 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 3 + .../postgresql/stdlib/sqlc.json | 12 + .../testdata/identical_tables/sqlite/go/db.go | 31 + .../identical_tables/sqlite/go/models.go | 13 + .../identical_tables/sqlite/go/query.sql.go | 37 + .../identical_tables/sqlite/query.sql | 2 + .../identical_tables/sqlite/schema.sql | 3 + .../identical_tables/sqlite/sqlc.json | 12 + .../identifier_case_sensitivity/db/db.go | 31 + .../identifier_case_sensitivity/db/models.go | 15 + .../db/query.sql.go | 78 + .../identifier_case_sensitivity/query.sql | 18 + .../identifier_case_sensitivity/schema.sql | 6 + .../identifier_case_sensitivity/sqlc.json | 11 + .../testdata/identifier_dollar_sign/db/db.go | 31 + .../identifier_dollar_sign/db/models.go | 5 + .../identifier_dollar_sign/db/query.sql.go | 21 + .../testdata/identifier_dollar_sign/query.sql | 2 + .../identifier_dollar_sign/schema.sql | 3 + .../testdata/identifier_dollar_sign/sqlc.json | 11 + .../endtoend/testdata/in_union/mysql/go/db.go | 31 + .../testdata/in_union/mysql/go/models.go | 25 + .../testdata/in_union/mysql/go/query.sql.go | 38 + .../testdata/in_union/mysql/query.sql | 3 + .../testdata/in_union/mysql/schema.sql | 15 + .../testdata/in_union/mysql/sqlc.json | 12 + .../testdata/inflection/mysql/go/db.go | 31 + .../testdata/inflection/mysql/go/models.go | 25 + .../testdata/inflection/mysql/go/query.sql.go | 145 + .../testdata/inflection/mysql/query.sql | 14 + .../testdata/inflection/mysql/schema.sql | 5 + .../testdata/inflection/mysql/sqlc.json | 12 + .../inflection/postgresql/pgx/v4/go/db.go | 32 + .../inflection/postgresql/pgx/v4/go/models.go | 25 + .../postgresql/pgx/v4/go/query.sql.go | 130 + .../inflection/postgresql/pgx/v4/query.sql | 14 + .../inflection/postgresql/pgx/v4/schema.sql | 5 + .../inflection/postgresql/pgx/v4/sqlc.json | 13 + .../inflection/postgresql/pgx/v5/go/db.go | 32 + .../inflection/postgresql/pgx/v5/go/models.go | 25 + .../postgresql/pgx/v5/go/query.sql.go | 130 + .../inflection/postgresql/pgx/v5/query.sql | 14 + .../inflection/postgresql/pgx/v5/schema.sql | 5 + .../inflection/postgresql/pgx/v5/sqlc.json | 13 + .../inflection/postgresql/stdlib/go/db.go | 31 + .../inflection/postgresql/stdlib/go/models.go | 25 + .../postgresql/stdlib/go/query.sql.go | 145 + .../inflection/postgresql/stdlib/query.sql | 14 + .../inflection/postgresql/stdlib/schema.sql | 5 + .../inflection/postgresql/stdlib/sqlc.json | 12 + .../testdata/inflection/sqlite/go/db.go | 31 + .../testdata/inflection/sqlite/go/models.go | 25 + .../inflection/sqlite/go/query.sql.go | 145 + .../testdata/inflection/sqlite/query.sql | 14 + .../testdata/inflection/sqlite/schema.sql | 5 + .../testdata/inflection/sqlite/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 20 + .../postgresql/pgx/v4/go/query.sql.go | 43 + .../postgresql/pgx/v4/query.sql | 8 + .../postgresql/pgx/v4/schema.sql | 4 + .../postgresql/pgx/v4/sqlc.json | 21 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 20 + .../postgresql/pgx/v5/go/query.sql.go | 43 + .../postgresql/pgx/v5/query.sql | 8 + .../postgresql/pgx/v5/schema.sql | 4 + .../postgresql/pgx/v5/sqlc.json | 21 + .../testdata/insert_cte/pgx/v4/go/db.go | 32 + .../testdata/insert_cte/pgx/v4/go/models.go | 31 + .../insert_cte/pgx/v4/go/query.sql.go | 51 + .../testdata/insert_cte/pgx/v4/query.sql | 11 + .../testdata/insert_cte/pgx/v4/schema.sql | 31 + .../testdata/insert_cte/pgx/v4/sqlc.json | 13 + .../testdata/insert_cte/pgx/v5/go/db.go | 32 + .../testdata/insert_cte/pgx/v5/go/models.go | 30 + .../insert_cte/pgx/v5/go/query.sql.go | 52 + .../testdata/insert_cte/pgx/v5/query.sql | 11 + .../testdata/insert_cte/pgx/v5/schema.sql | 31 + .../testdata/insert_cte/pgx/v5/sqlc.json | 13 + .../testdata/insert_cte/stdlib/go/db.go | 31 + .../testdata/insert_cte/stdlib/go/models.go | 31 + .../insert_cte/stdlib/go/query.sql.go | 51 + .../testdata/insert_cte/stdlib/query.sql | 11 + .../testdata/insert_cte/stdlib/schema.sql | 31 + .../testdata/insert_cte/stdlib/sqlc.json | 11 + .../insert_default_values/sqlite/go/db.go | 31 + .../insert_default_values/sqlite/go/models.go | 9 + .../sqlite/go/query.sql.go | 19 + .../insert_default_values/sqlite/query.sql | 2 + .../insert_default_values/sqlite/schema.sql | 3 + .../insert_default_values/sqlite/sqlc.json | 12 + .../testdata/insert_select/mysql/go/db.go | 31 + .../testdata/insert_select/mysql/go/models.go | 15 + .../insert_select/mysql/go/query.sql.go | 26 + .../testdata/insert_select/mysql/query.sql | 4 + .../testdata/insert_select/mysql/schema.sql | 3 + .../testdata/insert_select/mysql/sqlc.json | 12 + .../insert_select/postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 15 + .../postgresql/pgx/v4/go/query.sql.go | 26 + .../insert_select/postgresql/pgx/v4/query.sql | 4 + .../postgresql/pgx/v4/schema.sql | 3 + .../insert_select/postgresql/pgx/v4/sqlc.json | 13 + .../insert_select/postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 15 + .../postgresql/pgx/v5/go/query.sql.go | 26 + .../insert_select/postgresql/pgx/v5/query.sql | 4 + .../postgresql/pgx/v5/schema.sql | 3 + .../insert_select/postgresql/pgx/v5/sqlc.json | 13 + .../insert_select/postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 15 + .../postgresql/stdlib/go/query.sql.go | 26 + .../insert_select/postgresql/stdlib/query.sql | 4 + .../postgresql/stdlib/schema.sql | 3 + .../insert_select/postgresql/stdlib/sqlc.json | 12 + .../testdata/insert_select/sqlite/go/db.go | 31 + .../insert_select/sqlite/go/models.go | 15 + .../insert_select/sqlite/go/query.sql.go | 27 + .../testdata/insert_select/sqlite/query.sql | 5 + .../testdata/insert_select/sqlite/schema.sql | 3 + .../testdata/insert_select/sqlite/sqlc.json | 12 + .../testdata/insert_select_case/issue.md | 1 + .../postgresql/pgx/exec.json | 3 + .../postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 14 + .../postgresql/pgx/go/query.sql.go | 28 + .../postgresql/pgx/query.sql | 4 + .../postgresql/pgx/schema.sql | 4 + .../postgresql/pgx/sqlc.yaml | 12 + .../insert_select_invalid/mysql/query.sql | 3 + .../insert_select_invalid/mysql/schema.sql | 1 + .../insert_select_invalid/mysql/sqlc.json | 12 + .../insert_select_invalid/mysql/stderr.txt | 2 + .../postgresql/pgx/v4/query.sql | 3 + .../postgresql/pgx/v4/schema.sql | 1 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v4/stderr/base.txt | 2 + .../postgresql/pgx/v4/stderr/managed-db.txt | 2 + .../postgresql/pgx/v5/query.sql | 3 + .../postgresql/pgx/v5/schema.sql | 1 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/pgx/v5/stderr/base.txt | 2 + .../postgresql/pgx/v5/stderr/managed-db.txt | 2 + .../postgresql/stdlib/query.sql | 3 + .../postgresql/stdlib/schema.sql | 1 + .../postgresql/stdlib/sqlc.json | 12 + .../postgresql/stdlib/stderr/base.txt | 2 + .../postgresql/stdlib/stderr/managed-db.txt | 2 + .../insert_select_invalid/sqlite/exec.json | 3 + .../insert_select_invalid/sqlite/query.sql | 3 + .../insert_select_invalid/sqlite/schema.sql | 1 + .../insert_select_invalid/sqlite/sqlc.json | 12 + .../insert_select_invalid/sqlite/stderr.txt | 2 + .../testdata/insert_select_param/issue.md | 1 + .../postgresql/pgx/exec.json | 3 + .../postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 15 + .../postgresql/pgx/go/query.sql.go | 29 + .../postgresql/pgx/query.sql | 5 + .../postgresql/pgx/schema.sql | 5 + .../postgresql/pgx/sqlc.yaml | 10 + .../testdata/insert_values/mysql/go/db.go | 31 + .../testdata/insert_values/mysql/go/models.go | 14 + .../insert_values/mysql/go/query.sql.go | 46 + .../testdata/insert_values/mysql/query.sql | 5 + .../testdata/insert_values/mysql/schema.sql | 2 + .../testdata/insert_values/mysql/sqlc.json | 12 + .../insert_values/postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 14 + .../postgresql/pgx/v4/go/query.sql.go | 46 + .../insert_values/postgresql/pgx/v4/query.sql | 5 + .../postgresql/pgx/v4/schema.sql | 2 + .../insert_values/postgresql/pgx/v4/sqlc.json | 13 + .../insert_values/postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 14 + .../postgresql/pgx/v5/go/query.sql.go | 47 + .../insert_values/postgresql/pgx/v5/query.sql | 5 + .../postgresql/pgx/v5/schema.sql | 2 + .../insert_values/postgresql/pgx/v5/sqlc.json | 13 + .../insert_values/postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 14 + .../postgresql/stdlib/go/query.sql.go | 46 + .../insert_values/postgresql/stdlib/query.sql | 5 + .../postgresql/stdlib/schema.sql | 2 + .../insert_values/postgresql/stdlib/sqlc.json | 12 + .../testdata/insert_values/sqlite/go/db.go | 31 + .../insert_values/sqlite/go/models.go | 14 + .../insert_values/sqlite/go/query.sql.go | 46 + .../testdata/insert_values/sqlite/query.sql | 5 + .../testdata/insert_values/sqlite/schema.sql | 2 + .../testdata/insert_values/sqlite/sqlc.json | 12 + .../testdata/insert_values_only/issue.md | 1 + .../postgresql/pgx/exec.json | 3 + .../postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 10 + .../postgresql/pgx/go/query.sql.go | 26 + .../postgresql/pgx/query.sql | 2 + .../postgresql/pgx/schema.sql | 6 + .../postgresql/pgx/sqlc.yaml | 10 + .../insert_values_public/mysql/go/db.go | 31 + .../insert_values_public/mysql/go/models.go | 14 + .../mysql/go/query.sql.go | 25 + .../insert_values_public/mysql/query.sql | 2 + .../insert_values_public/mysql/schema.sql | 2 + .../insert_values_public/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 14 + .../postgresql/pgx/v4/go/query.sql.go | 25 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 14 + .../postgresql/pgx/v5/go/query.sql.go | 26 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 14 + .../postgresql/stdlib/go/query.sql.go | 25 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../testdata/interval/pgx/v4/exec.json | 3 + .../testdata/interval/pgx/v4/go/db.go | 32 + .../testdata/interval/pgx/v4/go/models.go | 10 + .../testdata/interval/pgx/v4/go/query.sql.go | 34 + .../testdata/interval/pgx/v4/query.sql | 2 + .../testdata/interval/pgx/v4/schema.sql | 2 + .../testdata/interval/pgx/v4/sqlc.json | 13 + .../testdata/interval/pgx/v5/exec.json | 3 + .../testdata/interval/pgx/v5/go/db.go | 32 + .../testdata/interval/pgx/v5/go/models.go | 14 + .../testdata/interval/pgx/v5/go/query.sql.go | 34 + .../testdata/interval/pgx/v5/query.sql | 2 + .../testdata/interval/pgx/v5/schema.sql | 2 + .../testdata/interval/pgx/v5/sqlc.json | 13 + .../testdata/interval/stdlib/exec.json | 3 + .../testdata/interval/stdlib/go/db.go | 31 + .../testdata/interval/stdlib/go/models.go | 10 + .../testdata/interval/stdlib/go/query.sql.go | 37 + .../testdata/interval/stdlib/query.sql | 2 + .../testdata/interval/stdlib/schema.sql | 2 + .../testdata/interval/stdlib/sqlc.json | 11 + .../invalid_func_args/pgx/v4/query.sql | 2 + .../invalid_func_args/pgx/v4/schema.sql | 0 .../invalid_func_args/pgx/v4/sqlc.json | 13 + .../invalid_func_args/pgx/v4/stderr/base.txt | 2 + .../pgx/v4/stderr/managed-db.txt | 2 + .../invalid_func_args/pgx/v5/query.sql | 2 + .../invalid_func_args/pgx/v5/schema.sql | 0 .../invalid_func_args/pgx/v5/sqlc.json | 13 + .../invalid_func_args/pgx/v5/stderr/base.txt | 2 + .../pgx/v5/stderr/managed-db.txt | 2 + .../invalid_func_args/stdlib/query.sql | 2 + .../invalid_func_args/stdlib/schema.sql | 0 .../invalid_func_args/stdlib/sqlc.json | 11 + .../invalid_func_args/stdlib/stderr/base.txt | 2 + .../stdlib/stderr/managed-db.txt | 2 + .../mysql/exec.json | 6 + .../mysql/query.sql | 4 + .../mysql/schema.sql | 5 + .../mysql/sqlc.json | 12 + .../mysql/stderr.txt | 2 + .../postgresql/query.sql | 4 + .../postgresql/schema.sql | 5 + .../postgresql/sqlc.json | 12 + .../postgresql/stderr/base.txt | 2 + .../postgresql/stderr/managed-db.txt | 2 + .../sqlite/exec.json | 3 + .../sqlite/query.sql | 4 + .../sqlite/schema.sql | 6 + .../sqlite/sqlc.json | 12 + .../sqlite/stderr.txt | 2 + .../invalid_insert_unknown_column/issue.md | 1 + .../postgresql/pgx/db/db.go | 32 + .../postgresql/pgx/db/models.go | 15 + .../postgresql/pgx/db/query.sql.go | 33 + .../postgresql/pgx/exec.json | 3 + .../postgresql/pgx/query.sql | 7 + .../postgresql/pgx/schema.sql | 5 + .../postgresql/pgx/sqlc.json | 19 + .../postgresql/pgx/stderr.txt | 2 + .../invalid_named_params/mysql/query.sql | 6 + .../invalid_named_params/mysql/schema.sql | 4 + .../invalid_named_params/mysql/sqlc.json | 12 + .../invalid_named_params/mysql/stderr.txt | 2 + .../testdata/invalid_params/pgx/v4/query.sql | 11 + .../testdata/invalid_params/pgx/v4/schema.sql | 1 + .../testdata/invalid_params/pgx/v4/sqlc.json | 11 + .../invalid_params/pgx/v4/stderr/base.txt | 5 + .../pgx/v4/stderr/managed-db.txt | 5 + .../testdata/invalid_params/pgx/v5/query.sql | 11 + .../testdata/invalid_params/pgx/v5/schema.sql | 1 + .../testdata/invalid_params/pgx/v5/sqlc.json | 11 + .../invalid_params/pgx/v5/stderr/base.txt | 5 + .../pgx/v5/stderr/managed-db.txt | 5 + .../testdata/invalid_params/stdlib/query.sql | 11 + .../testdata/invalid_params/stdlib/schema.sql | 1 + .../testdata/invalid_params/stdlib/sqlc.json | 13 + .../invalid_params/stdlib/stderr/base.txt | 5 + .../stdlib/stderr/managed-db.txt | 5 + .../invalid_params_type_mismatch/issue.md | 1 + .../postgresql/pgx/exec.json | 3 + .../postgresql/pgx/query.sql | 4 + .../postgresql/pgx/schema.sql | 5 + .../postgresql/pgx/sqlc.json | 13 + .../postgresql/pgx/stderr.txt | 2 + .../invalid_queries_bar/pgx/v4/query.sql | 5 + .../invalid_queries_bar/pgx/v4/schema.sql | 1 + .../invalid_queries_bar/pgx/v4/sqlc.json | 13 + .../pgx/v4/stderr/base.txt | 3 + .../pgx/v4/stderr/managed-db.txt | 3 + .../invalid_queries_bar/pgx/v5/query.sql | 5 + .../invalid_queries_bar/pgx/v5/schema.sql | 1 + .../invalid_queries_bar/pgx/v5/sqlc.json | 13 + .../pgx/v5/stderr/base.txt | 3 + .../pgx/v5/stderr/managed-db.txt | 3 + .../invalid_queries_bar/stdlib/query.sql | 5 + .../invalid_queries_bar/stdlib/schema.sql | 1 + .../invalid_queries_bar/stdlib/sqlc.json | 11 + .../stdlib/stderr/base.txt | 3 + .../stdlib/stderr/managed-db.txt | 3 + .../invalid_queries_foo/pgx/v4/query.sql | 20 + .../invalid_queries_foo/pgx/v4/schema.sql | 1 + .../invalid_queries_foo/pgx/v4/sqlc.json | 13 + .../invalid_queries_foo/pgx/v4/stderr.txt | 8 + .../invalid_queries_foo/pgx/v5/query.sql | 20 + .../invalid_queries_foo/pgx/v5/schema.sql | 1 + .../invalid_queries_foo/pgx/v5/sqlc.json | 13 + .../invalid_queries_foo/pgx/v5/stderr.txt | 8 + .../invalid_queries_foo/stdlib/query.sql | 17 + .../invalid_queries_foo/stdlib/schema.sql | 1 + .../invalid_queries_foo/stdlib/sqlc.json | 11 + .../invalid_queries_foo/stdlib/stderr.txt | 7 + .../invalid_table_alias/mysql/query.sql | 5 + .../invalid_table_alias/mysql/schema.sql | 7 + .../invalid_table_alias/mysql/sqlc.json | 12 + .../invalid_table_alias/mysql/stderr.txt | 2 + .../invalid_table_alias/postgresql/exec.json | 3 + .../invalid_table_alias/postgresql/query.sql | 5 + .../invalid_table_alias/postgresql/schema.sql | 6 + .../invalid_table_alias/postgresql/sqlc.json | 12 + .../postgresql/stderr/base.txt | 2 + .../postgresql/stderr/managed-db.txt | 2 + .../invalid_table_alias/sqlite/exec.json | 3 + .../invalid_table_alias/sqlite/query.sql | 5 + .../invalid_table_alias/sqlite/schema.sql | 6 + .../invalid_table_alias/sqlite/sqlc.json | 12 + .../invalid_table_alias/sqlite/stderr.txt | 2 + .../invalid_update_unknown_column/issue.md | 1 + .../postgresql/pgx/exec.json | 3 + .../postgresql/pgx/query.sql | 7 + .../postgresql/pgx/schema.sql | 10 + .../postgresql/pgx/sqlc.yaml | 10 + .../postgresql/pgx/stderr.txt | 2 + .../testdata/join_alias/mysql/go/db.go | 31 + .../testdata/join_alias/mysql/go/models.go | 18 + .../testdata/join_alias/mysql/go/query.sql.go | 82 + .../testdata/join_alias/mysql/query.sql | 11 + .../testdata/join_alias/mysql/schema.sql | 3 + .../testdata/join_alias/mysql/sqlc.json | 12 + .../join_alias/postgresql/pgx/v4/go/db.go | 32 + .../join_alias/postgresql/pgx/v4/go/models.go | 18 + .../postgresql/pgx/v4/go/query.sql.go | 76 + .../join_alias/postgresql/pgx/v4/query.sql | 11 + .../join_alias/postgresql/pgx/v4/schema.sql | 3 + .../join_alias/postgresql/pgx/v4/sqlc.json | 13 + .../join_alias/postgresql/pgx/v5/go/db.go | 32 + .../join_alias/postgresql/pgx/v5/go/models.go | 18 + .../postgresql/pgx/v5/go/query.sql.go | 77 + .../join_alias/postgresql/pgx/v5/query.sql | 11 + .../join_alias/postgresql/pgx/v5/schema.sql | 3 + .../join_alias/postgresql/pgx/v5/sqlc.json | 13 + .../join_alias/postgresql/stdlib/go/db.go | 31 + .../join_alias/postgresql/stdlib/go/models.go | 18 + .../postgresql/stdlib/go/query.sql.go | 82 + .../join_alias/postgresql/stdlib/query.sql | 11 + .../join_alias/postgresql/stdlib/schema.sql | 3 + .../join_alias/postgresql/stdlib/sqlc.json | 12 + .../testdata/join_alias/sqlite/go/db.go | 31 + .../testdata/join_alias/sqlite/go/models.go | 18 + .../join_alias/sqlite/go/query.sql.go | 82 + .../testdata/join_alias/sqlite/query.sql | 11 + .../testdata/join_alias/sqlite/schema.sql | 3 + .../testdata/join_alias/sqlite/sqlc.json | 12 + .../join_clauses_order/postgresql/go/db.go | 31 + .../postgresql/go/models.go | 34 + .../postgresql/go/query.sql.go | 175 + .../join_clauses_order/postgresql/query.sql | 27 + .../join_clauses_order/postgresql/schema.sql | 29 + .../join_clauses_order/postgresql/sqlc.json | 12 + .../testdata/join_from/mysql/go/db.go | 31 + .../testdata/join_from/mysql/go/models.go | 13 + .../testdata/join_from/mysql/go/query.sql.go | 37 + .../testdata/join_from/mysql/query.sql | 2 + .../testdata/join_from/mysql/schema.sql | 3 + .../testdata/join_from/mysql/sqlc.json | 12 + .../join_from/postgresql/pgx/v4/go/db.go | 32 + .../join_from/postgresql/pgx/v4/go/models.go | 13 + .../postgresql/pgx/v4/go/query.sql.go | 34 + .../join_from/postgresql/pgx/v4/query.sql | 2 + .../join_from/postgresql/pgx/v4/schema.sql | 3 + .../join_from/postgresql/pgx/v4/sqlc.json | 13 + .../join_from/postgresql/pgx/v5/go/db.go | 32 + .../join_from/postgresql/pgx/v5/go/models.go | 13 + .../postgresql/pgx/v5/go/query.sql.go | 34 + .../join_from/postgresql/pgx/v5/query.sql | 2 + .../join_from/postgresql/pgx/v5/schema.sql | 3 + .../join_from/postgresql/pgx/v5/sqlc.json | 13 + .../join_from/postgresql/stdlib/go/db.go | 31 + .../join_from/postgresql/stdlib/go/models.go | 13 + .../postgresql/stdlib/go/query.sql.go | 37 + .../join_from/postgresql/stdlib/query.sql | 2 + .../join_from/postgresql/stdlib/schema.sql | 3 + .../join_from/postgresql/stdlib/sqlc.json | 12 + .../testdata/join_from/sqlite/go/db.go | 31 + .../testdata/join_from/sqlite/go/models.go | 13 + .../testdata/join_from/sqlite/go/query.sql.go | 37 + .../testdata/join_from/sqlite/query.sql | 2 + .../testdata/join_from/sqlite/schema.sql | 3 + .../testdata/join_from/sqlite/sqlc.json | 12 + .../testdata/join_full/postgresql/go/db.go | 31 + .../join_full/postgresql/go/models.go | 18 + .../join_full/postgresql/go/query.sql.go | 47 + .../testdata/join_full/postgresql/query.sql | 5 + .../testdata/join_full/postgresql/schema.sql | 3 + .../testdata/join_full/postgresql/sqlc.json | 12 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 9 + .../postgresql/stdlib/go/query.sql.go | 39 + .../postgresql/stdlib/query.sql | 4 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../testdata/join_inner/postgresql/go/db.go | 31 + .../join_inner/postgresql/go/models.go | 18 + .../join_inner/postgresql/go/query.sql.go | 73 + .../testdata/join_inner/postgresql/query.sql | 13 + .../testdata/join_inner/postgresql/schema.sql | 12 + .../testdata/join_inner/postgresql/sqlc.json | 12 + .../testdata/join_left/mysql/go/db.go | 31 + .../testdata/join_left/mysql/go/models.go | 60 + .../testdata/join_left/mysql/go/query.sql.go | 433 ++ .../testdata/join_left/mysql/query.sql | 59 + .../testdata/join_left/mysql/schema.sql | 55 + .../testdata/join_left/mysql/sqlc.json | 12 + .../testdata/join_left/postgresql/exec.json | 3 + .../testdata/join_left/postgresql/go/db.go | 31 + .../join_left/postgresql/go/models.go | 62 + .../join_left/postgresql/go/query.sql.go | 439 ++ .../testdata/join_left/postgresql/query.sql | 59 + .../testdata/join_left/postgresql/schema.sql | 53 + .../testdata/join_left/postgresql/sqlc.json | 12 + .../testdata/join_left/sqlite/go/db.go | 31 + .../testdata/join_left/sqlite/go/models.go | 60 + .../testdata/join_left/sqlite/go/query.sql.go | 456 ++ .../testdata/join_left/sqlite/query.sql | 58 + .../testdata/join_left/sqlite/schema.sql | 50 + .../testdata/join_left/sqlite/sqlc.json | 12 + .../join_left_same_table/mysql/go/db.go | 31 + .../join_left_same_table/mysql/go/models.go | 15 + .../mysql/go/query.sql.go | 56 + .../join_left_same_table/mysql/query.sql | 8 + .../join_left_same_table/mysql/schema.sql | 7 + .../join_left_same_table/mysql/sqlc.json | 12 + .../join_left_same_table/postgres/go/db.go | 31 + .../postgres/go/models.go | 15 + .../postgres/go/query.sql.go | 55 + .../join_left_same_table/postgres/query.sql | 7 + .../join_left_same_table/postgres/schema.sql | 6 + .../join_left_same_table/postgres/sqlc.json | 12 + .../join_left_same_table/sqlite/go/db.go | 31 + .../join_left_same_table/sqlite/go/models.go | 15 + .../sqlite/go/query.sql.go | 56 + .../join_left_same_table/sqlite/query.sql | 8 + .../join_left_same_table/sqlite/schema.sql | 6 + .../join_left_same_table/sqlite/sqlc.json | 12 + .../testdata/join_left_table_alias/issue.md | 1 + .../postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 14 + .../postgresql/pgx/go/query.sql.go | 48 + .../postgresql/pgx/query.sql | 9 + .../postgresql/pgx/schema.sql | 9 + .../postgresql/pgx/sqlc.yaml | 10 + .../endtoend/testdata/join_order_by/issue.md | 1 + .../join_order_by/postgresql/pgx/exec.json | 3 + .../join_order_by/postgresql/pgx/go/db.go | 32 + .../join_order_by/postgresql/pgx/go/models.go | 15 + .../postgresql/pgx/go/query.sql.go | 23 + .../join_order_by/postgresql/pgx/query.sql | 4 + .../join_order_by/postgresql/pgx/schema.sql | 5 + .../join_order_by/postgresql/pgx/sqlc.yaml | 10 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 9 + .../postgresql/stdlib/go/query.sql.go | 39 + .../postgresql/stdlib/query.sql | 4 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../testdata/join_right/mysql/go/db.go | 31 + .../testdata/join_right/mysql/go/models.go | 18 + .../testdata/join_right/mysql/go/query.sql.go | 47 + .../testdata/join_right/mysql/query.sql | 5 + .../testdata/join_right/mysql/schema.sql | 8 + .../testdata/join_right/mysql/sqlc.json | 12 + .../testdata/join_right/postgresql/go/db.go | 31 + .../join_right/postgresql/go/models.go | 18 + .../join_right/postgresql/go/query.sql.go | 47 + .../testdata/join_right/postgresql/query.sql | 5 + .../testdata/join_right/postgresql/schema.sql | 3 + .../testdata/join_right/postgresql/sqlc.json | 12 + .../testdata/join_table_name/mysql/go/db.go | 31 + .../join_table_name/mysql/go/models.go | 18 + .../join_table_name/mysql/go/query.sql.go | 29 + .../testdata/join_table_name/mysql/query.sql | 5 + .../testdata/join_table_name/mysql/schema.sql | 7 + .../testdata/join_table_name/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 18 + .../postgresql/pgx/v4/go/query.sql.go | 29 + .../postgresql/pgx/v4/query.sql | 5 + .../postgresql/pgx/v4/schema.sql | 3 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 18 + .../postgresql/pgx/v5/go/query.sql.go | 29 + .../postgresql/pgx/v5/query.sql | 5 + .../postgresql/pgx/v5/schema.sql | 3 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 18 + .../postgresql/stdlib/go/query.sql.go | 29 + .../postgresql/stdlib/query.sql | 5 + .../postgresql/stdlib/schema.sql | 3 + .../postgresql/stdlib/sqlc.json | 12 + .../testdata/join_table_name/sqlite/go/db.go | 31 + .../join_table_name/sqlite/go/models.go | 18 + .../join_table_name/sqlite/go/query.sql.go | 29 + .../testdata/join_table_name/sqlite/query.sql | 5 + .../join_table_name/sqlite/schema.sql | 3 + .../testdata/join_table_name/sqlite/sqlc.json | 12 + .../testdata/join_two_tables/mysql/go/db.go | 31 + .../join_two_tables/mysql/go/models.go | 18 + .../join_two_tables/mysql/go/query.sql.go | 40 + .../testdata/join_two_tables/mysql/query.sql | 5 + .../testdata/join_two_tables/mysql/schema.sql | 4 + .../testdata/join_two_tables/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 18 + .../postgresql/pgx/v4/go/query.sql.go | 37 + .../postgresql/pgx/v4/query.sql | 5 + .../postgresql/pgx/v4/schema.sql | 4 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 18 + .../postgresql/pgx/v5/go/query.sql.go | 37 + .../postgresql/pgx/v5/query.sql | 5 + .../postgresql/pgx/v5/schema.sql | 4 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 18 + .../postgresql/stdlib/go/query.sql.go | 40 + .../postgresql/stdlib/query.sql | 5 + .../postgresql/stdlib/schema.sql | 4 + .../postgresql/stdlib/sqlc.json | 12 + .../testdata/join_two_tables/sqlite/go/db.go | 31 + .../join_two_tables/sqlite/go/models.go | 18 + .../join_two_tables/sqlite/go/query.sql.go | 40 + .../testdata/join_two_tables/sqlite/query.sql | 5 + .../join_two_tables/sqlite/schema.sql | 4 + .../testdata/join_two_tables/sqlite/sqlc.json | 12 + .../endtoend/testdata/join_update/issue.md | 1 + .../join_update/postgresql/pgx/go/db.go | 32 + .../join_update/postgresql/pgx/go/models.go | 24 + .../postgresql/pgx/go/query.sql.go | 23 + .../join_update/postgresql/pgx/query.sql | 6 + .../join_update/postgresql/pgx/schema.sql | 14 + .../join_update/postgresql/pgx/sqlc.yaml | 10 + .../endtoend/testdata/join_using/issue.md | 1 + .../join_using/postgresql/pgx/exec.json | 3 + .../join_using/postgresql/pgx/go/db.go | 32 + .../join_using/postgresql/pgx/go/models.go | 13 + .../join_using/postgresql/pgx/go/query.sql.go | 41 + .../join_using/postgresql/pgx/query.sql | 2 + .../join_using/postgresql/pgx/schema.sql | 6 + .../join_using/postgresql/pgx/sqlc.yaml | 10 + .../testdata/join_validate_columns/issue.md | 1 + .../postgresql/pgx/exec.json | 3 + .../postgresql/pgx/query.sql | 2 + .../postgresql/pgx/schema.sql | 10 + .../postgresql/pgx/sqlc.yaml | 10 + .../postgresql/pgx/stderr.txt | 2 + .../testdata/join_where_clause/mysql/go/db.go | 31 + .../join_where_clause/mysql/go/models.go | 14 + .../join_where_clause/mysql/go/query.sql.go | 110 + .../join_where_clause/mysql/query.sql | 17 + .../join_where_clause/mysql/schema.sql | 3 + .../join_where_clause/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 14 + .../postgresql/pgx/v4/go/query.sql.go | 101 + .../postgresql/pgx/v4/query.sql | 17 + .../postgresql/pgx/v4/schema.sql | 3 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 14 + .../postgresql/pgx/v5/go/query.sql.go | 101 + .../postgresql/pgx/v5/query.sql | 17 + .../postgresql/pgx/v5/schema.sql | 3 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 14 + .../postgresql/stdlib/go/query.sql.go | 110 + .../postgresql/stdlib/query.sql | 17 + .../postgresql/stdlib/schema.sql | 3 + .../postgresql/stdlib/sqlc.json | 12 + .../join_where_clause/sqlite/go/db.go | 31 + .../join_where_clause/sqlite/go/models.go | 14 + .../join_where_clause/sqlite/go/query.sql.go | 110 + .../join_where_clause/sqlite/query.sql | 17 + .../join_where_clause/sqlite/schema.sql | 3 + .../join_where_clause/sqlite/sqlc.json | 12 + .../testdata/json/mysql/go/copyfrom.go | 51 + .../endtoend/testdata/json/mysql/go/db.go | 31 + .../endtoend/testdata/json/mysql/go/models.go | 14 + .../testdata/json/mysql/go/query.sql.go | 29 + .../endtoend/testdata/json/mysql/query.sql | 5 + .../endtoend/testdata/json/mysql/schema.sql | 5 + .../endtoend/testdata/json/mysql/sqlc.json | 13 + .../testdata/json/postgresql/pgx/v4/go/db.go | 32 + .../json/postgresql/pgx/v4/go/models.go | 16 + .../json/postgresql/pgx/v4/go/query.sql.go | 19 + .../testdata/json/postgresql/pgx/v4/query.sql | 2 + .../json/postgresql/pgx/v4/schema.sql | 7 + .../testdata/json/postgresql/pgx/v4/sqlc.json | 13 + .../testdata/json/postgresql/pgx/v5/go/db.go | 32 + .../json/postgresql/pgx/v5/go/models.go | 12 + .../json/postgresql/pgx/v5/go/query.sql.go | 19 + .../testdata/json/postgresql/pgx/v5/query.sql | 2 + .../json/postgresql/pgx/v5/schema.sql | 7 + .../testdata/json/postgresql/pgx/v5/sqlc.json | 13 + .../testdata/json/postgresql/stdlib/go/db.go | 31 + .../json/postgresql/stdlib/go/models.go | 18 + .../json/postgresql/stdlib/go/query.sql.go | 19 + .../testdata/json/postgresql/stdlib/query.sql | 2 + .../json/postgresql/stdlib/schema.sql | 7 + .../testdata/json/postgresql/stdlib/sqlc.json | 12 + .../testdata/json_array_elements/issue.md | 1 + .../postgresql/pgx/exec.json | 3 + .../postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 13 + .../postgresql/pgx/go/query.sql.go | 32 + .../postgresql/pgx/query.sql | 6 + .../postgresql/pgx/schema.sql | 8 + .../postgresql/pgx/sqlc.yaml | 10 + .../json_build/postgresql/pgx/v4/go/db.go | 32 + .../json_build/postgresql/pgx/v4/go/models.go | 5 + .../postgresql/pgx/v4/go/query.sql.go | 132 + .../json_build/postgresql/pgx/v4/query.sql | 31 + .../json_build/postgresql/pgx/v4/schema.sql | 0 .../json_build/postgresql/pgx/v4/sqlc.json | 13 + .../json_build/postgresql/pgx/v5/go/db.go | 32 + .../json_build/postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 130 + .../json_build/postgresql/pgx/v5/query.sql | 31 + .../json_build/postgresql/pgx/v5/schema.sql | 0 .../json_build/postgresql/pgx/v5/sqlc.json | 13 + .../json_build/postgresql/stdlib/go/db.go | 31 + .../json_build/postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/query.sql.go | 131 + .../json_build/postgresql/stdlib/query.sql | 31 + .../json_build/postgresql/stdlib/schema.sql | 0 .../json_build/postgresql/stdlib/sqlc.json | 12 + .../testdata/json_param_type/issue.md | 1 + .../json_param_type/postgresql/pgx/exec.json | 3 + .../json_param_type/postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 10 + .../postgresql/pgx/go/query.sql.go | 23 + .../json_param_type/postgresql/pgx/query.sql | 2 + .../json_param_type/postgresql/pgx/schema.sql | 4 + .../json_param_type/postgresql/pgx/sqlc.yaml | 10 + .../testdata/json_param_type/sqlite/go/db.go | 31 + .../json_param_type/sqlite/go/models.go | 14 + .../json_param_type/sqlite/go/query.sql.go | 22 + .../testdata/json_param_type/sqlite/query.sql | 2 + .../json_param_type/sqlite/schema.sql | 4 + .../testdata/json_param_type/sqlite/sqlc.yaml | 9 + .../camel_case/postgresql/pgx/v4/go/db.go | 32 + .../camel_case/postgresql/pgx/v4/go/models.go | 15 + .../postgresql/pgx/v4/go/query.sql.go | 34 + .../camel_case/postgresql/pgx/v4/query.sql | 2 + .../camel_case/postgresql/pgx/v4/schema.sql | 6 + .../camel_case/postgresql/pgx/v4/sqlc.json | 15 + .../camel_case/postgresql/pgx/v5/go/db.go | 32 + .../camel_case/postgresql/pgx/v5/go/models.go | 15 + .../postgresql/pgx/v5/go/query.sql.go | 34 + .../camel_case/postgresql/pgx/v5/query.sql | 2 + .../camel_case/postgresql/pgx/v5/schema.sql | 6 + .../camel_case/postgresql/pgx/v5/sqlc.json | 15 + .../camel_case/postgresql/stdlib/go/db.go | 31 + .../camel_case/postgresql/stdlib/go/models.go | 15 + .../postgresql/stdlib/go/query.sql.go | 37 + .../camel_case/postgresql/stdlib/query.sql | 2 + .../camel_case/postgresql/stdlib/schema.sql | 6 + .../camel_case/postgresql/stdlib/sqlc.json | 14 + .../pascal_case/postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 15 + .../postgresql/pgx/v4/go/query.sql.go | 34 + .../pascal_case/postgresql/pgx/v4/query.sql | 2 + .../pascal_case/postgresql/pgx/v4/schema.sql | 6 + .../pascal_case/postgresql/pgx/v4/sqlc.json | 15 + .../pascal_case/postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 15 + .../postgresql/pgx/v5/go/query.sql.go | 34 + .../pascal_case/postgresql/pgx/v5/query.sql | 2 + .../pascal_case/postgresql/pgx/v5/schema.sql | 6 + .../pascal_case/postgresql/pgx/v5/sqlc.json | 15 + .../pascal_case/postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 15 + .../postgresql/stdlib/go/query.sql.go | 37 + .../pascal_case/postgresql/stdlib/query.sql | 2 + .../pascal_case/postgresql/stdlib/schema.sql | 6 + .../pascal_case/postgresql/stdlib/sqlc.json | 14 + .../snake_case/postgresql/pgx/v4/go/db.go | 32 + .../snake_case/postgresql/pgx/v4/go/models.go | 15 + .../postgresql/pgx/v4/go/query.sql.go | 34 + .../snake_case/postgresql/pgx/v4/query.sql | 2 + .../snake_case/postgresql/pgx/v4/schema.sql | 6 + .../snake_case/postgresql/pgx/v4/sqlc.json | 15 + .../snake_case/postgresql/pgx/v5/go/db.go | 32 + .../snake_case/postgresql/pgx/v5/go/models.go | 15 + .../postgresql/pgx/v5/go/query.sql.go | 34 + .../snake_case/postgresql/pgx/v5/query.sql | 2 + .../snake_case/postgresql/pgx/v5/schema.sql | 6 + .../snake_case/postgresql/pgx/v5/sqlc.json | 15 + .../snake_case/postgresql/stdlib/go/db.go | 31 + .../snake_case/postgresql/stdlib/go/models.go | 15 + .../postgresql/stdlib/go/query.sql.go | 37 + .../snake_case/postgresql/stdlib/query.sql | 2 + .../snake_case/postgresql/stdlib/schema.sql | 6 + .../snake_case/postgresql/stdlib/sqlc.json | 14 + .../camel_case/postgresql/stdlib/go/db.go | 31 + .../camel_case/postgresql/stdlib/go/models.go | 61 + .../postgresql/stdlib/go/query.sql.go | 27 + .../camel_case/postgresql/stdlib/query.sql | 3 + .../camel_case/postgresql/stdlib/schema.sql | 9 + .../camel_case/postgresql/stdlib/sqlc.json | 14 + .../none/postgresql/stdlib/go/db.go | 31 + .../none/postgresql/stdlib/go/models.go | 61 + .../none/postgresql/stdlib/go/query.sql.go | 27 + .../none/postgresql/stdlib/query.sql | 3 + .../none/postgresql/stdlib/schema.sql | 9 + .../none/postgresql/stdlib/sqlc.json | 14 + .../pascal_case/postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 61 + .../postgresql/stdlib/go/query.sql.go | 27 + .../pascal_case/postgresql/stdlib/query.sql | 3 + .../pascal_case/postgresql/stdlib/schema.sql | 9 + .../pascal_case/postgresql/stdlib/sqlc.json | 14 + .../snake_case/postgresql/stdlib/go/db.go | 31 + .../snake_case/postgresql/stdlib/go/models.go | 61 + .../postgresql/stdlib/go/query.sql.go | 27 + .../snake_case/postgresql/stdlib/query.sql | 3 + .../snake_case/postgresql/stdlib/schema.sql | 9 + .../snake_case/postgresql/stdlib/sqlc.json | 14 + .../v2_config/postgresql/stdlib/go/db.go | 31 + .../v2_config/postgresql/stdlib/go/models.go | 61 + .../postgresql/stdlib/go/query.sql.go | 27 + .../v2_config/postgresql/stdlib/query.sql | 3 + .../v2_config/postgresql/stdlib/schema.sql | 9 + .../v2_config/postgresql/stdlib/sqlc.json | 17 + internal/endtoend/testdata/jsonb/pgx/go/db.go | 32 + .../endtoend/testdata/jsonb/pgx/go/models.go | 12 + .../testdata/jsonb/pgx/go/query.sql.go | 50 + .../endtoend/testdata/jsonb/pgx/query.sql | 15 + .../endtoend/testdata/jsonb/pgx/schema.sql | 7 + .../endtoend/testdata/jsonb/pgx/sqlc.json | 13 + .../endtoend/testdata/jsonb/sqlite/go/db.go | 31 + .../testdata/jsonb/sqlite/go/models.go | 20 + .../testdata/jsonb/sqlite/go/query.sql.go | 69 + .../endtoend/testdata/jsonb/sqlite/query.sql | 25 + .../endtoend/testdata/jsonb/sqlite/schema.sql | 11 + .../endtoend/testdata/jsonb/sqlite/sqlc.json | 12 + .../endtoend/testdata/limit/mysql/go/db.go | 31 + .../testdata/limit/mysql/go/models.go | 9 + .../testdata/limit/mysql/go/query.sql.go | 28 + .../endtoend/testdata/limit/mysql/query.sql | 5 + .../endtoend/testdata/limit/mysql/schema.sql | 2 + .../endtoend/testdata/limit/mysql/sqlc.json | 12 + .../endtoend/testdata/limit/pgx/v4/exec.json | 3 + .../endtoend/testdata/limit/pgx/v4/go/db.go | 32 + .../testdata/limit/pgx/v4/go/models.go | 9 + .../testdata/limit/pgx/v4/go/query.sql.go | 34 + .../endtoend/testdata/limit/pgx/v4/query.sql | 2 + .../endtoend/testdata/limit/pgx/v4/schema.sql | 2 + .../endtoend/testdata/limit/pgx/v4/sqlc.json | 13 + .../endtoend/testdata/limit/pgx/v5/exec.json | 3 + .../endtoend/testdata/limit/pgx/v5/go/db.go | 32 + .../testdata/limit/pgx/v5/go/models.go | 9 + .../testdata/limit/pgx/v5/go/query.sql.go | 34 + .../endtoend/testdata/limit/pgx/v5/query.sql | 2 + .../endtoend/testdata/limit/pgx/v5/schema.sql | 2 + .../endtoend/testdata/limit/pgx/v5/sqlc.json | 13 + .../endtoend/testdata/limit/sqlite/go/db.go | 31 + .../testdata/limit/sqlite/go/models.go | 9 + .../testdata/limit/sqlite/go/query.sql.go | 37 + .../endtoend/testdata/limit/sqlite/query.sql | 2 + .../endtoend/testdata/limit/sqlite/schema.sql | 2 + .../endtoend/testdata/limit/sqlite/sqlc.json | 12 + .../endtoend/testdata/limit/stdlib/exec.json | 3 + .../endtoend/testdata/limit/stdlib/go/db.go | 31 + .../testdata/limit/stdlib/go/models.go | 9 + .../testdata/limit/stdlib/go/query.sql.go | 37 + .../endtoend/testdata/limit/stdlib/query.sql | 2 + .../endtoend/testdata/limit/stdlib/schema.sql | 2 + .../endtoend/testdata/limit/stdlib/sqlc.json | 11 + .../endtoend/testdata/lower/pgx/v4/go/db.go | 32 + .../testdata/lower/pgx/v4/go/models.go | 10 + .../testdata/lower/pgx/v4/go/query.sql.go | 39 + .../endtoend/testdata/lower/pgx/v4/query.sql | 2 + .../endtoend/testdata/lower/pgx/v4/schema.sql | 2 + .../endtoend/testdata/lower/pgx/v4/sqlc.json | 13 + .../endtoend/testdata/lower/pgx/v5/go/db.go | 32 + .../testdata/lower/pgx/v5/go/models.go | 10 + .../testdata/lower/pgx/v5/go/query.sql.go | 39 + .../endtoend/testdata/lower/pgx/v5/query.sql | 2 + .../endtoend/testdata/lower/pgx/v5/schema.sql | 2 + .../endtoend/testdata/lower/pgx/v5/sqlc.json | 13 + .../endtoend/testdata/lower/stdlib/go/db.go | 31 + .../testdata/lower/stdlib/go/models.go | 10 + .../testdata/lower/stdlib/go/query.sql.go | 42 + .../endtoend/testdata/lower/stdlib/query.sql | 2 + .../endtoend/testdata/lower/stdlib/schema.sql | 2 + .../endtoend/testdata/lower/stdlib/sqlc.json | 11 + .../lower_switched_order/pgx/v4/go/db.go | 32 + .../lower_switched_order/pgx/v4/go/models.go | 10 + .../pgx/v4/go/query.sql.go | 39 + .../lower_switched_order/pgx/v4/query.sql | 2 + .../lower_switched_order/pgx/v4/schema.sql | 2 + .../lower_switched_order/pgx/v4/sqlc.json | 13 + .../lower_switched_order/pgx/v5/go/db.go | 32 + .../lower_switched_order/pgx/v5/go/models.go | 10 + .../pgx/v5/go/query.sql.go | 39 + .../lower_switched_order/pgx/v5/query.sql | 2 + .../lower_switched_order/pgx/v5/schema.sql | 2 + .../lower_switched_order/pgx/v5/sqlc.json | 13 + .../lower_switched_order/stdlib/go/db.go | 31 + .../lower_switched_order/stdlib/go/models.go | 10 + .../stdlib/go/query.sql.go | 42 + .../lower_switched_order/stdlib/query.sql | 2 + .../lower_switched_order/stdlib/schema.sql | 2 + .../lower_switched_order/stdlib/sqlc.json | 11 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 20 + .../postgresql/pgx/v4/go/query.sql.go | 39 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 10 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 20 + .../postgresql/pgx/v5/go/query.sql.go | 39 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 10 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 20 + .../postgresql/stdlib/go/query.sql.go | 42 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 10 + .../postgresql/stdlib/sqlc.json | 12 + .../mathmatical_operator/pgx/v4/go/db.go | 32 + .../mathmatical_operator/pgx/v4/go/models.go | 9 + .../pgx/v4/go/query.sql.go | 39 + .../mathmatical_operator/pgx/v4/query.sql | 2 + .../mathmatical_operator/pgx/v4/schema.sql | 2 + .../mathmatical_operator/pgx/v4/sqlc.json | 13 + .../mathmatical_operator/pgx/v5/go/db.go | 32 + .../mathmatical_operator/pgx/v5/go/models.go | 9 + .../pgx/v5/go/query.sql.go | 39 + .../mathmatical_operator/pgx/v5/query.sql | 2 + .../mathmatical_operator/pgx/v5/schema.sql | 2 + .../mathmatical_operator/pgx/v5/sqlc.json | 13 + .../mathmatical_operator/stdlib/go/db.go | 31 + .../mathmatical_operator/stdlib/go/models.go | 9 + .../stdlib/go/query.sql.go | 42 + .../mathmatical_operator/stdlib/query.sql | 2 + .../mathmatical_operator/stdlib/schema.sql | 2 + .../mathmatical_operator/stdlib/sqlc.json | 11 + .../endtoend/testdata/min_max_date/issue.md | 1 + .../min_max_date/postgresql/pgx/exec.json | 3 + .../min_max_date/postgresql/pgx/go/db.go | 32 + .../min_max_date/postgresql/pgx/go/models.go | 14 + .../postgresql/pgx/go/query.sql.go | 33 + .../min_max_date/postgresql/pgx/query.sql | 6 + .../min_max_date/postgresql/pgx/schema.sql | 4 + .../min_max_date/postgresql/pgx/sqlc.yaml | 10 + .../testdata/missing_semicolon/mysql/go/db.go | 31 + .../missing_semicolon/mysql/go/models.go | 15 + .../missing_semicolon/mysql/go/query.sql.go | 26 + .../missing_semicolon/mysql/query.sql | 4 + .../missing_semicolon/mysql/schema.sql | 7 + .../missing_semicolon/mysql/sqlc.json | 12 + .../missing_semicolon/pgx/v4/query.sql | 5 + .../missing_semicolon/pgx/v4/schema.sql | 1 + .../missing_semicolon/pgx/v4/sqlc.json | 13 + .../missing_semicolon/pgx/v4/stderr.txt | 2 + .../missing_semicolon/pgx/v5/query.sql | 5 + .../missing_semicolon/pgx/v5/schema.sql | 1 + .../missing_semicolon/pgx/v5/sqlc.json | 13 + .../missing_semicolon/pgx/v5/stderr.txt | 2 + .../missing_semicolon/stdlib/query.sql | 5 + .../missing_semicolon/stdlib/schema.sql | 1 + .../missing_semicolon/stdlib/sqlc.json | 11 + .../missing_semicolon/stdlib/stderr.txt | 2 + .../testdata/mix_param_types/mysql/go/db.go | 31 + .../mix_param_types/mysql/go/models.go | 11 + .../mix_param_types/mysql/go/test.sql.go | 59 + .../testdata/mix_param_types/mysql/schema.sql | 5 + .../testdata/mix_param_types/mysql/sqlc.json | 12 + .../testdata/mix_param_types/mysql/test.sql | 8 + .../mix_param_types/postgresql/exec.json | 3 + .../mix_param_types/postgresql/go/db.go | 31 + .../mix_param_types/postgresql/go/models.go | 11 + .../mix_param_types/postgresql/go/test.sql.go | 60 + .../mix_param_types/postgresql/schema.sql | 5 + .../mix_param_types/postgresql/sqlc.json | 12 + .../mix_param_types/postgresql/test.sql | 8 + .../multibyte_comment/sqlite/go/db.go | 31 + .../multibyte_comment/sqlite/go/models.go | 11 + .../multibyte_comment/sqlite/go/query.sql.go | 87 + .../multibyte_comment/sqlite/query.sql | 22 + .../multibyte_comment/sqlite/schema.sql | 5 + .../multibyte_comment/sqlite/sqlc.json | 12 + .../multidimension_array/pgx/v4/go/db.go | 32 + .../multidimension_array/pgx/v4/go/models.go | 9 + .../pgx/v4/go/query.sql.go | 34 + .../multidimension_array/pgx/v4/query.sql | 2 + .../multidimension_array/pgx/v4/schema.sql | 2 + .../multidimension_array/pgx/v4/sqlc.json | 13 + .../multidimension_array/pgx/v5/go/db.go | 32 + .../multidimension_array/pgx/v5/go/models.go | 9 + .../pgx/v5/go/query.sql.go | 34 + .../multidimension_array/pgx/v5/query.sql | 2 + .../multidimension_array/pgx/v5/schema.sql | 2 + .../multidimension_array/pgx/v5/sqlc.json | 13 + .../multidimension_array/stdlib/go/db.go | 31 + .../multidimension_array/stdlib/go/models.go | 9 + .../stdlib/go/query.sql.go | 39 + .../multidimension_array/stdlib/query.sql | 2 + .../multidimension_array/stdlib/schema.sql | 2 + .../multidimension_array/stdlib/sqlc.json | 11 + .../testdata/multischema/pgx/v4/go/db.go | 32 + .../testdata/multischema/pgx/v4/go/models.go | 18 + .../multischema/pgx/v4/go/query.sql.go | 58 + .../testdata/multischema/pgx/v4/query.sql | 5 + .../multischema/pgx/v4/sql/ignore.txt | 3 + .../testdata/multischema/pgx/v4/sql/query.sql | 2 + .../testdata/multischema/pgx/v4/sqlc.json | 19 + .../testdata/multischema/pgx/v5/go/db.go | 32 + .../testdata/multischema/pgx/v5/go/models.go | 18 + .../multischema/pgx/v5/go/query.sql.go | 58 + .../testdata/multischema/pgx/v5/query.sql | 5 + .../multischema/pgx/v5/sql/ignore.txt | 3 + .../testdata/multischema/pgx/v5/sql/query.sql | 2 + .../testdata/multischema/pgx/v5/sqlc.json | 19 + .../testdata/multischema/stdlib/go/db.go | 31 + .../testdata/multischema/stdlib/go/models.go | 18 + .../multischema/stdlib/go/query.sql.go | 64 + .../testdata/multischema/stdlib/query.sql | 5 + .../multischema/stdlib/sql/ignore.txt | 3 + .../testdata/multischema/stdlib/sql/query.sql | 2 + .../testdata/multischema/stdlib/sqlc.json | 17 + .../mysql_ddl_routines/mysql/go/db.go | 31 + .../mysql_ddl_routines/mysql/go/models.go | 14 + .../mysql_ddl_routines/mysql/go/query.sql.go | 21 + .../mysql_ddl_routines/mysql/query.sql | 2 + .../mysql_ddl_routines/mysql/schema.sql | 12 + .../mysql_ddl_routines/mysql/sqlc.json | 14 + .../mysql_default_expression/mysql/go/db.go | 31 + .../mysql/go/models.go | 15 + .../mysql/go/query.sql.go | 21 + .../mysql_default_expression/mysql/query.sql | 2 + .../mysql_default_expression/mysql/schema.sql | 6 + .../mysql_default_expression/mysql/sqlc.json | 14 + .../mysql_default_value/mysql/go/db.go | 31 + .../mysql_default_value/mysql/go/models.go | 12 + .../mysql_default_value/mysql/go/query.sql.go | 42 + .../mysql_default_value/mysql/query.sql | 2 + .../mysql_default_value/mysql/schema.sql | 7 + .../mysql_default_value/mysql/sqlc.json | 14 + .../testdata/mysql_json_table/mysql/go/db.go | 31 + .../mysql_json_table/mysql/go/models.go | 13 + .../mysql_json_table/mysql/go/query.sql.go | 37 + .../testdata/mysql_json_table/mysql/query.sql | 2 + .../mysql_json_table/mysql/schema.sql | 12 + .../testdata/mysql_json_table/mysql/sqlc.json | 14 + .../mysql_optimizer_hints/mysql/go/db.go | 31 + .../mysql_optimizer_hints/mysql/go/models.go | 13 + .../mysql/go/query.sql.go | 37 + .../mysql_optimizer_hints/mysql/query.sql | 9 + .../mysql_optimizer_hints/mysql/schema.sql | 1 + .../mysql_optimizer_hints/mysql/sqlc.json | 12 + .../testdata/mysql_reference_manual/README.md | 2 + .../aggregate_functions/go/db.go | 31 + .../go/group_concat.sql.go | 80 + .../aggregate_functions/go/models.go | 14 + .../aggregate_functions/group_concat.sql | 10 + .../date_and_time_functions/date_add.sql | 24 + .../date_and_time_functions/date_sub.sql | 9 + .../go/date_add.sql.go | 84 + .../go/date_sub.sql.go | 45 + .../date_and_time_functions/go/db.go | 31 + .../date_and_time_functions/go/models.go | 14 + .../mysql_reference_manual/schema.sql | 4 + .../testdata/mysql_reference_manual/sqlc.json | 19 + .../testdata/mysql_vector/mysql/go/db.go | 31 + .../testdata/mysql_vector/mysql/go/models.go | 10 + .../mysql_vector/mysql/go/query.sql.go | 48 + .../testdata/mysql_vector/mysql/query.sql | 7 + .../testdata/mysql_vector/mysql/schema.sql | 4 + .../testdata/mysql_vector/mysql/sqlc.json | 14 + .../testdata/named_param/pgx/v4/go/db.go | 32 + .../testdata/named_param/pgx/v4/go/models.go | 10 + .../named_param/pgx/v4/go/query.sql.go | 122 + .../testdata/named_param/pgx/v4/query.sql | 21 + .../testdata/named_param/pgx/v4/schema.sql | 2 + .../testdata/named_param/pgx/v4/sqlc.json | 13 + .../testdata/named_param/pgx/v5/go/db.go | 32 + .../testdata/named_param/pgx/v5/go/models.go | 10 + .../named_param/pgx/v5/go/query.sql.go | 122 + .../testdata/named_param/pgx/v5/query.sql | 21 + .../testdata/named_param/pgx/v5/schema.sql | 2 + .../testdata/named_param/pgx/v5/sqlc.json | 13 + .../testdata/named_param/sqlite/go/db.go | 31 + .../testdata/named_param/sqlite/go/models.go | 10 + .../named_param/sqlite/go/query.sql.go | 96 + .../testdata/named_param/sqlite/query.sql | 11 + .../testdata/named_param/sqlite/schema.sql | 2 + .../testdata/named_param/sqlite/sqlc.json | 12 + .../testdata/named_param/stdlib/go/db.go | 31 + .../testdata/named_param/stdlib/go/models.go | 10 + .../named_param/stdlib/go/query.sql.go | 128 + .../testdata/named_param/stdlib/query.sql | 21 + .../testdata/named_param/stdlib/schema.sql | 2 + .../testdata/named_param/stdlib/sqlc.json | 11 + .../endtoend/testdata/nested_select/issue.md | 1 + .../nested_select/postgresql/pgx/exec.json | 3 + .../nested_select/postgresql/pgx/go/db.go | 32 + .../nested_select/postgresql/pgx/go/models.go | 11 + .../postgresql/pgx/go/query.sql.go | 42 + .../nested_select/postgresql/pgx/query.sql | 11 + .../nested_select/postgresql/pgx/schema.sql | 5 + .../nested_select/postgresql/pgx/sqlc.yaml | 14 + .../testdata/nextval/postgresql/go/db.go | 31 + .../testdata/nextval/postgresql/go/models.go | 9 + .../nextval/postgresql/go/query.sql.go | 27 + .../testdata/nextval/postgresql/query.sql | 4 + .../testdata/nextval/postgresql/schema.sql | 5 + .../testdata/nextval/postgresql/sqlc.json | 12 + .../notifylisten/postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 37 + .../notifylisten/postgresql/pgx/v5/query.sql | 8 + .../notifylisten/postgresql/pgx/v5/schema.sql | 0 .../notifylisten/postgresql/pgx/v5/sqlc.json | 13 + .../endtoend/testdata/null_if_type/issue.md | 1 + .../postgresql/pganalyzer/db/db.go | 31 + .../postgresql/pganalyzer/db/models.go | 9 + .../postgresql/pganalyzer/db/query.sql.go | 24 + .../postgresql/pganalyzer/exec.json | 3 + .../postgresql/pganalyzer/query.sql | 5 + .../postgresql/pganalyzer/schema.sql | 3 + .../postgresql/pganalyzer/sqlc.json | 12 + .../null_if_type/postgresql/stdlib/db/db.go | 31 + .../postgresql/stdlib/db/models.go | 9 + .../postgresql/stdlib/db/query.sql.go | 24 + .../null_if_type/postgresql/stdlib/exec.json | 3 + .../null_if_type/postgresql/stdlib/query.sql | 5 + .../null_if_type/postgresql/stdlib/schema.sql | 3 + .../null_if_type/postgresql/stdlib/sqlc.json | 12 + .../testdata/omit_sqlc_version/db/db.go | 29 + .../testdata/omit_sqlc_version/db/models.go | 13 + .../omit_sqlc_version/db/query.sql.go | 80 + .../testdata/omit_sqlc_version/query.sql | 19 + .../testdata/omit_sqlc_version/schema.sql | 5 + .../testdata/omit_sqlc_version/sqlc.json | 15 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 325 ++ .../postgresql/stdlib/go/query.sql.go | 136 + .../postgresql/stdlib/query.sql | 20 + .../postgresql/stdlib/schema.sql | 69 + .../postgresql/stdlib/sqlc.json | 13 + .../on_duplicate_key_update/mysql/db/db.go | 31 + .../mysql/db/models.go | 15 + .../mysql/db/query.sql.go | 46 + .../on_duplicate_key_update/mysql/query.sql | 11 + .../on_duplicate_key_update/mysql/schema.sql | 5 + .../on_duplicate_key_update/mysql/sqlc.json | 11 + .../postgresql/db/db.go | 31 + .../postgresql/db/models.go | 15 + .../postgresql/db/query.sql.go | 45 + .../postgresql/query.sql | 11 + .../postgresql/schema.sql | 5 + .../postgresql/sqlc.json | 11 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 9 + .../postgresql/pgx/v4/go/query.sql.go | 34 + .../postgresql/pgx/v4/query.sql | 7 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 9 + .../postgresql/pgx/v5/go/query.sql.go | 34 + .../postgresql/pgx/v5/query.sql | 7 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 9 + .../postgresql/stdlib/go/query.sql.go | 34 + .../postgresql/stdlib/query.sql | 7 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../testdata/order_by_binds/mysql/go/db.go | 31 + .../order_by_binds/mysql/go/models.go | 15 + .../order_by_binds/mysql/go/query.sql.go | 101 + .../testdata/order_by_binds/mysql/query.sql | 13 + .../testdata/order_by_binds/mysql/schema.sql | 6 + .../testdata/order_by_binds/mysql/sqlc.json | 12 + .../order_by_binds/pganalyze/exec.json | 3 + .../order_by_binds/pganalyze/go/db.go | 31 + .../order_by_binds/pganalyze/go/models.go | 15 + .../order_by_binds/pganalyze/go/query.sql.go | 74 + .../order_by_binds/pganalyze/query.sql | 9 + .../order_by_binds/pganalyze/schema.sql | 6 + .../order_by_binds/pganalyze/sqlc.json | 12 + .../order_by_binds/postgresql/exec.json | 3 + .../order_by_binds/postgresql/go/db.go | 31 + .../order_by_binds/postgresql/go/models.go | 15 + .../order_by_binds/postgresql/go/query.sql.go | 101 + .../order_by_binds/postgresql/query.sql | 13 + .../order_by_binds/postgresql/schema.sql | 6 + .../order_by_binds/postgresql/sqlc.json | 12 + .../postgresql/query.sql | 3 + .../postgresql/schema.sql | 5 + .../postgresql/sqlc.yaml | 7 + .../postgresql/stderr/base.txt | 2 + .../postgresql/stderr/managed-db.txt | 2 + .../testdata/order_by_union/mysql/go/db.go | 31 + .../order_by_union/mysql/go/models.go | 18 + .../order_by_union/mysql/go/query.sql.go | 40 + .../testdata/order_by_union/mysql/query.sql | 5 + .../testdata/order_by_union/mysql/schema.sql | 9 + .../testdata/order_by_union/mysql/sqlc.json | 12 + .../order_by_union/postgresql/go/db.go | 31 + .../order_by_union/postgresql/go/models.go | 19 + .../order_by_union/postgresql/go/query.sql.go | 40 + .../order_by_union/postgresql/query.sql | 5 + .../order_by_union/postgresql/schema.sql | 10 + .../order_by_union/postgresql/sqlc.json | 12 + .../output_file_names/pgx/v4/go/batch_gen.go | 76 + .../pgx/v4/go/copyfrom_gen.go | 42 + .../output_file_names/pgx/v4/go/db_gen.go | 34 + .../output_file_names/pgx/v4/go/models_gen.go | 9 + .../pgx/v4/go/querier_gen.go | 17 + .../output_file_names/pgx/v4/go/query.sql.go | 34 + .../output_file_names/pgx/v4/query.sql | 12 + .../output_file_names/pgx/v4/schema.sql | 2 + .../output_file_names/pgx/v4/sqlc.json | 19 + .../output_file_names/pgx/v5/go/batch_gen.go | 76 + .../pgx/v5/go/copyfrom_gen.go | 42 + .../output_file_names/pgx/v5/go/db_gen.go | 34 + .../output_file_names/pgx/v5/go/models_gen.go | 9 + .../pgx/v5/go/querier_gen.go | 17 + .../output_file_names/pgx/v5/go/query.sql.go | 34 + .../output_file_names/pgx/v5/query.sql | 12 + .../output_file_names/pgx/v5/schema.sql | 2 + .../output_file_names/pgx/v5/sqlc.json | 19 + .../output_file_names/stdlib/go/db_gen.go | 31 + .../output_file_names/stdlib/go/models_gen.go | 9 + .../stdlib/go/querier_gen.go | 15 + .../output_file_names/stdlib/go/query.sql.go | 37 + .../output_file_names/stdlib/query.sql | 2 + .../output_file_names/stdlib/schema.sql | 2 + .../output_file_names/stdlib/sqlc.json | 16 + .../output_files_suffix/pgx/v4/go/db.go | 32 + .../output_files_suffix/pgx/v4/go/models.go | 9 + .../pgx/v4/go/query.sql_gen.go | 34 + .../output_files_suffix/pgx/v4/query.sql | 2 + .../output_files_suffix/pgx/v4/schema.sql | 2 + .../output_files_suffix/pgx/v4/sqlc.json | 14 + .../output_files_suffix/pgx/v5/go/db.go | 32 + .../output_files_suffix/pgx/v5/go/models.go | 9 + .../pgx/v5/go/query.sql_gen.go | 34 + .../output_files_suffix/pgx/v5/query.sql | 2 + .../output_files_suffix/pgx/v5/schema.sql | 2 + .../output_files_suffix/pgx/v5/sqlc.json | 14 + .../output_files_suffix/stdlib/go/db.go | 31 + .../output_files_suffix/stdlib/go/models.go | 9 + .../stdlib/go/query.sql_gen.go | 37 + .../output_files_suffix/stdlib/query.sql | 2 + .../output_files_suffix/stdlib/schema.sql | 2 + .../output_files_suffix/stdlib/sqlc.json | 12 + .../output_models_path/postgresql/db/db.go | 31 + .../postgresql/db/querier.go | 21 + .../postgresql/db/query.sql.go | 126 + .../postgresql/model/models.go | 67 + .../output_models_path/postgresql/query.sql | 14 + .../output_models_path/postgresql/schema.sql | 14 + .../output_models_path/postgresql/sqlc.json | 19 + .../postgresql/model/models.go | 58 + .../postgresql/primary/db.go | 31 + .../postgresql/primary/query.sql.go | 39 + .../postgresql/queries/primary/query.sql | 5 + .../postgresql/queries/replica/query.sql | 5 + .../postgresql/replica/db.go | 31 + .../postgresql/replica/query.sql.go | 66 + .../postgresql/schema.sql | 7 + .../output_models_shared/postgresql/sqlc.json | 31 + .../testdata/overrides/mysql/go/db.go | 31 + .../testdata/overrides/mysql/go/models.go | 15 + .../testdata/overrides/mysql/go/query.sql.go | 21 + .../testdata/overrides/mysql/query.sql | 2 + .../testdata/overrides/mysql/schema.sql | 5 + .../testdata/overrides/mysql/sqlc.json | 18 + .../overrides/postgresql/pgx/v4/go/db.go | 32 + .../overrides/postgresql/pgx/v4/go/models.go | 19 + .../postgresql/pgx/v4/go/query.sql.go | 21 + .../overrides/postgresql/pgx/v4/query.sql | 2 + .../overrides/postgresql/pgx/v4/schema.sql | 8 + .../overrides/postgresql/pgx/v4/sqlc.json | 23 + .../overrides/postgresql/pgx/v5/go/db.go | 32 + .../overrides/postgresql/pgx/v5/go/models.go | 19 + .../postgresql/pgx/v5/go/query.sql.go | 21 + .../overrides/postgresql/pgx/v5/query.sql | 2 + .../overrides/postgresql/pgx/v5/schema.sql | 8 + .../overrides/postgresql/pgx/v5/sqlc.json | 23 + .../overrides/postgresql/stdlib/go/db.go | 31 + .../overrides/postgresql/stdlib/go/models.go | 19 + .../postgresql/stdlib/go/query.sql.go | 21 + .../overrides/postgresql/stdlib/query.sql | 2 + .../overrides/postgresql/stdlib/schema.sql | 8 + .../overrides/postgresql/stdlib/sqlc.json | 22 + .../testdata/overrides/sqlite/go/db.go | 31 + .../testdata/overrides/sqlite/go/models.go | 15 + .../testdata/overrides/sqlite/go/query.sql.go | 21 + .../testdata/overrides/sqlite/query.sql | 2 + .../testdata/overrides/sqlite/schema.sql | 5 + .../testdata/overrides/sqlite/sqlc.json | 18 + .../postgresql/pgx/v4/query.sql | 3 + .../postgresql/pgx/v4/query/db.go | 32 + .../postgresql/pgx/v4/query/models.go | 16 + .../postgresql/pgx/v4/query/query.sql.go | 27 + .../postgresql/pgx/v4/schema.sql | 8 + .../postgresql/pgx/v4/sqlc.json | 23 + .../postgresql/pgx/v5/query.sql | 3 + .../postgresql/pgx/v5/query/db.go | 32 + .../postgresql/pgx/v5/query/models.go | 18 + .../postgresql/pgx/v5/query/query.sql.go | 27 + .../postgresql/pgx/v5/schema.sql | 8 + .../postgresql/pgx/v5/sqlc.json | 23 + .../postgresql/stdlib/query.sql | 3 + .../postgresql/stdlib/query/db.go | 31 + .../postgresql/stdlib/query/models.go | 16 + .../postgresql/stdlib/query/query.sql.go | 29 + .../postgresql/stdlib/schema.sql | 8 + .../postgresql/stdlib/sqlc.json | 22 + .../testdata/overrides_config/query.sql | 2 + .../testdata/overrides_config/schema.sql | 7 + .../overrides_config/v2/yaml/global/db/db.go | 31 + .../v2/yaml/global/db/models.go | 17 + .../v2/yaml/global/db/query.sql.go | 21 + .../overrides_config/v2/yaml/global/sqlc.yaml | 19 + .../v2/yaml/global_and_queryset/db/db.go | 31 + .../v2/yaml/global_and_queryset/db/models.go | 17 + .../yaml/global_and_queryset/db/query.sql.go | 21 + .../v2/yaml/global_and_queryset/sqlc.yaml | 26 + .../v2/yaml/queryset/db/db.go | 31 + .../v2/yaml/queryset/db/models.go | 17 + .../v2/yaml/queryset/db/query.sql.go | 21 + .../v2/yaml/queryset/sqlc.yaml | 17 + .../invalid_tags/query.sql | 2 + .../invalid_tags/schema.sql | 14 + .../invalid_tags/sqlc.json | 22 + .../invalid_tags/stderr.txt | 2 + .../overrides_go_struct_tags/mysql/go/db.go | 31 + .../mysql/go/models.go | 21 + .../mysql/go/query.sql.go | 21 + .../overrides_go_struct_tags/mysql/query.sql | 2 + .../overrides_go_struct_tags/mysql/schema.sql | 15 + .../overrides_go_struct_tags/mysql/sqlc.json | 32 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 20 + .../postgresql/pgx/v4/go/query.sql.go | 21 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 14 + .../postgresql/pgx/v4/sqlc.json | 49 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 20 + .../postgresql/pgx/v5/go/query.sql.go | 21 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 14 + .../postgresql/pgx/v5/sqlc.json | 49 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 11 + .../postgresql/stdlib/go/query.sql.go | 21 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 5 + .../postgresql/stdlib/sqlc.json | 28 + .../overrides_go_struct_tags/sqlite/go/db.go | 31 + .../sqlite/go/models.go | 24 + .../sqlite/go/query.sql.go | 21 + .../overrides_go_struct_tags/sqlite/query.sql | 2 + .../sqlite/schema.sql | 18 + .../overrides_go_struct_tags/sqlite/sqlc.json | 36 + .../overrides_go_types/mysql/go/db.go | 31 + .../overrides_go_types/mysql/go/models.go | 27 + .../overrides_go_types/mysql/go/query.sql.go | 50 + .../overrides_go_types/mysql/query.sql | 2 + .../overrides_go_types/mysql/schema.sql | 17 + .../overrides_go_types/mysql/sqlc.json | 22 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 34 + .../postgresql/pgx/v4/go/query.sql.go | 95 + .../postgresql/pgx/v4/query.sql | 13 + .../postgresql/pgx/v4/schema.sql | 18 + .../postgresql/pgx/v4/sqlc.json | 64 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 33 + .../postgresql/pgx/v5/go/query.sql.go | 43 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 18 + .../postgresql/pgx/v5/sqlc.json | 64 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 22 + .../postgresql/stdlib/go/query.sql.go | 46 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 8 + .../postgresql/stdlib/sqlc.json | 62 + .../overrides_go_types/sqlite/go/db.go | 31 + .../overrides_go_types/sqlite/go/models.go | 27 + .../overrides_go_types/sqlite/go/query.sql.go | 21 + .../overrides_go_types/sqlite/query.sql | 2 + .../overrides_go_types/sqlite/schema.sql | 17 + .../overrides_go_types/sqlite/sqlc.json | 22 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 15 + .../postgresql/pgx/v4/go/query.sql.go | 34 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 6 + .../postgresql/pgx/v4/sqlc.json | 29 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 15 + .../postgresql/pgx/v5/go/query.sql.go | 34 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 6 + .../postgresql/pgx/v5/sqlc.json | 29 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 15 + .../postgresql/stdlib/go/query.sql.go | 37 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 6 + .../postgresql/stdlib/sqlc.json | 28 + .../overrides_pointers/mysql/go/db.go | 31 + .../overrides_pointers/mysql/go/models.go | 15 + .../overrides_pointers/mysql/go/query.sql.go | 26 + .../overrides_pointers/mysql/query.sql | 2 + .../overrides_pointers/mysql/schema.sql | 5 + .../overrides_pointers/mysql/sqlc.json | 23 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 18 + .../postgresql/pgx/v4/go/query.sql.go | 21 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 8 + .../postgresql/pgx/v4/sqlc.json | 24 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 18 + .../postgresql/pgx/v5/go/query.sql.go | 21 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 8 + .../postgresql/pgx/v5/sqlc.json | 24 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 18 + .../postgresql/stdlib/go/query.sql.go | 21 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 8 + .../postgresql/stdlib/sqlc.json | 23 + .../overrides_result_tag/stdlib/go/db.go | 31 + .../overrides_result_tag/stdlib/go/models.go | 21 + .../stdlib/go/query.sql.go | 38 + .../overrides_result_tag/stdlib/query.sql | 10 + .../overrides_result_tag/stdlib/schema.sql | 12 + .../overrides_result_tag/stdlib/sqlc.yaml | 12 + .../overrides_unsigned/mysql/go/db.go | 31 + .../overrides_unsigned/mysql/go/models.go | 17 + .../overrides_unsigned/mysql/go/query.sql.go | 91 + .../overrides_unsigned/mysql/query.sql | 18 + .../overrides_unsigned/mysql/schema.sql | 8 + .../overrides_unsigned/mysql/sqlc.json | 23 + .../testdata/params_duplicate/mysql/go/db.go | 31 + .../params_duplicate/mysql/go/models.go | 16 + .../params_duplicate/mysql/go/query.sql.go | 143 + .../testdata/params_duplicate/mysql/query.sql | 18 + .../params_duplicate/mysql/schema.sql | 6 + .../testdata/params_duplicate/mysql/sqlc.json | 12 + .../params_duplicate/postgresql/go/db.go | 31 + .../params_duplicate/postgresql/go/models.go | 15 + .../postgresql/go/query.sql.go | 97 + .../params_duplicate/postgresql/query.sql | 13 + .../params_duplicate/postgresql/schema.sql | 6 + .../params_duplicate/postgresql/sqlc.json | 12 + .../testdata/params_go_keywords/issue.md | 1 + .../params_go_keywords/postgresql/go/db.go | 32 + .../postgresql/go/models.go | 38 + .../postgresql/go/query.sql.go | 532 +++ .../params_go_keywords/postgresql/query.sql | 155 + .../params_go_keywords/postgresql/schema.sql | 28 + .../params_go_keywords/postgresql/sqlc.yaml | 10 + .../params_in_nested_func/mysql/db/db.go | 31 + .../params_in_nested_func/mysql/db/models.go | 19 + .../mysql/db/query.sql.go | 55 + .../params_in_nested_func/mysql/query.sql | 9 + .../params_in_nested_func/mysql/schema.sql | 10 + .../params_in_nested_func/mysql/sqlc.yaml | 8 + .../params_in_nested_func/postgresql/db/db.go | 31 + .../postgresql/db/models.go | 19 + .../postgresql/db/query.sql.go | 55 + .../postgresql/query.sql | 9 + .../postgresql/schema.sql | 10 + .../postgresql/sqlc.yaml | 8 + .../testdata/params_location/mysql/go/db.go | 31 + .../params_location/mysql/go/models.go | 23 + .../params_location/mysql/go/query.sql.go | 257 ++ .../testdata/params_location/mysql/query.sql | 33 + .../testdata/params_location/mysql/schema.sql | 14 + .../testdata/params_location/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/exec.json | 3 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 25 + .../postgresql/pgx/v4/go/query.sql.go | 241 ++ .../postgresql/pgx/v4/query.sql | 33 + .../postgresql/pgx/v4/schema.sql | 14 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/exec.json | 3 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 23 + .../postgresql/pgx/v5/go/query.sql.go | 240 ++ .../postgresql/pgx/v5/query.sql | 33 + .../postgresql/pgx/v5/schema.sql | 14 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/exec.json | 3 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 23 + .../postgresql/stdlib/go/query.sql.go | 257 ++ .../postgresql/stdlib/query.sql | 33 + .../postgresql/stdlib/schema.sql | 14 + .../postgresql/stdlib/sqlc.json | 12 + .../mysql/go/db.go | 31 + .../mysql/go/models.go | 14 + .../mysql/go/query.sql.go | 70 + .../mysql/query.sql | 5 + .../mysql/schema.sql | 5 + .../mysql/sqlc.json | 12 + .../postgresql/exec.json | 3 + .../postgresql/go/db.go | 31 + .../postgresql/go/models.go | 14 + .../postgresql/go/query.sql.go | 64 + .../postgresql/query.sql | 5 + .../postgresql/schema.sql | 5 + .../postgresql/sqlc.json | 12 + .../testdata/params_two/mysql/go/db.go | 31 + .../testdata/params_two/mysql/go/models.go | 14 + .../testdata/params_two/mysql/go/query.sql.go | 44 + .../testdata/params_two/mysql/query.sql | 3 + .../testdata/params_two/mysql/schema.sql | 2 + .../testdata/params_two/mysql/sqlc.json | 12 + .../params_two/postgresql/pgx/v4/go/db.go | 32 + .../params_two/postgresql/pgx/v4/go/models.go | 14 + .../postgresql/pgx/v4/go/query.sql.go | 41 + .../params_two/postgresql/pgx/v4/query.sql | 3 + .../params_two/postgresql/pgx/v4/schema.sql | 2 + .../params_two/postgresql/pgx/v4/sqlc.json | 13 + .../params_two/postgresql/pgx/v5/go/db.go | 32 + .../params_two/postgresql/pgx/v5/go/models.go | 14 + .../postgresql/pgx/v5/go/query.sql.go | 42 + .../params_two/postgresql/pgx/v5/query.sql | 3 + .../params_two/postgresql/pgx/v5/schema.sql | 2 + .../params_two/postgresql/pgx/v5/sqlc.json | 13 + .../params_two/postgresql/stdlib/go/db.go | 31 + .../params_two/postgresql/stdlib/go/models.go | 14 + .../postgresql/stdlib/go/query.sql.go | 44 + .../params_two/postgresql/stdlib/query.sql | 3 + .../params_two/postgresql/stdlib/schema.sql | 2 + .../params_two/postgresql/stdlib/sqlc.json | 12 + .../testdata/parse_basic/clickhouse/exec.json | 5 + .../testdata/parse_basic/clickhouse/query.sql | 2 + .../parse_basic/clickhouse/stdout.txt | 34 + .../testdata/parse_basic/duckdb/exec.json | 5 + .../testdata/parse_basic/duckdb/query.sql | 2 + .../testdata/parse_basic/duckdb/stdout.txt | 33 + .../testdata/parse_basic/googlesql/exec.json | 5 + .../testdata/parse_basic/googlesql/query.sql | 2 + .../testdata/parse_basic/googlesql/stdout.txt | 33 + .../testdata/parse_basic/mssql/exec.json | 5 + .../testdata/parse_basic/mssql/query.sql | 2 + .../testdata/parse_basic/mssql/stdout.txt | 33 + .../testdata/parse_basic/mysql/exec.json | 5 + .../testdata/parse_basic/mysql/query.sql | 2 + .../testdata/parse_basic/mysql/stdout.txt | 42 + .../testdata/parse_basic/postgresql/exec.json | 5 + .../testdata/parse_basic/postgresql/query.sql | 2 + .../parse_basic/postgresql/stdout.txt | 69 + .../testdata/parse_basic/sqlite/exec.json | 5 + .../testdata/parse_basic/sqlite/query.sql | 2 + .../testdata/parse_basic/sqlite/stdout.txt | 45 + .../testdata/pattern_in_expr/mysql/go/db.go | 31 + .../pattern_in_expr/mysql/go/models.go | 19 + .../pattern_in_expr/mysql/go/query.sql.go | 129 + .../testdata/pattern_in_expr/mysql/query.sql | 11 + .../testdata/pattern_in_expr/mysql/schema.sql | 2 + .../testdata/pattern_in_expr/mysql/sqlc.json | 12 + .../testdata/pattern_matching/mysql/go/db.go | 31 + .../pattern_matching/mysql/go/models.go | 13 + .../pattern_matching/mysql/go/query.sql.go | 38 + .../testdata/pattern_matching/mysql/query.sql | 2 + .../pattern_matching/mysql/schema.sql | 2 + .../testdata/pattern_matching/mysql/sqlc.json | 12 + .../pattern_matching/postgresql/go/db.go | 31 + .../pattern_matching/postgresql/go/models.go | 13 + .../postgresql/go/query.sql.go | 38 + .../pattern_matching/postgresql/query.sql | 2 + .../pattern_matching/postgresql/schema.sql | 2 + .../pattern_matching/postgresql/sqlc.json | 12 + .../postgresql/pgx/v4/exec.sql | 5 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/exec.sql.go | 31 + .../postgresql/pgx/v4/go/models.go | 5 + .../postgresql/pgx/v4/go/query.sql.go | 55 + .../postgresql/pgx/v4/query.sql | 8 + .../postgresql/pgx/v4/schema.sql | 0 .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/exec.sql | 5 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/exec.sql.go | 31 + .../postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 55 + .../postgresql/pgx/v5/query.sql | 8 + .../postgresql/pgx/v5/schema.sql | 0 .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/exec.sql | 5 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/exec.sql.go | 31 + .../postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/query.sql.go | 57 + .../postgresql/stdlib/query.sql | 8 + .../postgresql/stdlib/schema.sql | 0 .../postgresql/stdlib/sqlc.json | 12 + internal/endtoend/testdata/pg_dump/db/db.go | 31 + .../endtoend/testdata/pg_dump/db/models.go | 15 + .../endtoend/testdata/pg_dump/db/query.sql.go | 82 + internal/endtoend/testdata/pg_dump/exec.json | 6 + internal/endtoend/testdata/pg_dump/query.sql | 19 + internal/endtoend/testdata/pg_dump/schema.sql | 93 + internal/endtoend/testdata/pg_dump/sqlc.json | 12 + .../pg_ext_ltree/postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 15 + .../postgresql/pgx/v4/go/query.sql.go | 34 + .../pg_ext_ltree/postgresql/pgx/v4/query.sql | 2 + .../pg_ext_ltree/postgresql/pgx/v4/schema.sql | 8 + .../pg_ext_ltree/postgresql/pgx/v4/sqlc.json | 13 + .../pg_ext_ltree/postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 15 + .../postgresql/pgx/v5/go/query.sql.go | 34 + .../pg_ext_ltree/postgresql/pgx/v5/query.sql | 2 + .../pg_ext_ltree/postgresql/pgx/v5/schema.sql | 8 + .../pg_ext_ltree/postgresql/pgx/v5/sqlc.json | 13 + .../pg_ext_ltree/postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 15 + .../postgresql/stdlib/go/query.sql.go | 37 + .../pg_ext_ltree/postgresql/stdlib/query.sql | 2 + .../pg_ext_ltree/postgresql/stdlib/schema.sql | 8 + .../pg_ext_ltree/postgresql/stdlib/sqlc.json | 12 + .../pg_extensions/postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 5 + .../postgresql/pgx/v4/go/pg_trgm.sql.go | 21 + .../postgresql/pgx/v4/go/pgcrypto.sql.go | 21 + .../postgresql/pgx/v4/go/uuid_ossp.sql.go | 23 + .../postgresql/pgx/v4/schema.sql | 3 + .../postgresql/pgx/v4/sql/pg_trgm.sql | 2 + .../postgresql/pgx/v4/sql/pgcrypto.sql | 3 + .../postgresql/pgx/v4/sql/uuid_ossp.sql | 2 + .../pg_extensions/postgresql/pgx/v4/sqlc.json | 13 + .../pg_extensions/postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/pg_trgm.sql.go | 21 + .../postgresql/pgx/v5/go/pgcrypto.sql.go | 21 + .../postgresql/pgx/v5/go/uuid_ossp.sql.go | 23 + .../postgresql/pgx/v5/schema.sql | 3 + .../postgresql/pgx/v5/sql/pg_trgm.sql | 2 + .../postgresql/pgx/v5/sql/pgcrypto.sql | 3 + .../postgresql/pgx/v5/sql/uuid_ossp.sql | 2 + .../pg_extensions/postgresql/pgx/v5/sqlc.json | 13 + .../pg_extensions/postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/pg_trgm.sql.go | 21 + .../postgresql/stdlib/go/pgcrypto.sql.go | 21 + .../postgresql/stdlib/go/uuid_ossp.sql.go | 23 + .../postgresql/stdlib/schema.sql | 3 + .../postgresql/stdlib/sql/pg_trgm.sql | 2 + .../postgresql/stdlib/sql/pgcrypto.sql | 3 + .../postgresql/stdlib/sql/uuid_ossp.sql | 2 + .../pg_extensions/postgresql/stdlib/sqlc.json | 12 + .../postgresql/pgx/v4/exec.json | 3 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 5 + .../postgresql/pgx/v4/go/query.sql.go | 40 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 0 .../postgresql/pgx/v4/sqlc.json | 14 + .../postgresql/pgx/v5/exec.json | 3 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 41 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 0 .../postgresql/pgx/v5/sqlc.json | 14 + .../postgresql/stdlib/exec.json | 3 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/query.sql.go | 43 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 0 .../postgresql/stdlib/sqlc.json | 13 + .../pg_timezone_names/go_pgx/v4/db.go | 32 + .../pg_timezone_names/go_pgx/v4/models.go | 5 + .../pg_timezone_names/go_pgx/v4/query.sql.go | 100 + .../pg_timezone_names/go_pgx/v5/db.go | 32 + .../pg_timezone_names/go_pgx/v5/models.go | 5 + .../pg_timezone_names/go_pgx/v5/query.sql.go | 101 + .../pg_timezone_names/go_stdlib/db.go | 31 + .../pg_timezone_names/go_stdlib/models.go | 5 + .../pg_timezone_names/go_stdlib/query.sql.go | 109 + .../testdata/pg_timezone_names/query.sql | 8 + .../testdata/pg_timezone_names/schema.sql | 1 + .../testdata/pg_timezone_names/sqlc.json | 40 + .../pg_user_table/postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 9 + .../postgresql/pgx/v4/go/query.sql.go | 34 + .../pg_user_table/postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../pg_user_table/postgresql/pgx/v4/sqlc.json | 13 + .../pg_user_table/postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 9 + .../postgresql/pgx/v5/go/query.sql.go | 34 + .../pg_user_table/postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../pg_user_table/postgresql/pgx/v5/sqlc.json | 13 + .../pg_user_table/postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 9 + .../postgresql/stdlib/go/query.sql.go | 37 + .../pg_user_table/postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../pg_user_table/postgresql/stdlib/sqlc.json | 12 + .../pg_vector/postgresql/pgx/exec.json | 6 + .../pg_vector/postgresql/pgx/go/db.go | 32 + .../pg_vector/postgresql/pgx/go/models.go | 14 + .../pg_vector/postgresql/pgx/go/query.sql.go | 48 + .../pg_vector/postgresql/pgx/query.sql | 8 + .../pg_vector/postgresql/pgx/schema.sql | 3 + .../pg_vector/postgresql/pgx/sqlc.yaml | 10 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 16 + .../postgresql/pgx/v4/go/query.sql.go | 48 + .../postgresql/pgx/v4/query.sql | 5 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 14 + .../postgresql/pgx/v5/exec.json | 3 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 14 + .../postgresql/pgx/v5/go/query.sql.go | 46 + .../postgresql/pgx/v5/query.sql | 5 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../testdata/prepared_queries/mysql/go/db.go | 128 + .../prepared_queries/mysql/go/models.go | 15 + .../prepared_queries/mysql/go/query.sql.go | 104 + .../testdata/prepared_queries/mysql/query.sql | 14 + .../prepared_queries/mysql/schema.sql | 6 + .../testdata/prepared_queries/mysql/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 128 + .../postgresql/stdlib/go/models.go | 15 + .../postgresql/stdlib/go/query.sql.go | 104 + .../postgresql/stdlib/query.sql | 14 + .../postgresql/stdlib/schema.sql | 6 + .../postgresql/stdlib/sqlc.json | 13 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 15 + .../postgresql/pgx/v4/go/queries.sql.go | 27 + .../postgresql/pgx/v4/queries.sql | 9 + .../postgresql/pgx/v4/schema.sql | 7 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 15 + .../postgresql/pgx/v5/go/queries.sql.go | 27 + .../postgresql/pgx/v5/queries.sql | 9 + .../postgresql/pgx/v5/schema.sql | 7 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 15 + .../postgresql/stdlib/go/queries.sql.go | 27 + .../postgresql/stdlib/queries.sql | 9 + .../postgresql/stdlib/schema.sql | 7 + .../postgresql/stdlib/sqlc.json | 12 + .../process_plugin_disabled/exec.json | 6 + .../process_plugin_disabled/query.sql | 19 + .../process_plugin_disabled/schema.sql | 5 + .../process_plugin_disabled/sqlc.json | 28 + .../process_plugin_disabled/stderr.txt | 1 + .../process_plugin_format_json/exec.json | 4 + .../process_plugin_format_json/gen/hello.txt | 12 + .../process_plugin_format_json/query.sql | 19 + .../process_plugin_format_json/schema.sql | 5 + .../process_plugin_format_json/sqlc.json | 25 + .../process_plugin_sqlc_gen_json/exec.json | 4 + .../process_plugin_sqlc_gen_json/query.sql | 19 + .../process_plugin_sqlc_gen_json/schema.sql | 5 + .../process_plugin_sqlc_gen_json/sqlc.json | 28 + .../process_plugin_sqlc_gen_test/exec.json | 4 + .../process_plugin_sqlc_gen_test/gen/env.json | 6 + .../process_plugin_sqlc_gen_test/query.sql | 19 + .../process_plugin_sqlc_gen_test/schema.sql | 5 + .../process_plugin_sqlc_gen_test/sqlc.json | 25 + .../postgresql/query.sql | 19 + .../postgresql/schema.sql | 6 + .../postgresql/sqlc.json | 14 + .../postgresql/stderr.txt | 2 + .../postgresql/go/db.go | 31 + .../postgresql/go/models.go | 18 + .../postgresql/go/querier.go | 18 + .../postgresql/go/query.sql.go | 33 + .../postgresql/query.sql | 8 + .../postgresql/schema.sql | 8 + .../postgresql/sqlc.json | 14 + .../postgresql/go/db.go | 31 + .../postgresql/go/models.go | 22 + .../postgresql/go/query.sql.go | 164 + .../postgresql/query.sql | 34 + .../postgresql/schema.sql | 13 + .../postgresql/sqlc.json | 14 + .../postgresql/go/db.go | 31 + .../postgresql/go/models.go | 16 + .../postgresql/go/querier.go | 18 + .../postgresql/go/query.sql.go | 107 + .../postgresql/query.sql | 19 + .../postgresql/schema.sql | 8 + .../postgresql/sqlc.json | 15 + .../testdata/quoted_colname/sqlite/go/db.go | 31 + .../quoted_colname/sqlite/go/models.go | 9 + .../quoted_colname/sqlite/go/query.sql.go | 37 + .../testdata/quoted_colname/sqlite/query.sql | 2 + .../testdata/quoted_colname/sqlite/schema.sql | 6 + .../testdata/quoted_colname/sqlite/sqlc.json | 12 + .../quoted_names_complex/sqlite/go/db.go | 31 + .../quoted_names_complex/sqlite/go/models.go | 5 + .../sqlite/go/query.sql.go | 19 + .../quoted_names_complex/sqlite/query.sql | 2 + .../quoted_names_complex/sqlite/schema.sql | 22 + .../quoted_names_complex/sqlite/sqlc.json | 12 + .../testdata/quoted_tablename/sqlite/go/db.go | 31 + .../quoted_tablename/sqlite/go/models.go | 9 + .../quoted_tablename/sqlite/go/query.sql.go | 37 + .../quoted_tablename/sqlite/query.sql | 2 + .../quoted_tablename/sqlite/schema.sql | 6 + .../quoted_tablename/sqlite/sqlc.json | 12 + .../endtoend/testdata/ranges/pgx/v5/go/db.go | 32 + .../testdata/ranges/pgx/v5/go/models.go | 36 + .../testdata/ranges/pgx/v5/go/query.sql.go | 59 + .../endtoend/testdata/ranges/pgx/v5/query.sql | 2 + .../testdata/ranges/pgx/v5/schema.sql | 28 + .../endtoend/testdata/ranges/pgx/v5/sqlc.json | 13 + .../refreshmatview/postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 9 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../refreshmatview/postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 9 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/query.sql | 11 + .../postgresql/schema.sql | 0 .../postgresql/sqlc.json | 11 + .../postgresql/stderr/base.txt | 5 + .../postgresql/stderr/managed-db.txt | 5 + .../testdata/rename/v1/pgx/v4/go/db.go | 32 + .../testdata/rename/v1/pgx/v4/go/models.go | 58 + .../testdata/rename/v1/pgx/v4/go/query.sql.go | 70 + .../testdata/rename/v1/pgx/v4/query.sql | 8 + .../testdata/rename/v1/pgx/v4/schema.sql | 4 + .../testdata/rename/v1/pgx/v4/sqlc.json | 20 + .../testdata/rename/v1/pgx/v5/go/db.go | 32 + .../testdata/rename/v1/pgx/v5/go/models.go | 58 + .../testdata/rename/v1/pgx/v5/go/query.sql.go | 70 + .../testdata/rename/v1/pgx/v5/query.sql | 8 + .../testdata/rename/v1/pgx/v5/schema.sql | 4 + .../testdata/rename/v1/pgx/v5/sqlc.json | 20 + .../testdata/rename/v1/stdlib/go/db.go | 31 + .../testdata/rename/v1/stdlib/go/models.go | 58 + .../testdata/rename/v1/stdlib/go/query.sql.go | 76 + .../testdata/rename/v1/stdlib/query.sql | 8 + .../testdata/rename/v1/stdlib/schema.sql | 4 + .../testdata/rename/v1/stdlib/sqlc.json | 18 + .../testdata/rename/v2/pgx/v4/go/db.go | 32 + .../testdata/rename/v2/pgx/v4/go/models.go | 58 + .../testdata/rename/v2/pgx/v4/go/query.sql.go | 70 + .../testdata/rename/v2/pgx/v4/query.sql | 8 + .../testdata/rename/v2/pgx/v4/schema.sql | 4 + .../testdata/rename/v2/pgx/v4/sqlc.json | 24 + .../testdata/rename/v2/pgx/v5/go/db.go | 32 + .../testdata/rename/v2/pgx/v5/go/models.go | 58 + .../testdata/rename/v2/pgx/v5/go/query.sql.go | 70 + .../testdata/rename/v2/pgx/v5/query.sql | 8 + .../testdata/rename/v2/pgx/v5/schema.sql | 4 + .../testdata/rename/v2/pgx/v5/sqlc.json | 24 + .../testdata/rename/v2/stdlib/go/db.go | 31 + .../testdata/rename/v2/stdlib/go/models.go | 58 + .../testdata/rename/v2/stdlib/go/query.sql.go | 76 + .../testdata/rename/v2/stdlib/query.sql | 8 + .../testdata/rename/v2/stdlib/schema.sql | 4 + .../testdata/rename/v2/stdlib/sqlc.json | 23 + .../returning/postgresql/pgx/v4/go/db.go | 32 + .../returning/postgresql/pgx/v4/go/models.go | 14 + .../postgresql/pgx/v4/go/query.sql.go | 97 + .../returning/postgresql/pgx/v4/query.sql | 27 + .../returning/postgresql/pgx/v4/schema.sql | 1 + .../returning/postgresql/pgx/v4/sqlc.json | 13 + .../returning/postgresql/pgx/v5/go/db.go | 32 + .../returning/postgresql/pgx/v5/go/models.go | 14 + .../postgresql/pgx/v5/go/query.sql.go | 98 + .../returning/postgresql/pgx/v5/query.sql | 27 + .../returning/postgresql/pgx/v5/schema.sql | 1 + .../returning/postgresql/pgx/v5/sqlc.json | 13 + .../returning/postgresql/stdlib/go/db.go | 31 + .../returning/postgresql/stdlib/go/models.go | 14 + .../postgresql/stdlib/go/query.sql.go | 97 + .../returning/postgresql/stdlib/query.sql | 27 + .../returning/postgresql/stdlib/schema.sql | 1 + .../returning/postgresql/stdlib/sqlc.json | 12 + .../testdata/returning/sqlite/go/db.go | 31 + .../testdata/returning/sqlite/go/models.go | 14 + .../testdata/returning/sqlite/go/query.sql.go | 101 + .../testdata/returning/sqlite/query.sql | 31 + .../testdata/returning/sqlite/schema.sql | 1 + .../testdata/returning/sqlite/sqlc.json | 12 + .../postgresql/pgx/v5/exec.json | 3 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 15 + .../postgresql/pgx/v5/go/query.sql.go | 124 + .../postgresql/pgx/v5/query.sql | 23 + .../postgresql/pgx/v5/schema.sql | 5 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/exec.json | 3 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 15 + .../postgresql/stdlib/go/query.sql.go | 123 + .../postgresql/stdlib/query.sql | 23 + .../postgresql/stdlib/schema.sql | 5 + .../postgresql/stdlib/sqlc.json | 12 + .../schema_scoped_create/mysql/exec.json | 6 + .../schema_scoped_create/mysql/go/db.go | 31 + .../schema_scoped_create/mysql/go/models.go | 10 + .../mysql/go/query.sql.go | 24 + .../schema_scoped_create/mysql/query.sql | 2 + .../schema_scoped_create/mysql/schema.sql | 3 + .../schema_scoped_create/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 10 + .../postgresql/pgx/v4/go/query.sql.go | 26 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 3 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 10 + .../postgresql/pgx/v5/go/query.sql.go | 26 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 3 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 10 + .../postgresql/stdlib/go/query.sql.go | 26 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 3 + .../postgresql/stdlib/sqlc.json | 12 + .../schema_scoped_delete/mysql/exec.json | 7 + .../schema_scoped_delete/mysql/go/db.go | 31 + .../schema_scoped_delete/mysql/go/models.go | 9 + .../mysql/go/query.sql.go | 19 + .../schema_scoped_delete/mysql/query.sql | 2 + .../schema_scoped_delete/mysql/schema.sql | 3 + .../schema_scoped_delete/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 9 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 3 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 9 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 3 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 9 + .../postgresql/stdlib/go/query.sql.go | 19 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 3 + .../postgresql/stdlib/sqlc.json | 12 + .../schema_scoped_enum/pgx/v4/go/db.go | 32 + .../schema_scoped_enum/pgx/v4/go/models.go | 56 + .../schema_scoped_enum/pgx/v4/go/query.sql.go | 34 + .../schema_scoped_enum/pgx/v4/query.sql | 2 + .../schema_scoped_enum/pgx/v4/schema.sql | 8 + .../schema_scoped_enum/pgx/v4/sqlc.json | 13 + .../schema_scoped_enum/pgx/v5/go/db.go | 32 + .../schema_scoped_enum/pgx/v5/go/models.go | 56 + .../schema_scoped_enum/pgx/v5/go/query.sql.go | 34 + .../schema_scoped_enum/pgx/v5/query.sql | 2 + .../schema_scoped_enum/pgx/v5/schema.sql | 8 + .../schema_scoped_enum/pgx/v5/sqlc.json | 13 + .../schema_scoped_enum/stdlib/go/db.go | 31 + .../schema_scoped_enum/stdlib/go/models.go | 56 + .../schema_scoped_enum/stdlib/go/query.sql.go | 37 + .../schema_scoped_enum/stdlib/query.sql | 2 + .../schema_scoped_enum/stdlib/schema.sql | 8 + .../schema_scoped_enum/stdlib/sqlc.json | 11 + .../schema_scoped_filter/mysql/exec.json | 6 + .../schema_scoped_filter/mysql/go/db.go | 31 + .../schema_scoped_filter/mysql/go/models.go | 9 + .../mysql/go/query.sql.go | 37 + .../schema_scoped_filter/mysql/query.sql | 2 + .../schema_scoped_filter/mysql/schema.sql | 2 + .../schema_scoped_filter/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 9 + .../postgresql/pgx/v4/go/query.sql.go | 34 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 3 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 9 + .../postgresql/pgx/v5/go/query.sql.go | 34 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 3 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 9 + .../postgresql/stdlib/go/query.sql.go | 37 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 3 + .../postgresql/stdlib/sqlc.json | 12 + .../schema_scoped_list/mysql/exec.json | 6 + .../schema_scoped_list/mysql/go/db.go | 31 + .../schema_scoped_list/mysql/go/models.go | 9 + .../schema_scoped_list/mysql/go/query.sql.go | 64 + .../schema_scoped_list/mysql/query.sql | 5 + .../schema_scoped_list/mysql/schema.sql | 3 + .../schema_scoped_list/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 9 + .../postgresql/pgx/v4/go/query.sql.go | 58 + .../postgresql/pgx/v4/query.sql | 5 + .../postgresql/pgx/v4/schema.sql | 3 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 9 + .../postgresql/pgx/v5/go/query.sql.go | 58 + .../postgresql/pgx/v5/query.sql | 5 + .../postgresql/pgx/v5/schema.sql | 3 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 9 + .../postgresql/stdlib/go/query.sql.go | 64 + .../postgresql/stdlib/query.sql | 5 + .../postgresql/stdlib/schema.sql | 3 + .../postgresql/stdlib/sqlc.json | 12 + .../schema_scoped_update/mysql/exec.json | 6 + .../schema_scoped_update/mysql/go/db.go | 31 + .../schema_scoped_update/mysql/go/models.go | 10 + .../mysql/go/query.sql.go | 24 + .../schema_scoped_update/mysql/query.sql | 2 + .../schema_scoped_update/mysql/schema.sql | 3 + .../schema_scoped_update/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 10 + .../postgresql/pgx/v4/go/query.sql.go | 24 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 3 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 10 + .../postgresql/pgx/v5/go/query.sql.go | 24 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 3 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 10 + .../postgresql/stdlib/go/query.sql.go | 24 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 3 + .../postgresql/stdlib/sqlc.json | 12 + .../testdata/schema_table_column_ref/issue.md | 1 + .../postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 23 + .../postgresql/pgx/go/query.sql.go | 77 + .../postgresql/pgx/query.sql | 22 + .../postgresql/pgx/schema.sql | 15 + .../postgresql/pgx/sqlc.yaml | 10 + .../select_column_cast/mysql/go/db.go | 31 + .../select_column_cast/mysql/go/models.go | 9 + .../select_column_cast/mysql/go/query.sql.go | 37 + .../select_column_cast/mysql/query.sql | 2 + .../select_column_cast/mysql/schema.sql | 2 + .../select_column_cast/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 9 + .../postgresql/pgx/v4/go/query.sql.go | 34 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 9 + .../postgresql/pgx/v5/go/query.sql.go | 34 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 9 + .../postgresql/stdlib/go/query.sql.go | 37 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 11 + .../select_column_cast/sqlite/go/db.go | 31 + .../select_column_cast/sqlite/go/models.go | 9 + .../select_column_cast/sqlite/go/query.sql.go | 37 + .../select_column_cast/sqlite/query.sql | 2 + .../select_column_cast/sqlite/schema.sql | 2 + .../select_column_cast/sqlite/sqlc.json | 12 + .../testdata/select_cte/sqlite/go/db.go | 31 + .../testdata/select_cte/sqlite/go/models.go | 5 + .../select_cte/sqlite/go/query.sql.go | 40 + .../testdata/select_cte/sqlite/query.sql | 5 + .../testdata/select_cte/sqlite/schema.sql | 1 + .../testdata/select_cte/sqlite/sqlc.json | 12 + .../testdata/select_distinct/pgx/v4/go/db.go | 32 + .../select_distinct/pgx/v4/go/models.go | 14 + .../select_distinct/pgx/v4/go/query.sql.go | 35 + .../testdata/select_distinct/pgx/v4/query.sql | 3 + .../select_distinct/pgx/v4/schema.sql | 2 + .../testdata/select_distinct/pgx/v4/sqlc.json | 13 + .../testdata/select_distinct/pgx/v5/go/db.go | 32 + .../select_distinct/pgx/v5/go/models.go | 14 + .../select_distinct/pgx/v5/go/query.sql.go | 35 + .../testdata/select_distinct/pgx/v5/query.sql | 3 + .../select_distinct/pgx/v5/schema.sql | 2 + .../testdata/select_distinct/pgx/v5/sqlc.json | 13 + .../testdata/select_distinct/stdlib/go/db.go | 31 + .../select_distinct/stdlib/go/models.go | 14 + .../select_distinct/stdlib/go/query.sql.go | 38 + .../testdata/select_distinct/stdlib/query.sql | 3 + .../select_distinct/stdlib/schema.sql | 2 + .../testdata/select_distinct/stdlib/sqlc.json | 11 + .../select_empty_column_list/mysql/query.sql | 2 + .../select_empty_column_list/mysql/schema.sql | 1 + .../select_empty_column_list/mysql/sqlc.json | 12 + .../select_empty_column_list/mysql/stderr.txt | 2 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 14 + .../postgresql/pgx/v4/go/query.sql.go | 37 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 14 + .../postgresql/pgx/v5/go/query.sql.go | 37 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 14 + .../postgresql/stdlib/go/query.sql.go | 40 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../testdata/select_exists/pgx/v4/go/db.go | 32 + .../select_exists/pgx/v4/go/models.go | 9 + .../select_exists/pgx/v4/go/query.sql.go | 29 + .../testdata/select_exists/pgx/v4/query.sql | 10 + .../testdata/select_exists/pgx/v4/schema.sql | 2 + .../testdata/select_exists/pgx/v4/sqlc.json | 13 + .../testdata/select_exists/pgx/v5/go/db.go | 32 + .../select_exists/pgx/v5/go/models.go | 9 + .../select_exists/pgx/v5/go/query.sql.go | 29 + .../testdata/select_exists/pgx/v5/query.sql | 10 + .../testdata/select_exists/pgx/v5/schema.sql | 2 + .../testdata/select_exists/pgx/v5/sqlc.json | 13 + .../testdata/select_exists/sqlite/go/db.go | 31 + .../select_exists/sqlite/go/models.go | 9 + .../select_exists/sqlite/go/query.sql.go | 26 + .../testdata/select_exists/sqlite/query.sql | 7 + .../testdata/select_exists/sqlite/schema.sql | 1 + .../testdata/select_exists/sqlite/sqlc.json | 12 + .../testdata/select_exists/stdlib/go/db.go | 31 + .../select_exists/stdlib/go/models.go | 9 + .../select_exists/stdlib/go/query.sql.go | 29 + .../testdata/select_exists/stdlib/query.sql | 10 + .../testdata/select_exists/stdlib/schema.sql | 2 + .../testdata/select_exists/stdlib/sqlc.json | 11 + .../testdata/select_in_and/sqlite/go/db.go | 31 + .../select_in_and/sqlite/go/models.go | 28 + .../select_in_and/sqlite/go/query.sql.go | 37 + .../testdata/select_in_and/sqlite/query.sql | 13 + .../testdata/select_in_and/sqlite/schema.sql | 20 + .../testdata/select_in_and/sqlite/sqlc.json | 1 + .../testdata/select_limit/mysql/go/db.go | 31 + .../testdata/select_limit/mysql/go/models.go | 13 + .../select_limit/mysql/go/query.sql.go | 72 + .../testdata/select_limit/mysql/query.sql | 7 + .../testdata/select_limit/mysql/schema.sql | 2 + .../testdata/select_limit/mysql/sqlc.json | 12 + .../select_limit/postgresql/pgx/v4/exec.json | 3 + .../select_limit/postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 13 + .../postgresql/pgx/v4/go/query.sql.go | 66 + .../select_limit/postgresql/pgx/v4/query.sql | 7 + .../select_limit/postgresql/pgx/v4/schema.sql | 2 + .../select_limit/postgresql/pgx/v4/sqlc.json | 13 + .../select_limit/postgresql/pgx/v5/exec.json | 3 + .../select_limit/postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 13 + .../postgresql/pgx/v5/go/query.sql.go | 67 + .../select_limit/postgresql/pgx/v5/query.sql | 7 + .../select_limit/postgresql/pgx/v5/schema.sql | 2 + .../select_limit/postgresql/pgx/v5/sqlc.json | 13 + .../select_limit/postgresql/stdlib/exec.json | 3 + .../select_limit/postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 13 + .../postgresql/stdlib/go/query.sql.go | 72 + .../select_limit/postgresql/stdlib/query.sql | 7 + .../select_limit/postgresql/stdlib/schema.sql | 2 + .../select_limit/postgresql/stdlib/sqlc.json | 12 + .../testdata/select_limit/sqlite/go/db.go | 31 + .../testdata/select_limit/sqlite/go/models.go | 13 + .../select_limit/sqlite/go/query.sql.go | 75 + .../testdata/select_limit/sqlite/query.sql | 10 + .../testdata/select_limit/sqlite/schema.sql | 2 + .../testdata/select_limit/sqlite/sqlc.json | 12 + .../select_nested_count/mysql/go/db.go | 31 + .../select_nested_count/mysql/go/models.go | 21 + .../select_nested_count/mysql/go/query.sql.go | 54 + .../select_nested_count/mysql/query.sql | 6 + .../select_nested_count/mysql/schema.sql | 13 + .../select_nested_count/mysql/sqlc.json | 12 + .../select_nested_count/postgresql/go/db.go | 31 + .../postgresql/go/models.go | 21 + .../postgresql/go/query.sql.go | 54 + .../select_nested_count/postgresql/query.sql | 6 + .../select_nested_count/postgresql/schema.sql | 13 + .../select_nested_count/postgresql/sqlc.json | 11 + .../select_nested_count/sqlite/go/db.go | 31 + .../select_nested_count/sqlite/go/models.go | 21 + .../sqlite/go/query.sql.go | 57 + .../select_nested_count/sqlite/query.sql | 9 + .../select_nested_count/sqlite/schema.sql | 13 + .../select_nested_count/sqlite/sqlc.json | 12 + .../select_not_exists/pgx/v4/go/db.go | 32 + .../select_not_exists/pgx/v4/go/models.go | 9 + .../select_not_exists/pgx/v4/go/query.sql.go | 29 + .../select_not_exists/pgx/v4/query.sql | 10 + .../select_not_exists/pgx/v4/schema.sql | 2 + .../select_not_exists/pgx/v4/sqlc.json | 13 + .../select_not_exists/pgx/v5/go/db.go | 32 + .../select_not_exists/pgx/v5/go/models.go | 9 + .../select_not_exists/pgx/v5/go/query.sql.go | 29 + .../select_not_exists/pgx/v5/query.sql | 10 + .../select_not_exists/pgx/v5/schema.sql | 2 + .../select_not_exists/pgx/v5/sqlc.json | 13 + .../select_not_exists/sqlite/exec.json | 3 + .../select_not_exists/sqlite/go/db.go | 31 + .../select_not_exists/sqlite/go/models.go | 9 + .../select_not_exists/sqlite/go/query.sql.go | 26 + .../select_not_exists/sqlite/query.sql | 7 + .../select_not_exists/sqlite/schema.sql | 2 + .../select_not_exists/sqlite/sqlc.json | 12 + .../select_not_exists/stdlib/go/db.go | 31 + .../select_not_exists/stdlib/go/models.go | 9 + .../select_not_exists/stdlib/go/query.sql.go | 29 + .../select_not_exists/stdlib/query.sql | 10 + .../select_not_exists/stdlib/schema.sql | 2 + .../select_not_exists/stdlib/sqlc.json | 11 + .../testdata/select_sequence/issue.md | 1 + .../select_sequence/postgresql/pgx/exec.json | 3 + .../select_sequence/postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 5 + .../postgresql/pgx/go/query.sql.go | 21 + .../select_sequence/postgresql/pgx/query.sql | 2 + .../select_sequence/postgresql/pgx/schema.sql | 6 + .../select_sequence/postgresql/pgx/sqlc.yaml | 10 + .../testdata/select_star/mysql/go/db.go | 31 + .../testdata/select_star/mysql/go/models.go | 16 + .../select_star/mysql/go/query.sql.go | 69 + .../testdata/select_star/mysql/query.sql | 5 + .../testdata/select_star/mysql/schema.sql | 6 + .../testdata/select_star/mysql/sqlc.json | 12 + .../select_star/postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 16 + .../postgresql/pgx/v4/go/query.sql.go | 63 + .../select_star/postgresql/pgx/v4/query.sql | 5 + .../select_star/postgresql/pgx/v4/schema.sql | 6 + .../select_star/postgresql/pgx/v4/sqlc.json | 13 + .../select_star/postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 16 + .../postgresql/pgx/v5/go/query.sql.go | 63 + .../select_star/postgresql/pgx/v5/query.sql | 5 + .../select_star/postgresql/pgx/v5/schema.sql | 6 + .../select_star/postgresql/pgx/v5/sqlc.json | 13 + .../select_star/postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 16 + .../postgresql/stdlib/go/query.sql.go | 69 + .../select_star/postgresql/stdlib/query.sql | 5 + .../select_star/postgresql/stdlib/schema.sql | 6 + .../select_star/postgresql/stdlib/sqlc.json | 12 + .../testdata/select_star/sqlite/go/db.go | 31 + .../testdata/select_star/sqlite/go/models.go | 16 + .../select_star/sqlite/go/query.sql.go | 69 + .../testdata/select_star/sqlite/query.sql | 5 + .../testdata/select_star/sqlite/schema.sql | 6 + .../testdata/select_star/sqlite/sqlc.json | 12 + .../select_star_quoted/mysql/go/db.go | 31 + .../select_star_quoted/mysql/go/models.go | 13 + .../select_star_quoted/mysql/go/query.sql.go | 38 + .../select_star_quoted/mysql/query.sql | 2 + .../select_star_quoted/mysql/schema.sql | 3 + .../select_star_quoted/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 13 + .../postgresql/pgx/v4/go/query.sql.go | 35 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 3 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 13 + .../postgresql/pgx/v5/go/query.sql.go | 36 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 3 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 13 + .../postgresql/stdlib/go/query.sql.go | 38 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 3 + .../postgresql/stdlib/sqlc.json | 12 + .../select_subquery/postgresql/issue.md | 1 + .../postgresql/stdlib/exec.json | 3 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 19 + .../postgresql/stdlib/go/query.sql.go | 53 + .../postgresql/stdlib/query.sql | 6 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.yaml | 10 + .../testdata/select_subquery_alias/issue.md | 1 + .../postgresql/pgx/exec.json | 3 + .../postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 16 + .../postgresql/pgx/go/query.sql.go | 61 + .../postgresql/pgx/query.sql | 10 + .../postgresql/pgx/schema.sql | 7 + .../postgresql/pgx/sqlc.yaml | 10 + .../select_subquery_no_alias/mysql/go/db.go | 31 + .../mysql/go/models.go | 14 + .../mysql/go/query.sql.go | 37 + .../select_subquery_no_alias/mysql/query.sql | 2 + .../select_subquery_no_alias/mysql/schema.sql | 1 + .../select_subquery_no_alias/mysql/sqlc.yaml | 9 + .../postgres/stdlib/go/db.go | 31 + .../postgres/stdlib/go/models.go | 14 + .../postgres/stdlib/go/query.sql.go | 37 + .../postgres/stdlib/query.sql | 2 + .../postgres/stdlib/schema.sql | 1 + .../postgres/stdlib/sqlc.yaml | 10 + .../select_subquery_no_alias/sqlite/go/db.go | 31 + .../sqlite/go/models.go | 14 + .../sqlite/go/query.sql.go | 37 + .../select_subquery_no_alias/sqlite/query.sql | 2 + .../sqlite/schema.sql | 1 + .../select_subquery_no_alias/sqlite/sqlc.yaml | 10 + .../endtoend/testdata/select_system/issue.md | 1 + .../testdata/select_system/pgx/exec.json | 3 + .../testdata/select_system/pgx/go/db.go | 32 + .../testdata/select_system/pgx/go/models.go | 13 + .../select_system/pgx/go/query.sql.go | 41 + .../testdata/select_system/pgx/query.sql | 4 + .../testdata/select_system/pgx/schema.sql | 3 + .../testdata/select_system/pgx/sqlc.yaml | 10 + .../select_text_array/pgx/v4/go/db.go | 32 + .../select_text_array/pgx/v4/go/models.go | 5 + .../select_text_array/pgx/v4/go/query.sql.go | 34 + .../select_text_array/pgx/v4/query.sql | 2 + .../select_text_array/pgx/v4/schema.sql | 0 .../select_text_array/pgx/v4/sqlc.json | 13 + .../select_text_array/pgx/v5/go/db.go | 32 + .../select_text_array/pgx/v5/go/models.go | 5 + .../select_text_array/pgx/v5/go/query.sql.go | 34 + .../select_text_array/pgx/v5/query.sql | 2 + .../select_text_array/pgx/v5/schema.sql | 0 .../select_text_array/pgx/v5/sqlc.json | 13 + .../select_text_array/stdlib/go/db.go | 31 + .../select_text_array/stdlib/go/models.go | 5 + .../select_text_array/stdlib/go/query.sql.go | 39 + .../select_text_array/stdlib/query.sql | 2 + .../select_text_array/stdlib/schema.sql | 0 .../select_text_array/stdlib/sqlc.json | 11 + .../testdata/select_union/mysql/go/db.go | 31 + .../testdata/select_union/mysql/go/models.go | 19 + .../select_union/mysql/go/query.sql.go | 190 + .../testdata/select_union/mysql/query.sql | 30 + .../testdata/select_union/mysql/schema.sql | 3 + .../testdata/select_union/mysql/sqlc.json | 12 + .../select_union/postgres/pgx/v4/exec.json | 3 + .../select_union/postgres/pgx/v4/go/db.go | 32 + .../select_union/postgres/pgx/v4/go/models.go | 19 + .../postgres/pgx/v4/go/query.sql.go | 172 + .../select_union/postgres/pgx/v4/query.sql | 30 + .../select_union/postgres/pgx/v4/schema.sql | 3 + .../select_union/postgres/pgx/v4/sqlc.json | 13 + .../select_union/postgres/pgx/v5/exec.json | 3 + .../select_union/postgres/pgx/v5/go/db.go | 32 + .../select_union/postgres/pgx/v5/go/models.go | 19 + .../postgres/pgx/v5/go/query.sql.go | 172 + .../select_union/postgres/pgx/v5/query.sql | 30 + .../select_union/postgres/pgx/v5/schema.sql | 3 + .../select_union/postgres/pgx/v5/sqlc.json | 13 + .../select_union/postgres/stdlib/exec.json | 3 + .../select_union/postgres/stdlib/go/db.go | 31 + .../select_union/postgres/stdlib/go/models.go | 19 + .../postgres/stdlib/go/query.sql.go | 190 + .../select_union/postgres/stdlib/query.sql | 30 + .../select_union/postgres/stdlib/schema.sql | 3 + .../select_union/postgres/stdlib/sqlc.json | 12 + .../testdata/select_union/sqlite/go/db.go | 31 + .../testdata/select_union/sqlite/go/models.go | 19 + .../select_union/sqlite/go/query.sql.go | 162 + .../testdata/select_union/sqlite/query.sql | 26 + .../testdata/select_union/sqlite/schema.sql | 3 + .../testdata/select_union/sqlite/sqlc.json | 12 + .../testdata/select_union_subquery/issue.md | 1 + .../select_union_subquery/mysql/go/db.go | 31 + .../select_union_subquery/mysql/go/models.go | 15 + .../mysql/go/query.sql.go | 41 + .../select_union_subquery/mysql/query.sql | 6 + .../select_union_subquery/mysql/schema.sql | 5 + .../select_union_subquery/mysql/sqlc.yaml | 9 + .../select_union_subquery/postgresql/go/db.go | 32 + .../postgresql/go/models.go | 15 + .../postgresql/go/query.sql.go | 38 + .../postgresql/query.sql | 6 + .../postgresql/schema.sql | 5 + .../postgresql/sqlc.yaml | 10 + .../testdata/selectstatic/mysql/go/db.go | 31 + .../testdata/selectstatic/mysql/go/models.go | 5 + .../selectstatic/mysql/go/query.sql.go | 35 + .../testdata/selectstatic/mysql/query.sql | 2 + .../testdata/selectstatic/mysql/schema.sql | 0 .../testdata/selectstatic/mysql/sqlc.json | 13 + .../testdata/show_warnings/mysql/go/db.go | 31 + .../testdata/show_warnings/mysql/go/models.go | 5 + .../show_warnings/mysql/go/query.sql.go | 43 + .../testdata/show_warnings/mysql/query.sql | 2 + .../testdata/show_warnings/mysql/schema.sql | 0 .../testdata/show_warnings/mysql/sqlc.json | 12 + .../single_param_conflict/mysql/go/db.go | 31 + .../single_param_conflict/mysql/go/models.go | 19 + .../mysql/go/query.sql.go | 52 + .../single_param_conflict/mysql/query.sql | 17 + .../single_param_conflict/mysql/schema.sql | 11 + .../single_param_conflict/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 21 + .../postgresql/pgx/v4/go/query.sql.go | 70 + .../postgresql/pgx/v4/query.sql | 25 + .../postgresql/pgx/v4/schema.sql | 11 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 19 + .../postgresql/pgx/v5/go/query.sql.go | 70 + .../postgresql/pgx/v5/query.sql | 25 + .../postgresql/pgx/v5/schema.sql | 11 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 21 + .../postgresql/stdlib/go/query.sql.go | 70 + .../postgresql/stdlib/query.sql | 25 + .../postgresql/stdlib/schema.sql | 11 + .../postgresql/stdlib/sqlc.json | 12 + .../single_param_conflict/sqlite/go/db.go | 31 + .../single_param_conflict/sqlite/go/models.go | 19 + .../sqlite/go/query.sql.go | 52 + .../single_param_conflict/sqlite/query.sql | 17 + .../single_param_conflict/sqlite/schema.sql | 11 + .../single_param_conflict/sqlite/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 5 + .../postgresql/pgx/v4/go/query.sql.go | 76 + .../postgresql/pgx/v4/query.sql | 17 + .../postgresql/pgx/v4/schema.sql | 12 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 5 + .../postgresql/pgx/v5/go/query.sql.go | 76 + .../postgresql/pgx/v5/query.sql | 17 + .../postgresql/pgx/v5/schema.sql | 12 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 5 + .../postgresql/stdlib/go/query.sql.go | 76 + .../postgresql/stdlib/query.sql | 17 + .../postgresql/stdlib/schema.sql | 12 + .../postgresql/stdlib/sqlc.json | 12 + .../endtoend/testdata/sqlc_arg/mysql/go/db.go | 31 + .../testdata/sqlc_arg/mysql/go/models.go | 9 + .../testdata/sqlc_arg/mysql/go/query.sql.go | 96 + .../testdata/sqlc_arg/mysql/query.sql | 9 + .../testdata/sqlc_arg/mysql/schema.sql | 2 + .../testdata/sqlc_arg/mysql/sqlc.json | 12 + .../sqlc_arg/postgresql/pgx/v4/go/db.go | 32 + .../sqlc_arg/postgresql/pgx/v4/go/models.go | 9 + .../postgresql/pgx/v4/go/query.sql.go | 58 + .../sqlc_arg/postgresql/pgx/v4/query.sql | 5 + .../sqlc_arg/postgresql/pgx/v4/schema.sql | 2 + .../sqlc_arg/postgresql/pgx/v4/sqlc.json | 13 + .../sqlc_arg/postgresql/pgx/v5/go/db.go | 32 + .../sqlc_arg/postgresql/pgx/v5/go/models.go | 9 + .../postgresql/pgx/v5/go/query.sql.go | 58 + .../sqlc_arg/postgresql/pgx/v5/query.sql | 5 + .../sqlc_arg/postgresql/pgx/v5/schema.sql | 2 + .../sqlc_arg/postgresql/pgx/v5/sqlc.json | 13 + .../sqlc_arg/postgresql/stdlib/go/db.go | 31 + .../sqlc_arg/postgresql/stdlib/go/models.go | 9 + .../postgresql/stdlib/go/query.sql.go | 64 + .../sqlc_arg/postgresql/stdlib/query.sql | 5 + .../sqlc_arg/postgresql/stdlib/schema.sql | 2 + .../sqlc_arg/postgresql/stdlib/sqlc.json | 12 + .../testdata/sqlc_arg/sqlite/go/db.go | 31 + .../testdata/sqlc_arg/sqlite/go/models.go | 9 + .../testdata/sqlc_arg/sqlite/go/query.sql.go | 64 + .../testdata/sqlc_arg/sqlite/query.sql | 5 + .../testdata/sqlc_arg/sqlite/schema.sql | 2 + .../testdata/sqlc_arg/sqlite/sqlc.json | 12 + .../testdata/sqlc_arg_invalid/mysql/query.sql | 14 + .../sqlc_arg_invalid/mysql/schema.sql | 4 + .../testdata/sqlc_arg_invalid/mysql/sqlc.json | 12 + .../sqlc_arg_invalid/mysql/stderr.txt | 6 + .../sqlc_arg_invalid/postgresql/query.sql | 14 + .../sqlc_arg_invalid/postgresql/schema.sql | 4 + .../sqlc_arg_invalid/postgresql/sqlc.json | 12 + .../sqlc_arg_invalid/postgresql/stderr.txt | 6 + .../sqlc_arg_invalid/sqlite/query.sql | 19 + .../sqlc_arg_invalid/sqlite/sqlc.json | 12 + .../sqlc_arg_invalid/sqlite/stderr.txt | 6 + .../testdata/sqlc_embed/mysql/exec.json | 6 + .../testdata/sqlc_embed/mysql/go/db.go | 31 + .../testdata/sqlc_embed/mysql/go/models.go | 25 + .../testdata/sqlc_embed/mysql/go/query.sql.go | 203 + .../testdata/sqlc_embed/mysql/query.sql | 25 + .../testdata/sqlc_embed/mysql/schema.sql | 19 + .../testdata/sqlc_embed/mysql/sqlc.json | 12 + .../sqlc_embed/postgresql/pgx/go/db.go | 32 + .../sqlc_embed/postgresql/pgx/go/models.go | 25 + .../sqlc_embed/postgresql/pgx/go/query.sql.go | 197 + .../sqlc_embed/postgresql/pgx/query.sql | 25 + .../sqlc_embed/postgresql/pgx/schema.sql | 19 + .../sqlc_embed/postgresql/pgx/sqlc.json | 15 + .../sqlc_embed/postgresql/stdlib/go/db.go | 31 + .../sqlc_embed/postgresql/stdlib/go/models.go | 26 + .../postgresql/stdlib/go/query.sql.go | 206 + .../sqlc_embed/postgresql/stdlib/query.sql | 25 + .../sqlc_embed/postgresql/stdlib/schema.sql | 20 + .../sqlc_embed/postgresql/stdlib/sqlc.json | 12 + .../testdata/sqlc_embed/sqlite/go/db.go | 31 + .../testdata/sqlc_embed/sqlite/go/models.go | 25 + .../sqlc_embed/sqlite/go/query.sql.go | 203 + .../testdata/sqlc_embed/sqlite/query.sql | 25 + .../testdata/sqlc_embed/sqlite/schema.sql | 19 + .../testdata/sqlc_embed/sqlite/sqlc.json | 12 + .../testdata/sqlc_narg/mysql/go/db.go | 31 + .../testdata/sqlc_narg/mysql/go/models.go | 14 + .../testdata/sqlc_narg/mysql/go/query.sql.go | 119 + .../testdata/sqlc_narg/mysql/query.sql | 11 + .../testdata/sqlc_narg/mysql/schema.sql | 2 + .../testdata/sqlc_narg/mysql/sqlc.json | 12 + .../sqlc_narg/postgresql/pgx/v4/go/db.go | 32 + .../sqlc_narg/postgresql/pgx/v4/go/models.go | 14 + .../postgresql/pgx/v4/go/query.sql.go | 107 + .../sqlc_narg/postgresql/pgx/v4/query.sql | 11 + .../sqlc_narg/postgresql/pgx/v4/schema.sql | 2 + .../sqlc_narg/postgresql/pgx/v4/sqlc.json | 13 + .../sqlc_narg/postgresql/pgx/v5/go/db.go | 32 + .../sqlc_narg/postgresql/pgx/v5/go/models.go | 14 + .../postgresql/pgx/v5/go/query.sql.go | 108 + .../sqlc_narg/postgresql/pgx/v5/query.sql | 11 + .../sqlc_narg/postgresql/pgx/v5/schema.sql | 2 + .../sqlc_narg/postgresql/pgx/v5/sqlc.json | 13 + .../sqlc_narg/postgresql/stdlib/go/db.go | 31 + .../sqlc_narg/postgresql/stdlib/go/models.go | 14 + .../postgresql/stdlib/go/query.sql.go | 119 + .../postgresql/stdlib/go_strict/db.go | 31 + .../postgresql/stdlib/go_strict/models.go | 14 + .../postgresql/stdlib/go_strict/query.sql.go | 119 + .../sqlc_narg/postgresql/stdlib/query.sql | 11 + .../sqlc_narg/postgresql/stdlib/schema.sql | 1 + .../sqlc_narg/postgresql/stdlib/sqlc.json | 28 + .../testdata/sqlc_narg/sqlite/go/db.go | 31 + .../testdata/sqlc_narg/sqlite/go/models.go | 14 + .../testdata/sqlc_narg/sqlite/go/query.sql.go | 119 + .../testdata/sqlc_narg/sqlite/query.sql | 11 + .../testdata/sqlc_narg/sqlite/schema.sql | 2 + .../testdata/sqlc_narg/sqlite/sqlc.json | 16 + .../testdata/sqlc_slice/mysql/go/db.go | 31 + .../testdata/sqlc_slice/mysql/go/models.go | 18 + .../testdata/sqlc_slice/mysql/go/query.sql.go | 282 ++ .../testdata/sqlc_slice/mysql/query.sql | 29 + .../testdata/sqlc_slice/mysql/schema.sql | 2 + .../testdata/sqlc_slice/mysql/sqlc.json | 18 + .../sqlc_slice/postgresql/pgx/go/db.go | 32 + .../sqlc_slice/postgresql/pgx/go/models.go | 10 + .../sqlc_slice/postgresql/pgx/go/query.sql.go | 70 + .../sqlc_slice/postgresql/pgx/query.sql | 7 + .../sqlc_slice/postgresql/pgx/schema.sql | 2 + .../sqlc_slice/postgresql/pgx/sqlc.json | 13 + .../sqlc_slice/postgresql/stdlib/go/db.go | 31 + .../sqlc_slice/postgresql/stdlib/go/models.go | 10 + .../postgresql/stdlib/go/query.sql.go | 101 + .../sqlc_slice/postgresql/stdlib/query.sql | 11 + .../sqlc_slice/postgresql/stdlib/schema.sql | 2 + .../sqlc_slice/postgresql/stdlib/sqlc.json | 12 + .../testdata/sqlc_slice/sqlite/go/db.go | 31 + .../testdata/sqlc_slice/sqlite/go/models.go | 15 + .../sqlc_slice/sqlite/go/query.sql.go | 242 ++ .../testdata/sqlc_slice/sqlite/query.sql | 25 + .../testdata/sqlc_slice/sqlite/schema.sql | 2 + .../testdata/sqlc_slice/sqlite/sqlc.json | 12 + .../sqlc_slice_prepared/sqlite/go/db.go | 88 + .../sqlc_slice_prepared/sqlite/go/models.go | 15 + .../sqlite/go/query.sql.go | 56 + .../sqlc_slice_prepared/sqlite/query.sql | 4 + .../sqlc_slice_prepared/sqlite/schema.sql | 2 + .../sqlc_slice_prepared/sqlite/sqlc.json | 13 + .../testdata/sqlite_skip_todo/db/db.go | 31 + .../testdata/sqlite_skip_todo/db/models.go | 13 + .../testdata/sqlite_skip_todo/db/query.sql.go | 67 + .../testdata/sqlite_skip_todo/query.sql | 16 + .../testdata/sqlite_skip_todo/schema.sql | 3 + .../testdata/sqlite_skip_todo/sqlc.json | 16 + .../sqlite_table_options/sqlite/go/db.go | 31 + .../sqlite_table_options/sqlite/go/models.go | 33 + .../sqlite/go/query.sql.go | 24 + .../sqlite_table_options/sqlite/query.sql | 5 + .../sqlite_table_options/sqlite/schema.sql | 24 + .../sqlite_table_options/sqlite/sqlc.json | 12 + .../testdata/star_expansion/mysql/go/db.go | 31 + .../star_expansion/mysql/go/models.go | 14 + .../star_expansion/mysql/go/query.sql.go | 81 + .../testdata/star_expansion/mysql/query.sql | 5 + .../testdata/star_expansion/mysql/schema.sql | 2 + .../testdata/star_expansion/mysql/sqlc.json | 12 + .../star_expansion/postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 14 + .../postgresql/pgx/v4/go/query.sql.go | 75 + .../postgresql/pgx/v4/query.sql | 5 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../star_expansion/postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 14 + .../postgresql/pgx/v5/go/query.sql.go | 76 + .../postgresql/pgx/v5/query.sql | 5 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../star_expansion/postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 14 + .../postgresql/stdlib/go/query.sql.go | 81 + .../postgresql/stdlib/query.sql | 5 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../testdata/star_expansion/sqlite/go/db.go | 31 + .../star_expansion/sqlite/go/models.go | 14 + .../star_expansion/sqlite/go/query.sql.go | 81 + .../testdata/star_expansion/sqlite/query.sql | 5 + .../testdata/star_expansion/sqlite/schema.sql | 2 + .../testdata/star_expansion/sqlite/sqlc.json | 12 + .../star_expansion_core/mysql/exec.json | 6 + .../star_expansion_core/mysql/go/db.go | 31 + .../star_expansion_core/mysql/go/models.go | 24 + .../star_expansion_core/mysql/go/query.sql.go | 209 + .../star_expansion_core/mysql/query.sql | 17 + .../star_expansion_core/mysql/schema.sql | 3 + .../star_expansion_core/mysql/sqlc.json | 12 + .../star_expansion_core/postgresql/exec.json | 6 + .../star_expansion_core/postgresql/go/db.go | 31 + .../postgresql/go/models.go | 24 + .../postgresql/go/query.sql.go | 225 + .../star_expansion_core/postgresql/query.sql | 20 + .../star_expansion_core/postgresql/schema.sql | 3 + .../star_expansion_core/postgresql/sqlc.json | 12 + .../star_expansion_core/sqlite/exec.json | 6 + .../star_expansion_core/sqlite/go/db.go | 31 + .../star_expansion_core/sqlite/go/models.go | 33 + .../sqlite/go/query.sql.go | 279 ++ .../star_expansion_core/sqlite/query.sql | 26 + .../star_expansion_core/sqlite/schema.sql | 5 + .../star_expansion_core/sqlite/sqlc.json | 12 + .../star_expansion_cte/pgx/v4/go/db.go | 32 + .../star_expansion_cte/pgx/v4/go/models.go | 19 + .../star_expansion_cte/pgx/v4/go/query.sql.go | 68 + .../star_expansion_cte/pgx/v4/query.sql | 8 + .../star_expansion_cte/pgx/v4/schema.sql | 3 + .../star_expansion_cte/pgx/v4/sqlc.json | 13 + .../star_expansion_cte/pgx/v5/go/db.go | 32 + .../star_expansion_cte/pgx/v5/go/models.go | 19 + .../star_expansion_cte/pgx/v5/go/query.sql.go | 69 + .../star_expansion_cte/pgx/v5/query.sql | 8 + .../star_expansion_cte/pgx/v5/schema.sql | 3 + .../star_expansion_cte/pgx/v5/sqlc.json | 13 + .../star_expansion_cte/stdlib/go/db.go | 31 + .../star_expansion_cte/stdlib/go/models.go | 19 + .../star_expansion_cte/stdlib/go/query.sql.go | 74 + .../star_expansion_cte/stdlib/query.sql | 8 + .../star_expansion_cte/stdlib/schema.sql | 3 + .../star_expansion_cte/stdlib/sqlc.json | 11 + .../postgresql/pgx/exec.json | 3 + .../postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 15 + .../postgresql/pgx/go/query.sql.go | 32 + .../postgresql/pgx/query.sql | 13 + .../postgresql/pgx/schema.sql | 6 + .../postgresql/pgx/sqlc.yaml | 10 + .../postgresql/pgx/stderr.txt | 2 + .../star_expansion_from_cte/pgx/v4/go/db.go | 32 + .../pgx/v4/go/models.go | 19 + .../pgx/v4/go/query.sql.go | 40 + .../star_expansion_from_cte/pgx/v4/query.sql | 2 + .../star_expansion_from_cte/pgx/v4/schema.sql | 2 + .../star_expansion_from_cte/pgx/v4/sqlc.json | 13 + .../star_expansion_from_cte/pgx/v5/go/db.go | 32 + .../pgx/v5/go/models.go | 19 + .../pgx/v5/go/query.sql.go | 41 + .../star_expansion_from_cte/pgx/v5/query.sql | 2 + .../star_expansion_from_cte/pgx/v5/schema.sql | 2 + .../star_expansion_from_cte/pgx/v5/sqlc.json | 13 + .../star_expansion_from_cte/stdlib/go/db.go | 31 + .../stdlib/go/models.go | 19 + .../stdlib/go/query.sql.go | 43 + .../star_expansion_from_cte/stdlib/query.sql | 2 + .../star_expansion_from_cte/stdlib/schema.sql | 2 + .../star_expansion_from_cte/stdlib/sqlc.json | 11 + .../star_expansion_join/mysql/go/db.go | 31 + .../star_expansion_join/mysql/go/models.go | 19 + .../star_expansion_join/mysql/go/query.sql.go | 50 + .../star_expansion_join/mysql/query.sql | 2 + .../star_expansion_join/mysql/schema.sql | 3 + .../star_expansion_join/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 19 + .../postgresql/pgx/v4/go/query.sql.go | 47 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 19 + .../postgresql/pgx/v5/go/query.sql.go | 48 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 19 + .../postgresql/stdlib/go/query.sql.go | 50 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../star_expansion_reserved/mysql/go/db.go | 31 + .../mysql/go/models.go | 14 + .../mysql/go/query.sql.go | 37 + .../star_expansion_reserved/mysql/query.sql | 2 + .../star_expansion_reserved/mysql/schema.sql | 2 + .../star_expansion_reserved/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 14 + .../postgresql/pgx/v4/go/query.sql.go | 34 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 1 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 14 + .../postgresql/pgx/v5/go/query.sql.go | 34 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 1 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 14 + .../postgresql/stdlib/go/query.sql.go | 37 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 1 + .../postgresql/stdlib/sqlc.json | 12 + .../testdata/star_expansion_series/issue.md | 1 + .../postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 13 + .../postgresql/pgx/go/query.sql.go | 56 + .../postgresql/pgx/query.sql | 11 + .../postgresql/pgx/schema.sql | 3 + .../postgresql/pgx/sqlc.yaml | 10 + .../star_expansion_subquery/mysql/go/db.go | 31 + .../mysql/go/models.go | 14 + .../mysql/go/query.sql.go | 37 + .../star_expansion_subquery/mysql/query.sql | 2 + .../star_expansion_subquery/mysql/schema.sql | 2 + .../star_expansion_subquery/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 14 + .../postgresql/pgx/v4/go/query.sql.go | 34 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 14 + .../postgresql/pgx/v5/go/query.sql.go | 34 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 14 + .../postgresql/stdlib/go/query.sql.go | 37 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../postgresql/query.sql | 2 + .../postgresql/schema.sql | 0 .../postgresql/sqlc.json | 13 + .../postgresql/stderr/base.txt | 2 + .../postgresql/stderr/managed-db.txt | 2 + .../subquery_calculated_column/mysql/go/db.go | 31 + .../mysql/go/models.go | 14 + .../mysql/go/query.sql.go | 37 + .../mysql/query.sql | 2 + .../mysql/schema.sql | 2 + .../mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 14 + .../postgresql/pgx/v4/go/query.sql.go | 34 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 14 + .../postgresql/pgx/v5/go/query.sql.go | 34 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 14 + .../postgresql/stdlib/go/query.sql.go | 37 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../sqlite/go/db.go | 31 + .../sqlite/go/models.go | 14 + .../sqlite/go/query.sql.go | 37 + .../sqlite/query.sql | 2 + .../sqlite/schema.sql | 2 + .../sqlite/sqlc.json | 12 + internal/endtoend/testdata/sum_type/issue.md | 1 + .../sum_type/postgresql/pgx/exec.json | 3 + .../testdata/sum_type/postgresql/pgx/go/db.go | 32 + .../sum_type/postgresql/pgx/go/models.go | 15 + .../sum_type/postgresql/pgx/go/query.sql.go | 23 + .../sum_type/postgresql/pgx/query.sql | 2 + .../sum_type/postgresql/pgx/schema.sql | 5 + .../sum_type/postgresql/pgx/sqlc.yaml | 10 + .../syntax_errors/mysql/query/from.sql | 2 + .../syntax_errors/mysql/query/select.sql | 2 + .../syntax_errors/mysql/query/typo.sql | 4 + .../testdata/syntax_errors/mysql/schema.sql | 4 + .../testdata/syntax_errors/mysql/sqlc.json | 12 + .../testdata/syntax_errors/mysql/stderr.txt | 4 + .../syntax_errors/postgresql/query/from.sql | 2 + .../syntax_errors/postgresql/query/select.sql | 2 + .../syntax_errors/postgresql/query/typo.sql | 4 + .../syntax_errors/postgresql/schema.sql | 4 + .../syntax_errors/postgresql/sqlc.json | 12 + .../syntax_errors/postgresql/stderr.txt | 4 + .../table_function/postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 16 + .../postgresql/pgx/v4/go/query.sql.go | 56 + .../postgresql/pgx/v4/query.sql | 12 + .../postgresql/pgx/v4/schema.sql | 7 + .../postgresql/pgx/v4/sqlc.json | 13 + .../table_function/postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 12 + .../postgresql/pgx/v5/go/query.sql.go | 54 + .../postgresql/pgx/v5/query.sql | 12 + .../postgresql/pgx/v5/schema.sql | 7 + .../postgresql/pgx/v5/sqlc.json | 13 + .../table_function/postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 16 + .../postgresql/stdlib/go/query.sql.go | 58 + .../postgresql/stdlib/query.sql | 12 + .../postgresql/stdlib/schema.sql | 7 + .../postgresql/stdlib/sqlc.json | 12 + .../testdata/table_function/sqlite/go/db.go | 31 + .../table_function/sqlite/go/models.go | 11 + .../table_function/sqlite/go/query.sql.go | 56 + .../testdata/table_function/sqlite/query.sql | 10 + .../testdata/table_function/sqlite/schema.sql | 6 + .../testdata/table_function/sqlite/sqlc.json | 12 + .../sqlite/go/db.go | 31 + .../sqlite/go/models.go | 24 + .../sqlite/go/query.sql.go | 183 + .../sqlite/query.sql | 47 + .../sqlite/schema.sql | 13 + .../sqlite/sqlc.json | 12 + .../endtoend/testdata/truncate/mysql/go/db.go | 31 + .../testdata/truncate/mysql/go/models.go | 9 + .../testdata/truncate/mysql/go/query.sql.go | 19 + .../testdata/truncate/mysql/query.sql | 2 + .../testdata/truncate/mysql/schema.sql | 2 + .../testdata/truncate/mysql/sqlc.json | 12 + .../truncate/postgresql/pgx/v4/go/db.go | 32 + .../truncate/postgresql/pgx/v4/go/models.go | 9 + .../postgresql/pgx/v4/go/query.sql.go | 19 + .../truncate/postgresql/pgx/v4/query.sql | 2 + .../truncate/postgresql/pgx/v4/schema.sql | 2 + .../truncate/postgresql/pgx/v4/sqlc.json | 13 + .../truncate/postgresql/pgx/v5/go/db.go | 32 + .../truncate/postgresql/pgx/v5/go/models.go | 9 + .../postgresql/pgx/v5/go/query.sql.go | 19 + .../truncate/postgresql/pgx/v5/query.sql | 2 + .../truncate/postgresql/pgx/v5/schema.sql | 2 + .../truncate/postgresql/pgx/v5/sqlc.json | 13 + .../truncate/postgresql/stdlib/go/db.go | 31 + .../truncate/postgresql/stdlib/go/models.go | 9 + .../postgresql/stdlib/go/query.sql.go | 19 + .../truncate/postgresql/stdlib/query.sql | 2 + .../truncate/postgresql/stdlib/schema.sql | 2 + .../truncate/postgresql/stdlib/sqlc.json | 12 + .../types_uuid/postgresql/stdlib/go/db.go | 31 + .../types_uuid/postgresql/stdlib/go/models.go | 17 + .../postgresql/stdlib/go/query.sql.go | 50 + .../types_uuid/postgresql/stdlib/query.sql | 5 + .../types_uuid/postgresql/stdlib/schema.sql | 6 + .../types_uuid/postgresql/stdlib/sqlc.json | 11 + .../testdata/unknown_func/pganalyze/exec.json | 3 + .../testdata/unknown_func/pganalyze/query.sql | 2 + .../unknown_func/pganalyze/schema.sql | 1 + .../testdata/unknown_func/pganalyze/sqlc.json | 13 + .../unknown_func/pganalyze/stderr.txt | 2 + .../testdata/unknown_func/pgx/v4/exec.json | 3 + .../testdata/unknown_func/pgx/v4/go/db.go | 32 + .../testdata/unknown_func/pgx/v4/go/models.go | 9 + .../unknown_func/pgx/v4/go/query.sql.go | 21 + .../testdata/unknown_func/pgx/v4/query.sql | 2 + .../testdata/unknown_func/pgx/v4/schema.sql | 1 + .../testdata/unknown_func/pgx/v4/sqlc.json | 13 + .../testdata/unknown_func/pgx/v5/exec.json | 3 + .../testdata/unknown_func/pgx/v5/go/db.go | 32 + .../testdata/unknown_func/pgx/v5/go/models.go | 9 + .../unknown_func/pgx/v5/go/query.sql.go | 21 + .../testdata/unknown_func/pgx/v5/query.sql | 2 + .../testdata/unknown_func/pgx/v5/schema.sql | 1 + .../testdata/unknown_func/pgx/v5/sqlc.json | 13 + .../testdata/unknown_func/stdlib/exec.json | 3 + .../testdata/unknown_func/stdlib/go/db.go | 31 + .../testdata/unknown_func/stdlib/go/models.go | 9 + .../unknown_func/stdlib/go/query.sql.go | 21 + .../testdata/unknown_func/stdlib/query.sql | 2 + .../testdata/unknown_func/stdlib/schema.sql | 1 + .../testdata/unknown_func/stdlib/sqlc.json | 11 + .../unnest/postgresql/pgx/v4/go/db.go | 32 + .../unnest/postgresql/pgx/v4/go/models.go | 23 + .../unnest/postgresql/pgx/v4/go/querier.go | 18 + .../unnest/postgresql/pgx/v4/go/query.sql.go | 69 + .../unnest/postgresql/pgx/v4/query.sql | 9 + .../unnest/postgresql/pgx/v4/schema.sql | 10 + .../unnest/postgresql/pgx/v4/sqlc.json | 14 + .../unnest/postgresql/pgx/v5/go/db.go | 32 + .../unnest/postgresql/pgx/v5/go/models.go | 20 + .../unnest/postgresql/pgx/v5/go/querier.go | 18 + .../unnest/postgresql/pgx/v5/go/query.sql.go | 69 + .../unnest/postgresql/pgx/v5/query.sql | 9 + .../unnest/postgresql/pgx/v5/schema.sql | 10 + .../unnest/postgresql/pgx/v5/sqlc.json | 14 + .../unnest/postgresql/stdlib/go/db.go | 31 + .../unnest/postgresql/stdlib/go/models.go | 23 + .../unnest/postgresql/stdlib/go/querier.go | 18 + .../unnest/postgresql/stdlib/go/query.sql.go | 76 + .../unnest/postgresql/stdlib/query.sql | 9 + .../unnest/postgresql/stdlib/schema.sql | 10 + .../unnest/postgresql/stdlib/sqlc.json | 13 + .../endtoend/testdata/unnest_star/issue.md | 1 + .../unnest_star/postgresql/pgx/exec.json | 3 + .../unnest_star/postgresql/pgx/go/db.go | 32 + .../unnest_star/postgresql/pgx/go/models.go | 19 + .../postgresql/pgx/go/query.sql.go | 57 + .../unnest_star/postgresql/pgx/query.sql | 12 + .../unnest_star/postgresql/pgx/schema.sql | 13 + .../unnest_star/postgresql/pgx/sqlc.yaml | 10 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 10 + .../postgresql/pgx/v4/go/querier.go | 15 + .../postgresql/pgx/v4/go/query.sql.go | 41 + .../postgresql/pgx/v4/query.sql | 3 + .../postgresql/pgx/v4/schema.sql | 4 + .../postgresql/pgx/v4/sqlc.json | 14 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 10 + .../postgresql/pgx/v5/go/querier.go | 15 + .../postgresql/pgx/v5/go/query.sql.go | 41 + .../postgresql/pgx/v5/query.sql | 3 + .../postgresql/pgx/v5/schema.sql | 4 + .../postgresql/pgx/v5/sqlc.json | 14 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 10 + .../postgresql/stdlib/go/querier.go | 15 + .../postgresql/stdlib/go/query.sql.go | 44 + .../postgresql/stdlib/query.sql | 3 + .../postgresql/stdlib/schema.sql | 4 + .../postgresql/stdlib/sqlc.json | 13 + .../testdata/unsigned_params/mysql/go/db.go | 31 + .../unsigned_params/mysql/go/models.go | 9 + .../unsigned_params/mysql/go/query.sql.go | 19 + .../testdata/unsigned_params/mysql/query.sql | 2 + .../testdata/unsigned_params/mysql/schema.sql | 2 + .../testdata/unsigned_params/mysql/sqlc.json | 12 + .../untyped_columns/sqlite/stdlib/db/db.go | 31 + .../sqlite/stdlib/db/models.go | 11 + .../sqlite/stdlib/db/query.sql.go | 21 + .../untyped_columns/sqlite/stdlib/query.sql | 2 + .../untyped_columns/sqlite/stdlib/schema.sql | 3 + .../untyped_columns/sqlite/stdlib/sqlc.json | 16 + .../testdata/update_array_index/issue.md | 1 + .../postgresql/pgx/exec.json | 3 + .../postgresql/pgx/go/db.go | 32 + .../postgresql/pgx/go/models.go | 10 + .../postgresql/pgx/go/query.sql.go | 30 + .../postgresql/pgx/query.sql | 5 + .../postgresql/pgx/schema.sql | 4 + .../postgresql/pgx/sqlc.yaml | 10 + .../testdata/update_cte/pgx/v4/go/db.go | 32 + .../testdata/update_cte/pgx/v4/go/models.go | 31 + .../update_cte/pgx/v4/go/query.sql.go | 72 + .../testdata/update_cte/pgx/v4/query.sql | 19 + .../testdata/update_cte/pgx/v4/schema.sql | 31 + .../testdata/update_cte/pgx/v4/sqlc.json | 13 + .../testdata/update_cte/pgx/v5/go/db.go | 32 + .../testdata/update_cte/pgx/v5/go/models.go | 30 + .../update_cte/pgx/v5/go/query.sql.go | 72 + .../testdata/update_cte/pgx/v5/query.sql | 19 + .../testdata/update_cte/pgx/v5/schema.sql | 31 + .../testdata/update_cte/pgx/v5/sqlc.json | 13 + .../testdata/update_cte/stdlib/go/db.go | 31 + .../testdata/update_cte/stdlib/go/models.go | 31 + .../update_cte/stdlib/go/query.sql.go | 72 + .../testdata/update_cte/stdlib/query.sql | 19 + .../testdata/update_cte/stdlib/schema.sql | 31 + .../testdata/update_cte/stdlib/sqlc.json | 11 + .../testdata/update_inner_join/db/db.go | 31 + .../testdata/update_inner_join/db/models.go | 19 + .../update_inner_join/db/query.sql.go | 19 + .../testdata/update_inner_join/query.sql | 2 + .../testdata/update_inner_join/schema.sql | 10 + .../testdata/update_inner_join/sqlc.json | 11 + .../testdata/update_join/mysql/db/db.go | 31 + .../testdata/update_join/mysql/db/models.go | 17 + .../update_join/mysql/db/query.sql.go | 70 + .../testdata/update_join/mysql/query.sql | 23 + .../testdata/update_join/mysql/schema.sql | 14 + .../testdata/update_join/mysql/sqlc.json | 11 + .../testdata/update_join/postgresql/db/db.go | 31 + .../update_join/postgresql/db/models.go | 17 + .../update_join/postgresql/db/query.sql.go | 30 + .../testdata/update_join/postgresql/query.sql | 7 + .../update_join/postgresql/schema.sql | 12 + .../testdata/update_join/postgresql/sqlc.json | 11 + .../testdata/update_set/myql/go/db.go | 31 + .../testdata/update_set/myql/go/models.go | 10 + .../testdata/update_set/myql/go/query.sql.go | 24 + .../testdata/update_set/myql/query.sql | 2 + .../testdata/update_set/myql/schema.sql | 2 + .../testdata/update_set/myql/sqlc.json | 12 + .../update_set/postgresql/pgx/v4/go/db.go | 32 + .../update_set/postgresql/pgx/v4/go/models.go | 10 + .../postgresql/pgx/v4/go/query.sql.go | 24 + .../update_set/postgresql/pgx/v4/query.sql | 2 + .../update_set/postgresql/pgx/v4/schema.sql | 2 + .../update_set/postgresql/pgx/v4/sqlc.json | 13 + .../update_set/postgresql/pgx/v5/go/db.go | 32 + .../update_set/postgresql/pgx/v5/go/models.go | 10 + .../postgresql/pgx/v5/go/query.sql.go | 24 + .../update_set/postgresql/pgx/v5/query.sql | 2 + .../update_set/postgresql/pgx/v5/schema.sql | 2 + .../update_set/postgresql/pgx/v5/sqlc.json | 13 + .../update_set/postgresql/stdlib/go/db.go | 31 + .../update_set/postgresql/stdlib/go/models.go | 10 + .../postgresql/stdlib/go/query.sql.go | 24 + .../update_set/postgresql/stdlib/query.sql | 2 + .../update_set/postgresql/stdlib/schema.sql | 2 + .../update_set/postgresql/stdlib/sqlc.json | 12 + .../testdata/update_set/sqlite/go/db.go | 31 + .../testdata/update_set/sqlite/go/models.go | 10 + .../update_set/sqlite/go/query.sql.go | 24 + .../testdata/update_set/sqlite/query.sql | 2 + .../testdata/update_set/sqlite/schema.sql | 2 + .../testdata/update_set/sqlite/sqlc.json | 12 + .../update_set_multiple/mysql/go/db.go | 31 + .../update_set_multiple/mysql/go/models.go | 10 + .../update_set_multiple/mysql/go/query.sql.go | 24 + .../update_set_multiple/mysql/query.sql | 2 + .../update_set_multiple/mysql/schema.sql | 2 + .../update_set_multiple/mysql/sqlc.json | 12 + .../postgresql/pgx/v4/go/db.go | 32 + .../postgresql/pgx/v4/go/models.go | 10 + .../postgresql/pgx/v4/go/query.sql.go | 24 + .../postgresql/pgx/v4/query.sql | 2 + .../postgresql/pgx/v4/schema.sql | 2 + .../postgresql/pgx/v4/sqlc.json | 13 + .../postgresql/pgx/v5/go/db.go | 32 + .../postgresql/pgx/v5/go/models.go | 10 + .../postgresql/pgx/v5/go/query.sql.go | 24 + .../postgresql/pgx/v5/query.sql | 2 + .../postgresql/pgx/v5/schema.sql | 2 + .../postgresql/pgx/v5/sqlc.json | 13 + .../postgresql/stdlib/go/db.go | 31 + .../postgresql/stdlib/go/models.go | 10 + .../postgresql/stdlib/go/query.sql.go | 24 + .../postgresql/stdlib/query.sql | 2 + .../postgresql/stdlib/schema.sql | 2 + .../postgresql/stdlib/sqlc.json | 12 + .../update_set_multiple/sqlite/go/db.go | 31 + .../update_set_multiple/sqlite/go/models.go | 10 + .../sqlite/go/query.sql.go | 24 + .../update_set_multiple/sqlite/query.sql | 2 + .../update_set_multiple/sqlite/schema.sql | 2 + .../update_set_multiple/sqlite/sqlc.json | 12 + .../testdata/update_set_on_conflict/issue.md | 1 + .../postgresql/pgx/exec.json | 3 + .../postgresql/pgx/query.sql | 23 + .../postgresql/pgx/schema.sql | 4 + .../postgresql/pgx/sqlc.yaml | 10 + .../postgresql/pgx/stderr.txt | 6 + .../testdata/update_two_table/mysql/go/db.go | 31 + .../update_two_table/mysql/go/models.go | 23 + .../update_two_table/mysql/go/query.sql.go | 27 + .../testdata/update_two_table/mysql/query.sql | 10 + .../update_two_table/mysql/schema.sql | 15 + .../testdata/update_two_table/mysql/sqlc.json | 12 + .../endtoend/testdata/upsert/sqlite/go/db.go | 31 + .../testdata/upsert/sqlite/go/models.go | 14 + .../testdata/upsert/sqlite/go/query.sql.go | 46 + .../endtoend/testdata/upsert/sqlite/query.sql | 15 + .../testdata/upsert/sqlite/schema.sql | 12 + .../endtoend/testdata/upsert/sqlite/sqlc.json | 12 + .../valid_group_by_reference/mysql/go/db.go | 31 + .../mysql/go/models.go | 36 + .../mysql/go/query.sql.go | 112 + .../valid_group_by_reference/mysql/query.sql | 16 + .../valid_group_by_reference/mysql/schema.sql | 26 + .../valid_group_by_reference/mysql/sqlc.json | 12 + .../pganalyzer/exec.json | 3 + .../pganalyzer/go/db.go | 31 + .../pganalyzer/go/models.go | 36 + .../pganalyzer/go/query.sql.go | 105 + .../pganalyzer/query.sql | 14 + .../pganalyzer/schema.sql | 26 + .../pganalyzer/sqlc.json | 12 + .../postgresql/exec.json | 3 + .../postgresql/go/db.go | 31 + .../postgresql/go/models.go | 36 + .../postgresql/go/query.sql.go | 104 + .../postgresql/query.sql | 14 + .../postgresql/schema.sql | 26 + .../postgresql/sqlc.json | 12 + .../endtoend/testdata/vet_disable/exec.json | 3 + .../endtoend/testdata/vet_disable/query.sql | 29 + .../endtoend/testdata/vet_disable/sqlc.yaml | 21 + .../endtoend/testdata/vet_disable/stderr.txt | 5 + .../testdata/vet_explain/mysql/db/db.go | 31 + .../testdata/vet_explain/mysql/db/models.go | 137 + .../vet_explain/mysql/db/query.sql.go | 444 ++ .../testdata/vet_explain/mysql/query.sql | 290 ++ .../testdata/vet_explain/mysql/schema.sql | 38 + .../testdata/vet_explain/mysql/sqlc.yaml | 16 + .../endtoend/testdata/vet_failures/exec.json | 3 + .../endtoend/testdata/vet_failures/query.sql | 19 + .../endtoend/testdata/vet_failures/schema.sql | 5 + .../endtoend/testdata/vet_failures/sqlc.yaml | 31 + .../endtoend/testdata/vet_failures/stderr.txt | 7 + .../testdata/virtual_table/sqlite/go/db.go | 31 + .../virtual_table/sqlite/go/models.go | 26 + .../virtual_table/sqlite/go/query.sql.go | 255 ++ .../testdata/virtual_table/sqlite/query.sql | 42 + .../testdata/virtual_table/sqlite/schema.sql | 15 + .../testdata/virtual_table/sqlite/sqlc.yaml | 9 + .../sqlite/exec.json | 3 + .../virtual_table_fts5_hidden/sqlite/go/db.go | 31 + .../sqlite/go/models.go | 14 + .../sqlite/go/query.sql.go | 81 + .../sqlite/query.sql | 10 + .../sqlite/schema.sql | 10 + .../sqlite/sqlc.yaml | 9 + .../gen/hello.txt | 1 + .../wasm_plugin_sqlc_gen_greeter/query.sql | 19 + .../wasm_plugin_sqlc_gen_greeter/schema.sql | 5 + .../wasm_plugin_sqlc_gen_greeter/sqlc.json | 25 + .../wasm_plugin_sqlc_gen_test/gen/env.json | 6 + .../wasm_plugin_sqlc_gen_test/query.sql | 19 + .../wasm_plugin_sqlc_gen_test/schema.sql | 5 + .../wasm_plugin_sqlc_gen_test/sqlc.json | 26 + .../query.sql | 19 + .../schema.sql | 5 + .../sqlc.json | 25 + .../stderr.txt | 2 + .../stderr_windows.txt | 2 + .../testdata/where_collate/sqlite/go/db.go | 31 + .../where_collate/sqlite/go/models.go | 10 + .../where_collate/sqlite/go/query.sql.go | 24 + .../testdata/where_collate/sqlite/query.sql | 5 + .../testdata/where_collate/sqlite/schema.sql | 7 + .../testdata/where_collate/sqlite/sqlc.json | 12 + .../testdata/wrap_errors/mysql/db/db.go | 31 + .../testdata/wrap_errors/mysql/db/models.go | 15 + .../wrap_errors/mysql/db/query.sql.go | 123 + .../testdata/wrap_errors/mysql/query.sql | 30 + .../testdata/wrap_errors/mysql/schema.sql | 5 + .../testdata/wrap_errors/mysql/sqlc.yaml | 10 + .../wrap_errors/postgresql/pgx/db/db.go | 32 + .../wrap_errors/postgresql/pgx/db/models.go | 15 + .../postgresql/pgx/db/query.sql.go | 122 + .../wrap_errors/postgresql/pgx/query.sql | 31 + .../wrap_errors/postgresql/pgx/schema.sql | 5 + .../wrap_errors/postgresql/pgx/sqlc.yaml | 11 + .../wrap_errors/postgresql/stdlib/db/db.go | 31 + .../postgresql/stdlib/db/models.go | 15 + .../postgresql/stdlib/db/query.sql.go | 131 + .../wrap_errors/postgresql/stdlib/query.sql | 31 + .../wrap_errors/postgresql/stdlib/schema.sql | 5 + .../wrap_errors/postgresql/stdlib/sqlc.yaml | 10 + .../testdata/wrap_errors/sqlite/db/db.go | 31 + .../testdata/wrap_errors/sqlite/db/models.go | 15 + .../wrap_errors/sqlite/db/query.sql.go | 128 + .../testdata/wrap_errors/sqlite/query.sql | 30 + .../testdata/wrap_errors/sqlite/schema.sql | 5 + .../testdata/wrap_errors/sqlite/sqlc.yaml | 10 + .../endtoend/testdata/yaml_overrides/go/db.go | 31 + .../testdata/yaml_overrides/go/models.go | 19 + .../testdata/yaml_overrides/go/query.sql.go | 21 + .../testdata/yaml_overrides/sql/query.sql | 2 + .../testdata/yaml_overrides/sql/schema.sql | 8 + .../testdata/yaml_overrides/sqlc.yaml | 11 + internal/endtoend/vet_test.go | 82 + internal/engine/clickhouse/catalog.go | 16 + internal/engine/clickhouse/convert.go | 1398 +++++++ .../engine/clickhouse/dialect/dialect.json | 41 + .../engine/clickhouse/dialect/functions.jsonl | 581 +++ .../engine/clickhouse/dialect/types.jsonl | 66 + internal/engine/clickhouse/format.go | 29 + internal/engine/clickhouse/parse.go | 125 + internal/engine/clickhouse/reserved.go | 150 + internal/engine/clickhouse/seed.go | 25 + internal/engine/clickhouse/stdlib.go | 9 + internal/engine/clickhouse/utils.go | 59 + internal/engine/dolphin/CLAUDE.md | 225 + internal/engine/dolphin/catalog.go | 16 + internal/engine/dolphin/convert.go | 2266 ++++++++++ internal/engine/dolphin/dialect/dialect.json | 50 + .../engine/dolphin/dialect/functions.jsonl | 520 +++ .../engine/dolphin/dialect/operators.jsonl | 3 + .../engine/dolphin/dialect/relations.jsonl | 84 + internal/engine/dolphin/dialect/types.jsonl | 39 + internal/engine/dolphin/fingerprint.go | 55 + internal/engine/dolphin/format.go | 36 + internal/engine/dolphin/parse.go | 162 + internal/engine/dolphin/reserved.go | 273 ++ internal/engine/dolphin/seed.go | 34 + internal/engine/dolphin/stdlib.go | 11 + internal/engine/dolphin/utils.go | 94 + internal/engine/duckdb/convert.go | 1244 ++++++ internal/engine/duckdb/dialect/dialect.json | 26 + .../engine/duckdb/dialect/operators.jsonl | 157 + internal/engine/duckdb/dialect/types.jsonl | 40 + internal/engine/duckdb/parse.go | 67 + internal/engine/duckdb/reserved.go | 9 + internal/engine/duckdb/seed.go | 23 + internal/engine/duckdb/utils.go | 47 + internal/engine/googlesql/catalog.go | 16 + internal/engine/googlesql/convert.go | 977 +++++ .../engine/googlesql/dialect/dialect.json | 15 + .../engine/googlesql/dialect/functions.jsonl | 1 + .../engine/googlesql/dialect/operators.jsonl | 1 + .../engine/googlesql/dialect/relations.jsonl | 98 + internal/engine/googlesql/dialect/types.jsonl | 23 + internal/engine/googlesql/parse.go | 70 + internal/engine/googlesql/reserved.go | 11 + internal/engine/googlesql/seed.go | 16 + internal/engine/googlesql/stdlib.go | 9 + internal/engine/googlesql/utils.go | 298 ++ internal/engine/mssql/convert.go | 1199 ++++++ internal/engine/mssql/dialect/dialect.json | 84 + internal/engine/mssql/dialect/functions.jsonl | 76 + internal/engine/mssql/dialect/types.jsonl | 34 + internal/engine/mssql/parse.go | 187 + internal/engine/mssql/reserved.go | 196 + internal/engine/mssql/seed.go | 16 + internal/engine/mssql/utils.go | 65 + .../engine/postgresql/analyzer/analyze.go | 322 ++ internal/engine/postgresql/catalog.go | 40 + internal/engine/postgresql/catalog_test.go | 170 + internal/engine/postgresql/convert.go | 3728 +++++++++++++++++ .../engine/postgresql/dialect/dialect.json | 15 + .../extensions/adminpack/functions.jsonl | 6 + .../extensions/amcheck/functions.jsonl | 6 + .../extensions/btree_gin/functions.jsonl | 2 + .../extensions/btree_gist/functions.jsonl | 24 + .../dialect/extensions/btree_gist/types.jsonl | 6 + .../dialect/extensions/citext/functions.jsonl | 46 + .../dialect/extensions/citext/types.jsonl | 1 + .../dialect/extensions/cube/functions.jsonl | 33 + .../dialect/extensions/cube/types.jsonl | 1 + .../dialect/extensions/dblink/functions.jsonl | 41 + .../dialect/extensions/dblink/types.jsonl | 1 + .../extensions/earthdistance/functions.jsonl | 9 + .../extensions/earthdistance/types.jsonl | 1 + .../extensions/file_fdw/functions.jsonl | 2 + .../extensions/fuzzystrmatch/functions.jsonl | 11 + .../dialect/extensions/hstore/functions.jsonl | 47 + .../dialect/extensions/hstore/types.jsonl | 2 + .../dialect/extensions/intagg/functions.jsonl | 2 + .../extensions/intarray/functions.jsonl | 29 + .../dialect/extensions/intarray/types.jsonl | 2 + .../dialect/extensions/isn/functions.jsonl | 245 ++ .../dialect/extensions/isn/types.jsonl | 8 + .../dialect/extensions/lo/functions.jsonl | 2 + .../dialect/extensions/lo/types.jsonl | 1 + .../dialect/extensions/ltree/functions.jsonl | 59 + .../dialect/extensions/ltree/types.jsonl | 4 + .../extensions/pageinspect/functions.jsonl | 31 + .../extensions/pg_buffercache/functions.jsonl | 3 + .../pg_freespacemap/functions.jsonl | 2 + .../extensions/pg_prewarm/functions.jsonl | 3 + .../pg_stat_statements/functions.jsonl | 3 + .../extensions/pg_trgm/functions.jsonl | 18 + .../dialect/extensions/pg_trgm/types.jsonl | 1 + .../extensions/pg_visibility/functions.jsonl | 8 + .../extensions/pgcrypto/functions.jsonl | 35 + .../extensions/pgrowlocks/functions.jsonl | 1 + .../extensions/pgstattuple/functions.jsonl | 9 + .../extensions/postgres_fdw/functions.jsonl | 5 + .../dialect/extensions/seg/functions.jsonl | 22 + .../dialect/extensions/seg/types.jsonl | 1 + .../extensions/sslinfo/functions.jsonl | 10 + .../extensions/tablefunc/functions.jsonl | 11 + .../dialect/extensions/tablefunc/types.jsonl | 3 + .../dialect/extensions/tcn/functions.jsonl | 1 + .../extensions/unaccent/functions.jsonl | 2 + .../extensions/uuid-ossp/functions.jsonl | 10 + .../dialect/extensions/xml2/functions.jsonl | 13 + .../engine/postgresql/dialect/operators.jsonl | 21 + .../engine/postgresql/dialect/types.jsonl | 48 + internal/engine/postgresql/extension.go | 27 + internal/engine/postgresql/parse.go | 798 ++++ internal/engine/postgresql/pg_temp.go | 9 + internal/engine/postgresql/reserved.go | 187 + internal/engine/postgresql/rewrite_test.go | 45 + internal/engine/postgresql/seed.go | 45 + internal/engine/postgresql/utils.go | 53 + internal/engine/sqlite/analyzer/analyze.go | 233 ++ internal/engine/sqlite/catalog.go | 15 + internal/engine/sqlite/convert.go | 1185 ++++++ internal/engine/sqlite/dialect/dialect.json | 45 + .../extensions/enable_fts3/functions.jsonl | 5 + .../extensions/enable_fts5/functions.jsonl | 7 + .../extensions/enable_geopoly/functions.jsonl | 15 + .../enable_offset_sql_func/functions.jsonl | 1 + .../enable_percentile/functions.jsonl | 4 + .../extensions/enable_rtree/functions.jsonl | 3 + .../extensions/soundex/functions.jsonl | 1 + .../engine/sqlite/dialect/functions.jsonl | 236 ++ .../engine/sqlite/dialect/operators.jsonl | 1 + internal/engine/sqlite/dialect/types.jsonl | 10 + internal/engine/sqlite/extension.go | 26 + internal/engine/sqlite/format.go | 59 + internal/engine/sqlite/parse.go | 158 + internal/engine/sqlite/reserved.go | 10 + internal/engine/sqlite/seed.go | 34 + internal/engine/sqlite/stdlib.go | 13 + internal/engine/sqlite/utils.go | 144 + internal/ext/handler.go | 52 + internal/ext/process/gen.go | 105 + internal/ext/wasm/runner.go | 7 + internal/ext/wasm/wasm.go | 291 ++ internal/goldeneye/README.md | 342 ++ internal/goldeneye/analysis/analysis.go | 64 + internal/goldeneye/clickhouse/analyze.go | 272 ++ internal/goldeneye/clickhouse/check.go | 43 + internal/goldeneye/clickhouse/clickhouse.go | 146 + .../goldeneye/clickhouse/clickhouse_test.go | 66 + internal/goldeneye/clickhouse/install.go | 221 + internal/goldeneye/clickhouse/local.go | 82 + internal/goldeneye/clickhouse/queries.go | 68 + internal/goldeneye/clickhouse/tree.go | 236 ++ internal/goldeneye/clickhouse/types.go | 160 + internal/goldeneye/cmd/goldeneye/main.go | 277 ++ internal/goldeneye/dialect/dialect.go | 303 ++ internal/goldeneye/duckdb/analyze.go | 846 ++++ internal/goldeneye/duckdb/duckdb.go | 351 ++ internal/goldeneye/duckdb/duckdb_test.go | 66 + internal/goldeneye/duckdb/install.go | 136 + internal/goldeneye/duckdb/text.go | 657 +++ internal/goldeneye/duckdb/types.go | 220 + internal/goldeneye/endtoend/endtoend.go | 140 + internal/goldeneye/endtoend/query.go | 183 + internal/goldeneye/go.mod | 52 + internal/goldeneye/go.sum | 137 + internal/goldeneye/mssql/analyze.go | 725 ++++ internal/goldeneye/mssql/mssql.go | 153 + internal/goldeneye/mssql/mssql_test.go | 66 + internal/goldeneye/mssql/plan.go | 243 ++ internal/goldeneye/mssql/relations.go | 123 + internal/goldeneye/mysql/analyze.go | 787 ++++ internal/goldeneye/mysql/mysql.go | 150 + internal/goldeneye/mysql/mysql_test.go | 66 + internal/goldeneye/mysql/relations.go | 99 + internal/goldeneye/mysql/text.go | 678 +++ internal/goldeneye/mysql/trace.go | 87 + internal/goldeneye/postgresql/postgresql.go | 364 ++ .../goldeneye/postgresql/postgresql_test.go | 37 + internal/goldeneye/postgresql/proc.go | 163 + internal/goldeneye/postgresql/relation.go | 118 + internal/goldeneye/spanner/analyze.go | 673 +++ internal/goldeneye/spanner/plan.go | 220 + internal/goldeneye/spanner/relations.go | 96 + internal/goldeneye/spanner/spanner.go | 224 + internal/goldeneye/spanner/spanner_test.go | 66 + internal/goldeneye/sqlite/analyze.go | 269 ++ internal/goldeneye/sqlite/bytecode.go | 456 ++ internal/goldeneye/sqlite/catalog.go | 294 ++ internal/goldeneye/sqlite/install.go | 347 ++ internal/goldeneye/sqlite/shell.go | 254 ++ internal/goldeneye/sqlite/signatures.go | 136 + internal/goldeneye/sqlite/source.go | 521 +++ internal/goldeneye/sqlite/sqlite.go | 444 ++ internal/goldeneye/sqlite/sqlite_test.go | 66 + internal/inflection/singular.go | 52 + internal/info/facts.go | 5 + internal/metadata/meta.go | 172 + internal/metadata/meta_test.go | 182 + internal/migrations/migrations.go | 62 + internal/migrations/migrations_test.go | 107 + internal/multierr/error.go | 52 + internal/opts/experiment.go | 105 + internal/opts/experiment_test.go | 155 + internal/opts/parser.go | 5 + internal/pattern/match.go | 86 + internal/pgx/poolcache/poolcache.go | 61 + internal/plugin/codegen.pb.go | 1648 ++++++++ internal/plugin/codegen_grpc.pb.go | 109 + internal/quickdb/mysql.go | 16 + internal/quickdb/rpc.go | 57 + internal/quickdb/v1/quickdb.pb.go | 1142 +++++ internal/quickdb/v1/quickdb_grpc.pb.go | 257 ++ internal/rpc/errors.go | 13 + internal/rpc/interceptor.go | 22 + internal/shfmt/shfmt.go | 38 + internal/shfmt/shfmt_test.go | 17 + internal/source/code.go | 171 + internal/source/mutate_test.go | 210 + internal/sql/ast/CLAUDE.md | 169 + internal/sql/ast/a_array_expr.go | 23 + internal/sql/ast/a_const.go | 27 + internal/sql/ast/a_expr.go | 178 + internal/sql/ast/a_expr_kind.go | 24 + internal/sql/ast/a_indices.go | 34 + internal/sql/ast/a_indirection.go | 12 + internal/sql/ast/a_star.go | 18 + internal/sql/ast/access_priv.go | 12 + internal/sql/ast/agg_split.go | 7 + internal/sql/ast/agg_strategy.go | 7 + internal/sql/ast/aggref.go | 27 + internal/sql/ast/alias.go | 28 + internal/sql/ast/alter_collation_stmt.go | 11 + internal/sql/ast/alter_database_set_stmt.go | 12 + internal/sql/ast/alter_database_stmt.go | 12 + .../sql/ast/alter_default_privileges_stmt.go | 12 + internal/sql/ast/alter_domain_stmt.go | 16 + internal/sql/ast/alter_enum_stmt.go | 16 + internal/sql/ast/alter_event_trig_stmt.go | 12 + .../sql/ast/alter_extension_contents_stmt.go | 14 + internal/sql/ast/alter_extension_stmt.go | 12 + internal/sql/ast/alter_fdw_stmt.go | 13 + internal/sql/ast/alter_foreign_server_stmt.go | 14 + internal/sql/ast/alter_function_stmt.go | 12 + internal/sql/ast/alter_object_depends_stmt.go | 14 + internal/sql/ast/alter_object_schema_stmt.go | 15 + internal/sql/ast/alter_op_family_stmt.go | 14 + internal/sql/ast/alter_operator_stmt.go | 12 + internal/sql/ast/alter_owner_stmt.go | 14 + internal/sql/ast/alter_policy_stmt.go | 15 + internal/sql/ast/alter_publication_stmt.go | 15 + internal/sql/ast/alter_role_set_stmt.go | 13 + internal/sql/ast/alter_role_stmt.go | 13 + internal/sql/ast/alter_seq_stmt.go | 14 + internal/sql/ast/alter_subscription_stmt.go | 15 + internal/sql/ast/alter_subscription_type.go | 7 + internal/sql/ast/alter_system_stmt.go | 11 + internal/sql/ast/alter_table_cmd.go | 59 + internal/sql/ast/alter_table_move_all_stmt.go | 15 + .../sql/ast/alter_table_set_schema_stmt.go | 13 + .../sql/ast/alter_table_space_options_stmt.go | 13 + internal/sql/ast/alter_table_stmt.go | 38 + internal/sql/ast/alter_table_type.go | 7 + internal/sql/ast/alter_ts_config_type.go | 7 + .../sql/ast/alter_ts_configuration_stmt.go | 17 + internal/sql/ast/alter_ts_dictionary_stmt.go | 12 + internal/sql/ast/alter_type_add_value_stmt.go | 16 + .../sql/ast/alter_type_rename_value_stmt.go | 13 + .../sql/ast/alter_type_set_schema_stmt.go | 12 + internal/sql/ast/alter_user_mapping_stmt.go | 13 + internal/sql/ast/alternative_sub_plan.go | 12 + internal/sql/ast/array_coerce_expr.go | 19 + internal/sql/ast/array_expr.go | 17 + internal/sql/ast/array_ref.go | 19 + internal/sql/ast/between_expr.go | 36 + internal/sql/ast/bit_string.go | 11 + internal/sql/ast/block_id_data.go | 12 + internal/sql/ast/bool_expr.go | 70 + internal/sql/ast/bool_expr_type.go | 19 + internal/sql/ast/bool_test_type.go | 7 + internal/sql/ast/boolean.go | 28 + internal/sql/ast/boolean_test_expr.go | 14 + internal/sql/ast/call_stmt.go | 21 + internal/sql/ast/case_expr.go | 36 + internal/sql/ast/case_test_expr.go | 14 + internal/sql/ast/case_when.go | 26 + internal/sql/ast/check_point_stmt.go | 9 + internal/sql/ast/close_portal_stmt.go | 11 + internal/sql/ast/cluster_stmt.go | 13 + internal/sql/ast/cmd_type.go | 7 + internal/sql/ast/coalesce_expr.go | 28 + internal/sql/ast/coerce_to_domain.go | 17 + internal/sql/ast/coerce_to_domain_value.go | 15 + internal/sql/ast/coerce_via_io.go | 16 + internal/sql/ast/coercion_context.go | 7 + internal/sql/ast/coercion_form.go | 7 + internal/sql/ast/collate_clause.go | 13 + internal/sql/ast/collate_expr.go | 25 + internal/sql/ast/column_def.go | 72 + internal/sql/ast/column_ref.go | 40 + internal/sql/ast/comment.go | 235 ++ internal/sql/ast/comment_on_column_stmt.go | 13 + internal/sql/ast/comment_on_schema_stmt.go | 12 + internal/sql/ast/comment_on_table_stmt.go | 12 + internal/sql/ast/comment_on_type_stmt.go | 12 + internal/sql/ast/comment_on_view_stmt.go | 12 + internal/sql/ast/comment_stmt.go | 13 + internal/sql/ast/common_table_expr.go | 49 + internal/sql/ast/composite_type_stmt.go | 13 + internal/sql/ast/const.go | 19 + internal/sql/ast/constr_type.go | 14 + internal/sql/ast/constraint.go | 36 + internal/sql/ast/constraints_set_stmt.go | 12 + internal/sql/ast/convert_rowtype_expr.go | 15 + internal/sql/ast/copy_stmt.go | 17 + internal/sql/ast/create_am_stmt.go | 13 + internal/sql/ast/create_cast_stmt.go | 15 + internal/sql/ast/create_conversion_stmt.go | 15 + internal/sql/ast/create_domain_stmt.go | 14 + internal/sql/ast/create_enum_stmt.go | 12 + internal/sql/ast/create_event_trig_stmt.go | 14 + internal/sql/ast/create_extension_stmt.go | 28 + internal/sql/ast/create_fdw_stmt.go | 13 + .../sql/ast/create_foreign_server_stmt.go | 16 + internal/sql/ast/create_foreign_table_stmt.go | 13 + internal/sql/ast/create_function_stmt.go | 47 + internal/sql/ast/create_op_class_item.go | 16 + internal/sql/ast/create_op_class_stmt.go | 16 + internal/sql/ast/create_op_family_stmt.go | 12 + internal/sql/ast/create_p_lang_stmt.go | 16 + internal/sql/ast/create_policy_stmt.go | 17 + internal/sql/ast/create_publication_stmt.go | 14 + internal/sql/ast/create_range_stmt.go | 12 + internal/sql/ast/create_role_stmt.go | 13 + internal/sql/ast/create_schema_stmt.go | 14 + internal/sql/ast/create_seq_stmt.go | 15 + internal/sql/ast/create_stats_stmt.go | 15 + internal/sql/ast/create_stmt.go | 21 + internal/sql/ast/create_subscription_stmt.go | 14 + internal/sql/ast/create_table_as_stmt.go | 15 + internal/sql/ast/create_table_space_stmt.go | 14 + internal/sql/ast/create_table_stmt.go | 106 + internal/sql/ast/create_transform_stmt.go | 15 + internal/sql/ast/create_trig_stmt.go | 24 + internal/sql/ast/create_user_mapping_stmt.go | 14 + internal/sql/ast/createdb_stmt.go | 12 + internal/sql/ast/current_of_expr.go | 14 + internal/sql/ast/deallocate_stmt.go | 11 + internal/sql/ast/declare_cursor_stmt.go | 13 + internal/sql/ast/def_elem.go | 70 + internal/sql/ast/def_elem_action.go | 7 + internal/sql/ast/define_stmt.go | 16 + internal/sql/ast/delete_stmt.go | 91 + internal/sql/ast/discard_mode.go | 7 + internal/sql/ast/discard_stmt.go | 11 + internal/sql/ast/do_stmt.go | 32 + internal/sql/ast/drop_behavior.go | 7 + internal/sql/ast/drop_function_stmt.go | 12 + internal/sql/ast/drop_owned_stmt.go | 12 + internal/sql/ast/drop_role_stmt.go | 12 + internal/sql/ast/drop_schema_stmt.go | 12 + internal/sql/ast/drop_stmt.go | 15 + internal/sql/ast/drop_subscription_stmt.go | 13 + internal/sql/ast/drop_table_space_stmt.go | 12 + internal/sql/ast/drop_table_stmt.go | 12 + internal/sql/ast/drop_type_stmt.go | 12 + internal/sql/ast/drop_user_mapping_stmt.go | 13 + internal/sql/ast/dropdb_stmt.go | 12 + internal/sql/ast/execute_stmt.go | 12 + internal/sql/ast/explain_stmt.go | 12 + internal/sql/ast/expr.go | 9 + internal/sql/ast/fetch_direction.go | 7 + internal/sql/ast/fetch_stmt.go | 14 + internal/sql/ast/field_select.go | 16 + internal/sql/ast/field_store.go | 15 + internal/sql/ast/float.go | 20 + internal/sql/ast/from_expr.go | 12 + internal/sql/ast/func_call.go | 68 + internal/sql/ast/func_expr.go | 20 + internal/sql/ast/func_name.go | 28 + internal/sql/ast/func_param.go | 49 + internal/sql/ast/func_spec.go | 13 + internal/sql/ast/function_parameter.go | 14 + internal/sql/ast/function_parameter_mode.go | 7 + internal/sql/ast/grant_object_type.go | 7 + internal/sql/ast/grant_role_stmt.go | 15 + internal/sql/ast/grant_stmt.go | 18 + internal/sql/ast/grant_target_type.go | 7 + internal/sql/ast/grouping_func.go | 16 + internal/sql/ast/grouping_set.go | 13 + internal/sql/ast/grouping_set_kind.go | 7 + .../sql/ast/import_foreign_schema_stmt.go | 16 + .../sql/ast/import_foreign_schema_type.go | 7 + internal/sql/ast/in.go | 50 + internal/sql/ast/index_elem.go | 30 + internal/sql/ast/index_stmt.go | 28 + internal/sql/ast/infer_clause.go | 34 + internal/sql/ast/inference_elem.go | 14 + internal/sql/ast/inline_code_block.go | 13 + internal/sql/ast/insert_stmt.go | 86 + internal/sql/ast/integer.go | 24 + internal/sql/ast/interval_expr.go | 26 + internal/sql/ast/into_clause.go | 17 + internal/sql/ast/join_expr.go | 59 + internal/sql/ast/join_type.go | 28 + internal/sql/ast/list.go | 20 + internal/sql/ast/listen_stmt.go | 23 + internal/sql/ast/load_stmt.go | 11 + internal/sql/ast/lock_clause_strength.go | 7 + internal/sql/ast/lock_stmt.go | 13 + internal/sql/ast/lock_wait_policy.go | 7 + internal/sql/ast/locking_clause.go | 59 + internal/sql/ast/min_max_expr.go | 17 + internal/sql/ast/min_max_op.go | 7 + internal/sql/ast/multi_assign_ref.go | 22 + internal/sql/ast/named_arg_expr.go | 28 + internal/sql/ast/next_value_expr.go | 13 + internal/sql/ast/node.go | 5 + internal/sql/ast/node_tag.go | 40 + internal/sql/ast/notify_stmt.go | 29 + internal/sql/ast/null.go | 14 + internal/sql/ast/null_test_expr.go | 36 + internal/sql/ast/null_test_type.go | 7 + internal/sql/ast/object_type.go | 7 + internal/sql/ast/object_with_args.go | 13 + internal/sql/ast/on_commit_action.go | 7 + internal/sql/ast/on_conflict_action.go | 7 + internal/sql/ast/on_conflict_clause.go | 75 + internal/sql/ast/on_conflict_expr.go | 18 + internal/sql/ast/on_duplicate_key_update.go | 39 + internal/sql/ast/op_expr.go | 18 + internal/sql/ast/overriding_kind.go | 7 + internal/sql/ast/param.go | 17 + internal/sql/ast/param_exec_data.go | 13 + internal/sql/ast/param_extern_data.go | 14 + internal/sql/ast/param_kind.go | 7 + internal/sql/ast/param_list_info_data.go | 14 + internal/sql/ast/param_ref.go | 25 + internal/sql/ast/paren_expr.go | 24 + internal/sql/ast/partition_bound_spec.go | 15 + internal/sql/ast/partition_cmd.go | 12 + internal/sql/ast/partition_elem.go | 15 + internal/sql/ast/partition_range_datum.go | 13 + .../sql/ast/partition_range_datum_kind.go | 7 + internal/sql/ast/partition_spec.go | 13 + internal/sql/ast/prepare_stmt.go | 13 + internal/sql/ast/print.go | 269 ++ internal/sql/ast/printer/printer.go | 250 ++ internal/sql/ast/query.go | 46 + internal/sql/ast/query_source.go | 7 + internal/sql/ast/range_function.go | 35 + internal/sql/ast/range_subselect.go | 31 + internal/sql/ast/range_table_func.go | 17 + internal/sql/ast/range_table_func_col.go | 17 + internal/sql/ast/range_table_sample.go | 15 + internal/sql/ast/range_tbl_entry.go | 41 + internal/sql/ast/range_tbl_function.go | 17 + internal/sql/ast/range_tbl_ref.go | 11 + internal/sql/ast/range_var.go | 36 + internal/sql/ast/raw_stmt.go | 24 + internal/sql/ast/reassign_owned_stmt.go | 12 + internal/sql/ast/refresh_mat_view_stmt.go | 23 + internal/sql/ast/reindex_object_type.go | 7 + internal/sql/ast/reindex_stmt.go | 14 + internal/sql/ast/relabel_type.go | 17 + internal/sql/ast/rename_column_stmt.go | 14 + internal/sql/ast/rename_stmt.go | 18 + internal/sql/ast/rename_table_stmt.go | 13 + internal/sql/ast/rename_type_stmt.go | 12 + internal/sql/ast/replica_identity_stmt.go | 12 + internal/sql/ast/res_target.go | 37 + internal/sql/ast/returning.go | 24 + internal/sql/ast/role_spec.go | 13 + internal/sql/ast/role_spec_type.go | 7 + internal/sql/ast/role_stmt_type.go | 7 + internal/sql/ast/row_compare_expr.go | 17 + internal/sql/ast/row_compare_type.go | 7 + internal/sql/ast/row_expr.go | 33 + internal/sql/ast/row_mark_clause.go | 14 + internal/sql/ast/rte_kind.go | 7 + internal/sql/ast/rule_stmt.go | 17 + internal/sql/ast/scalar_array_op_expr.go | 37 + internal/sql/ast/scan_direction.go | 7 + internal/sql/ast/sec_label_stmt.go | 14 + internal/sql/ast/select_stmt.go | 183 + internal/sql/ast/set_op_cmd.go | 7 + internal/sql/ast/set_op_strategy.go | 7 + internal/sql/ast/set_operation.go | 31 + internal/sql/ast/set_operation_stmt.go | 18 + internal/sql/ast/set_to_default.go | 15 + internal/sql/ast/sort_by.go | 36 + internal/sql/ast/sort_by_dir.go | 15 + internal/sql/ast/sort_by_nulls.go | 14 + internal/sql/ast/sort_group_clause.go | 15 + internal/sql/ast/sql_value_function.go | 41 + internal/sql/ast/sql_value_function_op.go | 27 + internal/sql/ast/statement.go | 11 + internal/sql/ast/string.go | 20 + internal/sql/ast/sub_link.go | 67 + internal/sql/ast/sub_plan.go | 27 + internal/sql/ast/table_func.go | 23 + internal/sql/ast/table_like_clause.go | 12 + internal/sql/ast/table_like_option.go | 7 + internal/sql/ast/table_name.go | 28 + internal/sql/ast/table_sample_clause.go | 13 + internal/sql/ast/target_entry.go | 18 + internal/sql/ast/todo.go | 9 + internal/sql/ast/transaction_stmt.go | 13 + internal/sql/ast/transaction_stmt_kind.go | 7 + internal/sql/ast/trigger_transition.go | 13 + internal/sql/ast/truncate_stmt.go | 23 + internal/sql/ast/type_cast.go | 29 + internal/sql/ast/type_name.go | 76 + internal/sql/ast/typedefs.go | 150 + internal/sql/ast/unlisten_stmt.go | 11 + internal/sql/ast/update_stmt.go | 164 + internal/sql/ast/vacuum_option.go | 7 + internal/sql/ast/vacuum_stmt.go | 13 + internal/sql/ast/var.go | 20 + internal/sql/ast/variable_expr.go | 24 + internal/sql/ast/variable_set_kind.go | 7 + internal/sql/ast/variable_set_stmt.go | 14 + internal/sql/ast/variable_show_stmt.go | 11 + internal/sql/ast/view_check_option.go | 7 + internal/sql/ast/view_stmt.go | 16 + internal/sql/ast/wco_kind.go | 7 + internal/sql/ast/window_clause.go | 19 + internal/sql/ast/window_def.go | 116 + internal/sql/ast/window_func.go | 21 + internal/sql/ast/with_check_option.go | 15 + internal/sql/ast/with_clause.go | 26 + internal/sql/ast/xml_expr.go | 20 + internal/sql/ast/xml_expr_op.go | 7 + internal/sql/ast/xml_option_type.go | 7 + internal/sql/ast/xml_serialize.go | 14 + internal/sql/astutils/CLAUDE.md | 122 + internal/sql/astutils/join.go | 21 + internal/sql/astutils/rewrite.go | 1271 ++++++ internal/sql/astutils/search.go | 21 + internal/sql/astutils/walk.go | 2200 ++++++++++ internal/sql/catalog/catalog.go | 142 + internal/sql/catalog/comment_on.go | 76 + internal/sql/catalog/extension.go | 41 + internal/sql/catalog/func.go | 122 + internal/sql/catalog/public.go | 133 + internal/sql/catalog/schema.go | 134 + internal/sql/catalog/table.go | 505 +++ internal/sql/catalog/types.go | 374 ++ internal/sql/catalog/view.go | 52 + internal/sql/format/format.go | 23 + internal/sql/info/info.go | 59 + internal/sql/lang/operator.go | 63 + internal/sql/named/CLAUDE.md | 58 + internal/sql/named/param.go | 129 + internal/sql/named/param_set.go | 85 + internal/sql/named/param_set_test.go | 58 + internal/sql/named/param_test.go | 82 + internal/sql/preprocess/CLAUDE.md | 114 + internal/sql/preprocess/dialect.go | 114 + internal/sql/preprocess/lexer.go | 284 ++ internal/sql/preprocess/preprocess.go | 398 ++ internal/sql/preprocess/preprocess_test.go | 232 + internal/sql/preprocess/scan.go | 209 + .../preprocess/testdata/mysql/arg/input.sql | 1 + .../preprocess/testdata/mysql/arg/output.sql | 1 + .../testdata/mysql/arg/side_table.json | 23 + .../input.sql | 1 + .../output.sql | 1 + .../side_table.json | 7 + .../mysql/double_quoted_argument/input.sql | 4 + .../mysql/double_quoted_argument/output.sql | 4 + .../double_quoted_argument/side_table.json | 31 + .../preprocess/testdata/mysql/embed/input.sql | 1 + .../testdata/mysql/embed/output.sql | 1 + .../testdata/mysql/embed/side_table.json | 15 + .../mysql/error_invalid_calls/input.sql | 11 + .../mysql/error_invalid_calls/output.sql | 11 + .../mysql/error_invalid_calls/side_table.json | 30 + .../mysql/error_invalid_calls/stderr.txt | 4 + .../input.sql | 1 + .../output.sql | 1 + .../side_table.json | 28 + .../testdata/mysql/narg_identifier/input.sql | 1 + .../testdata/mysql/narg_identifier/output.sql | 1 + .../mysql/narg_identifier/side_table.json | 17 + .../mysql/on_duplicate_key_update/input.sql | 2 + .../mysql/on_duplicate_key_update/output.sql | 2 + .../on_duplicate_key_update/side_table.json | 23 + .../mysql/skip_backslash_escape/input.sql | 1 + .../mysql/skip_backslash_escape/output.sql | 1 + .../skip_backslash_escape/side_table.json | 7 + .../mysql/skip_backtick_identifier/input.sql | 1 + .../mysql/skip_backtick_identifier/output.sql | 1 + .../skip_backtick_identifier/side_table.json | 7 + .../mysql/skip_double_quoted_string/input.sql | 1 + .../skip_double_quoted_string/output.sql | 1 + .../skip_double_quoted_string/side_table.json | 7 + .../mysql/skip_hash_comment/input.sql | 2 + .../mysql/skip_hash_comment/output.sql | 2 + .../mysql/skip_hash_comment/side_table.json | 7 + .../preprocess/testdata/mysql/slice/input.sql | 1 + .../testdata/mysql/slice/output.sql | 1 + .../testdata/mysql/slice/side_table.json | 17 + .../mysql/slice_folds_identifier/input.sql | 1 + .../mysql/slice_folds_identifier/output.sql | 1 + .../slice_folds_identifier/side_table.json | 17 + .../testdata/mysql/string_constant/input.sql | 1 + .../testdata/mysql/string_constant/output.sql | 1 + .../mysql/string_constant/side_table.json | 32 + .../string_constant_keeps_case/input.sql | 1 + .../string_constant_keeps_case/output.sql | 1 + .../side_table.json | 23 + .../input.sql | 1 + .../output.sql | 1 + .../side_table.json | 16 + .../testdata/postgresql/arg/input.sql | 2 + .../testdata/postgresql/arg/output.sql | 2 + .../testdata/postgresql/arg/side_table.json | 16 + .../testdata/postgresql/at_sign/input.sql | 1 + .../testdata/postgresql/at_sign/output.sql | 1 + .../postgresql/at_sign/side_table.json | 23 + .../postgresql/at_sign_cast/input.sql | 1 + .../postgresql/at_sign_cast/output.sql | 1 + .../postgresql/at_sign_cast/side_table.json | 16 + .../at_sign_in_vet_directive/input.sql | 3 + .../at_sign_in_vet_directive/output.sql | 3 + .../at_sign_in_vet_directive/side_table.json | 16 + .../postgresql/comment_inside_call/input.sql | 1 + .../postgresql/comment_inside_call/output.sql | 1 + .../comment_inside_call/side_table.json | 16 + .../testdata/postgresql/embed/input.sql | 1 + .../testdata/postgresql/embed/output.sql | 1 + .../testdata/postgresql/embed/side_table.json | 21 + .../postgresql/embed_and_user_star/input.sql | 1 + .../postgresql/embed_and_user_star/output.sql | 1 + .../embed_and_user_star/side_table.json | 15 + .../embed_quoted_identifier/input.sql | 1 + .../embed_quoted_identifier/output.sql | 1 + .../embed_quoted_identifier/side_table.json | 15 + .../embed_string_constant/input.sql | 1 + .../embed_string_constant/output.sql | 1 + .../embed_string_constant/side_table.json | 15 + .../postgresql/embed_with_args/input.sql | 1 + .../postgresql/embed_with_args/output.sql | 1 + .../embed_with_args/side_table.json | 24 + .../error_is_per_statement/input.sql | 2 + .../error_is_per_statement/output.sql | 2 + .../error_is_per_statement/side_table.json | 23 + .../error_is_per_statement/stderr.txt | 1 + .../postgresql/error_nested_call/input.sql | 1 + .../postgresql/error_nested_call/output.sql | 1 + .../error_nested_call/side_table.json | 9 + .../postgresql/error_nested_call/stderr.txt | 1 + .../postgresql/error_no_arguments/input.sql | 1 + .../postgresql/error_no_arguments/output.sql | 1 + .../error_no_arguments/side_table.json | 9 + .../postgresql/error_no_arguments/stderr.txt | 1 + .../postgresql/error_numbering_gap/input.sql | 1 + .../postgresql/error_numbering_gap/output.sql | 1 + .../error_numbering_gap/side_table.json | 22 + .../postgresql/error_numbering_gap/stderr.txt | 1 + .../error_placeholder_argument/input.sql | 1 + .../error_placeholder_argument/output.sql | 1 + .../side_table.json | 9 + .../error_placeholder_argument/stderr.txt | 1 + .../error_too_many_arguments/input.sql | 1 + .../error_too_many_arguments/output.sql | 1 + .../error_too_many_arguments/side_table.json | 9 + .../error_too_many_arguments/stderr.txt | 1 + .../error_unknown_function/input.sql | 1 + .../error_unknown_function/output.sql | 1 + .../error_unknown_function/side_table.json | 9 + .../error_unknown_function/stderr.txt | 1 + .../postgresql/existing_placeholder/input.sql | 1 + .../existing_placeholder/output.sql | 1 + .../existing_placeholder/side_table.json | 22 + .../postgresql/extra_whitespace/input.sql | 1 + .../postgresql/extra_whitespace/output.sql | 1 + .../extra_whitespace/side_table.json | 23 + .../jsonb_operator_and_path_string/input.sql | 2 + .../jsonb_operator_and_path_string/output.sql | 2 + .../side_table.json | 16 + .../postgresql/multiline_call/input.sql | 3 + .../postgresql/multiline_call/output.sql | 1 + .../postgresql/multiline_call/side_table.json | 16 + .../testdata/postgresql/narg/input.sql | 2 + .../testdata/postgresql/narg/output.sql | 2 + .../testdata/postgresql/narg/side_table.json | 17 + .../postgresql/narg_string_constant/input.sql | 1 + .../narg_string_constant/output.sql | 1 + .../narg_string_constant/side_table.json | 17 + .../input.sql | 2 + .../output.sql | 2 + .../side_table.json | 30 + .../postgresql/quoted_names/input.sql | 1 + .../postgresql/quoted_names/output.sql | 1 + .../postgresql/quoted_names/side_table.json | 23 + .../postgresql/repeated_name/input.sql | 1 + .../postgresql/repeated_name/output.sql | 1 + .../postgresql/repeated_name/side_table.json | 30 + .../postgresql/skip_block_comment/input.sql | 3 + .../postgresql/skip_block_comment/output.sql | 3 + .../skip_block_comment/side_table.json | 7 + .../postgresql/skip_dollar_quoted/input.sql | 1 + .../postgresql/skip_dollar_quoted/output.sql | 1 + .../skip_dollar_quoted/side_table.json | 7 + .../postgresql/skip_escape_string/input.sql | 1 + .../postgresql/skip_escape_string/output.sql | 1 + .../skip_escape_string/side_table.json | 7 + .../postgresql/skip_jsonb_operators/input.sql | 1 + .../skip_jsonb_operators/output.sql | 1 + .../skip_jsonb_operators/side_table.json | 7 + .../postgresql/skip_line_comment/input.sql | 2 + .../postgresql/skip_line_comment/output.sql | 2 + .../skip_line_comment/side_table.json | 7 + .../skip_nested_block_comment/input.sql | 1 + .../skip_nested_block_comment/output.sql | 1 + .../skip_nested_block_comment/side_table.json | 7 + .../postgresql/skip_other_schemas/input.sql | 1 + .../postgresql/skip_other_schemas/output.sql | 1 + .../skip_other_schemas/side_table.json | 7 + .../skip_quoted_identifier/input.sql | 1 + .../skip_quoted_identifier/output.sql | 1 + .../skip_quoted_identifier/side_table.json | 7 + .../postgresql/skip_string_literal/input.sql | 1 + .../postgresql/skip_string_literal/output.sql | 1 + .../skip_string_literal/side_table.json | 7 + .../skip_tagged_dollar_quoted/input.sql | 1 + .../skip_tagged_dollar_quoted/output.sql | 1 + .../skip_tagged_dollar_quoted/side_table.json | 7 + .../postgresql/slice_is_an_array/input.sql | 1 + .../postgresql/slice_is_an_array/output.sql | 1 + .../slice_is_an_array/side_table.json | 17 + .../slice_string_constant/input.sql | 1 + .../slice_string_constant/output.sql | 1 + .../slice_string_constant/side_table.json | 17 + .../statement_terminator_in_string/input.sql | 2 + .../statement_terminator_in_string/output.sql | 2 + .../side_table.json | 30 + .../string_constant_escaped_quote/input.sql | 1 + .../string_constant_escaped_quote/output.sql | 1 + .../side_table.json | 16 + .../string_constant_keeps_case/input.sql | 1 + .../string_constant_keeps_case/output.sql | 1 + .../side_table.json | 23 + .../testdata/postgresql/uppercase/input.sql | 1 + .../testdata/postgresql/uppercase/output.sql | 1 + .../postgresql/uppercase/side_table.json | 16 + .../preprocess/testdata/sqlite/arg/input.sql | 1 + .../preprocess/testdata/sqlite/arg/output.sql | 1 + .../testdata/sqlite/arg/side_table.json | 23 + .../testdata/sqlite/at_sign/input.sql | 1 + .../testdata/sqlite/at_sign/output.sql | 1 + .../testdata/sqlite/at_sign/side_table.json | 16 + .../testdata/sqlite/embed/input.sql | 1 + .../testdata/sqlite/embed/output.sql | 1 + .../testdata/sqlite/embed/side_table.json | 24 + .../sqlite/error_invalid_calls/input.sql | 11 + .../sqlite/error_invalid_calls/output.sql | 11 + .../error_invalid_calls/side_table.json | 30 + .../sqlite/error_invalid_calls/stderr.txt | 4 + .../error_mixed_placeholder_styles/input.sql | 1 + .../error_mixed_placeholder_styles/output.sql | 1 + .../side_table.json | 22 + .../error_mixed_placeholder_styles/stderr.txt | 1 + .../existing_numbered_placeholder/input.sql | 1 + .../existing_numbered_placeholder/output.sql | 1 + .../side_table.json | 22 + .../testdata/sqlite/narg_identifier/input.sql | 1 + .../sqlite/narg_identifier/output.sql | 1 + .../sqlite/narg_identifier/side_table.json | 17 + .../testdata/sqlite/repeated_name/input.sql | 1 + .../testdata/sqlite/repeated_name/output.sql | 1 + .../sqlite/repeated_name/side_table.json | 23 + .../testdata/sqlite/slice/input.sql | 1 + .../testdata/sqlite/slice/output.sql | 1 + .../testdata/sqlite/slice/side_table.json | 17 + .../testdata/sqlite/string_constant/input.sql | 1 + .../sqlite/string_constant/output.sql | 1 + .../sqlite/string_constant/side_table.json | 32 + internal/sql/sqlerr/errors.go | 111 + internal/sql/sqlfile/split.go | 241 ++ internal/sql/sqlfile/split_test.go | 149 + .../sqlfile/testdata/complex_query/input.sql | 13 + .../testdata/complex_query/output_1.sql | 2 + .../testdata/complex_query/output_2.sql | 8 + .../testdata/complex_query/output_3.sql | 1 + .../dollar_quote_with_newlines/input.sql | 3 + .../dollar_quote_with_newlines/output_1.sql | 3 + .../testdata/dollar_quoted_function/input.sql | 5 + .../dollar_quoted_function/output_1.sql | 5 + .../testdata/dollar_quoted_string/input.sql | 1 + .../dollar_quoted_string/output_1.sql | 1 + .../double_quoted_identifier/input.sql | 1 + .../double_quoted_identifier/output_1.sql | 1 + .../sqlfile/testdata/empty_input/input.sql | 0 .../testdata/escaped_double_quotes/input.sql | 1 + .../escaped_double_quotes/output_1.sql | 1 + .../sqlfile/testdata/escaped_quotes/input.sql | 1 + .../testdata/escaped_quotes/output_1.sql | 1 + .../last_query_no_semicolon/input.sql | 2 + .../last_query_no_semicolon/output_1.sql | 1 + .../last_query_no_semicolon/output_2.sql | 1 + .../testdata/multi_line_comment/input.sql | 3 + .../testdata/multi_line_comment/output_1.sql | 2 + .../testdata/multi_line_comment/output_2.sql | 1 + .../input.sql | 2 + .../output_1.sql | 1 + .../output_2.sql | 1 + .../testdata/multiple_queries/input.sql | 3 + .../testdata/multiple_queries/output_1.sql | 1 + .../testdata/multiple_queries/output_2.sql | 1 + .../testdata/multiple_queries/output_3.sql | 1 + .../testdata/nested_dollar_quotes/input.sql | 1 + .../nested_dollar_quotes/output_1.sql | 1 + .../testdata/no_trailing_semicolon/input.sql | 1 + .../no_trailing_semicolon/output_1.sql | 1 + .../testdata/only_semicolons/input.sql | 1 + .../testdata/semicolon_in_string/input.sql | 1 + .../testdata/semicolon_in_string/output_1.sql | 1 + .../testdata/single_line_comment/input.sql | 2 + .../testdata/single_line_comment/output_1.sql | 1 + .../testdata/single_line_comment/output_2.sql | 1 + .../input.sql | 2 + .../output_1.sql | 1 + .../output_2.sql | 1 + .../sqlfile/testdata/single_query/input.sql | 1 + .../testdata/single_query/output_1.sql | 1 + .../tagged_dollar_quoted_string/input.sql | 1 + .../tagged_dollar_quoted_string/output_1.sql | 1 + .../testdata/whitespace_only/input.sql | 2 + internal/sql/sqlpath/read.go | 66 + internal/sql/sqlpath/read_test.go | 243 ++ internal/sql/sqlpath/testdata/.hidden.sql | 0 .../sql/sqlpath/testdata/.hiddendir/file1.sql | 0 internal/sql/sqlpath/testdata/extra.txt | 0 internal/sql/sqlpath/testdata/file1.sql | 0 .../sql/sqlpath/testdata/file1.symlink.sql | 1 + internal/sql/sqlpath/testdata/file2.sql | 0 internal/sql/sqlpath/testdata/file3.down.sql | 0 internal/sql/sqlpath/testdata/file4.SQL | 0 .../testdata/glob/sub1/queries/file1.sql | 0 .../testdata/glob/sub2/queries/file2.sql | 0 .../testdata/glob/sub3/queries/file3.sql | 0 .../testdata/glob/sub3/queries/file4.sql | 0 .../sql/sqlpath/testdata/subdir/file2.sql | 0 internal/sql/sqlpath/testdata/symlink | 1 + internal/sql/validate/cmd.go | 88 + internal/sql/validate/func_call.go | 48 + internal/sql/validate/insert_stmt.go | 141 + internal/sql/validate/slice.go | 70 + internal/sqlcdebug/sqlcdebug.go | 182 + internal/sqlcdebug/sqlcdebug_test.go | 107 + internal/sqlite3ext/sqlite3ext.go | 21 + internal/sqltest/docker/enabled.go | 23 + internal/sqltest/docker/mysql.go | 104 + internal/sqltest/docker/postgres.go | 105 + internal/sqltest/local/id.go | 13 + internal/sqltest/local/mysql.go | 109 + internal/sqltest/local/postgres.go | 136 + internal/sqltest/mysql.go | 104 + internal/sqltest/native/enabled.go | 20 + internal/sqltest/native/mysql.go | 203 + internal/sqltest/native/postgres.go | 221 + internal/sqltest/sqlite.go | 56 + internal/tracer/trace.go | 44 + internal/vet/vet.pb.go | 1649 ++++++++ internal/x/expander/expander.go | 507 +++ internal/x/expander/expander_test.go | 435 ++ pkg/cli/cli.go | 30 + placeholder.go | 6 + protos/analysis/analysis.proto | 39 + protos/buf.yaml | 8 + protos/plugin/codegen.proto | 132 + protos/vet/vet.proto | 129 + scripts/build/main.go | 45 + scripts/bump-version/main.go | 150 + scripts/cleanup-test-dbs/main.go | 55 + scripts/mirror-go-plugin/main.go | 88 + scripts/release.go | 59 + scripts/report.sh | 17 + scripts/test-json-process-plugin/main.go | 39 + 7340 files changed, 238743 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/BUG_REPORT.yml create mode 100644 .github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/buf.yml create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/ci-kotlin.yml create mode 100644 .github/workflows/ci-python.yml create mode 100644 .github/workflows/ci-typescript.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/gen.yml create mode 100644 .gitignore create mode 100644 .vscode/settings.json create mode 100644 CLAUDE.md create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 NOTICE create mode 100644 README.md create mode 100644 buf.gen.yaml create mode 100644 buf.lock create mode 100644 buf.work.yaml create mode 100644 cliff.toml create mode 100644 cmd/sqlc-gen-json/main.go create mode 100644 cmd/sqlc-test-setup/main.go create mode 100644 cmd/sqlc/main.go create mode 100644 devenv.lock create mode 100644 devenv.nix create mode 100644 devenv.yaml create mode 100644 docker-compose.yml create mode 100644 docs/.gitignore create mode 100644 docs/guides/development.md create mode 100644 docs/guides/migrating-off-hosted-managed-databases.md create mode 100644 docs/guides/migrating-to-sqlc-gen-kotlin.md create mode 100644 docs/guides/migrating-to-sqlc-gen-python.md create mode 100644 docs/guides/plugins.md create mode 100644 docs/guides/privacy.md create mode 100644 docs/guides/using-go-and-pgx.md create mode 100644 docs/howto/analyze.md create mode 100644 docs/howto/ci-cd.md create mode 100644 docs/howto/ddl.md create mode 100644 docs/howto/delete.md create mode 100644 docs/howto/embedding.md create mode 100644 docs/howto/fmt.md create mode 100644 docs/howto/generate.md create mode 100644 docs/howto/insert.md create mode 100644 docs/howto/managed-databases.md create mode 100644 docs/howto/named_parameters.md create mode 100644 docs/howto/overrides.md create mode 100644 docs/howto/parse.md create mode 100644 docs/howto/prepared_query.md create mode 100644 docs/howto/push.md create mode 100644 docs/howto/query_count.md create mode 100644 docs/howto/rename.md create mode 100644 docs/howto/select.md create mode 100644 docs/howto/structs.md create mode 100644 docs/howto/transactions.md create mode 100644 docs/howto/update.md create mode 100644 docs/howto/verify.md create mode 100644 docs/howto/vet.md create mode 100644 docs/index.md create mode 100644 docs/overview/install.md create mode 100644 docs/reference/changelog.md create mode 100644 docs/reference/cli.md create mode 100644 docs/reference/config.md create mode 100644 docs/reference/datatypes.md create mode 100644 docs/reference/environment-variables.md create mode 100644 docs/reference/language-support.md create mode 100644 docs/reference/macros.md create mode 100644 docs/reference/query-annotations.md create mode 100644 docs/toc.yaml create mode 100644 docs/tutorials/getting-started-mysql.md create mode 100644 docs/tutorials/getting-started-postgresql.md create mode 100644 docs/tutorials/getting-started-sqlite.md create mode 100644 examples/authors/mysql/db.go create mode 100644 examples/authors/mysql/db_test.go create mode 100644 examples/authors/mysql/models.go create mode 100644 examples/authors/mysql/query.sql create mode 100644 examples/authors/mysql/query.sql.go create mode 100644 examples/authors/mysql/schema.sql create mode 100644 examples/authors/postgresql/db.go create mode 100644 examples/authors/postgresql/db_test.go create mode 100644 examples/authors/postgresql/models.go create mode 100644 examples/authors/postgresql/query.sql create mode 100644 examples/authors/postgresql/query.sql.go create mode 100644 examples/authors/postgresql/schema.sql create mode 100644 examples/authors/sqlc.yaml create mode 100644 examples/authors/sqlite/db.go create mode 100644 examples/authors/sqlite/db_test.go create mode 100644 examples/authors/sqlite/models.go create mode 100644 examples/authors/sqlite/query.sql create mode 100644 examples/authors/sqlite/query.sql.go create mode 100644 examples/authors/sqlite/schema.sql create mode 100644 examples/batch/postgresql/batch.go create mode 100644 examples/batch/postgresql/db.go create mode 100644 examples/batch/postgresql/db_test.go create mode 100644 examples/batch/postgresql/models.go create mode 100644 examples/batch/postgresql/querier.go create mode 100644 examples/batch/postgresql/query.sql create mode 100644 examples/batch/postgresql/query.sql.go create mode 100644 examples/batch/postgresql/schema.sql create mode 100644 examples/batch/sqlc.json create mode 100644 examples/booktest/mysql/db.go create mode 100644 examples/booktest/mysql/db_test.go create mode 100644 examples/booktest/mysql/models.go create mode 100644 examples/booktest/mysql/query.sql create mode 100644 examples/booktest/mysql/query.sql.go create mode 100644 examples/booktest/mysql/schema.sql create mode 100644 examples/booktest/postgresql/db.go create mode 100644 examples/booktest/postgresql/db_test.go create mode 100644 examples/booktest/postgresql/models.go create mode 100644 examples/booktest/postgresql/query.sql create mode 100644 examples/booktest/postgresql/query.sql.go create mode 100644 examples/booktest/postgresql/schema.sql create mode 100644 examples/booktest/sqlc.json create mode 100644 examples/booktest/sqlite/db.go create mode 100644 examples/booktest/sqlite/db_test.go create mode 100644 examples/booktest/sqlite/models.go create mode 100644 examples/booktest/sqlite/query.sql create mode 100644 examples/booktest/sqlite/query.sql.go create mode 100644 examples/booktest/sqlite/schema.sql create mode 100644 examples/jets/README.md create mode 100644 examples/jets/postgresql/db.go create mode 100644 examples/jets/postgresql/models.go create mode 100644 examples/jets/postgresql/query-building.sql create mode 100644 examples/jets/postgresql/query-building.sql.go create mode 100644 examples/jets/postgresql/schema.sql create mode 100644 examples/jets/sqlc.json create mode 100644 examples/ondeck/mysql/city.sql.go create mode 100644 examples/ondeck/mysql/db.go create mode 100644 examples/ondeck/mysql/db_test.go create mode 100644 examples/ondeck/mysql/models.go create mode 100644 examples/ondeck/mysql/querier.go create mode 100644 examples/ondeck/mysql/query/city.sql create mode 100644 examples/ondeck/mysql/query/venue.sql create mode 100644 examples/ondeck/mysql/schema/0001_city.sql create mode 100644 examples/ondeck/mysql/schema/0002_venue.sql create mode 100644 examples/ondeck/mysql/schema/0003_add_column.sql create mode 100644 examples/ondeck/mysql/venue.sql.go create mode 100644 examples/ondeck/postgresql/city.sql.go create mode 100644 examples/ondeck/postgresql/db.go create mode 100644 examples/ondeck/postgresql/db_test.go create mode 100644 examples/ondeck/postgresql/models.go create mode 100644 examples/ondeck/postgresql/querier.go create mode 100644 examples/ondeck/postgresql/query/city.sql create mode 100644 examples/ondeck/postgresql/query/venue.sql create mode 100644 examples/ondeck/postgresql/schema/0001_city.sql create mode 100644 examples/ondeck/postgresql/schema/0002_venue.sql create mode 100644 examples/ondeck/postgresql/schema/0003_add_column.sql create mode 100644 examples/ondeck/postgresql/venue.sql.go create mode 100644 examples/ondeck/sqlc.json create mode 100644 examples/ondeck/sqlite/city.sql.go create mode 100644 examples/ondeck/sqlite/db.go create mode 100644 examples/ondeck/sqlite/db_test.go create mode 100644 examples/ondeck/sqlite/models.go create mode 100644 examples/ondeck/sqlite/querier.go create mode 100644 examples/ondeck/sqlite/query/city.sql create mode 100644 examples/ondeck/sqlite/query/venue.sql create mode 100644 examples/ondeck/sqlite/schema/0001_city.sql create mode 100644 examples/ondeck/sqlite/schema/0002_venue.sql create mode 100644 examples/ondeck/sqlite/schema/0003_add_column.sql create mode 100644 examples/ondeck/sqlite/venue.sql.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 gomod_test.go create mode 100644 internal/analysis/analysis.pb.go create mode 100644 internal/analysis/analysis_vtproto.pb.go create mode 100644 internal/analyzer/analyzer.go create mode 100644 internal/bundler/multipart.go create mode 100644 internal/bundler/upload.go create mode 100644 internal/cache/action.go create mode 100644 internal/cache/cache.go create mode 100644 internal/cache/cas.go create mode 100644 internal/cache/digest.go create mode 100644 internal/cache/tool.go create mode 100644 internal/cmd/analyze.go create mode 100644 internal/cmd/cmd.go create mode 100644 internal/cmd/createdb.go create mode 100644 internal/cmd/diff.go create mode 100644 internal/cmd/fmt.go create mode 100644 internal/cmd/generate.go create mode 100644 internal/cmd/options.go create mode 100644 internal/cmd/parse.go create mode 100644 internal/cmd/process.go create mode 100644 internal/cmd/push.go create mode 100644 internal/cmd/shim.go create mode 100644 internal/cmd/verify.go create mode 100644 internal/cmd/vet.go create mode 100644 internal/cmd/vet_sqlite.go create mode 100644 internal/codegen/golang/driver.go create mode 100644 internal/codegen/golang/enum.go create mode 100644 internal/codegen/golang/field.go create mode 100644 internal/codegen/golang/gen.go create mode 100644 internal/codegen/golang/go_type.go create mode 100644 internal/codegen/golang/imports.go create mode 100644 internal/codegen/golang/mysql_type.go create mode 100644 internal/codegen/golang/opts/enum.go create mode 100644 internal/codegen/golang/opts/go_type.go create mode 100644 internal/codegen/golang/opts/options.go create mode 100644 internal/codegen/golang/opts/override.go create mode 100644 internal/codegen/golang/opts/override_test.go create mode 100644 internal/codegen/golang/opts/shim.go create mode 100644 internal/codegen/golang/postgresql_type.go create mode 100644 internal/codegen/golang/qualify.go create mode 100644 internal/codegen/golang/query.go create mode 100644 internal/codegen/golang/reserved.go create mode 100644 internal/codegen/golang/result.go create mode 100644 internal/codegen/golang/result_test.go create mode 100644 internal/codegen/golang/sqlite_type.go create mode 100644 internal/codegen/golang/struct.go create mode 100644 internal/codegen/golang/template.go create mode 100644 internal/codegen/golang/templates/go-sql-driver-mysql/copyfromCopy.tmpl create mode 100644 internal/codegen/golang/templates/pgx/batchCode.tmpl create mode 100644 internal/codegen/golang/templates/pgx/copyfromCopy.tmpl create mode 100644 internal/codegen/golang/templates/pgx/dbCode.tmpl create mode 100644 internal/codegen/golang/templates/pgx/interfaceCode.tmpl create mode 100644 internal/codegen/golang/templates/pgx/queryCode.tmpl create mode 100644 internal/codegen/golang/templates/stdlib/dbCode.tmpl create mode 100644 internal/codegen/golang/templates/stdlib/interfaceCode.tmpl create mode 100644 internal/codegen/golang/templates/stdlib/queryCode.tmpl create mode 100644 internal/codegen/golang/templates/template.tmpl create mode 100644 internal/codegen/json/gen.go create mode 100644 internal/codegen/json/opts.go create mode 100644 internal/codegen/sdk/sdk.go create mode 100644 internal/codegen/sdk/utils.go create mode 100644 internal/codegen/sdk/utils_test.go create mode 100644 internal/compiler/analyze.go create mode 100644 internal/compiler/catalog_core.go create mode 100644 internal/compiler/compat.go create mode 100644 internal/compiler/compile.go create mode 100644 internal/compiler/engine.go create mode 100644 internal/compiler/expand.go create mode 100644 internal/compiler/expand_core.go create mode 100644 internal/compiler/find_params.go create mode 100644 internal/compiler/output_columns.go create mode 100644 internal/compiler/parse.go create mode 100644 internal/compiler/parse_core.go create mode 100644 internal/compiler/query.go create mode 100644 internal/compiler/query_catalog.go create mode 100644 internal/compiler/resolve.go create mode 100644 internal/compiler/result.go create mode 100644 internal/compiler/returning.go create mode 100644 internal/compiler/selector.go create mode 100644 internal/compiler/selector_test.go create mode 100644 internal/compiler/to_column.go create mode 100644 internal/config/config.go create mode 100644 internal/config/config_test.go create mode 100644 internal/config/convert/convert.go create mode 100644 internal/config/convert/convert_test.go create mode 100644 internal/config/env.go create mode 100644 internal/config/v_one.go create mode 100644 internal/config/v_one.json create mode 100644 internal/config/v_two.go create mode 100644 internal/config/v_two.json create mode 100644 internal/config/validate.go create mode 100644 internal/constants/query.go create mode 100644 internal/core/analysis.go create mode 100644 internal/core/analyzer/analyzer.go create mode 100644 internal/core/analyzer/bench_test.go create mode 100644 internal/core/analyzer/dml.go create mode 100644 internal/core/analyzer/expr.go create mode 100644 internal/core/analyzer/projection.go create mode 100644 internal/core/analyzer/scope.go create mode 100644 internal/core/attribute.go create mode 100644 internal/core/cache.go create mode 100644 internal/core/cast.go create mode 100644 internal/core/catalog.go create mode 100644 internal/core/catalogdb/db.go create mode 100644 internal/core/catalogdb/models.go create mode 100644 internal/core/catalogdb/query.sql.go create mode 100644 internal/core/catalogdef/embed.go create mode 100644 internal/core/catalogdef/query.sql create mode 100644 internal/core/catalogdef/schema.sql create mode 100644 internal/core/class.go create mode 100644 internal/core/constraint.go create mode 100644 internal/core/db.go create mode 100644 internal/core/dialect.go create mode 100644 internal/core/namespace.go create mode 100644 internal/core/operator.go create mode 100644 internal/core/proc.go create mode 100644 internal/core/rewrite.go create mode 100644 internal/core/schema/schema.go create mode 100644 internal/core/seed/extension.go create mode 100644 internal/core/seed/seed.go create mode 100644 internal/core/sqlc.json create mode 100644 internal/core/typeexpr.go create mode 100644 internal/core/typename.go create mode 100644 internal/core/types.go create mode 100644 internal/core/types.md create mode 100644 internal/dbmanager/client.go create mode 100644 internal/debug/dump.go create mode 100644 internal/docs/lint.go create mode 100644 internal/docs/lint_test.go create mode 100644 internal/endtoend/CLAUDE.md create mode 100644 internal/endtoend/case_test.go create mode 100644 internal/endtoend/ddl_test.go create mode 100644 internal/endtoend/endtoend_test.go create mode 100644 internal/endtoend/fmt_test.go create mode 100644 internal/endtoend/json_schema_test.go create mode 100644 internal/endtoend/testdata/alias/mysql/go/db.go create mode 100644 internal/endtoend/testdata/alias/mysql/go/models.go create mode 100644 internal/endtoend/testdata/alias/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/alias/mysql/query.sql create mode 100644 internal/endtoend/testdata/alias/mysql/schema.sql create mode 100644 internal/endtoend/testdata/alias/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/alias/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/alias/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/alias/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/alias/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/alias/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/alias/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/alias/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/alias/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/alias/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/alias/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/alias/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/alias/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/alias/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/alias/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/alias/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/alias/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/alias/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/alias/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/alias/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/alias/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/alias/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/alias/sqlite/query.sql create mode 100644 internal/endtoend/testdata/alias/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/alias/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/analyze_ast/postgresql/exec.json create mode 100644 internal/endtoend/testdata/analyze_ast/postgresql/query.sql create mode 100644 internal/endtoend/testdata/analyze_ast/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/analyze_ast/postgresql/stdout.json create mode 100644 internal/endtoend/testdata/analyze_basic/clickhouse/exec.json create mode 100644 internal/endtoend/testdata/analyze_basic/clickhouse/fixture.sql create mode 100644 internal/endtoend/testdata/analyze_basic/clickhouse/query.sql create mode 100644 internal/endtoend/testdata/analyze_basic/clickhouse/schema.sql create mode 100644 internal/endtoend/testdata/analyze_basic/clickhouse/stdout.json create mode 100644 internal/endtoend/testdata/analyze_basic/duckdb/exec.json create mode 100644 internal/endtoend/testdata/analyze_basic/duckdb/query.sql create mode 100644 internal/endtoend/testdata/analyze_basic/duckdb/schema.sql create mode 100644 internal/endtoend/testdata/analyze_basic/duckdb/stdout.json create mode 100644 internal/endtoend/testdata/analyze_basic/googlesql/exec.json create mode 100644 internal/endtoend/testdata/analyze_basic/googlesql/query.sql create mode 100644 internal/endtoend/testdata/analyze_basic/googlesql/schema.sql create mode 100644 internal/endtoend/testdata/analyze_basic/googlesql/stdout.json create mode 100644 internal/endtoend/testdata/analyze_basic/mssql/exec.json create mode 100644 internal/endtoend/testdata/analyze_basic/mssql/query.sql create mode 100644 internal/endtoend/testdata/analyze_basic/mssql/schema.sql create mode 100644 internal/endtoend/testdata/analyze_basic/mssql/stdout.json create mode 100644 internal/endtoend/testdata/analyze_basic/mysql/exec.json create mode 100644 internal/endtoend/testdata/analyze_basic/mysql/query.sql create mode 100644 internal/endtoend/testdata/analyze_basic/mysql/schema.sql create mode 100644 internal/endtoend/testdata/analyze_basic/mysql/stdout.json create mode 100644 internal/endtoend/testdata/analyze_basic/postgresql/exec.json create mode 100644 internal/endtoend/testdata/analyze_basic/postgresql/query.sql create mode 100644 internal/endtoend/testdata/analyze_basic/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/analyze_basic/postgresql/stdout.json create mode 100644 internal/endtoend/testdata/analyze_basic/sqlite/exec.json create mode 100644 internal/endtoend/testdata/analyze_basic/sqlite/query.sql create mode 100644 internal/endtoend/testdata/analyze_basic/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/analyze_basic/sqlite/stdout.json create mode 100644 internal/endtoend/testdata/analyze_dml/duckdb/exec.json create mode 100644 internal/endtoend/testdata/analyze_dml/duckdb/query.sql create mode 100644 internal/endtoend/testdata/analyze_dml/duckdb/schema.sql create mode 100644 internal/endtoend/testdata/analyze_dml/duckdb/stdout.json create mode 100644 internal/endtoend/testdata/analyze_dml/googlesql/exec.json create mode 100644 internal/endtoend/testdata/analyze_dml/googlesql/query.sql create mode 100644 internal/endtoend/testdata/analyze_dml/googlesql/schema.sql create mode 100644 internal/endtoend/testdata/analyze_dml/googlesql/stdout.json create mode 100644 internal/endtoend/testdata/analyze_dml/mssql/exec.json create mode 100644 internal/endtoend/testdata/analyze_dml/mssql/query.sql create mode 100644 internal/endtoend/testdata/analyze_dml/mssql/schema.sql create mode 100644 internal/endtoend/testdata/analyze_dml/mssql/stdout.json create mode 100644 internal/endtoend/testdata/analyze_dml/mysql/exec.json create mode 100644 internal/endtoend/testdata/analyze_dml/mysql/query.sql create mode 100644 internal/endtoend/testdata/analyze_dml/mysql/schema.sql create mode 100644 internal/endtoend/testdata/analyze_dml/mysql/stdout.json create mode 100644 internal/endtoend/testdata/analyze_dml/postgresql/exec.json create mode 100644 internal/endtoend/testdata/analyze_dml/postgresql/query.sql create mode 100644 internal/endtoend/testdata/analyze_dml/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/analyze_dml/postgresql/stdout.json create mode 100644 internal/endtoend/testdata/analyze_dml/sqlite/exec.json create mode 100644 internal/endtoend/testdata/analyze_dml/sqlite/query.sql create mode 100644 internal/endtoend/testdata/analyze_dml/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/analyze_dml/sqlite/stdout.json create mode 100644 internal/endtoend/testdata/analyze_exec/clickhouse/exec.json create mode 100644 internal/endtoend/testdata/analyze_exec/clickhouse/fixture.sql create mode 100644 internal/endtoend/testdata/analyze_exec/clickhouse/query.sql create mode 100644 internal/endtoend/testdata/analyze_exec/clickhouse/schema.sql create mode 100644 internal/endtoend/testdata/analyze_exec/clickhouse/stdout.json create mode 100644 internal/endtoend/testdata/analyze_expressions/clickhouse/exec.json create mode 100644 internal/endtoend/testdata/analyze_expressions/clickhouse/fixture.sql create mode 100644 internal/endtoend/testdata/analyze_expressions/clickhouse/query.sql create mode 100644 internal/endtoend/testdata/analyze_expressions/clickhouse/schema.sql create mode 100644 internal/endtoend/testdata/analyze_expressions/clickhouse/stdout.json create mode 100644 internal/endtoend/testdata/analyze_expressions/sqlite/exec.json create mode 100644 internal/endtoend/testdata/analyze_expressions/sqlite/fixture.sql create mode 100644 internal/endtoend/testdata/analyze_expressions/sqlite/query.sql create mode 100644 internal/endtoend/testdata/analyze_expressions/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/analyze_expressions/sqlite/stdout.json create mode 100644 internal/endtoend/testdata/analyze_extension/postgresql/exec.json create mode 100644 internal/endtoend/testdata/analyze_extension/postgresql/query.sql create mode 100644 internal/endtoend/testdata/analyze_extension/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/analyze_extension/postgresql/stdout.json create mode 100644 internal/endtoend/testdata/analyze_params/clickhouse/exec.json create mode 100644 internal/endtoend/testdata/analyze_params/clickhouse/fixture.sql create mode 100644 internal/endtoend/testdata/analyze_params/clickhouse/query.sql create mode 100644 internal/endtoend/testdata/analyze_params/clickhouse/schema.sql create mode 100644 internal/endtoend/testdata/analyze_params/clickhouse/stdout.json create mode 100644 internal/endtoend/testdata/analyze_params/duckdb/exec.json create mode 100644 internal/endtoend/testdata/analyze_params/duckdb/query.sql create mode 100644 internal/endtoend/testdata/analyze_params/duckdb/schema.sql create mode 100644 internal/endtoend/testdata/analyze_params/duckdb/stdout.json create mode 100644 internal/endtoend/testdata/analyze_params/mssql/exec.json create mode 100644 internal/endtoend/testdata/analyze_params/mssql/query.sql create mode 100644 internal/endtoend/testdata/analyze_params/mssql/schema.sql create mode 100644 internal/endtoend/testdata/analyze_params/mssql/stdout.json create mode 100644 internal/endtoend/testdata/analyze_params/mysql/exec.json create mode 100644 internal/endtoend/testdata/analyze_params/mysql/query.sql create mode 100644 internal/endtoend/testdata/analyze_params/mysql/schema.sql create mode 100644 internal/endtoend/testdata/analyze_params/mysql/stdout.json create mode 100644 internal/endtoend/testdata/analyze_params/postgresql/exec.json create mode 100644 internal/endtoend/testdata/analyze_params/postgresql/query.sql create mode 100644 internal/endtoend/testdata/analyze_params/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/analyze_params/postgresql/stdout.json create mode 100644 internal/endtoend/testdata/analyze_params/sqlite/exec.json create mode 100644 internal/endtoend/testdata/analyze_params/sqlite/query.sql create mode 100644 internal/endtoend/testdata/analyze_params/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/analyze_params/sqlite/stdout.json create mode 100644 internal/endtoend/testdata/analyze_select/duckdb/exec.json create mode 100644 internal/endtoend/testdata/analyze_select/duckdb/query.sql create mode 100644 internal/endtoend/testdata/analyze_select/duckdb/schema.sql create mode 100644 internal/endtoend/testdata/analyze_select/duckdb/stdout.json create mode 100644 internal/endtoend/testdata/analyze_select/googlesql/exec.json create mode 100644 internal/endtoend/testdata/analyze_select/googlesql/query.sql create mode 100644 internal/endtoend/testdata/analyze_select/googlesql/schema.sql create mode 100644 internal/endtoend/testdata/analyze_select/googlesql/stdout.json create mode 100644 internal/endtoend/testdata/analyze_select/mysql/exec.json create mode 100644 internal/endtoend/testdata/analyze_select/mysql/query.sql create mode 100644 internal/endtoend/testdata/analyze_select/mysql/schema.sql create mode 100644 internal/endtoend/testdata/analyze_select/mysql/stdout.json create mode 100644 internal/endtoend/testdata/analyze_select/postgresql/exec.json create mode 100644 internal/endtoend/testdata/analyze_select/postgresql/query.sql create mode 100644 internal/endtoend/testdata/analyze_select/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/analyze_select/postgresql/stdout.json create mode 100644 internal/endtoend/testdata/analyze_select/sqlite/exec.json create mode 100644 internal/endtoend/testdata/analyze_select/sqlite/query.sql create mode 100644 internal/endtoend/testdata/analyze_select/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/analyze_select/sqlite/stdout.json create mode 100644 internal/endtoend/testdata/analyze_subqueries/clickhouse/exec.json create mode 100644 internal/endtoend/testdata/analyze_subqueries/clickhouse/fixture.sql create mode 100644 internal/endtoend/testdata/analyze_subqueries/clickhouse/query.sql create mode 100644 internal/endtoend/testdata/analyze_subqueries/clickhouse/schema.sql create mode 100644 internal/endtoend/testdata/analyze_subqueries/clickhouse/stdout.json create mode 100644 internal/endtoend/testdata/analyze_system_catalog/mysql/exec.json create mode 100644 internal/endtoend/testdata/analyze_system_catalog/mysql/query.sql create mode 100644 internal/endtoend/testdata/analyze_system_catalog/mysql/schema.sql create mode 100644 internal/endtoend/testdata/analyze_system_catalog/mysql/stdout.json create mode 100644 internal/endtoend/testdata/analyze_system_catalog/postgresql/exec.json create mode 100644 internal/endtoend/testdata/analyze_system_catalog/postgresql/query.sql create mode 100644 internal/endtoend/testdata/analyze_system_catalog/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/analyze_system_catalog/postgresql/stdout.json create mode 100644 internal/endtoend/testdata/analyze_types/bigquery/exec.json create mode 100644 internal/endtoend/testdata/analyze_types/bigquery/query.sql create mode 100644 internal/endtoend/testdata/analyze_types/bigquery/schema.sql create mode 100644 internal/endtoend/testdata/analyze_types/bigquery/stdout.json create mode 100644 internal/endtoend/testdata/analyze_types/clickhouse/exec.json create mode 100644 internal/endtoend/testdata/analyze_types/clickhouse/fixture.sql create mode 100644 internal/endtoend/testdata/analyze_types/clickhouse/query.sql create mode 100644 internal/endtoend/testdata/analyze_types/clickhouse/schema.sql create mode 100644 internal/endtoend/testdata/analyze_types/clickhouse/stdout.json create mode 100644 internal/endtoend/testdata/analyze_types/duckdb/exec.json create mode 100644 internal/endtoend/testdata/analyze_types/duckdb/query.sql create mode 100644 internal/endtoend/testdata/analyze_types/duckdb/schema.sql create mode 100644 internal/endtoend/testdata/analyze_types/duckdb/stdout.json create mode 100644 internal/endtoend/testdata/analyze_types/googlesql/exec.json create mode 100644 internal/endtoend/testdata/analyze_types/googlesql/query.sql create mode 100644 internal/endtoend/testdata/analyze_types/googlesql/schema.sql create mode 100644 internal/endtoend/testdata/analyze_types/googlesql/stdout.json create mode 100644 internal/endtoend/testdata/analyze_types/mssql/exec.json create mode 100644 internal/endtoend/testdata/analyze_types/mssql/query.sql create mode 100644 internal/endtoend/testdata/analyze_types/mssql/schema.sql create mode 100644 internal/endtoend/testdata/analyze_types/mssql/stdout.json create mode 100644 internal/endtoend/testdata/analyze_types/mysql/exec.json create mode 100644 internal/endtoend/testdata/analyze_types/mysql/query.sql create mode 100644 internal/endtoend/testdata/analyze_types/mysql/schema.sql create mode 100644 internal/endtoend/testdata/analyze_types/mysql/stdout.json create mode 100644 internal/endtoend/testdata/analyze_types/postgresql/exec.json create mode 100644 internal/endtoend/testdata/analyze_types/postgresql/query.sql create mode 100644 internal/endtoend/testdata/analyze_types/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/analyze_types/postgresql/stdout.json create mode 100644 internal/endtoend/testdata/analyze_types/sqlite/exec.json create mode 100644 internal/endtoend/testdata/analyze_types/sqlite/fixture.sql create mode 100644 internal/endtoend/testdata/analyze_types/sqlite/query.sql create mode 100644 internal/endtoend/testdata/analyze_types/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/analyze_types/sqlite/stdout.json create mode 100644 internal/endtoend/testdata/any/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/any/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/any/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/any/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/any/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/any/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/any/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/any/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/any/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/any/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/any/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/any/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/any/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/any/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/any/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/any/stdlib/query.sql create mode 100644 internal/endtoend/testdata/any/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/any/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/array_in/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/array_in/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/array_in/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/array_in/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/array_in/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/array_in/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/array_in/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/array_in/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/array_in/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/array_in/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/array_in/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/array_in/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/array_in/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/array_in/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/array_in/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/array_in/stdlib/query.sql create mode 100644 internal/endtoend/testdata/array_in/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/array_in/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/array_text/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/array_text/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/array_text/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/array_text/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/array_text/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/array_text/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/array_text/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/array_text/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/array_text/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/array_text/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/array_text/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/array_text/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/array_text/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/array_text/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/array_text/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/array_text/stdlib/query.sql create mode 100644 internal/endtoend/testdata/array_text/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/array_text/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/array_text_join/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/array_text_join/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/array_text_join/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/array_text_join/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/array_text_join/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/array_text_join/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/array_text_join/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/array_text_join/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/array_text_join/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/array_text_join/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/array_text_join/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/array_text_join/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/array_text_join/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/array_text_join/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/array_text_join/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/array_text_join/stdlib/query.sql create mode 100644 internal/endtoend/testdata/array_text_join/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/array_text_join/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/bad_config/engine/query.sql create mode 100644 internal/endtoend/testdata/bad_config/engine/sqlc.yaml create mode 100644 internal/endtoend/testdata/bad_config/engine/stderr.txt create mode 100644 internal/endtoend/testdata/batch/postgresql/pgx/v4/go/batch.go create mode 100644 internal/endtoend/testdata/batch/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/batch/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/batch/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/batch/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/batch/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/batch/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/batch/postgresql/pgx/v5/go/batch.go create mode 100644 internal/endtoend/testdata/batch/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/batch/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/batch/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/batch/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/batch/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/batch/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/go/batch.go create mode 100644 internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/go/batch.go create mode 100644 internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/batch_parameter_limit/issue.md create mode 100644 internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/go/batch.go create mode 100644 internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/batch_parameter_type/issue.md create mode 100644 internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/go/batch.go create mode 100644 internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/between_args/mysql/go/db.go create mode 100644 internal/endtoend/testdata/between_args/mysql/go/models.go create mode 100644 internal/endtoend/testdata/between_args/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/between_args/mysql/query.sql create mode 100644 internal/endtoend/testdata/between_args/mysql/schema.sql create mode 100644 internal/endtoend/testdata/between_args/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/between_args/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/between_args/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/between_args/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/between_args/sqlite/query.sql create mode 100644 internal/endtoend/testdata/between_args/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/between_args/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/bit_string/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/bit_string/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/bit_string/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/bit_string/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/bit_string/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/bit_string/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/bit_string/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/bit_string/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/bit_string/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/bit_string/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/bit_string/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/bit_string/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/build_tags/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/build_tags/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/build_tags/postgresql/stdlib/go/querier.go create mode 100644 internal/endtoend/testdata/build_tags/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/build_tags/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/build_tags/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/build_tags/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/builtins/postgresql/exec.json create mode 100644 internal/endtoend/testdata/builtins/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/builtins/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/builtins/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/builtins/postgresql/query.sql create mode 100644 internal/endtoend/testdata/builtins/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/builtins/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/builtins/sqlite/go/aggfunc.sql.go create mode 100644 internal/endtoend/testdata/builtins/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/builtins/sqlite/go/mathfunc.sql.go create mode 100644 internal/endtoend/testdata/builtins/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/builtins/sqlite/go/scalarfunc.sql.go create mode 100644 internal/endtoend/testdata/builtins/sqlite/queries/aggfunc.sql create mode 100644 internal/endtoend/testdata/builtins/sqlite/queries/mathfunc.sql create mode 100644 internal/endtoend/testdata/builtins/sqlite/queries/scalarfunc.sql create mode 100644 internal/endtoend/testdata/builtins/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/builtins/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/case_named_params/mysql/go/db.go create mode 100644 internal/endtoend/testdata/case_named_params/mysql/go/models.go create mode 100644 internal/endtoend/testdata/case_named_params/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/case_named_params/mysql/query.sql create mode 100644 internal/endtoend/testdata/case_named_params/mysql/schema.sql create mode 100644 internal/endtoend/testdata/case_named_params/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/case_named_params/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/case_named_params/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/case_named_params/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/case_named_params/postgresql/query.sql create mode 100644 internal/endtoend/testdata/case_named_params/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/case_named_params/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/case_named_params/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/case_named_params/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/case_named_params/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/case_named_params/sqlite/query.sql create mode 100644 internal/endtoend/testdata/case_named_params/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/case_named_params/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/case_sensitive/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/case_sensitive/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/case_sensitive/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/case_sensitive/sqlite/query.sql create mode 100644 internal/endtoend/testdata/case_sensitive/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/case_sensitive/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/case_stmt_bool/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/case_stmt_bool/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/case_stmt_bool/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/case_stmt_bool/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/case_stmt_bool/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/case_stmt_bool/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/case_stmt_bool/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/case_stmt_bool/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/case_stmt_bool/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/case_stmt_bool/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/case_stmt_bool/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/case_stmt_bool/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/case_stmt_bool/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/case_stmt_bool/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/case_stmt_bool/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/case_stmt_bool/stdlib/query.sql create mode 100644 internal/endtoend/testdata/case_stmt_bool/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/case_stmt_bool/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/case_text/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/case_text/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/case_text/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/case_text/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/case_text/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/case_text/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/case_text/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/case_text/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/case_text/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/case_text/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/case_text/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/case_text/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/case_text/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/case_text/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/case_text/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/case_text/stdlib/query.sql create mode 100644 internal/endtoend/testdata/case_text/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/case_text/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/case_value_param/issue.md create mode 100644 internal/endtoend/testdata/case_value_param/mysql/go/db.go create mode 100644 internal/endtoend/testdata/case_value_param/mysql/go/models.go create mode 100644 internal/endtoend/testdata/case_value_param/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/case_value_param/mysql/query.sql create mode 100644 internal/endtoend/testdata/case_value_param/mysql/schema.sql create mode 100644 internal/endtoend/testdata/case_value_param/mysql/sqlc.yaml create mode 100644 internal/endtoend/testdata/case_value_param/postgresql/exec.json create mode 100644 internal/endtoend/testdata/case_value_param/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/case_value_param/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/case_value_param/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/case_value_param/postgresql/query.sql create mode 100644 internal/endtoend/testdata/case_value_param/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/case_value_param/postgresql/sqlc.yaml create mode 100644 internal/endtoend/testdata/cast_coalesce/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/cast_coalesce/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/cast_coalesce/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/cast_coalesce/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/cast_coalesce/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/cast_coalesce/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/cast_coalesce/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/cast_coalesce/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/cast_coalesce/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/cast_coalesce/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/cast_coalesce/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/cast_coalesce/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/cast_coalesce/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/cast_coalesce/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/cast_coalesce/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/cast_coalesce/stdlib/query.sql create mode 100644 internal/endtoend/testdata/cast_coalesce/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/cast_coalesce/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/cast_null/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/cast_null/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/cast_null/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/cast_null/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/cast_null/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/cast_null/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/cast_null/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/cast_null/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/cast_null/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/cast_null/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/cast_null/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/cast_null/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/cast_null/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/cast_null/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/cast_null/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/cast_null/stdlib/query.sql create mode 100644 internal/endtoend/testdata/cast_null/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/cast_null/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/cast_param/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/cast_param/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/cast_param/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/cast_param/sqlite/query.sql create mode 100644 internal/endtoend/testdata/cast_param/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/cast_param/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/citext/pgx/go/db.go create mode 100644 internal/endtoend/testdata/citext/pgx/go/models.go create mode 100644 internal/endtoend/testdata/citext/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/citext/pgx/query.sql create mode 100644 internal/endtoend/testdata/citext/pgx/schema.sql create mode 100644 internal/endtoend/testdata/citext/pgx/sqlc.json create mode 100644 internal/endtoend/testdata/citext/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/citext/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/citext/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/citext/stdlib/query.sql create mode 100644 internal/endtoend/testdata/citext/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/citext/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/coalesce/mysql/go/db.go create mode 100644 internal/endtoend/testdata/coalesce/mysql/go/models.go create mode 100644 internal/endtoend/testdata/coalesce/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/coalesce/mysql/query.sql create mode 100644 internal/endtoend/testdata/coalesce/mysql/schema.sql create mode 100644 internal/endtoend/testdata/coalesce/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/coalesce/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/coalesce/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/coalesce/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/coalesce/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/coalesce/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/coalesce/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/coalesce/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/coalesce/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/coalesce/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/coalesce/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/coalesce/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/coalesce/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/coalesce/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/coalesce/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/coalesce/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/coalesce/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/coalesce/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/coalesce/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/coalesce/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/coalesce/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/coalesce/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/coalesce/sqlite/query.sql create mode 100644 internal/endtoend/testdata/coalesce/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/coalesce/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/coalesce_as/mysql/go/db.go create mode 100644 internal/endtoend/testdata/coalesce_as/mysql/go/models.go create mode 100644 internal/endtoend/testdata/coalesce_as/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/coalesce_as/mysql/query.sql create mode 100644 internal/endtoend/testdata/coalesce_as/mysql/schema.sql create mode 100644 internal/endtoend/testdata/coalesce_as/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/exec.json create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/go/db.go create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/go/models.go create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/go/query.sql.go create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/query.sql create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/schema.sql create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/sqlc.json create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/exec.json create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/exec.json create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/stdlib/exec.json create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/coalesce_as/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/coalesce_as/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/coalesce_as/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/coalesce_as/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/coalesce_as/sqlite/query.sql create mode 100644 internal/endtoend/testdata/coalesce_as/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/coalesce_as/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/coalesce_join/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/coalesce_join/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/coalesce_join/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/coalesce_join/postgresql/query.sql create mode 100644 internal/endtoend/testdata/coalesce_join/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/coalesce_join/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/coalesce_params/issue.md create mode 100644 internal/endtoend/testdata/coalesce_params/mysql/exec.json create mode 100644 internal/endtoend/testdata/coalesce_params/mysql/go/db.go create mode 100644 internal/endtoend/testdata/coalesce_params/mysql/go/models.go create mode 100644 internal/endtoend/testdata/coalesce_params/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/coalesce_params/mysql/query.sql create mode 100644 internal/endtoend/testdata/coalesce_params/mysql/schema.sql create mode 100644 internal/endtoend/testdata/coalesce_params/mysql/sqlc.yaml create mode 100644 internal/endtoend/testdata/codegen_json/exec.json create mode 100644 internal/endtoend/testdata/codegen_json/postgresql/query.sql create mode 100644 internal/endtoend/testdata/codegen_json/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/codegen_json/sqlc.json create mode 100644 internal/endtoend/testdata/codegen_struct_field_names/stdlib/README.md create mode 100644 internal/endtoend/testdata/codegen_struct_field_names/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/codegen_struct_field_names/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/codegen_struct_field_names/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/codegen_struct_field_names/stdlib/query.sql create mode 100644 internal/endtoend/testdata/codegen_struct_field_names/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/codegen_struct_field_names/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/column_alias/issue.md create mode 100644 internal/endtoend/testdata/column_alias/stdlib/exec.json create mode 100644 internal/endtoend/testdata/column_alias/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/column_alias/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/column_alias/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/column_alias/stdlib/query.sql create mode 100644 internal/endtoend/testdata/column_alias/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/column_alias/stdlib/sqlc.yaml create mode 100644 internal/endtoend/testdata/column_as/mysql/go/db.go create mode 100644 internal/endtoend/testdata/column_as/mysql/go/models.go create mode 100644 internal/endtoend/testdata/column_as/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/column_as/mysql/query.sql create mode 100644 internal/endtoend/testdata/column_as/mysql/schema.sql create mode 100644 internal/endtoend/testdata/column_as/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/column_as/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/column_as/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/column_as/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/column_as/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/column_as/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/column_as/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/column_as/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/column_as/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/column_as/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/column_as/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/column_as/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/column_as/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/column_as/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/column_as/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/column_as/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/column_as/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/column_as/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/column_as/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/column_as/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/column_as/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/column_as/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/column_as/sqlite/query.sql create mode 100644 internal/endtoend/testdata/column_as/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/column_as/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/comment_godoc/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/comment_godoc/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/comment_godoc/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/comment_godoc/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/comment_godoc/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/comment_godoc/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/comment_godoc/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/comment_godoc/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/comment_godoc/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/comment_godoc/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/comment_godoc/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/comment_godoc/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/comment_on/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/comment_on/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/comment_on/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/comment_on/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/comment_on/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/comment_on/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/comment_on/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/comment_on/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/comment_on/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/comment_on/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/comment_on/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/comment_on/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/comment_on/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/comment_on/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/comment_on/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/comment_on/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/comment_on/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/comment_on/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/comment_syntax/mysql/go/db.go create mode 100644 internal/endtoend/testdata/comment_syntax/mysql/go/models.go create mode 100644 internal/endtoend/testdata/comment_syntax/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/comment_syntax/mysql/query.sql create mode 100644 internal/endtoend/testdata/comment_syntax/mysql/schema.sql create mode 100644 internal/endtoend/testdata/comment_syntax/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/comment_syntax/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/comment_syntax/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/comment_syntax/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/comment_syntax/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/comment_syntax/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/comment_syntax/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/comment_syntax/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/comment_syntax/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/comment_syntax/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/comment_syntax/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/comment_syntax/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/comment_syntax/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/comment_syntax/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/comment_syntax/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/comment_syntax/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/comment_syntax/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/comment_syntax/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/comment_syntax/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/comment_syntax/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/comment_syntax/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/comment_syntax/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/comment_syntax/sqlite/query.sql create mode 100644 internal/endtoend/testdata/comment_syntax/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/comment_syntax/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/comparisons/mysql/go/db.go create mode 100644 internal/endtoend/testdata/comparisons/mysql/go/models.go create mode 100644 internal/endtoend/testdata/comparisons/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/comparisons/mysql/query.sql create mode 100644 internal/endtoend/testdata/comparisons/mysql/schema.sql create mode 100644 internal/endtoend/testdata/comparisons/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/comparisons/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/comparisons/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/comparisons/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/comparisons/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/comparisons/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/comparisons/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/comparisons/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/comparisons/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/comparisons/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/comparisons/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/comparisons/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/comparisons/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/comparisons/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/comparisons/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/comparisons/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/comparisons/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/comparisons/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/comparisons/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/comparisons/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/comparisons/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/comparisons/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/comparisons/sqlite/query.sql create mode 100644 internal/endtoend/testdata/comparisons/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/comparisons/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/composite_type/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/composite_type/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/composite_type/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/composite_type/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/composite_type/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/composite_type/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/composite_type/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/composite_type/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/composite_type/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/composite_type/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/composite_type/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/composite_type/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/composite_type/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/composite_type/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/composite_type/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/composite_type/stdlib/query.sql create mode 100644 internal/endtoend/testdata/composite_type/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/composite_type/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/conflicted_arg_name/postgresql/db/db.go create mode 100644 internal/endtoend/testdata/conflicted_arg_name/postgresql/db/models.go create mode 100644 internal/endtoend/testdata/conflicted_arg_name/postgresql/db/query.sql.go create mode 100644 internal/endtoend/testdata/conflicted_arg_name/postgresql/query.sql create mode 100644 internal/endtoend/testdata/conflicted_arg_name/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/conflicted_arg_name/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/copyfrom/mysql/go/copyfrom.go create mode 100644 internal/endtoend/testdata/copyfrom/mysql/go/db.go create mode 100644 internal/endtoend/testdata/copyfrom/mysql/go/models.go create mode 100644 internal/endtoend/testdata/copyfrom/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/copyfrom/mysql/query.sql create mode 100644 internal/endtoend/testdata/copyfrom/mysql/schema.sql create mode 100644 internal/endtoend/testdata/copyfrom/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/go/copyfrom.go create mode 100644 internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/go/querier.go create mode 100644 internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/go/copyfrom.go create mode 100644 internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/go/querier.go create mode 100644 internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/go/copyfrom.go create mode 100644 internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/go/copyfrom.go create mode 100644 internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/go/copyfrom.go create mode 100644 internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/go/db.go create mode 100644 internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/go/models.go create mode 100644 internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/query.sql create mode 100644 internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/schema.sql create mode 100644 internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/copyfrom_named_params/issue.md create mode 100644 internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/go/copyfrom.go create mode 100644 internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/go/copyfrom.go create mode 100644 internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/go/querier.go create mode 100644 internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/go/copyfrom.go create mode 100644 internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/go/querier.go create mode 100644 internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/issue.md create mode 100644 internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/go/copyfrom.go create mode 100644 internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/go/db.go create mode 100644 internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/go/models.go create mode 100644 internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/query.sql create mode 100644 internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/schema.sql create mode 100644 internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/count_star/mysql/go/db.go create mode 100644 internal/endtoend/testdata/count_star/mysql/go/models.go create mode 100644 internal/endtoend/testdata/count_star/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/count_star/mysql/query.sql create mode 100644 internal/endtoend/testdata/count_star/mysql/schema.sql create mode 100644 internal/endtoend/testdata/count_star/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/count_star/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/count_star/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/count_star/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/count_star/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/count_star/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/count_star/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/count_star/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/count_star/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/count_star/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/count_star/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/count_star/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/count_star/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/count_star/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/count_star/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/count_star/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/count_star/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/count_star/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/count_star/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/count_star/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/count_star/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/count_star/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/count_star/sqlite/query.sql create mode 100644 internal/endtoend/testdata/count_star/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/count_star/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/create_materialized_view/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/create_materialized_view/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/create_materialized_view/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/create_materialized_view/postgresql/query.sql create mode 100644 internal/endtoend/testdata/create_materialized_view/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/create_materialized_view/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/create_table_as/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/create_table_as/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/create_table_as/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/create_table_as/postgresql/query.sql create mode 100644 internal/endtoend/testdata/create_table_as/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/create_table_as/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/create_table_like/mysql/go/db.go create mode 100644 internal/endtoend/testdata/create_table_like/mysql/go/models.go create mode 100644 internal/endtoend/testdata/create_table_like/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/create_table_like/mysql/query.sql create mode 100644 internal/endtoend/testdata/create_table_like/mysql/schema.sql create mode 100644 internal/endtoend/testdata/create_table_like/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/create_table_like/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/create_table_like/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/create_table_like/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/create_table_like/postgresql/query.sql create mode 100644 internal/endtoend/testdata/create_table_like/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/create_table_like/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/create_view/mysql/go/db.go create mode 100644 internal/endtoend/testdata/create_view/mysql/go/models.go create mode 100644 internal/endtoend/testdata/create_view/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/create_view/mysql/query.sql create mode 100644 internal/endtoend/testdata/create_view/mysql/schema.sql create mode 100644 internal/endtoend/testdata/create_view/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/create_view/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/create_view/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/create_view/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/create_view/postgresql/query.sql create mode 100644 internal/endtoend/testdata/create_view/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/create_view/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/create_view/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/create_view/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/create_view/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/create_view/sqlite/query.sql create mode 100644 internal/endtoend/testdata/create_view/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/create_view/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/cte_count/mysql/go/db.go create mode 100644 internal/endtoend/testdata/cte_count/mysql/go/models.go create mode 100644 internal/endtoend/testdata/cte_count/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_count/mysql/query.sql create mode 100644 internal/endtoend/testdata/cte_count/mysql/schema.sql create mode 100644 internal/endtoend/testdata/cte_count/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/cte_count/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/cte_count/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/cte_count/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_count/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/cte_count/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/cte_count/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/cte_count/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/cte_count/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/cte_count/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_count/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/cte_count/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/cte_count/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/cte_count/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/cte_count/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/cte_count/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_count/stdlib/query.sql create mode 100644 internal/endtoend/testdata/cte_count/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/cte_count/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/cte_filter/mysql/go/db.go create mode 100644 internal/endtoend/testdata/cte_filter/mysql/go/models.go create mode 100644 internal/endtoend/testdata/cte_filter/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_filter/mysql/query.sql create mode 100644 internal/endtoend/testdata/cte_filter/mysql/schema.sql create mode 100644 internal/endtoend/testdata/cte_filter/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/cte_filter/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/cte_filter/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/cte_filter/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_filter/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/cte_filter/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/cte_filter/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/cte_filter/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/cte_filter/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/cte_filter/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_filter/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/cte_filter/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/cte_filter/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/cte_filter/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/cte_filter/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/cte_filter/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_filter/stdlib/query.sql create mode 100644 internal/endtoend/testdata/cte_filter/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/cte_filter/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/cte_in_delete/mysql/go/db.go create mode 100644 internal/endtoend/testdata/cte_in_delete/mysql/go/models.go create mode 100644 internal/endtoend/testdata/cte_in_delete/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_in_delete/mysql/query.sql create mode 100644 internal/endtoend/testdata/cte_in_delete/mysql/schema.sql create mode 100644 internal/endtoend/testdata/cte_in_delete/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/cte_in_delete/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/cte_in_delete/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/cte_in_delete/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_in_delete/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/cte_in_delete/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/cte_in_delete/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/cte_in_delete/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/cte_in_delete/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/cte_in_delete/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_in_delete/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/cte_in_delete/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/cte_in_delete/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/cte_in_delete/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/cte_in_delete/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/cte_in_delete/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_in_delete/stdlib/query.sql create mode 100644 internal/endtoend/testdata/cte_in_delete/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/cte_in_delete/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/cte_join_self/issue.md create mode 100644 internal/endtoend/testdata/cte_join_self/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/cte_join_self/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/cte_join_self/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/cte_join_self/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_join_self/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/cte_join_self/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/cte_join_self/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/cte_left_join/issue.md create mode 100644 internal/endtoend/testdata/cte_left_join/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/cte_left_join/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/cte_left_join/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/cte_left_join/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_left_join/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/cte_left_join/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/cte_left_join/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/cte_multiple_alias/issue.md create mode 100644 internal/endtoend/testdata/cte_multiple_alias/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/cte_multiple_alias/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/cte_multiple_alias/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_multiple_alias/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/cte_multiple_alias/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/cte_multiple_alias/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/cte_nested_with/issue.md create mode 100644 internal/endtoend/testdata/cte_nested_with/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/cte_nested_with/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/cte_nested_with/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/cte_nested_with/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_nested_with/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/cte_nested_with/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/cte_nested_with/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/cte_recursive/mysql/go/db.go create mode 100644 internal/endtoend/testdata/cte_recursive/mysql/go/models.go create mode 100644 internal/endtoend/testdata/cte_recursive/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_recursive/mysql/query.sql create mode 100644 internal/endtoend/testdata/cte_recursive/mysql/schema.sql create mode 100644 internal/endtoend/testdata/cte_recursive/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/cte_recursive/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/cte_recursive/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/cte_recursive/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_recursive/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/cte_recursive/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/cte_recursive/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/cte_recursive/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/cte_recursive/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/cte_recursive/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_recursive/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/cte_recursive/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/cte_recursive/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/cte_recursive/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/cte_recursive/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/cte_recursive/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_recursive/stdlib/query.sql create mode 100644 internal/endtoend/testdata/cte_recursive/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/cte_recursive/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/cte_recursive_employees/issue.md create mode 100644 internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/cte_recursive_star/issue.md create mode 100644 internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/cte_recursive_subquery/issue.md create mode 100644 internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/cte_recursive_union/issue.md create mode 100644 internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/cte_select_one/issue.md create mode 100644 internal/endtoend/testdata/cte_select_one/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/cte_select_one/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/cte_select_one/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_select_one/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/cte_select_one/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/cte_select_one/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/cte_update/issue.md create mode 100644 internal/endtoend/testdata/cte_update/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/cte_update/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/cte_update/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/cte_update/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_update/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/cte_update/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/cte_update/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/cte_update_multiple/issue.md create mode 100644 internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/cte_with_in/issue.md create mode 100644 internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/exec.json create mode 100644 internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/go/db.go create mode 100644 internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/go/models.go create mode 100644 internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/go/query.sql.go create mode 100644 internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/query.sql create mode 100644 internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/schema.sql create mode 100644 internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/sqlc.json create mode 100644 internal/endtoend/testdata/data_type_boolean/mysql/db/db.go create mode 100644 internal/endtoend/testdata/data_type_boolean/mysql/db/models.go create mode 100644 internal/endtoend/testdata/data_type_boolean/mysql/db/query.sql.go create mode 100644 internal/endtoend/testdata/data_type_boolean/mysql/query.sql create mode 100644 internal/endtoend/testdata/data_type_boolean/mysql/schema.sql create mode 100644 internal/endtoend/testdata/data_type_boolean/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/data_type_boolean/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/data_type_boolean/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/data_type_boolean/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/data_type_boolean/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/data_type_boolean/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/data_type_boolean/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/data_type_boolean/sqlite/db/db.go create mode 100644 internal/endtoend/testdata/data_type_boolean/sqlite/db/models.go create mode 100644 internal/endtoend/testdata/data_type_boolean/sqlite/db/query.sql.go create mode 100644 internal/endtoend/testdata/data_type_boolean/sqlite/query.sql create mode 100644 internal/endtoend/testdata/data_type_boolean/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/data_type_boolean/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/datatype/mysql/go/db.go create mode 100644 internal/endtoend/testdata/datatype/mysql/go/models.go create mode 100644 internal/endtoend/testdata/datatype/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/datatype/mysql/sql/character.sql create mode 100644 internal/endtoend/testdata/datatype/mysql/sql/datetime.sql create mode 100644 internal/endtoend/testdata/datatype/mysql/sql/numeric.sql create mode 100644 internal/endtoend/testdata/datatype/mysql/sql/query.sql create mode 100644 internal/endtoend/testdata/datatype/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/datatype/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/datatype/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/datatype/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/datatype/pgx/v4/sql/character.sql create mode 100644 internal/endtoend/testdata/datatype/pgx/v4/sql/datetime.sql create mode 100644 internal/endtoend/testdata/datatype/pgx/v4/sql/net-types.sql create mode 100644 internal/endtoend/testdata/datatype/pgx/v4/sql/numeric.sql create mode 100644 internal/endtoend/testdata/datatype/pgx/v4/sql/query.sql create mode 100644 internal/endtoend/testdata/datatype/pgx/v4/sql/rangetypes.sql create mode 100644 internal/endtoend/testdata/datatype/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/datatype/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/datatype/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/datatype/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/datatype/pgx/v5/sql/character.sql create mode 100644 internal/endtoend/testdata/datatype/pgx/v5/sql/datetime.sql create mode 100644 internal/endtoend/testdata/datatype/pgx/v5/sql/net-types.sql create mode 100644 internal/endtoend/testdata/datatype/pgx/v5/sql/numeric.sql create mode 100644 internal/endtoend/testdata/datatype/pgx/v5/sql/query.sql create mode 100644 internal/endtoend/testdata/datatype/pgx/v5/sql/rangetypes.sql create mode 100644 internal/endtoend/testdata/datatype/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/datatype/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/datatype/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/datatype/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/datatype/sqlite/sql/character.sql create mode 100644 internal/endtoend/testdata/datatype/sqlite/sql/datetime.sql create mode 100644 internal/endtoend/testdata/datatype/sqlite/sql/numeric.sql create mode 100644 internal/endtoend/testdata/datatype/sqlite/sql/query.sql create mode 100644 internal/endtoend/testdata/datatype/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/datatype/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/datatype/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/datatype/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/datatype/stdlib/sql/character.sql create mode 100644 internal/endtoend/testdata/datatype/stdlib/sql/datetime.sql create mode 100644 internal/endtoend/testdata/datatype/stdlib/sql/net-types.sql create mode 100644 internal/endtoend/testdata/datatype/stdlib/sql/numeric.sql create mode 100644 internal/endtoend/testdata/datatype/stdlib/sql/query.sql create mode 100644 internal/endtoend/testdata/datatype/stdlib/sql/rangetypes.sql create mode 100644 internal/endtoend/testdata/datatype/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/issue.md create mode 100644 internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/mysql/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/mysql/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/mysql/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/mysql/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/sqlite/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_case_sensitivity/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_case_sensitivity/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_case_sensitivity/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_case_sensitivity/sqlite/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_case_sensitivity/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_case_sensitivity/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/mysql/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/mysql/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/mysql/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/mysql/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/mysql/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/mysql/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/mysql/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/mysql/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/mysql/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/mysql/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/mysql/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/mysql/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/sqlite/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/exec.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/exec.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_index/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_index/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_index/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_index/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_index/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_index/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/mysql/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/mysql/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/mysql/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/mysql/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/sqlite/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/mysql/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/mysql/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/mysql/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/mysql/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/sqlite/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_rename_column/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_data_type/mysql/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_data_type/mysql/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_data_type/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_data_type/mysql/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_data_type/mysql/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_data_type/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_not_null/mysql/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_not_null/mysql/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_not_null/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_not_null/mysql/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_not_null/mysql/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_not_null/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_schema/mysql/README.md create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_type_add_value/mysql/README.md create mode 100644 internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_value/mysql/README.md create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_comment/mysql/README.md create mode 100644 internal/endtoend/testdata/ddl_comment/mysql/go/db.go create mode 100644 internal/endtoend/testdata/ddl_comment/mysql/go/models.go create mode 100644 internal/endtoend/testdata/ddl_comment/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_comment/mysql/query.sql create mode 100644 internal/endtoend/testdata/ddl_comment/mysql/schema.sql create mode 100644 internal/endtoend/testdata/ddl_comment/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_comment/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_comment/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_comment/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_comment/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_comment/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_comment/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_comment/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_comment/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_comment/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_comment/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_comment/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_comment/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_comment/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_comment/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_comment/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_comment/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_comment/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_comment/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_enum/mysql/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_enum/mysql/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_enum/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_enum/mysql/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_enum/mysql/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_enum/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_enum/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_enum/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_enum/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_enum/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_enum/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_enum/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_func_exists/exec.json create mode 100644 internal/endtoend/testdata/ddl_create_func_exists/mysql/README.md create mode 100644 internal/endtoend/testdata/ddl_create_func_exists/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_func_exists/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_func_exists/stderr.txt create mode 100644 internal/endtoend/testdata/ddl_create_function/mysql/README.md create mode 100644 internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_function/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_function/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_function/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_function/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_function/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_function/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_function_args/mysql/README.md create mode 100644 internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_function_args/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_function_args/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_function_args/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_function_args/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_function_args/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_function_args/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_function_return/mysql/README.md create mode 100644 internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_function_return/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_function_return/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_function_return/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_function_return/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_function_return/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_function_return/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_function_types/mysql/README.md create mode 100644 internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_function_types/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_function_types/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_function_types/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_function_types/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_function_types/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_function_types/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_procedure/mysql/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_procedure/mysql/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_procedure/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_procedure/mysql/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_procedure/mysql/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_procedure/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_procedure/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_procedure/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_procedure/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_procedure/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_procedure/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_procedure/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_table/mysql/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_table/mysql/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_table/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_table/mysql/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_table/mysql/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_table/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_table/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_table/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_table/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_table/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_table/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_table/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_table/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_table/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_table/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_table/sqlite/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_table/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_table/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_table_include/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_table_include/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_table_include/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_table_include/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_include/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_include/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_table_invalid_inherits/postgresql/stdlib/exec.json create mode 100644 internal/endtoend/testdata/ddl_create_table_invalid_inherits/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_invalid_inherits/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_invalid_inherits/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_table_invalid_inherits/postgresql/stdlib/stderr.txt create mode 100644 internal/endtoend/testdata/ddl_create_table_like/issue.md create mode 100644 internal/endtoend/testdata/ddl_create_table_like/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_table_like/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_table_like/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_table_like/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_like/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_like/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_table_partition/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_table_partition/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_table_partition/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_table_partition/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_partition/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_partition/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_table_reserved/mysql/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_table_reserved/mysql/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_table_reserved/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_table_reserved/mysql/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_reserved/mysql/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_reserved/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_table_reserved/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_table_reserved/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_table_reserved/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_table_reserved/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_reserved/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_reserved/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_table_strict/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_table_strict/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_table_strict/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_table_strict/sqlite/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_strict/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_strict/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_table_unknown_type/issue.md create mode 100644 internal/endtoend/testdata/ddl_create_table_unknown_type/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/ddl_create_table_unknown_type/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_unknown_type/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_unknown_type/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/ddl_create_table_unknown_type/postgresql/pgx/stderr.txt create mode 100644 internal/endtoend/testdata/ddl_create_table_without_rowid/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_table_without_rowid/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_table_without_rowid/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_table_without_rowid/sqlite/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_without_rowid/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_table_without_rowid/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_trigger/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_trigger/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_trigger/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_trigger/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_trigger/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_trigger/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_create_trigger/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/ddl_create_trigger/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/ddl_create_trigger/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_create_trigger/sqlite/query.sql create mode 100644 internal/endtoend/testdata/ddl_create_trigger/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/ddl_create_trigger/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_function/mysql/README.md create mode 100644 internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_function/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_function/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_function/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_function/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_function/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_function/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_function_args/mysql/README.md create mode 100644 internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_function_args/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_function_args/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_function_args/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_function_args/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_function_args/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_function_args/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_function_if_exists/mysql/README.md create mode 100644 internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_schema/mysql/exec.json create mode 100644 internal/endtoend/testdata/ddl_drop_schema/mysql/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_schema/mysql/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_schema/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_schema/mysql/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_schema/mysql/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_schema/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_schema/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_schema/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_schema/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_schema/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_schema/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_schema/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_table/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_table/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_table/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_table/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_table/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_table/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_table/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_table/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_table/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_table/sqlite/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_table/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_table/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_table_if_exists/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_table_if_exists/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_table_if_exists/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_table_if_exists/sqlite/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_table_if_exists/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_table_if_exists/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_type/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_type/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_type/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_type/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_type/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_type/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_generated_columns/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_generated_columns/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_generated_columns/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_generated_columns/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_generated_columns/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_generated_columns/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_materialized_views_invalid/issue.md create mode 100644 internal/endtoend/testdata/ddl_materialized_views_invalid/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/ddl_materialized_views_invalid/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/ddl_materialized_views_invalid/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/ddl_materialized_views_invalid/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/ddl_materialized_views_invalid/postgresql/pgx/stderr.txt create mode 100644 internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_pg_temp/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_pg_temp/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_pg_temp/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_pg_temp/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_pg_temp/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_pg_temp/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_rename_drop_materialized_views/issue.md create mode 100644 internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/exec.json create mode 100644 internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/sqlc.yaml create mode 100644 internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/exec.json create mode 100644 internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/sqlc.yaml create mode 100644 internal/endtoend/testdata/delete_from/mysql/go/db.go create mode 100644 internal/endtoend/testdata/delete_from/mysql/go/models.go create mode 100644 internal/endtoend/testdata/delete_from/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/delete_from/mysql/query.sql create mode 100644 internal/endtoend/testdata/delete_from/mysql/schema.sql create mode 100644 internal/endtoend/testdata/delete_from/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/delete_from/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/delete_from/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/delete_from/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/delete_from/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/delete_from/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/delete_from/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/delete_from/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/delete_from/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/delete_from/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/delete_from/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/delete_from/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/delete_from/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/delete_from/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/delete_from/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/delete_from/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/delete_from/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/delete_from/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/delete_from/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/delete_from/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/delete_from/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/delete_from/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/delete_from/sqlite/query.sql create mode 100644 internal/endtoend/testdata/delete_from/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/delete_from/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/delete_inner_join/mysql/go/db.go create mode 100644 internal/endtoend/testdata/delete_inner_join/mysql/go/models.go create mode 100644 internal/endtoend/testdata/delete_inner_join/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/delete_inner_join/mysql/query.sql create mode 100644 internal/endtoend/testdata/delete_inner_join/mysql/schema.sql create mode 100644 internal/endtoend/testdata/delete_inner_join/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/delete_join/mysql/db/db.go create mode 100644 internal/endtoend/testdata/delete_join/mysql/db/models.go create mode 100644 internal/endtoend/testdata/delete_join/mysql/db/query.sql.go create mode 100644 internal/endtoend/testdata/delete_join/mysql/query.sql create mode 100644 internal/endtoend/testdata/delete_join/mysql/schema.sql create mode 100644 internal/endtoend/testdata/delete_join/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/delete_using/issue.md create mode 100644 internal/endtoend/testdata/delete_using/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/delete_using/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/delete_using/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/delete_using/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/delete_using/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/delete_using/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/delete_using/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/diff_no_output/exec.json create mode 100644 internal/endtoend/testdata/diff_no_output/go/db.go create mode 100644 internal/endtoend/testdata/diff_no_output/go/models.go create mode 100644 internal/endtoend/testdata/diff_no_output/go/query.sql.go create mode 100644 internal/endtoend/testdata/diff_no_output/query.sql create mode 100644 internal/endtoend/testdata/diff_no_output/schema.sql create mode 100644 internal/endtoend/testdata/diff_no_output/sqlc.json create mode 100644 internal/endtoend/testdata/diff_output/exec.json create mode 100644 internal/endtoend/testdata/diff_output/go/db.go create mode 100644 internal/endtoend/testdata/diff_output/go/models.go create mode 100644 internal/endtoend/testdata/diff_output/go/query.sql.go create mode 100644 internal/endtoend/testdata/diff_output/query.sql create mode 100644 internal/endtoend/testdata/diff_output/schema.sql create mode 100644 internal/endtoend/testdata/diff_output/sqlc.json create mode 100644 internal/endtoend/testdata/diff_output/stderr.txt create mode 100644 internal/endtoend/testdata/do/postgresql/pgx/db/db.go create mode 100644 internal/endtoend/testdata/do/postgresql/pgx/db/models.go create mode 100644 internal/endtoend/testdata/do/postgresql/pgx/db/query.sql.go create mode 100644 internal/endtoend/testdata/do/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/do/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/do/postgresql/pgx/sqlc.json create mode 100644 internal/endtoend/testdata/do/postgresql/pq/db/db.go create mode 100644 internal/endtoend/testdata/do/postgresql/pq/db/models.go create mode 100644 internal/endtoend/testdata/do/postgresql/pq/db/query.sql.go create mode 100644 internal/endtoend/testdata/do/postgresql/pq/query.sql create mode 100644 internal/endtoend/testdata/do/postgresql/pq/schema.sql create mode 100644 internal/endtoend/testdata/do/postgresql/pq/sqlc.json create mode 100644 internal/endtoend/testdata/duplicate_go_names/enum/query.sql create mode 100644 internal/endtoend/testdata/duplicate_go_names/enum/schema.sql create mode 100644 internal/endtoend/testdata/duplicate_go_names/enum/sqlc.yaml create mode 100644 internal/endtoend/testdata/duplicate_go_names/enum/stderr.txt create mode 100644 internal/endtoend/testdata/duplicate_go_names/null_enum/query.sql create mode 100644 internal/endtoend/testdata/duplicate_go_names/null_enum/schema.sql create mode 100644 internal/endtoend/testdata/duplicate_go_names/null_enum/sqlc.yaml create mode 100644 internal/endtoend/testdata/duplicate_go_names/null_enum/stderr.txt create mode 100644 internal/endtoend/testdata/duplicate_go_names/query_constant/query.sql create mode 100644 internal/endtoend/testdata/duplicate_go_names/query_constant/schema.sql create mode 100644 internal/endtoend/testdata/duplicate_go_names/query_constant/sqlc.yaml create mode 100644 internal/endtoend/testdata/duplicate_go_names/query_constant/stderr.txt create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/mysql/go/db.go create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/mysql/go/models.go create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/mysql/query.sql create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/mysql/schema.sql create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/sqlite/query.sql create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/emit_db_and_json_tags/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/emit_db_tags/mysql/go/db.go create mode 100644 internal/endtoend/testdata/emit_db_tags/mysql/go/models.go create mode 100644 internal/endtoend/testdata/emit_db_tags/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_db_tags/mysql/query.sql create mode 100644 internal/endtoend/testdata/emit_db_tags/mysql/schema.sql create mode 100644 internal/endtoend/testdata/emit_db_tags/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/emit_db_tags/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/emit_db_tags/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/emit_db_tags/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_db_tags/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/emit_db_tags/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/emit_db_tags/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/emit_db_tags/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/emit_db_tags/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/emit_db_tags/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_db_tags/sqlite/query.sql create mode 100644 internal/endtoend/testdata/emit_db_tags/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/emit_db_tags/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/emit_empty_slices/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/emit_empty_slices/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/emit_empty_slices/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_empty_slices/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/emit_empty_slices/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/emit_empty_slices/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/emit_empty_slices/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/emit_empty_slices/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/emit_empty_slices/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_empty_slices/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/emit_empty_slices/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/emit_empty_slices/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/emit_empty_slices/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/emit_empty_slices/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/emit_empty_slices/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_empty_slices/stdlib/query.sql create mode 100644 internal/endtoend/testdata/emit_empty_slices/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/emit_empty_slices/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/emit_enum_valid_and_values/go/db.go create mode 100644 internal/endtoend/testdata/emit_enum_valid_and_values/go/models.go create mode 100644 internal/endtoend/testdata/emit_enum_valid_and_values/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_enum_valid_and_values/query.sql create mode 100644 internal/endtoend/testdata/emit_enum_valid_and_values/schema.sql create mode 100644 internal/endtoend/testdata/emit_enum_valid_and_values/sqlc.json create mode 100644 internal/endtoend/testdata/emit_exported_queries/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/emit_exported_queries/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/emit_exported_queries/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_exported_queries/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/emit_exported_queries/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/emit_exported_queries/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/emit_exported_queries/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/emit_exported_queries/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/emit_exported_queries/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_exported_queries/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/emit_exported_queries/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/emit_exported_queries/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/emit_exported_queries/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/emit_exported_queries/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/emit_exported_queries/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_exported_queries/stdlib/query.sql create mode 100644 internal/endtoend/testdata/emit_exported_queries/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/emit_exported_queries/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/mysql/go/db.go create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/mysql/go/models.go create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/mysql/query.sql create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/mysql/schema.sql create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/sqlite/query.sql create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/emit_methods_with_db_argument/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_enum_types/optin/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_enum_types/optin/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_enum_types/optin/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_enum_types/optin/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_enum_types/optin/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_enum_types/optin/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_enum_types/optout/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_enum_types/optout/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_enum_types/optout/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_enum_types/optout/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_enum_types/optout/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_enum_types/optout/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sql/character.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sql/datetime.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sql/net-types.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sql/numeric.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sql/query.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sql/rangetypes.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sql/character.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sql/datetime.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sql/net-types.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sql/numeric.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sql/query.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sql/rangetypes.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/sqlite/sql/query.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/sqlite/sql/types.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sql/character.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sql/datetime.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sql/net-types.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sql/numeric.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sql/query.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sql/rangetypes.sql create mode 100644 internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/go/db.go create mode 100644 internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/go/models.go create mode 100644 internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/go/querier.go create mode 100644 internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/query.sql create mode 100644 internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/schema.sql create mode 100644 internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/go/batch.go create mode 100644 internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/go/batch.go create mode 100644 internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/emit_sql_as_comment/stdlib/exec.json create mode 100644 internal/endtoend/testdata/emit_sql_as_comment/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/emit_sql_as_comment/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/emit_sql_as_comment/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/emit_sql_as_comment/stdlib/query.sql create mode 100644 internal/endtoend/testdata/emit_sql_as_comment/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/emit_sql_as_comment/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/enum/mysql/go/db.go create mode 100644 internal/endtoend/testdata/enum/mysql/go/models.go create mode 100644 internal/endtoend/testdata/enum/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/enum/mysql/query.sql create mode 100644 internal/endtoend/testdata/enum/mysql/schema.sql create mode 100644 internal/endtoend/testdata/enum/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/enum/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/enum/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/enum/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/enum/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/enum/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/enum/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/enum/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/enum/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/enum/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/enum/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/enum/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/enum/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/enum/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/enum/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/enum/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/enum/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/enum/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/enum/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/enum_column/issue.md create mode 100644 internal/endtoend/testdata/enum_column/mysql/go/db.go create mode 100644 internal/endtoend/testdata/enum_column/mysql/go/models.go create mode 100644 internal/endtoend/testdata/enum_column/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/enum_column/mysql/query.sql create mode 100644 internal/endtoend/testdata/enum_column/mysql/schema.sql create mode 100644 internal/endtoend/testdata/enum_column/mysql/sqlc.yaml create mode 100644 internal/endtoend/testdata/enum_ordering/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/enum_ordering/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/enum_ordering/postgresql/stdlib/go/querier.go create mode 100644 internal/endtoend/testdata/enum_ordering/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/enum_ordering/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/enum_ordering/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/enum_ordering/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/exec_create_table/mysql/db/db.go create mode 100644 internal/endtoend/testdata/exec_create_table/mysql/db/models.go create mode 100644 internal/endtoend/testdata/exec_create_table/mysql/db/mysql.query.sql.go create mode 100644 internal/endtoend/testdata/exec_create_table/mysql/mysql.query.sql create mode 100644 internal/endtoend/testdata/exec_create_table/mysql/mysql.schema.sql create mode 100644 internal/endtoend/testdata/exec_create_table/mysql/sqlc.yaml create mode 100644 internal/endtoend/testdata/exec_create_table/postgresql/db/db.go create mode 100644 internal/endtoend/testdata/exec_create_table/postgresql/db/models.go create mode 100644 internal/endtoend/testdata/exec_create_table/postgresql/db/postgresql.query.sql.go create mode 100644 internal/endtoend/testdata/exec_create_table/postgresql/postgresql.query.sql create mode 100644 internal/endtoend/testdata/exec_create_table/postgresql/postgresql.schema.sql create mode 100644 internal/endtoend/testdata/exec_create_table/postgresql/sqlc.yaml create mode 100644 internal/endtoend/testdata/exec_create_table/sqlite/db/db.go create mode 100644 internal/endtoend/testdata/exec_create_table/sqlite/db/models.go create mode 100644 internal/endtoend/testdata/exec_create_table/sqlite/db/sqlite.query.sql.go create mode 100644 internal/endtoend/testdata/exec_create_table/sqlite/sqlc.yaml create mode 100644 internal/endtoend/testdata/exec_create_table/sqlite/sqlite.query.sql create mode 100644 internal/endtoend/testdata/exec_create_table/sqlite/sqlite.schema.sql create mode 100644 internal/endtoend/testdata/exec_imports/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/exec_imports/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/exec_imports/pgx/v4/go/querier.go create mode 100644 internal/endtoend/testdata/exec_imports/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/exec_imports/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/exec_imports/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/exec_imports/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/exec_imports/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/exec_imports/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/exec_imports/pgx/v5/go/querier.go create mode 100644 internal/endtoend/testdata/exec_imports/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/exec_imports/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/exec_imports/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/exec_imports/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/exec_imports/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/exec_imports/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/exec_imports/stdlib/go/querier.go create mode 100644 internal/endtoend/testdata/exec_imports/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/exec_imports/stdlib/query.sql create mode 100644 internal/endtoend/testdata/exec_imports/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/exec_imports/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/db.go create mode 100644 internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/models.go create mode 100644 internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/querier.go create mode 100644 internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/query.sql create mode 100644 internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/schema.sql create mode 100644 internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/exec_no_return_struct/issue.md create mode 100644 internal/endtoend/testdata/exec_no_return_struct/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/exec_no_return_struct/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/exec_no_return_struct/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/exec_no_return_struct/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/exec_no_return_struct/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/exec_no_return_struct/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/go/querier.go create mode 100644 internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/go/querier.go create mode 100644 internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/exec_result/go_postgresql_stdlib/go/db.go create mode 100644 internal/endtoend/testdata/exec_result/go_postgresql_stdlib/go/models.go create mode 100644 internal/endtoend/testdata/exec_result/go_postgresql_stdlib/go/querier.go create mode 100644 internal/endtoend/testdata/exec_result/go_postgresql_stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/exec_result/go_postgresql_stdlib/query.sql create mode 100644 internal/endtoend/testdata/exec_result/go_postgresql_stdlib/schema.sql create mode 100644 internal/endtoend/testdata/exec_result/go_postgresql_stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/go/querier.go create mode 100644 internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/go/querier.go create mode 100644 internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/go/db.go create mode 100644 internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/go/models.go create mode 100644 internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/go/querier.go create mode 100644 internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/query.sql create mode 100644 internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/schema.sql create mode 100644 internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/experiment_coreanalyzer/mysql/exec.json create mode 100644 internal/endtoend/testdata/experiment_coreanalyzer/mysql/go/db.go create mode 100644 internal/endtoend/testdata/experiment_coreanalyzer/mysql/go/models.go create mode 100644 internal/endtoend/testdata/experiment_coreanalyzer/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/experiment_coreanalyzer/mysql/query.sql create mode 100644 internal/endtoend/testdata/experiment_coreanalyzer/mysql/schema.sql create mode 100644 internal/endtoend/testdata/experiment_coreanalyzer/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/exec.json create mode 100644 internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/experiment_coreanalyzer/sqlite/exec.json create mode 100644 internal/endtoend/testdata/experiment_coreanalyzer/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/experiment_coreanalyzer/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/experiment_coreanalyzer/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/experiment_coreanalyzer/sqlite/query.sql create mode 100644 internal/endtoend/testdata/experiment_coreanalyzer/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/experiment_coreanalyzer/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/fmt/mysql/exec.json create mode 100644 internal/endtoend/testdata/fmt/mysql/query.sql create mode 100644 internal/endtoend/testdata/fmt/mysql/schema.sql create mode 100644 internal/endtoend/testdata/fmt/mysql/sqlc.yaml create mode 100644 internal/endtoend/testdata/fmt/mysql/stdout.txt create mode 100644 internal/endtoend/testdata/fmt/postgresql/exec.json create mode 100644 internal/endtoend/testdata/fmt/postgresql/query.sql create mode 100644 internal/endtoend/testdata/fmt/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/fmt/postgresql/sqlc.yaml create mode 100644 internal/endtoend/testdata/fmt/postgresql/stdout.txt create mode 100644 internal/endtoend/testdata/fmt/sqlite/exec.json create mode 100644 internal/endtoend/testdata/fmt/sqlite/query.sql create mode 100644 internal/endtoend/testdata/fmt/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/fmt/sqlite/sqlc.yaml create mode 100644 internal/endtoend/testdata/fmt/sqlite/stdout.txt create mode 100644 internal/endtoend/testdata/full_outer_join/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/full_outer_join/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/full_outer_join/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/full_outer_join/sqlite/query.sql create mode 100644 internal/endtoend/testdata/full_outer_join/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/full_outer_join/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/func_aggregate/pganalyze/exec.json create mode 100644 internal/endtoend/testdata/func_aggregate/pganalyze/go/db.go create mode 100644 internal/endtoend/testdata/func_aggregate/pganalyze/go/models.go create mode 100644 internal/endtoend/testdata/func_aggregate/pganalyze/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_aggregate/pganalyze/query.sql create mode 100644 internal/endtoend/testdata/func_aggregate/pganalyze/schema.sql create mode 100644 internal/endtoend/testdata/func_aggregate/pganalyze/sqlc.json create mode 100644 internal/endtoend/testdata/func_aggregate/postgresql/exec.json create mode 100644 internal/endtoend/testdata/func_aggregate/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/func_aggregate/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/func_aggregate/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_aggregate/postgresql/query.sql create mode 100644 internal/endtoend/testdata/func_aggregate/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/func_aggregate/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/func_args/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/func_args/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/func_args/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_args/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/func_args/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/func_args/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/func_args/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/func_args/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/func_args/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_args/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/func_args/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/func_args/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/func_args/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/func_args/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/func_args/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_args/stdlib/query.sql create mode 100644 internal/endtoend/testdata/func_args/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/func_args/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/func_args_typecast/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/func_args_typecast/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/func_args_typecast/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_args_typecast/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/func_args_typecast/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/func_args_typecast/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/func_args_typecast/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/func_args_typecast/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/func_args_typecast/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_args_typecast/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/func_args_typecast/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/func_args_typecast/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/func_args_typecast/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/func_args_typecast/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/func_args_typecast/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_args_typecast/stdlib/query.sql create mode 100644 internal/endtoend/testdata/func_args_typecast/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/func_args_typecast/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/func_call_cast/mysql/go/db.go create mode 100644 internal/endtoend/testdata/func_call_cast/mysql/go/models.go create mode 100644 internal/endtoend/testdata/func_call_cast/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_call_cast/mysql/query.sql create mode 100644 internal/endtoend/testdata/func_call_cast/mysql/schema.sql create mode 100644 internal/endtoend/testdata/func_call_cast/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/func_call_cast/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/func_call_cast/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/func_call_cast/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_call_cast/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/func_call_cast/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/func_call_cast/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/func_call_cast/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/func_call_cast/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/func_call_cast/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_call_cast/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/func_call_cast/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/func_call_cast/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/func_call_cast/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/func_call_cast/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/func_call_cast/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_call_cast/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/func_call_cast/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/func_call_cast/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/func_call_cast/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/func_call_cast/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/func_call_cast/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_call_cast/sqlite/query.sql create mode 100644 internal/endtoend/testdata/func_call_cast/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/func_call_cast/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/func_match_types/mysql/go/db.go create mode 100644 internal/endtoend/testdata/func_match_types/mysql/go/models.go create mode 100644 internal/endtoend/testdata/func_match_types/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_match_types/mysql/query.sql create mode 100644 internal/endtoend/testdata/func_match_types/mysql/schema.sql create mode 100644 internal/endtoend/testdata/func_match_types/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/func_match_types/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/func_match_types/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/func_match_types/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_match_types/postgresql/query.sql create mode 100644 internal/endtoend/testdata/func_match_types/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/func_match_types/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/func_match_types/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/func_match_types/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/func_match_types/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_match_types/sqlite/query.sql create mode 100644 internal/endtoend/testdata/func_match_types/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/func_match_types/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/func_out_param/issue.md create mode 100644 internal/endtoend/testdata/func_out_param/pgx/go/db.go create mode 100644 internal/endtoend/testdata/func_out_param/pgx/go/models.go create mode 100644 internal/endtoend/testdata/func_out_param/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_out_param/pgx/query.sql create mode 100644 internal/endtoend/testdata/func_out_param/pgx/schema.sql create mode 100644 internal/endtoend/testdata/func_out_param/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/func_return_date/postgresql/pganalyze/exec.json create mode 100644 internal/endtoend/testdata/func_return_date/postgresql/pganalyze/go/db.go create mode 100644 internal/endtoend/testdata/func_return_date/postgresql/pganalyze/go/models.go create mode 100644 internal/endtoend/testdata/func_return_date/postgresql/pganalyze/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_return_date/postgresql/pganalyze/query.sql create mode 100644 internal/endtoend/testdata/func_return_date/postgresql/pganalyze/schema.sql create mode 100644 internal/endtoend/testdata/func_return_date/postgresql/pganalyze/sqlc.json create mode 100644 internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/exec.json create mode 100644 internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/func_return_date/postgresql/stdlib/exec.json create mode 100644 internal/endtoend/testdata/func_return_date/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/func_return_date/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/func_return_date/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_return_date/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/func_return_date/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/func_return_date/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/func_return_record/issue.md create mode 100644 internal/endtoend/testdata/func_return_record/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/func_return_record/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/func_return_record/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/func_return_record/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_return_record/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/func_return_record/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/func_return_record/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/func_return_series/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/func_return_series/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/func_return_series/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_return_series/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/func_return_series/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/func_return_series/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/func_return_series/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/func_return_series/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/func_return_series/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_return_series/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/func_return_series/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/func_return_series/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/func_return_series/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/func_return_series/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/func_return_series/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_return_series/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/func_return_series/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/func_return_series/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/func_return_table/issue.md create mode 100644 internal/endtoend/testdata/func_return_table/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/func_return_table/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/func_return_table/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/func_return_table/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_return_table/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/func_return_table/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/func_return_table/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/func_return_table_columns/issue.md create mode 100644 internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/func_star_expansion/issue.md create mode 100644 internal/endtoend/testdata/func_star_expansion/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/func_star_expansion/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/func_star_expansion/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/func_star_expansion/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_star_expansion/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/func_star_expansion/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/func_star_expansion/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/func_variadic/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/func_variadic/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/func_variadic/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/func_variadic/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/func_variadic/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/func_variadic/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/geometric/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/geometric/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/geometric/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/geometric/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/geometric/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/geometric/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/geometric/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/geometric/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/geometric/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/geometric/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/geometric/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/geometric/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/go.mod create mode 100644 internal/endtoend/testdata/go.sum create mode 100644 internal/endtoend/testdata/golang_initialisms_empty/db/db.go create mode 100644 internal/endtoend/testdata/golang_initialisms_empty/db/models.go create mode 100644 internal/endtoend/testdata/golang_initialisms_empty/db/query.sql.go create mode 100644 internal/endtoend/testdata/golang_initialisms_empty/query.sql create mode 100644 internal/endtoend/testdata/golang_initialisms_empty/schema.sql create mode 100644 internal/endtoend/testdata/golang_initialisms_empty/sqlc.json create mode 100644 internal/endtoend/testdata/golang_initialisms_url/db/db.go create mode 100644 internal/endtoend/testdata/golang_initialisms_url/db/models.go create mode 100644 internal/endtoend/testdata/golang_initialisms_url/db/query.sql.go create mode 100644 internal/endtoend/testdata/golang_initialisms_url/query.sql create mode 100644 internal/endtoend/testdata/golang_initialisms_url/schema.sql create mode 100644 internal/endtoend/testdata/golang_initialisms_url/sqlc.json create mode 100644 internal/endtoend/testdata/golang_invalid_sql_driver/db/db.go create mode 100644 internal/endtoend/testdata/golang_invalid_sql_driver/db/models.go create mode 100644 internal/endtoend/testdata/golang_invalid_sql_driver/db/query.sql.go create mode 100644 internal/endtoend/testdata/golang_invalid_sql_driver/query.sql create mode 100644 internal/endtoend/testdata/golang_invalid_sql_driver/schema.sql create mode 100644 internal/endtoend/testdata/golang_invalid_sql_driver/sqlc.json create mode 100644 internal/endtoend/testdata/golang_invalid_sql_driver/stderr.txt create mode 100644 internal/endtoend/testdata/golang_invalid_sql_package/db/db.go create mode 100644 internal/endtoend/testdata/golang_invalid_sql_package/db/models.go create mode 100644 internal/endtoend/testdata/golang_invalid_sql_package/db/query.sql.go create mode 100644 internal/endtoend/testdata/golang_invalid_sql_package/query.sql create mode 100644 internal/endtoend/testdata/golang_invalid_sql_package/schema.sql create mode 100644 internal/endtoend/testdata/golang_invalid_sql_package/sqlc.json create mode 100644 internal/endtoend/testdata/golang_invalid_sql_package/stderr.txt create mode 100644 internal/endtoend/testdata/having/mysql/go/db.go create mode 100644 internal/endtoend/testdata/having/mysql/go/models.go create mode 100644 internal/endtoend/testdata/having/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/having/mysql/query.sql create mode 100644 internal/endtoend/testdata/having/mysql/schema.sql create mode 100644 internal/endtoend/testdata/having/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/having/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/having/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/having/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/having/postgresql/query.sql create mode 100644 internal/endtoend/testdata/having/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/having/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/hstore/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/hstore/pgx/v4/go/hstore.sql.go create mode 100644 internal/endtoend/testdata/hstore/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/hstore/pgx/v4/hstore.sql create mode 100644 internal/endtoend/testdata/hstore/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/hstore/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/hstore/pgx/v5/go/hstore.sql.go create mode 100644 internal/endtoend/testdata/hstore/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/hstore/pgx/v5/hstore.sql create mode 100644 internal/endtoend/testdata/hstore/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/hstore/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/hstore/stdlib/go/hstore.sql.go create mode 100644 internal/endtoend/testdata/hstore/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/hstore/stdlib/hstore.sql create mode 100644 internal/endtoend/testdata/hstore/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/identical_tables/mysql/go/db.go create mode 100644 internal/endtoend/testdata/identical_tables/mysql/go/models.go create mode 100644 internal/endtoend/testdata/identical_tables/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/identical_tables/mysql/query.sql create mode 100644 internal/endtoend/testdata/identical_tables/mysql/schema.sql create mode 100644 internal/endtoend/testdata/identical_tables/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/identical_tables/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/identical_tables/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/identical_tables/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/identical_tables/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/identical_tables/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/identical_tables/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/identical_tables/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/identical_tables/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/identical_tables/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/identical_tables/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/identical_tables/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/identical_tables/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/identical_tables/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/identical_tables/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/identical_tables/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/identical_tables/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/identical_tables/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/identical_tables/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/identical_tables/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/identical_tables/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/identical_tables/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/identical_tables/sqlite/query.sql create mode 100644 internal/endtoend/testdata/identical_tables/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/identical_tables/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/identifier_case_sensitivity/db/db.go create mode 100644 internal/endtoend/testdata/identifier_case_sensitivity/db/models.go create mode 100644 internal/endtoend/testdata/identifier_case_sensitivity/db/query.sql.go create mode 100644 internal/endtoend/testdata/identifier_case_sensitivity/query.sql create mode 100644 internal/endtoend/testdata/identifier_case_sensitivity/schema.sql create mode 100644 internal/endtoend/testdata/identifier_case_sensitivity/sqlc.json create mode 100644 internal/endtoend/testdata/identifier_dollar_sign/db/db.go create mode 100644 internal/endtoend/testdata/identifier_dollar_sign/db/models.go create mode 100644 internal/endtoend/testdata/identifier_dollar_sign/db/query.sql.go create mode 100644 internal/endtoend/testdata/identifier_dollar_sign/query.sql create mode 100644 internal/endtoend/testdata/identifier_dollar_sign/schema.sql create mode 100644 internal/endtoend/testdata/identifier_dollar_sign/sqlc.json create mode 100644 internal/endtoend/testdata/in_union/mysql/go/db.go create mode 100644 internal/endtoend/testdata/in_union/mysql/go/models.go create mode 100644 internal/endtoend/testdata/in_union/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/in_union/mysql/query.sql create mode 100644 internal/endtoend/testdata/in_union/mysql/schema.sql create mode 100644 internal/endtoend/testdata/in_union/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/inflection/mysql/go/db.go create mode 100644 internal/endtoend/testdata/inflection/mysql/go/models.go create mode 100644 internal/endtoend/testdata/inflection/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/inflection/mysql/query.sql create mode 100644 internal/endtoend/testdata/inflection/mysql/schema.sql create mode 100644 internal/endtoend/testdata/inflection/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/inflection/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/inflection/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/inflection/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/inflection/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/inflection/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/inflection/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/inflection/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/inflection/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/inflection/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/inflection/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/inflection/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/inflection/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/inflection/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/inflection/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/inflection/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/inflection/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/inflection/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/inflection/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/inflection/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/inflection/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/inflection/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/inflection/sqlite/query.sql create mode 100644 internal/endtoend/testdata/inflection/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/inflection/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/insert_cte/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/insert_cte/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/insert_cte/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/insert_cte/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/insert_cte/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/insert_cte/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/insert_cte/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/insert_cte/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/insert_cte/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/insert_cte/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/insert_cte/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/insert_cte/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/insert_cte/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/insert_cte/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/insert_cte/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/insert_cte/stdlib/query.sql create mode 100644 internal/endtoend/testdata/insert_cte/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/insert_cte/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/insert_default_values/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/insert_default_values/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/insert_default_values/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/insert_default_values/sqlite/query.sql create mode 100644 internal/endtoend/testdata/insert_default_values/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/insert_default_values/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/insert_select/mysql/go/db.go create mode 100644 internal/endtoend/testdata/insert_select/mysql/go/models.go create mode 100644 internal/endtoend/testdata/insert_select/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/insert_select/mysql/query.sql create mode 100644 internal/endtoend/testdata/insert_select/mysql/schema.sql create mode 100644 internal/endtoend/testdata/insert_select/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/insert_select/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/insert_select/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/insert_select/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/insert_select/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/insert_select/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/insert_select/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/insert_select/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/insert_select/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/insert_select/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/insert_select/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/insert_select/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/insert_select/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/insert_select/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/insert_select/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/insert_select/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/insert_select/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/insert_select/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/insert_select/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/insert_select/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/insert_select/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/insert_select/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/insert_select/sqlite/query.sql create mode 100644 internal/endtoend/testdata/insert_select/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/insert_select/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/insert_select_case/issue.md create mode 100644 internal/endtoend/testdata/insert_select_case/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/insert_select_case/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/insert_select_case/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/insert_select_case/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/insert_select_case/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/insert_select_case/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/insert_select_case/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/insert_select_invalid/mysql/query.sql create mode 100644 internal/endtoend/testdata/insert_select_invalid/mysql/schema.sql create mode 100644 internal/endtoend/testdata/insert_select_invalid/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/insert_select_invalid/mysql/stderr.txt create mode 100644 internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v4/stderr/base.txt create mode 100644 internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v4/stderr/managed-db.txt create mode 100644 internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v5/stderr/base.txt create mode 100644 internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v5/stderr/managed-db.txt create mode 100644 internal/endtoend/testdata/insert_select_invalid/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/insert_select_invalid/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/insert_select_invalid/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/insert_select_invalid/postgresql/stdlib/stderr/base.txt create mode 100644 internal/endtoend/testdata/insert_select_invalid/postgresql/stdlib/stderr/managed-db.txt create mode 100644 internal/endtoend/testdata/insert_select_invalid/sqlite/exec.json create mode 100644 internal/endtoend/testdata/insert_select_invalid/sqlite/query.sql create mode 100644 internal/endtoend/testdata/insert_select_invalid/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/insert_select_invalid/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/insert_select_invalid/sqlite/stderr.txt create mode 100644 internal/endtoend/testdata/insert_select_param/issue.md create mode 100644 internal/endtoend/testdata/insert_select_param/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/insert_select_param/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/insert_select_param/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/insert_select_param/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/insert_select_param/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/insert_select_param/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/insert_select_param/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/insert_values/mysql/go/db.go create mode 100644 internal/endtoend/testdata/insert_values/mysql/go/models.go create mode 100644 internal/endtoend/testdata/insert_values/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/insert_values/mysql/query.sql create mode 100644 internal/endtoend/testdata/insert_values/mysql/schema.sql create mode 100644 internal/endtoend/testdata/insert_values/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/insert_values/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/insert_values/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/insert_values/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/insert_values/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/insert_values/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/insert_values/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/insert_values/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/insert_values/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/insert_values/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/insert_values/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/insert_values/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/insert_values/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/insert_values/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/insert_values/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/insert_values/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/insert_values/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/insert_values/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/insert_values/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/insert_values/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/insert_values/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/insert_values/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/insert_values/sqlite/query.sql create mode 100644 internal/endtoend/testdata/insert_values/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/insert_values/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/insert_values_only/issue.md create mode 100644 internal/endtoend/testdata/insert_values_only/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/insert_values_only/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/insert_values_only/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/insert_values_only/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/insert_values_only/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/insert_values_only/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/insert_values_only/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/insert_values_public/mysql/go/db.go create mode 100644 internal/endtoend/testdata/insert_values_public/mysql/go/models.go create mode 100644 internal/endtoend/testdata/insert_values_public/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/insert_values_public/mysql/query.sql create mode 100644 internal/endtoend/testdata/insert_values_public/mysql/schema.sql create mode 100644 internal/endtoend/testdata/insert_values_public/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/insert_values_public/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/insert_values_public/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/insert_values_public/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/insert_values_public/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/insert_values_public/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/insert_values_public/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/insert_values_public/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/insert_values_public/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/insert_values_public/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/insert_values_public/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/insert_values_public/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/insert_values_public/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/insert_values_public/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/insert_values_public/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/insert_values_public/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/insert_values_public/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/insert_values_public/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/insert_values_public/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/interval/pgx/v4/exec.json create mode 100644 internal/endtoend/testdata/interval/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/interval/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/interval/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/interval/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/interval/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/interval/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/interval/pgx/v5/exec.json create mode 100644 internal/endtoend/testdata/interval/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/interval/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/interval/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/interval/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/interval/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/interval/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/interval/stdlib/exec.json create mode 100644 internal/endtoend/testdata/interval/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/interval/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/interval/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/interval/stdlib/query.sql create mode 100644 internal/endtoend/testdata/interval/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/interval/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/invalid_func_args/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/invalid_func_args/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/invalid_func_args/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/invalid_func_args/pgx/v4/stderr/base.txt create mode 100644 internal/endtoend/testdata/invalid_func_args/pgx/v4/stderr/managed-db.txt create mode 100644 internal/endtoend/testdata/invalid_func_args/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/invalid_func_args/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/invalid_func_args/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/invalid_func_args/pgx/v5/stderr/base.txt create mode 100644 internal/endtoend/testdata/invalid_func_args/pgx/v5/stderr/managed-db.txt create mode 100644 internal/endtoend/testdata/invalid_func_args/stdlib/query.sql create mode 100644 internal/endtoend/testdata/invalid_func_args/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/invalid_func_args/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/invalid_func_args/stdlib/stderr/base.txt create mode 100644 internal/endtoend/testdata/invalid_func_args/stdlib/stderr/managed-db.txt create mode 100644 internal/endtoend/testdata/invalid_group_by_reference/mysql/exec.json create mode 100644 internal/endtoend/testdata/invalid_group_by_reference/mysql/query.sql create mode 100644 internal/endtoend/testdata/invalid_group_by_reference/mysql/schema.sql create mode 100644 internal/endtoend/testdata/invalid_group_by_reference/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/invalid_group_by_reference/mysql/stderr.txt create mode 100644 internal/endtoend/testdata/invalid_group_by_reference/postgresql/query.sql create mode 100644 internal/endtoend/testdata/invalid_group_by_reference/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/invalid_group_by_reference/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/invalid_group_by_reference/postgresql/stderr/base.txt create mode 100644 internal/endtoend/testdata/invalid_group_by_reference/postgresql/stderr/managed-db.txt create mode 100644 internal/endtoend/testdata/invalid_group_by_reference/sqlite/exec.json create mode 100644 internal/endtoend/testdata/invalid_group_by_reference/sqlite/query.sql create mode 100644 internal/endtoend/testdata/invalid_group_by_reference/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/invalid_group_by_reference/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/invalid_group_by_reference/sqlite/stderr.txt create mode 100644 internal/endtoend/testdata/invalid_insert_unknown_column/issue.md create mode 100644 internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/db/db.go create mode 100644 internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/db/models.go create mode 100644 internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/db/query.sql.go create mode 100644 internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/sqlc.json create mode 100644 internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/stderr.txt create mode 100644 internal/endtoend/testdata/invalid_named_params/mysql/query.sql create mode 100644 internal/endtoend/testdata/invalid_named_params/mysql/schema.sql create mode 100644 internal/endtoend/testdata/invalid_named_params/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/invalid_named_params/mysql/stderr.txt create mode 100644 internal/endtoend/testdata/invalid_params/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/invalid_params/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/invalid_params/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/invalid_params/pgx/v4/stderr/base.txt create mode 100644 internal/endtoend/testdata/invalid_params/pgx/v4/stderr/managed-db.txt create mode 100644 internal/endtoend/testdata/invalid_params/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/invalid_params/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/invalid_params/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/invalid_params/pgx/v5/stderr/base.txt create mode 100644 internal/endtoend/testdata/invalid_params/pgx/v5/stderr/managed-db.txt create mode 100644 internal/endtoend/testdata/invalid_params/stdlib/query.sql create mode 100644 internal/endtoend/testdata/invalid_params/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/invalid_params/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/invalid_params/stdlib/stderr/base.txt create mode 100644 internal/endtoend/testdata/invalid_params/stdlib/stderr/managed-db.txt create mode 100644 internal/endtoend/testdata/invalid_params_type_mismatch/issue.md create mode 100644 internal/endtoend/testdata/invalid_params_type_mismatch/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/invalid_params_type_mismatch/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/invalid_params_type_mismatch/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/invalid_params_type_mismatch/postgresql/pgx/sqlc.json create mode 100644 internal/endtoend/testdata/invalid_params_type_mismatch/postgresql/pgx/stderr.txt create mode 100644 internal/endtoend/testdata/invalid_queries_bar/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/invalid_queries_bar/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/invalid_queries_bar/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/invalid_queries_bar/pgx/v4/stderr/base.txt create mode 100644 internal/endtoend/testdata/invalid_queries_bar/pgx/v4/stderr/managed-db.txt create mode 100644 internal/endtoend/testdata/invalid_queries_bar/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/invalid_queries_bar/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/invalid_queries_bar/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/invalid_queries_bar/pgx/v5/stderr/base.txt create mode 100644 internal/endtoend/testdata/invalid_queries_bar/pgx/v5/stderr/managed-db.txt create mode 100644 internal/endtoend/testdata/invalid_queries_bar/stdlib/query.sql create mode 100644 internal/endtoend/testdata/invalid_queries_bar/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/invalid_queries_bar/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/invalid_queries_bar/stdlib/stderr/base.txt create mode 100644 internal/endtoend/testdata/invalid_queries_bar/stdlib/stderr/managed-db.txt create mode 100644 internal/endtoend/testdata/invalid_queries_foo/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/invalid_queries_foo/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/invalid_queries_foo/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/invalid_queries_foo/pgx/v4/stderr.txt create mode 100644 internal/endtoend/testdata/invalid_queries_foo/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/invalid_queries_foo/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/invalid_queries_foo/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/invalid_queries_foo/pgx/v5/stderr.txt create mode 100644 internal/endtoend/testdata/invalid_queries_foo/stdlib/query.sql create mode 100644 internal/endtoend/testdata/invalid_queries_foo/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/invalid_queries_foo/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/invalid_queries_foo/stdlib/stderr.txt create mode 100644 internal/endtoend/testdata/invalid_table_alias/mysql/query.sql create mode 100644 internal/endtoend/testdata/invalid_table_alias/mysql/schema.sql create mode 100644 internal/endtoend/testdata/invalid_table_alias/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/invalid_table_alias/mysql/stderr.txt create mode 100644 internal/endtoend/testdata/invalid_table_alias/postgresql/exec.json create mode 100644 internal/endtoend/testdata/invalid_table_alias/postgresql/query.sql create mode 100644 internal/endtoend/testdata/invalid_table_alias/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/invalid_table_alias/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/invalid_table_alias/postgresql/stderr/base.txt create mode 100644 internal/endtoend/testdata/invalid_table_alias/postgresql/stderr/managed-db.txt create mode 100644 internal/endtoend/testdata/invalid_table_alias/sqlite/exec.json create mode 100644 internal/endtoend/testdata/invalid_table_alias/sqlite/query.sql create mode 100644 internal/endtoend/testdata/invalid_table_alias/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/invalid_table_alias/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/invalid_table_alias/sqlite/stderr.txt create mode 100644 internal/endtoend/testdata/invalid_update_unknown_column/issue.md create mode 100644 internal/endtoend/testdata/invalid_update_unknown_column/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/invalid_update_unknown_column/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/invalid_update_unknown_column/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/invalid_update_unknown_column/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/invalid_update_unknown_column/postgresql/pgx/stderr.txt create mode 100644 internal/endtoend/testdata/join_alias/mysql/go/db.go create mode 100644 internal/endtoend/testdata/join_alias/mysql/go/models.go create mode 100644 internal/endtoend/testdata/join_alias/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_alias/mysql/query.sql create mode 100644 internal/endtoend/testdata/join_alias/mysql/schema.sql create mode 100644 internal/endtoend/testdata/join_alias/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/join_alias/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/join_alias/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/join_alias/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_alias/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/join_alias/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/join_alias/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/join_alias/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/join_alias/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/join_alias/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_alias/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/join_alias/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/join_alias/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/join_alias/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/join_alias/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/join_alias/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_alias/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/join_alias/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/join_alias/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/join_alias/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/join_alias/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/join_alias/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_alias/sqlite/query.sql create mode 100644 internal/endtoend/testdata/join_alias/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/join_alias/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/join_clauses_order/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/join_clauses_order/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/join_clauses_order/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_clauses_order/postgresql/query.sql create mode 100644 internal/endtoend/testdata/join_clauses_order/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/join_clauses_order/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/join_from/mysql/go/db.go create mode 100644 internal/endtoend/testdata/join_from/mysql/go/models.go create mode 100644 internal/endtoend/testdata/join_from/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_from/mysql/query.sql create mode 100644 internal/endtoend/testdata/join_from/mysql/schema.sql create mode 100644 internal/endtoend/testdata/join_from/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/join_from/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/join_from/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/join_from/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_from/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/join_from/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/join_from/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/join_from/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/join_from/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/join_from/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_from/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/join_from/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/join_from/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/join_from/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/join_from/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/join_from/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_from/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/join_from/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/join_from/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/join_from/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/join_from/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/join_from/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_from/sqlite/query.sql create mode 100644 internal/endtoend/testdata/join_from/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/join_from/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/join_full/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/join_full/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/join_full/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_full/postgresql/query.sql create mode 100644 internal/endtoend/testdata/join_full/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/join_full/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/join_group_by_alias/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/join_group_by_alias/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/join_group_by_alias/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_group_by_alias/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/join_group_by_alias/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/join_group_by_alias/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/join_inner/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/join_inner/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/join_inner/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_inner/postgresql/query.sql create mode 100644 internal/endtoend/testdata/join_inner/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/join_inner/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/join_left/mysql/go/db.go create mode 100644 internal/endtoend/testdata/join_left/mysql/go/models.go create mode 100644 internal/endtoend/testdata/join_left/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_left/mysql/query.sql create mode 100644 internal/endtoend/testdata/join_left/mysql/schema.sql create mode 100644 internal/endtoend/testdata/join_left/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/join_left/postgresql/exec.json create mode 100644 internal/endtoend/testdata/join_left/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/join_left/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/join_left/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_left/postgresql/query.sql create mode 100644 internal/endtoend/testdata/join_left/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/join_left/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/join_left/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/join_left/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/join_left/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_left/sqlite/query.sql create mode 100644 internal/endtoend/testdata/join_left/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/join_left/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/join_left_same_table/mysql/go/db.go create mode 100644 internal/endtoend/testdata/join_left_same_table/mysql/go/models.go create mode 100644 internal/endtoend/testdata/join_left_same_table/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_left_same_table/mysql/query.sql create mode 100644 internal/endtoend/testdata/join_left_same_table/mysql/schema.sql create mode 100644 internal/endtoend/testdata/join_left_same_table/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/join_left_same_table/postgres/go/db.go create mode 100644 internal/endtoend/testdata/join_left_same_table/postgres/go/models.go create mode 100644 internal/endtoend/testdata/join_left_same_table/postgres/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_left_same_table/postgres/query.sql create mode 100644 internal/endtoend/testdata/join_left_same_table/postgres/schema.sql create mode 100644 internal/endtoend/testdata/join_left_same_table/postgres/sqlc.json create mode 100644 internal/endtoend/testdata/join_left_same_table/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/join_left_same_table/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/join_left_same_table/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_left_same_table/sqlite/query.sql create mode 100644 internal/endtoend/testdata/join_left_same_table/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/join_left_same_table/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/join_left_table_alias/issue.md create mode 100644 internal/endtoend/testdata/join_left_table_alias/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/join_left_table_alias/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/join_left_table_alias/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_left_table_alias/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/join_left_table_alias/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/join_left_table_alias/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/join_order_by/issue.md create mode 100644 internal/endtoend/testdata/join_order_by/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/join_order_by/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/join_order_by/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/join_order_by/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_order_by/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/join_order_by/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/join_order_by/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/join_order_by_alias/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/join_order_by_alias/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/join_order_by_alias/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_order_by_alias/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/join_order_by_alias/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/join_order_by_alias/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/join_right/mysql/go/db.go create mode 100644 internal/endtoend/testdata/join_right/mysql/go/models.go create mode 100644 internal/endtoend/testdata/join_right/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_right/mysql/query.sql create mode 100644 internal/endtoend/testdata/join_right/mysql/schema.sql create mode 100644 internal/endtoend/testdata/join_right/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/join_right/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/join_right/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/join_right/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_right/postgresql/query.sql create mode 100644 internal/endtoend/testdata/join_right/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/join_right/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/join_table_name/mysql/go/db.go create mode 100644 internal/endtoend/testdata/join_table_name/mysql/go/models.go create mode 100644 internal/endtoend/testdata/join_table_name/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_table_name/mysql/query.sql create mode 100644 internal/endtoend/testdata/join_table_name/mysql/schema.sql create mode 100644 internal/endtoend/testdata/join_table_name/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/join_table_name/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/join_table_name/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/join_table_name/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_table_name/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/join_table_name/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/join_table_name/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/join_table_name/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/join_table_name/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/join_table_name/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_table_name/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/join_table_name/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/join_table_name/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/join_table_name/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/join_table_name/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/join_table_name/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_table_name/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/join_table_name/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/join_table_name/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/join_table_name/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/join_table_name/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/join_table_name/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_table_name/sqlite/query.sql create mode 100644 internal/endtoend/testdata/join_table_name/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/join_table_name/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/join_two_tables/mysql/go/db.go create mode 100644 internal/endtoend/testdata/join_two_tables/mysql/go/models.go create mode 100644 internal/endtoend/testdata/join_two_tables/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_two_tables/mysql/query.sql create mode 100644 internal/endtoend/testdata/join_two_tables/mysql/schema.sql create mode 100644 internal/endtoend/testdata/join_two_tables/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/join_two_tables/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/join_two_tables/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/join_two_tables/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_two_tables/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/join_two_tables/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/join_two_tables/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/join_two_tables/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/join_two_tables/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/join_two_tables/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_two_tables/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/join_two_tables/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/join_two_tables/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/join_two_tables/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/join_two_tables/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/join_two_tables/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_two_tables/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/join_two_tables/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/join_two_tables/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/join_two_tables/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/join_two_tables/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/join_two_tables/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_two_tables/sqlite/query.sql create mode 100644 internal/endtoend/testdata/join_two_tables/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/join_two_tables/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/join_update/issue.md create mode 100644 internal/endtoend/testdata/join_update/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/join_update/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/join_update/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_update/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/join_update/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/join_update/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/join_using/issue.md create mode 100644 internal/endtoend/testdata/join_using/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/join_using/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/join_using/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/join_using/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_using/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/join_using/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/join_using/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/join_validate_columns/issue.md create mode 100644 internal/endtoend/testdata/join_validate_columns/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/join_validate_columns/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/join_validate_columns/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/join_validate_columns/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/join_validate_columns/postgresql/pgx/stderr.txt create mode 100644 internal/endtoend/testdata/join_where_clause/mysql/go/db.go create mode 100644 internal/endtoend/testdata/join_where_clause/mysql/go/models.go create mode 100644 internal/endtoend/testdata/join_where_clause/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_where_clause/mysql/query.sql create mode 100644 internal/endtoend/testdata/join_where_clause/mysql/schema.sql create mode 100644 internal/endtoend/testdata/join_where_clause/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/join_where_clause/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/join_where_clause/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/join_where_clause/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_where_clause/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/join_where_clause/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/join_where_clause/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/join_where_clause/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/join_where_clause/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/join_where_clause/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/join_where_clause/sqlite/query.sql create mode 100644 internal/endtoend/testdata/join_where_clause/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/join_where_clause/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/json/mysql/go/copyfrom.go create mode 100644 internal/endtoend/testdata/json/mysql/go/db.go create mode 100644 internal/endtoend/testdata/json/mysql/go/models.go create mode 100644 internal/endtoend/testdata/json/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/json/mysql/query.sql create mode 100644 internal/endtoend/testdata/json/mysql/schema.sql create mode 100644 internal/endtoend/testdata/json/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/json/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/json/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/json/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/json/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/json/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/json/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/json/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/json/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/json/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/json/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/json/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/json/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/json/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/json/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/json/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/json/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/json/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/json/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/json_array_elements/issue.md create mode 100644 internal/endtoend/testdata/json_array_elements/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/json_array_elements/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/json_array_elements/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/json_array_elements/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/json_array_elements/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/json_array_elements/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/json_array_elements/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/json_build/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/json_build/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/json_build/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/json_build/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/json_build/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/json_build/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/json_build/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/json_build/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/json_build/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/json_build/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/json_build/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/json_build/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/json_build/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/json_build/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/json_build/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/json_build/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/json_build/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/json_build/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/json_param_type/issue.md create mode 100644 internal/endtoend/testdata/json_param_type/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/json_param_type/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/json_param_type/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/json_param_type/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/json_param_type/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/json_param_type/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/json_param_type/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/json_param_type/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/json_param_type/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/json_param_type/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/json_param_type/sqlite/query.sql create mode 100644 internal/endtoend/testdata/json_param_type/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/json_param_type/sqlite/sqlc.yaml create mode 100644 internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/json_tags/camel_case/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/json_tags/camel_case/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/json_tags/camel_case/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/json_tags/camel_case/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/json_tags/camel_case/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/json_tags/camel_case/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/json_tags/pascal_case/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/json_tags/pascal_case/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/json_tags/pascal_case/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/json_tags/pascal_case/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/json_tags/pascal_case/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/json_tags/pascal_case/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/json_tags/snake_case/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/json_tags/snake_case/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/json_tags/snake_case/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/json_tags/snake_case/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/json_tags/snake_case/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/json_tags/snake_case/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/json_tags_null_enum/camel_case/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/json_tags_null_enum/camel_case/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/json_tags_null_enum/camel_case/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/json_tags_null_enum/camel_case/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/json_tags_null_enum/camel_case/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/json_tags_null_enum/camel_case/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/json_tags_null_enum/none/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/json_tags_null_enum/none/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/json_tags_null_enum/none/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/json_tags_null_enum/none/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/json_tags_null_enum/none/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/json_tags_null_enum/none/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/json_tags_null_enum/pascal_case/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/json_tags_null_enum/pascal_case/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/json_tags_null_enum/pascal_case/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/json_tags_null_enum/pascal_case/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/json_tags_null_enum/pascal_case/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/json_tags_null_enum/pascal_case/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/json_tags_null_enum/snake_case/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/json_tags_null_enum/snake_case/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/json_tags_null_enum/snake_case/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/json_tags_null_enum/snake_case/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/json_tags_null_enum/snake_case/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/json_tags_null_enum/snake_case/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/json_tags_null_enum/v2_config/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/json_tags_null_enum/v2_config/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/json_tags_null_enum/v2_config/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/json_tags_null_enum/v2_config/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/json_tags_null_enum/v2_config/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/json_tags_null_enum/v2_config/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/jsonb/pgx/go/db.go create mode 100644 internal/endtoend/testdata/jsonb/pgx/go/models.go create mode 100644 internal/endtoend/testdata/jsonb/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/jsonb/pgx/query.sql create mode 100644 internal/endtoend/testdata/jsonb/pgx/schema.sql create mode 100644 internal/endtoend/testdata/jsonb/pgx/sqlc.json create mode 100644 internal/endtoend/testdata/jsonb/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/jsonb/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/jsonb/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/jsonb/sqlite/query.sql create mode 100644 internal/endtoend/testdata/jsonb/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/jsonb/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/limit/mysql/go/db.go create mode 100644 internal/endtoend/testdata/limit/mysql/go/models.go create mode 100644 internal/endtoend/testdata/limit/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/limit/mysql/query.sql create mode 100644 internal/endtoend/testdata/limit/mysql/schema.sql create mode 100644 internal/endtoend/testdata/limit/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/limit/pgx/v4/exec.json create mode 100644 internal/endtoend/testdata/limit/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/limit/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/limit/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/limit/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/limit/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/limit/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/limit/pgx/v5/exec.json create mode 100644 internal/endtoend/testdata/limit/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/limit/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/limit/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/limit/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/limit/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/limit/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/limit/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/limit/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/limit/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/limit/sqlite/query.sql create mode 100644 internal/endtoend/testdata/limit/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/limit/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/limit/stdlib/exec.json create mode 100644 internal/endtoend/testdata/limit/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/limit/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/limit/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/limit/stdlib/query.sql create mode 100644 internal/endtoend/testdata/limit/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/limit/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/lower/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/lower/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/lower/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/lower/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/lower/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/lower/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/lower/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/lower/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/lower/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/lower/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/lower/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/lower/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/lower/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/lower/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/lower/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/lower/stdlib/query.sql create mode 100644 internal/endtoend/testdata/lower/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/lower/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/lower_switched_order/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/lower_switched_order/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/lower_switched_order/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/lower_switched_order/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/lower_switched_order/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/lower_switched_order/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/lower_switched_order/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/lower_switched_order/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/lower_switched_order/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/lower_switched_order/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/lower_switched_order/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/lower_switched_order/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/lower_switched_order/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/lower_switched_order/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/lower_switched_order/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/lower_switched_order/stdlib/query.sql create mode 100644 internal/endtoend/testdata/lower_switched_order/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/lower_switched_order/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/materialized_views/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/materialized_views/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/materialized_views/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/materialized_views/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/materialized_views/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/materialized_views/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/materialized_views/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/materialized_views/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/materialized_views/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/materialized_views/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/materialized_views/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/materialized_views/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/materialized_views/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/materialized_views/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/materialized_views/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/materialized_views/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/materialized_views/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/materialized_views/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/mathmatical_operator/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/mathmatical_operator/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/mathmatical_operator/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/mathmatical_operator/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/mathmatical_operator/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/mathmatical_operator/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/mathmatical_operator/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/mathmatical_operator/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/mathmatical_operator/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/mathmatical_operator/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/mathmatical_operator/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/mathmatical_operator/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/mathmatical_operator/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/mathmatical_operator/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/mathmatical_operator/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/mathmatical_operator/stdlib/query.sql create mode 100644 internal/endtoend/testdata/mathmatical_operator/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/mathmatical_operator/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/min_max_date/issue.md create mode 100644 internal/endtoend/testdata/min_max_date/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/min_max_date/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/min_max_date/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/min_max_date/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/min_max_date/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/min_max_date/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/min_max_date/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/missing_semicolon/mysql/go/db.go create mode 100644 internal/endtoend/testdata/missing_semicolon/mysql/go/models.go create mode 100644 internal/endtoend/testdata/missing_semicolon/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/missing_semicolon/mysql/query.sql create mode 100644 internal/endtoend/testdata/missing_semicolon/mysql/schema.sql create mode 100644 internal/endtoend/testdata/missing_semicolon/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/missing_semicolon/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/missing_semicolon/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/missing_semicolon/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/missing_semicolon/pgx/v4/stderr.txt create mode 100644 internal/endtoend/testdata/missing_semicolon/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/missing_semicolon/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/missing_semicolon/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/missing_semicolon/pgx/v5/stderr.txt create mode 100644 internal/endtoend/testdata/missing_semicolon/stdlib/query.sql create mode 100644 internal/endtoend/testdata/missing_semicolon/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/missing_semicolon/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/missing_semicolon/stdlib/stderr.txt create mode 100644 internal/endtoend/testdata/mix_param_types/mysql/go/db.go create mode 100644 internal/endtoend/testdata/mix_param_types/mysql/go/models.go create mode 100644 internal/endtoend/testdata/mix_param_types/mysql/go/test.sql.go create mode 100644 internal/endtoend/testdata/mix_param_types/mysql/schema.sql create mode 100644 internal/endtoend/testdata/mix_param_types/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/mix_param_types/mysql/test.sql create mode 100644 internal/endtoend/testdata/mix_param_types/postgresql/exec.json create mode 100644 internal/endtoend/testdata/mix_param_types/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/mix_param_types/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/mix_param_types/postgresql/go/test.sql.go create mode 100644 internal/endtoend/testdata/mix_param_types/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/mix_param_types/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/mix_param_types/postgresql/test.sql create mode 100644 internal/endtoend/testdata/multibyte_comment/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/multibyte_comment/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/multibyte_comment/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/multibyte_comment/sqlite/query.sql create mode 100644 internal/endtoend/testdata/multibyte_comment/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/multibyte_comment/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/multidimension_array/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/multidimension_array/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/multidimension_array/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/multidimension_array/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/multidimension_array/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/multidimension_array/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/multidimension_array/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/multidimension_array/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/multidimension_array/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/multidimension_array/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/multidimension_array/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/multidimension_array/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/multidimension_array/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/multidimension_array/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/multidimension_array/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/multidimension_array/stdlib/query.sql create mode 100644 internal/endtoend/testdata/multidimension_array/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/multidimension_array/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/multischema/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/multischema/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/multischema/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/multischema/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/multischema/pgx/v4/sql/ignore.txt create mode 100644 internal/endtoend/testdata/multischema/pgx/v4/sql/query.sql create mode 100644 internal/endtoend/testdata/multischema/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/multischema/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/multischema/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/multischema/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/multischema/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/multischema/pgx/v5/sql/ignore.txt create mode 100644 internal/endtoend/testdata/multischema/pgx/v5/sql/query.sql create mode 100644 internal/endtoend/testdata/multischema/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/multischema/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/multischema/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/multischema/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/multischema/stdlib/query.sql create mode 100644 internal/endtoend/testdata/multischema/stdlib/sql/ignore.txt create mode 100644 internal/endtoend/testdata/multischema/stdlib/sql/query.sql create mode 100644 internal/endtoend/testdata/multischema/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/mysql_ddl_routines/mysql/go/db.go create mode 100644 internal/endtoend/testdata/mysql_ddl_routines/mysql/go/models.go create mode 100644 internal/endtoend/testdata/mysql_ddl_routines/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/mysql_ddl_routines/mysql/query.sql create mode 100644 internal/endtoend/testdata/mysql_ddl_routines/mysql/schema.sql create mode 100644 internal/endtoend/testdata/mysql_ddl_routines/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/mysql_default_expression/mysql/go/db.go create mode 100644 internal/endtoend/testdata/mysql_default_expression/mysql/go/models.go create mode 100644 internal/endtoend/testdata/mysql_default_expression/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/mysql_default_expression/mysql/query.sql create mode 100644 internal/endtoend/testdata/mysql_default_expression/mysql/schema.sql create mode 100644 internal/endtoend/testdata/mysql_default_expression/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/mysql_default_value/mysql/go/db.go create mode 100644 internal/endtoend/testdata/mysql_default_value/mysql/go/models.go create mode 100644 internal/endtoend/testdata/mysql_default_value/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/mysql_default_value/mysql/query.sql create mode 100644 internal/endtoend/testdata/mysql_default_value/mysql/schema.sql create mode 100644 internal/endtoend/testdata/mysql_default_value/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/mysql_json_table/mysql/go/db.go create mode 100644 internal/endtoend/testdata/mysql_json_table/mysql/go/models.go create mode 100644 internal/endtoend/testdata/mysql_json_table/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/mysql_json_table/mysql/query.sql create mode 100644 internal/endtoend/testdata/mysql_json_table/mysql/schema.sql create mode 100644 internal/endtoend/testdata/mysql_json_table/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/mysql_optimizer_hints/mysql/go/db.go create mode 100644 internal/endtoend/testdata/mysql_optimizer_hints/mysql/go/models.go create mode 100644 internal/endtoend/testdata/mysql_optimizer_hints/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/mysql_optimizer_hints/mysql/query.sql create mode 100644 internal/endtoend/testdata/mysql_optimizer_hints/mysql/schema.sql create mode 100644 internal/endtoend/testdata/mysql_optimizer_hints/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/mysql_reference_manual/README.md create mode 100644 internal/endtoend/testdata/mysql_reference_manual/aggregate_functions/go/db.go create mode 100644 internal/endtoend/testdata/mysql_reference_manual/aggregate_functions/go/group_concat.sql.go create mode 100644 internal/endtoend/testdata/mysql_reference_manual/aggregate_functions/go/models.go create mode 100644 internal/endtoend/testdata/mysql_reference_manual/aggregate_functions/group_concat.sql create mode 100644 internal/endtoend/testdata/mysql_reference_manual/date_and_time_functions/date_add.sql create mode 100644 internal/endtoend/testdata/mysql_reference_manual/date_and_time_functions/date_sub.sql create mode 100644 internal/endtoend/testdata/mysql_reference_manual/date_and_time_functions/go/date_add.sql.go create mode 100644 internal/endtoend/testdata/mysql_reference_manual/date_and_time_functions/go/date_sub.sql.go create mode 100644 internal/endtoend/testdata/mysql_reference_manual/date_and_time_functions/go/db.go create mode 100644 internal/endtoend/testdata/mysql_reference_manual/date_and_time_functions/go/models.go create mode 100644 internal/endtoend/testdata/mysql_reference_manual/schema.sql create mode 100644 internal/endtoend/testdata/mysql_reference_manual/sqlc.json create mode 100644 internal/endtoend/testdata/mysql_vector/mysql/go/db.go create mode 100644 internal/endtoend/testdata/mysql_vector/mysql/go/models.go create mode 100644 internal/endtoend/testdata/mysql_vector/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/mysql_vector/mysql/query.sql create mode 100644 internal/endtoend/testdata/mysql_vector/mysql/schema.sql create mode 100644 internal/endtoend/testdata/mysql_vector/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/named_param/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/named_param/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/named_param/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/named_param/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/named_param/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/named_param/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/named_param/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/named_param/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/named_param/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/named_param/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/named_param/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/named_param/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/named_param/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/named_param/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/named_param/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/named_param/sqlite/query.sql create mode 100644 internal/endtoend/testdata/named_param/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/named_param/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/named_param/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/named_param/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/named_param/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/named_param/stdlib/query.sql create mode 100644 internal/endtoend/testdata/named_param/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/named_param/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/nested_select/issue.md create mode 100644 internal/endtoend/testdata/nested_select/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/nested_select/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/nested_select/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/nested_select/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/nested_select/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/nested_select/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/nested_select/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/nextval/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/nextval/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/nextval/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/nextval/postgresql/query.sql create mode 100644 internal/endtoend/testdata/nextval/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/nextval/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/notifylisten/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/notifylisten/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/notifylisten/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/notifylisten/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/notifylisten/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/notifylisten/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/null_if_type/issue.md create mode 100644 internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/db/db.go create mode 100644 internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/db/models.go create mode 100644 internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/db/query.sql.go create mode 100644 internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/exec.json create mode 100644 internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/query.sql create mode 100644 internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/schema.sql create mode 100644 internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/sqlc.json create mode 100644 internal/endtoend/testdata/null_if_type/postgresql/stdlib/db/db.go create mode 100644 internal/endtoend/testdata/null_if_type/postgresql/stdlib/db/models.go create mode 100644 internal/endtoend/testdata/null_if_type/postgresql/stdlib/db/query.sql.go create mode 100644 internal/endtoend/testdata/null_if_type/postgresql/stdlib/exec.json create mode 100644 internal/endtoend/testdata/null_if_type/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/null_if_type/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/null_if_type/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/omit_sqlc_version/db/db.go create mode 100644 internal/endtoend/testdata/omit_sqlc_version/db/models.go create mode 100644 internal/endtoend/testdata/omit_sqlc_version/db/query.sql.go create mode 100644 internal/endtoend/testdata/omit_sqlc_version/query.sql create mode 100644 internal/endtoend/testdata/omit_sqlc_version/schema.sql create mode 100644 internal/endtoend/testdata/omit_sqlc_version/sqlc.json create mode 100644 internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/on_duplicate_key_update/mysql/db/db.go create mode 100644 internal/endtoend/testdata/on_duplicate_key_update/mysql/db/models.go create mode 100644 internal/endtoend/testdata/on_duplicate_key_update/mysql/db/query.sql.go create mode 100644 internal/endtoend/testdata/on_duplicate_key_update/mysql/query.sql create mode 100644 internal/endtoend/testdata/on_duplicate_key_update/mysql/schema.sql create mode 100644 internal/endtoend/testdata/on_duplicate_key_update/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/on_duplicate_key_update/postgresql/db/db.go create mode 100644 internal/endtoend/testdata/on_duplicate_key_update/postgresql/db/models.go create mode 100644 internal/endtoend/testdata/on_duplicate_key_update/postgresql/db/query.sql.go create mode 100644 internal/endtoend/testdata/on_duplicate_key_update/postgresql/query.sql create mode 100644 internal/endtoend/testdata/on_duplicate_key_update/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/on_duplicate_key_update/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/operator_string_concat/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/operator_string_concat/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/operator_string_concat/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/operator_string_concat/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/operator_string_concat/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/operator_string_concat/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/order_by_binds/mysql/go/db.go create mode 100644 internal/endtoend/testdata/order_by_binds/mysql/go/models.go create mode 100644 internal/endtoend/testdata/order_by_binds/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/order_by_binds/mysql/query.sql create mode 100644 internal/endtoend/testdata/order_by_binds/mysql/schema.sql create mode 100644 internal/endtoend/testdata/order_by_binds/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/order_by_binds/pganalyze/exec.json create mode 100644 internal/endtoend/testdata/order_by_binds/pganalyze/go/db.go create mode 100644 internal/endtoend/testdata/order_by_binds/pganalyze/go/models.go create mode 100644 internal/endtoend/testdata/order_by_binds/pganalyze/go/query.sql.go create mode 100644 internal/endtoend/testdata/order_by_binds/pganalyze/query.sql create mode 100644 internal/endtoend/testdata/order_by_binds/pganalyze/schema.sql create mode 100644 internal/endtoend/testdata/order_by_binds/pganalyze/sqlc.json create mode 100644 internal/endtoend/testdata/order_by_binds/postgresql/exec.json create mode 100644 internal/endtoend/testdata/order_by_binds/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/order_by_binds/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/order_by_binds/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/order_by_binds/postgresql/query.sql create mode 100644 internal/endtoend/testdata/order_by_binds/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/order_by_binds/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/order_by_non_existing_column/postgresql/query.sql create mode 100644 internal/endtoend/testdata/order_by_non_existing_column/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/order_by_non_existing_column/postgresql/sqlc.yaml create mode 100644 internal/endtoend/testdata/order_by_non_existing_column/postgresql/stderr/base.txt create mode 100644 internal/endtoend/testdata/order_by_non_existing_column/postgresql/stderr/managed-db.txt create mode 100644 internal/endtoend/testdata/order_by_union/mysql/go/db.go create mode 100644 internal/endtoend/testdata/order_by_union/mysql/go/models.go create mode 100644 internal/endtoend/testdata/order_by_union/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/order_by_union/mysql/query.sql create mode 100644 internal/endtoend/testdata/order_by_union/mysql/schema.sql create mode 100644 internal/endtoend/testdata/order_by_union/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/order_by_union/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/order_by_union/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/order_by_union/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/order_by_union/postgresql/query.sql create mode 100644 internal/endtoend/testdata/order_by_union/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/order_by_union/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/output_file_names/pgx/v4/go/batch_gen.go create mode 100644 internal/endtoend/testdata/output_file_names/pgx/v4/go/copyfrom_gen.go create mode 100644 internal/endtoend/testdata/output_file_names/pgx/v4/go/db_gen.go create mode 100644 internal/endtoend/testdata/output_file_names/pgx/v4/go/models_gen.go create mode 100644 internal/endtoend/testdata/output_file_names/pgx/v4/go/querier_gen.go create mode 100644 internal/endtoend/testdata/output_file_names/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/output_file_names/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/output_file_names/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/output_file_names/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/output_file_names/pgx/v5/go/batch_gen.go create mode 100644 internal/endtoend/testdata/output_file_names/pgx/v5/go/copyfrom_gen.go create mode 100644 internal/endtoend/testdata/output_file_names/pgx/v5/go/db_gen.go create mode 100644 internal/endtoend/testdata/output_file_names/pgx/v5/go/models_gen.go create mode 100644 internal/endtoend/testdata/output_file_names/pgx/v5/go/querier_gen.go create mode 100644 internal/endtoend/testdata/output_file_names/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/output_file_names/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/output_file_names/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/output_file_names/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/output_file_names/stdlib/go/db_gen.go create mode 100644 internal/endtoend/testdata/output_file_names/stdlib/go/models_gen.go create mode 100644 internal/endtoend/testdata/output_file_names/stdlib/go/querier_gen.go create mode 100644 internal/endtoend/testdata/output_file_names/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/output_file_names/stdlib/query.sql create mode 100644 internal/endtoend/testdata/output_file_names/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/output_file_names/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/output_files_suffix/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/output_files_suffix/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/output_files_suffix/pgx/v4/go/query.sql_gen.go create mode 100644 internal/endtoend/testdata/output_files_suffix/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/output_files_suffix/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/output_files_suffix/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/output_files_suffix/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/output_files_suffix/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/output_files_suffix/pgx/v5/go/query.sql_gen.go create mode 100644 internal/endtoend/testdata/output_files_suffix/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/output_files_suffix/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/output_files_suffix/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/output_files_suffix/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/output_files_suffix/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/output_files_suffix/stdlib/go/query.sql_gen.go create mode 100644 internal/endtoend/testdata/output_files_suffix/stdlib/query.sql create mode 100644 internal/endtoend/testdata/output_files_suffix/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/output_files_suffix/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/output_models_path/postgresql/db/db.go create mode 100644 internal/endtoend/testdata/output_models_path/postgresql/db/querier.go create mode 100644 internal/endtoend/testdata/output_models_path/postgresql/db/query.sql.go create mode 100644 internal/endtoend/testdata/output_models_path/postgresql/model/models.go create mode 100644 internal/endtoend/testdata/output_models_path/postgresql/query.sql create mode 100644 internal/endtoend/testdata/output_models_path/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/output_models_path/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/output_models_shared/postgresql/model/models.go create mode 100644 internal/endtoend/testdata/output_models_shared/postgresql/primary/db.go create mode 100644 internal/endtoend/testdata/output_models_shared/postgresql/primary/query.sql.go create mode 100644 internal/endtoend/testdata/output_models_shared/postgresql/queries/primary/query.sql create mode 100644 internal/endtoend/testdata/output_models_shared/postgresql/queries/replica/query.sql create mode 100644 internal/endtoend/testdata/output_models_shared/postgresql/replica/db.go create mode 100644 internal/endtoend/testdata/output_models_shared/postgresql/replica/query.sql.go create mode 100644 internal/endtoend/testdata/output_models_shared/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/output_models_shared/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/overrides/mysql/go/db.go create mode 100644 internal/endtoend/testdata/overrides/mysql/go/models.go create mode 100644 internal/endtoend/testdata/overrides/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/overrides/mysql/query.sql create mode 100644 internal/endtoend/testdata/overrides/mysql/schema.sql create mode 100644 internal/endtoend/testdata/overrides/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/overrides/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/overrides/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/overrides/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/overrides/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/overrides/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/overrides/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/overrides/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/overrides/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/overrides/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/overrides/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/overrides/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/overrides/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/overrides/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/overrides/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/overrides/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/overrides/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/overrides/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/overrides/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/overrides/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/overrides/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/overrides/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/overrides/sqlite/query.sql create mode 100644 internal/endtoend/testdata/overrides/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/overrides/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/overrides_array/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/overrides_array/postgresql/pgx/v4/query/db.go create mode 100644 internal/endtoend/testdata/overrides_array/postgresql/pgx/v4/query/models.go create mode 100644 internal/endtoend/testdata/overrides_array/postgresql/pgx/v4/query/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_array/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/overrides_array/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/overrides_array/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/overrides_array/postgresql/pgx/v5/query/db.go create mode 100644 internal/endtoend/testdata/overrides_array/postgresql/pgx/v5/query/models.go create mode 100644 internal/endtoend/testdata/overrides_array/postgresql/pgx/v5/query/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_array/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/overrides_array/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/overrides_array/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/overrides_array/postgresql/stdlib/query/db.go create mode 100644 internal/endtoend/testdata/overrides_array/postgresql/stdlib/query/models.go create mode 100644 internal/endtoend/testdata/overrides_array/postgresql/stdlib/query/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_array/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/overrides_array/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/overrides_config/query.sql create mode 100644 internal/endtoend/testdata/overrides_config/schema.sql create mode 100644 internal/endtoend/testdata/overrides_config/v2/yaml/global/db/db.go create mode 100644 internal/endtoend/testdata/overrides_config/v2/yaml/global/db/models.go create mode 100644 internal/endtoend/testdata/overrides_config/v2/yaml/global/db/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_config/v2/yaml/global/sqlc.yaml create mode 100644 internal/endtoend/testdata/overrides_config/v2/yaml/global_and_queryset/db/db.go create mode 100644 internal/endtoend/testdata/overrides_config/v2/yaml/global_and_queryset/db/models.go create mode 100644 internal/endtoend/testdata/overrides_config/v2/yaml/global_and_queryset/db/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_config/v2/yaml/global_and_queryset/sqlc.yaml create mode 100644 internal/endtoend/testdata/overrides_config/v2/yaml/queryset/db/db.go create mode 100644 internal/endtoend/testdata/overrides_config/v2/yaml/queryset/db/models.go create mode 100644 internal/endtoend/testdata/overrides_config/v2/yaml/queryset/db/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_config/v2/yaml/queryset/sqlc.yaml create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/invalid_tags/query.sql create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/invalid_tags/schema.sql create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/invalid_tags/sqlc.json create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/invalid_tags/stderr.txt create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/mysql/go/db.go create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/mysql/go/models.go create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/mysql/query.sql create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/mysql/schema.sql create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/sqlite/query.sql create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/overrides_go_struct_tags/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/overrides_go_types/mysql/go/db.go create mode 100644 internal/endtoend/testdata/overrides_go_types/mysql/go/models.go create mode 100644 internal/endtoend/testdata/overrides_go_types/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_go_types/mysql/query.sql create mode 100644 internal/endtoend/testdata/overrides_go_types/mysql/schema.sql create mode 100644 internal/endtoend/testdata/overrides_go_types/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/overrides_go_types/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/overrides_go_types/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/overrides_go_types/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_go_types/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/overrides_go_types/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/overrides_go_types/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/overrides_go_types/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/overrides_go_types/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/overrides_go_types/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_go_types/sqlite/query.sql create mode 100644 internal/endtoend/testdata/overrides_go_types/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/overrides_go_types/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/overrides_nullable/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/overrides_nullable/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/overrides_nullable/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_nullable/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/overrides_nullable/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/overrides_nullable/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/overrides_pointers/mysql/go/db.go create mode 100644 internal/endtoend/testdata/overrides_pointers/mysql/go/models.go create mode 100644 internal/endtoend/testdata/overrides_pointers/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_pointers/mysql/query.sql create mode 100644 internal/endtoend/testdata/overrides_pointers/mysql/schema.sql create mode 100644 internal/endtoend/testdata/overrides_pointers/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/overrides_pointers/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/overrides_pointers/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/overrides_pointers/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_pointers/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/overrides_pointers/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/overrides_pointers/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/overrides_result_tag/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/overrides_result_tag/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/overrides_result_tag/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_result_tag/stdlib/query.sql create mode 100644 internal/endtoend/testdata/overrides_result_tag/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/overrides_result_tag/stdlib/sqlc.yaml create mode 100644 internal/endtoend/testdata/overrides_unsigned/mysql/go/db.go create mode 100644 internal/endtoend/testdata/overrides_unsigned/mysql/go/models.go create mode 100644 internal/endtoend/testdata/overrides_unsigned/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_unsigned/mysql/query.sql create mode 100644 internal/endtoend/testdata/overrides_unsigned/mysql/schema.sql create mode 100644 internal/endtoend/testdata/overrides_unsigned/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/params_duplicate/mysql/go/db.go create mode 100644 internal/endtoend/testdata/params_duplicate/mysql/go/models.go create mode 100644 internal/endtoend/testdata/params_duplicate/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/params_duplicate/mysql/query.sql create mode 100644 internal/endtoend/testdata/params_duplicate/mysql/schema.sql create mode 100644 internal/endtoend/testdata/params_duplicate/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/params_duplicate/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/params_duplicate/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/params_duplicate/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/params_duplicate/postgresql/query.sql create mode 100644 internal/endtoend/testdata/params_duplicate/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/params_duplicate/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/params_go_keywords/issue.md create mode 100644 internal/endtoend/testdata/params_go_keywords/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/params_go_keywords/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/params_go_keywords/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/params_go_keywords/postgresql/query.sql create mode 100644 internal/endtoend/testdata/params_go_keywords/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/params_go_keywords/postgresql/sqlc.yaml create mode 100644 internal/endtoend/testdata/params_in_nested_func/mysql/db/db.go create mode 100644 internal/endtoend/testdata/params_in_nested_func/mysql/db/models.go create mode 100644 internal/endtoend/testdata/params_in_nested_func/mysql/db/query.sql.go create mode 100644 internal/endtoend/testdata/params_in_nested_func/mysql/query.sql create mode 100644 internal/endtoend/testdata/params_in_nested_func/mysql/schema.sql create mode 100644 internal/endtoend/testdata/params_in_nested_func/mysql/sqlc.yaml create mode 100644 internal/endtoend/testdata/params_in_nested_func/postgresql/db/db.go create mode 100644 internal/endtoend/testdata/params_in_nested_func/postgresql/db/models.go create mode 100644 internal/endtoend/testdata/params_in_nested_func/postgresql/db/query.sql.go create mode 100644 internal/endtoend/testdata/params_in_nested_func/postgresql/query.sql create mode 100644 internal/endtoend/testdata/params_in_nested_func/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/params_in_nested_func/postgresql/sqlc.yaml create mode 100644 internal/endtoend/testdata/params_location/mysql/go/db.go create mode 100644 internal/endtoend/testdata/params_location/mysql/go/models.go create mode 100644 internal/endtoend/testdata/params_location/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/params_location/mysql/query.sql create mode 100644 internal/endtoend/testdata/params_location/mysql/schema.sql create mode 100644 internal/endtoend/testdata/params_location/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/params_location/postgresql/pgx/v4/exec.json create mode 100644 internal/endtoend/testdata/params_location/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/params_location/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/params_location/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/params_location/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/params_location/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/params_location/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/params_location/postgresql/pgx/v5/exec.json create mode 100644 internal/endtoend/testdata/params_location/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/params_location/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/params_location/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/params_location/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/params_location/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/params_location/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/params_location/postgresql/stdlib/exec.json create mode 100644 internal/endtoend/testdata/params_location/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/params_location/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/params_location/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/params_location/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/params_location/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/params_location/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/params_placeholder_in_left_expr/mysql/go/db.go create mode 100644 internal/endtoend/testdata/params_placeholder_in_left_expr/mysql/go/models.go create mode 100644 internal/endtoend/testdata/params_placeholder_in_left_expr/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/params_placeholder_in_left_expr/mysql/query.sql create mode 100644 internal/endtoend/testdata/params_placeholder_in_left_expr/mysql/schema.sql create mode 100644 internal/endtoend/testdata/params_placeholder_in_left_expr/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/exec.json create mode 100644 internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/query.sql create mode 100644 internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/params_two/mysql/go/db.go create mode 100644 internal/endtoend/testdata/params_two/mysql/go/models.go create mode 100644 internal/endtoend/testdata/params_two/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/params_two/mysql/query.sql create mode 100644 internal/endtoend/testdata/params_two/mysql/schema.sql create mode 100644 internal/endtoend/testdata/params_two/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/params_two/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/params_two/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/params_two/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/params_two/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/params_two/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/params_two/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/params_two/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/params_two/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/params_two/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/params_two/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/params_two/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/params_two/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/params_two/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/params_two/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/params_two/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/params_two/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/params_two/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/params_two/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/parse_basic/clickhouse/exec.json create mode 100644 internal/endtoend/testdata/parse_basic/clickhouse/query.sql create mode 100644 internal/endtoend/testdata/parse_basic/clickhouse/stdout.txt create mode 100644 internal/endtoend/testdata/parse_basic/duckdb/exec.json create mode 100644 internal/endtoend/testdata/parse_basic/duckdb/query.sql create mode 100644 internal/endtoend/testdata/parse_basic/duckdb/stdout.txt create mode 100644 internal/endtoend/testdata/parse_basic/googlesql/exec.json create mode 100644 internal/endtoend/testdata/parse_basic/googlesql/query.sql create mode 100644 internal/endtoend/testdata/parse_basic/googlesql/stdout.txt create mode 100644 internal/endtoend/testdata/parse_basic/mssql/exec.json create mode 100644 internal/endtoend/testdata/parse_basic/mssql/query.sql create mode 100644 internal/endtoend/testdata/parse_basic/mssql/stdout.txt create mode 100644 internal/endtoend/testdata/parse_basic/mysql/exec.json create mode 100644 internal/endtoend/testdata/parse_basic/mysql/query.sql create mode 100644 internal/endtoend/testdata/parse_basic/mysql/stdout.txt create mode 100644 internal/endtoend/testdata/parse_basic/postgresql/exec.json create mode 100644 internal/endtoend/testdata/parse_basic/postgresql/query.sql create mode 100644 internal/endtoend/testdata/parse_basic/postgresql/stdout.txt create mode 100644 internal/endtoend/testdata/parse_basic/sqlite/exec.json create mode 100644 internal/endtoend/testdata/parse_basic/sqlite/query.sql create mode 100644 internal/endtoend/testdata/parse_basic/sqlite/stdout.txt create mode 100644 internal/endtoend/testdata/pattern_in_expr/mysql/go/db.go create mode 100644 internal/endtoend/testdata/pattern_in_expr/mysql/go/models.go create mode 100644 internal/endtoend/testdata/pattern_in_expr/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/pattern_in_expr/mysql/query.sql create mode 100644 internal/endtoend/testdata/pattern_in_expr/mysql/schema.sql create mode 100644 internal/endtoend/testdata/pattern_in_expr/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/pattern_matching/mysql/go/db.go create mode 100644 internal/endtoend/testdata/pattern_matching/mysql/go/models.go create mode 100644 internal/endtoend/testdata/pattern_matching/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/pattern_matching/mysql/query.sql create mode 100644 internal/endtoend/testdata/pattern_matching/mysql/schema.sql create mode 100644 internal/endtoend/testdata/pattern_matching/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/pattern_matching/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/pattern_matching/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/pattern_matching/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/pattern_matching/postgresql/query.sql create mode 100644 internal/endtoend/testdata/pattern_matching/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/pattern_matching/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/exec.sql create mode 100644 internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/go/exec.sql.go create mode 100644 internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/exec.sql create mode 100644 internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/go/exec.sql.go create mode 100644 internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/exec.sql create mode 100644 internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/go/exec.sql.go create mode 100644 internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/pg_dump/db/db.go create mode 100644 internal/endtoend/testdata/pg_dump/db/models.go create mode 100644 internal/endtoend/testdata/pg_dump/db/query.sql.go create mode 100644 internal/endtoend/testdata/pg_dump/exec.json create mode 100644 internal/endtoend/testdata/pg_dump/query.sql create mode 100644 internal/endtoend/testdata/pg_dump/schema.sql create mode 100644 internal/endtoend/testdata/pg_dump/sqlc.json create mode 100644 internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/pg_ext_ltree/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/pg_ext_ltree/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/pg_ext_ltree/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/pg_ext_ltree/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/pg_ext_ltree/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/pg_ext_ltree/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/go/pg_trgm.sql.go create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/go/pgcrypto.sql.go create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/go/uuid_ossp.sql.go create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/sql/pg_trgm.sql create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/sql/pgcrypto.sql create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/sql/uuid_ossp.sql create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/go/pg_trgm.sql.go create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/go/pgcrypto.sql.go create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/go/uuid_ossp.sql.go create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/sql/pg_trgm.sql create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/sql/pgcrypto.sql create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/sql/uuid_ossp.sql create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/stdlib/go/pg_trgm.sql.go create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/stdlib/go/pgcrypto.sql.go create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/stdlib/go/uuid_ossp.sql.go create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/stdlib/sql/pg_trgm.sql create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/stdlib/sql/pgcrypto.sql create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/stdlib/sql/uuid_ossp.sql create mode 100644 internal/endtoend/testdata/pg_extensions/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/exec.json create mode 100644 internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/exec.json create mode 100644 internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/exec.json create mode 100644 internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/pg_timezone_names/go_pgx/v4/db.go create mode 100644 internal/endtoend/testdata/pg_timezone_names/go_pgx/v4/models.go create mode 100644 internal/endtoend/testdata/pg_timezone_names/go_pgx/v4/query.sql.go create mode 100644 internal/endtoend/testdata/pg_timezone_names/go_pgx/v5/db.go create mode 100644 internal/endtoend/testdata/pg_timezone_names/go_pgx/v5/models.go create mode 100644 internal/endtoend/testdata/pg_timezone_names/go_pgx/v5/query.sql.go create mode 100644 internal/endtoend/testdata/pg_timezone_names/go_stdlib/db.go create mode 100644 internal/endtoend/testdata/pg_timezone_names/go_stdlib/models.go create mode 100644 internal/endtoend/testdata/pg_timezone_names/go_stdlib/query.sql.go create mode 100644 internal/endtoend/testdata/pg_timezone_names/query.sql create mode 100644 internal/endtoend/testdata/pg_timezone_names/schema.sql create mode 100644 internal/endtoend/testdata/pg_timezone_names/sqlc.json create mode 100644 internal/endtoend/testdata/pg_user_table/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/pg_user_table/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/pg_user_table/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/pg_user_table/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/pg_user_table/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/pg_user_table/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/pg_user_table/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/pg_user_table/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/pg_user_table/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/pg_user_table/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/pg_user_table/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/pg_user_table/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/pg_user_table/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/pg_user_table/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/pg_user_table/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/pg_user_table/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/pg_user_table/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/pg_user_table/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/pg_vector/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/pg_vector/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/pg_vector/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/pg_vector/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/pg_vector/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/pg_vector/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/pg_vector/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/exec.json create mode 100644 internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/prepared_queries/mysql/go/db.go create mode 100644 internal/endtoend/testdata/prepared_queries/mysql/go/models.go create mode 100644 internal/endtoend/testdata/prepared_queries/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/prepared_queries/mysql/query.sql create mode 100644 internal/endtoend/testdata/prepared_queries/mysql/schema.sql create mode 100644 internal/endtoend/testdata/prepared_queries/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/prepared_queries/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/prepared_queries/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/prepared_queries/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/prepared_queries/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/prepared_queries/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/prepared_queries/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/primary_key_later/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/primary_key_later/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/primary_key_later/postgresql/pgx/v4/go/queries.sql.go create mode 100644 internal/endtoend/testdata/primary_key_later/postgresql/pgx/v4/queries.sql create mode 100644 internal/endtoend/testdata/primary_key_later/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/primary_key_later/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/primary_key_later/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/primary_key_later/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/primary_key_later/postgresql/pgx/v5/go/queries.sql.go create mode 100644 internal/endtoend/testdata/primary_key_later/postgresql/pgx/v5/queries.sql create mode 100644 internal/endtoend/testdata/primary_key_later/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/primary_key_later/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/primary_key_later/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/primary_key_later/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/primary_key_later/postgresql/stdlib/go/queries.sql.go create mode 100644 internal/endtoend/testdata/primary_key_later/postgresql/stdlib/queries.sql create mode 100644 internal/endtoend/testdata/primary_key_later/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/primary_key_later/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/process_plugin_disabled/exec.json create mode 100644 internal/endtoend/testdata/process_plugin_disabled/query.sql create mode 100644 internal/endtoend/testdata/process_plugin_disabled/schema.sql create mode 100644 internal/endtoend/testdata/process_plugin_disabled/sqlc.json create mode 100644 internal/endtoend/testdata/process_plugin_disabled/stderr.txt create mode 100644 internal/endtoend/testdata/process_plugin_format_json/exec.json create mode 100644 internal/endtoend/testdata/process_plugin_format_json/gen/hello.txt create mode 100644 internal/endtoend/testdata/process_plugin_format_json/query.sql create mode 100644 internal/endtoend/testdata/process_plugin_format_json/schema.sql create mode 100644 internal/endtoend/testdata/process_plugin_format_json/sqlc.json create mode 100644 internal/endtoend/testdata/process_plugin_sqlc_gen_json/exec.json create mode 100644 internal/endtoend/testdata/process_plugin_sqlc_gen_json/query.sql create mode 100644 internal/endtoend/testdata/process_plugin_sqlc_gen_json/schema.sql create mode 100644 internal/endtoend/testdata/process_plugin_sqlc_gen_json/sqlc.json create mode 100644 internal/endtoend/testdata/process_plugin_sqlc_gen_test/exec.json create mode 100644 internal/endtoend/testdata/process_plugin_sqlc_gen_test/gen/env.json create mode 100644 internal/endtoend/testdata/process_plugin_sqlc_gen_test/query.sql create mode 100644 internal/endtoend/testdata/process_plugin_sqlc_gen_test/schema.sql create mode 100644 internal/endtoend/testdata/process_plugin_sqlc_gen_test/sqlc.json create mode 100644 internal/endtoend/testdata/query_parameter_limit_invalid/postgresql/query.sql create mode 100644 internal/endtoend/testdata/query_parameter_limit_invalid/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/query_parameter_limit_invalid/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/query_parameter_limit_invalid/postgresql/stderr.txt create mode 100644 internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/go/querier.go create mode 100644 internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/query.sql create mode 100644 internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/query.sql create mode 100644 internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/go/querier.go create mode 100644 internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/query.sql create mode 100644 internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/quoted_colname/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/quoted_colname/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/quoted_colname/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/quoted_colname/sqlite/query.sql create mode 100644 internal/endtoend/testdata/quoted_colname/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/quoted_colname/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/quoted_names_complex/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/quoted_names_complex/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/quoted_names_complex/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/quoted_names_complex/sqlite/query.sql create mode 100644 internal/endtoend/testdata/quoted_names_complex/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/quoted_names_complex/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/quoted_tablename/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/quoted_tablename/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/quoted_tablename/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/quoted_tablename/sqlite/query.sql create mode 100644 internal/endtoend/testdata/quoted_tablename/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/quoted_tablename/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/ranges/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ranges/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ranges/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ranges/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ranges/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ranges/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/refreshmatview/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/refreshmatview/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/refreshmatview/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/refreshmatview/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/refreshmatview/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/refreshmatview/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/refreshmatview/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/refreshmatview/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/refreshmatview/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/refreshmatview/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/refreshmatview/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/refreshmatview/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/relation_does_not_exist/postgresql/query.sql create mode 100644 internal/endtoend/testdata/relation_does_not_exist/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/relation_does_not_exist/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/relation_does_not_exist/postgresql/stderr/base.txt create mode 100644 internal/endtoend/testdata/relation_does_not_exist/postgresql/stderr/managed-db.txt create mode 100644 internal/endtoend/testdata/rename/v1/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/rename/v1/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/rename/v1/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/rename/v1/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/rename/v1/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/rename/v1/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/rename/v1/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/rename/v1/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/rename/v1/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/rename/v1/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/rename/v1/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/rename/v1/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/rename/v1/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/rename/v1/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/rename/v1/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/rename/v1/stdlib/query.sql create mode 100644 internal/endtoend/testdata/rename/v1/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/rename/v1/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/rename/v2/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/rename/v2/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/rename/v2/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/rename/v2/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/rename/v2/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/rename/v2/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/rename/v2/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/rename/v2/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/rename/v2/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/rename/v2/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/rename/v2/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/rename/v2/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/rename/v2/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/rename/v2/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/rename/v2/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/rename/v2/stdlib/query.sql create mode 100644 internal/endtoend/testdata/rename/v2/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/rename/v2/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/returning/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/returning/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/returning/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/returning/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/returning/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/returning/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/returning/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/returning/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/returning/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/returning/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/returning/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/returning/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/returning/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/returning/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/returning/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/returning/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/returning/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/returning/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/returning/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/returning/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/returning/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/returning/sqlite/query.sql create mode 100644 internal/endtoend/testdata/returning/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/returning/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/exec.json create mode 100644 internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/returning_old_new/postgresql/stdlib/exec.json create mode 100644 internal/endtoend/testdata/returning_old_new/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/returning_old_new/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/returning_old_new/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/returning_old_new/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/returning_old_new/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/returning_old_new/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/schema_scoped_create/mysql/exec.json create mode 100644 internal/endtoend/testdata/schema_scoped_create/mysql/go/db.go create mode 100644 internal/endtoend/testdata/schema_scoped_create/mysql/go/models.go create mode 100644 internal/endtoend/testdata/schema_scoped_create/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/schema_scoped_create/mysql/query.sql create mode 100644 internal/endtoend/testdata/schema_scoped_create/mysql/schema.sql create mode 100644 internal/endtoend/testdata/schema_scoped_create/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/schema_scoped_create/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/schema_scoped_create/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/schema_scoped_create/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/schema_scoped_create/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/schema_scoped_create/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/schema_scoped_create/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/schema_scoped_delete/mysql/exec.json create mode 100644 internal/endtoend/testdata/schema_scoped_delete/mysql/go/db.go create mode 100644 internal/endtoend/testdata/schema_scoped_delete/mysql/go/models.go create mode 100644 internal/endtoend/testdata/schema_scoped_delete/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/schema_scoped_delete/mysql/query.sql create mode 100644 internal/endtoend/testdata/schema_scoped_delete/mysql/schema.sql create mode 100644 internal/endtoend/testdata/schema_scoped_delete/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/schema_scoped_delete/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/schema_scoped_delete/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/schema_scoped_delete/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/schema_scoped_delete/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/schema_scoped_delete/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/schema_scoped_delete/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/schema_scoped_enum/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/schema_scoped_enum/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/schema_scoped_enum/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/schema_scoped_enum/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/schema_scoped_enum/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/schema_scoped_enum/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/schema_scoped_enum/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/schema_scoped_enum/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/schema_scoped_enum/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/schema_scoped_enum/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/schema_scoped_enum/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/schema_scoped_enum/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/schema_scoped_enum/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/schema_scoped_enum/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/schema_scoped_enum/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/schema_scoped_enum/stdlib/query.sql create mode 100644 internal/endtoend/testdata/schema_scoped_enum/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/schema_scoped_enum/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/schema_scoped_filter/mysql/exec.json create mode 100644 internal/endtoend/testdata/schema_scoped_filter/mysql/go/db.go create mode 100644 internal/endtoend/testdata/schema_scoped_filter/mysql/go/models.go create mode 100644 internal/endtoend/testdata/schema_scoped_filter/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/schema_scoped_filter/mysql/query.sql create mode 100644 internal/endtoend/testdata/schema_scoped_filter/mysql/schema.sql create mode 100644 internal/endtoend/testdata/schema_scoped_filter/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/schema_scoped_filter/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/schema_scoped_filter/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/schema_scoped_filter/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/schema_scoped_filter/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/schema_scoped_filter/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/schema_scoped_filter/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/schema_scoped_list/mysql/exec.json create mode 100644 internal/endtoend/testdata/schema_scoped_list/mysql/go/db.go create mode 100644 internal/endtoend/testdata/schema_scoped_list/mysql/go/models.go create mode 100644 internal/endtoend/testdata/schema_scoped_list/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/schema_scoped_list/mysql/query.sql create mode 100644 internal/endtoend/testdata/schema_scoped_list/mysql/schema.sql create mode 100644 internal/endtoend/testdata/schema_scoped_list/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/schema_scoped_update/mysql/exec.json create mode 100644 internal/endtoend/testdata/schema_scoped_update/mysql/go/db.go create mode 100644 internal/endtoend/testdata/schema_scoped_update/mysql/go/models.go create mode 100644 internal/endtoend/testdata/schema_scoped_update/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/schema_scoped_update/mysql/query.sql create mode 100644 internal/endtoend/testdata/schema_scoped_update/mysql/schema.sql create mode 100644 internal/endtoend/testdata/schema_scoped_update/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/schema_scoped_update/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/schema_scoped_update/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/schema_scoped_update/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/schema_scoped_update/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/schema_scoped_update/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/schema_scoped_update/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/schema_table_column_ref/issue.md create mode 100644 internal/endtoend/testdata/schema_table_column_ref/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/schema_table_column_ref/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/schema_table_column_ref/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/schema_table_column_ref/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/schema_table_column_ref/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/schema_table_column_ref/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/select_column_cast/mysql/go/db.go create mode 100644 internal/endtoend/testdata/select_column_cast/mysql/go/models.go create mode 100644 internal/endtoend/testdata/select_column_cast/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_column_cast/mysql/query.sql create mode 100644 internal/endtoend/testdata/select_column_cast/mysql/schema.sql create mode 100644 internal/endtoend/testdata/select_column_cast/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/select_column_cast/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/select_column_cast/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/select_column_cast/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_column_cast/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/select_column_cast/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/select_column_cast/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/select_column_cast/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/select_column_cast/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/select_column_cast/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_column_cast/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/select_column_cast/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/select_column_cast/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/select_column_cast/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/select_column_cast/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/select_column_cast/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_column_cast/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/select_column_cast/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/select_column_cast/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/select_column_cast/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/select_column_cast/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/select_column_cast/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_column_cast/sqlite/query.sql create mode 100644 internal/endtoend/testdata/select_column_cast/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/select_column_cast/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/select_cte/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/select_cte/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/select_cte/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_cte/sqlite/query.sql create mode 100644 internal/endtoend/testdata/select_cte/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/select_cte/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/select_distinct/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/select_distinct/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/select_distinct/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_distinct/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/select_distinct/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/select_distinct/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/select_distinct/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/select_distinct/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/select_distinct/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_distinct/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/select_distinct/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/select_distinct/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/select_distinct/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/select_distinct/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/select_distinct/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_distinct/stdlib/query.sql create mode 100644 internal/endtoend/testdata/select_distinct/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/select_distinct/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/select_empty_column_list/mysql/query.sql create mode 100644 internal/endtoend/testdata/select_empty_column_list/mysql/schema.sql create mode 100644 internal/endtoend/testdata/select_empty_column_list/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/select_empty_column_list/mysql/stderr.txt create mode 100644 internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/select_empty_column_list/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/select_empty_column_list/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/select_empty_column_list/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_empty_column_list/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/select_empty_column_list/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/select_empty_column_list/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/select_exists/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/select_exists/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/select_exists/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_exists/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/select_exists/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/select_exists/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/select_exists/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/select_exists/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/select_exists/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_exists/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/select_exists/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/select_exists/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/select_exists/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/select_exists/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/select_exists/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_exists/sqlite/query.sql create mode 100644 internal/endtoend/testdata/select_exists/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/select_exists/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/select_exists/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/select_exists/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/select_exists/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_exists/stdlib/query.sql create mode 100644 internal/endtoend/testdata/select_exists/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/select_exists/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/select_in_and/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/select_in_and/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/select_in_and/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_in_and/sqlite/query.sql create mode 100644 internal/endtoend/testdata/select_in_and/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/select_in_and/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/select_limit/mysql/go/db.go create mode 100644 internal/endtoend/testdata/select_limit/mysql/go/models.go create mode 100644 internal/endtoend/testdata/select_limit/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_limit/mysql/query.sql create mode 100644 internal/endtoend/testdata/select_limit/mysql/schema.sql create mode 100644 internal/endtoend/testdata/select_limit/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/select_limit/postgresql/pgx/v4/exec.json create mode 100644 internal/endtoend/testdata/select_limit/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/select_limit/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/select_limit/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_limit/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/select_limit/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/select_limit/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/select_limit/postgresql/pgx/v5/exec.json create mode 100644 internal/endtoend/testdata/select_limit/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/select_limit/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/select_limit/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_limit/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/select_limit/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/select_limit/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/select_limit/postgresql/stdlib/exec.json create mode 100644 internal/endtoend/testdata/select_limit/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/select_limit/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/select_limit/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_limit/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/select_limit/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/select_limit/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/select_limit/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/select_limit/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/select_limit/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_limit/sqlite/query.sql create mode 100644 internal/endtoend/testdata/select_limit/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/select_limit/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/select_nested_count/mysql/go/db.go create mode 100644 internal/endtoend/testdata/select_nested_count/mysql/go/models.go create mode 100644 internal/endtoend/testdata/select_nested_count/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_nested_count/mysql/query.sql create mode 100644 internal/endtoend/testdata/select_nested_count/mysql/schema.sql create mode 100644 internal/endtoend/testdata/select_nested_count/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/select_nested_count/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/select_nested_count/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/select_nested_count/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_nested_count/postgresql/query.sql create mode 100644 internal/endtoend/testdata/select_nested_count/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/select_nested_count/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/select_nested_count/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/select_nested_count/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/select_nested_count/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_nested_count/sqlite/query.sql create mode 100644 internal/endtoend/testdata/select_nested_count/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/select_nested_count/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/select_not_exists/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/select_not_exists/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/select_not_exists/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_not_exists/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/select_not_exists/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/select_not_exists/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/select_not_exists/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/select_not_exists/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/select_not_exists/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_not_exists/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/select_not_exists/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/select_not_exists/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/select_not_exists/sqlite/exec.json create mode 100644 internal/endtoend/testdata/select_not_exists/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/select_not_exists/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/select_not_exists/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_not_exists/sqlite/query.sql create mode 100644 internal/endtoend/testdata/select_not_exists/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/select_not_exists/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/select_not_exists/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/select_not_exists/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/select_not_exists/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_not_exists/stdlib/query.sql create mode 100644 internal/endtoend/testdata/select_not_exists/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/select_not_exists/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/select_sequence/issue.md create mode 100644 internal/endtoend/testdata/select_sequence/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/select_sequence/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/select_sequence/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/select_sequence/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_sequence/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/select_sequence/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/select_sequence/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/select_star/mysql/go/db.go create mode 100644 internal/endtoend/testdata/select_star/mysql/go/models.go create mode 100644 internal/endtoend/testdata/select_star/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_star/mysql/query.sql create mode 100644 internal/endtoend/testdata/select_star/mysql/schema.sql create mode 100644 internal/endtoend/testdata/select_star/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/select_star/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/select_star/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/select_star/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_star/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/select_star/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/select_star/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/select_star/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/select_star/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/select_star/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_star/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/select_star/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/select_star/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/select_star/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/select_star/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/select_star/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_star/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/select_star/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/select_star/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/select_star/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/select_star/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/select_star/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_star/sqlite/query.sql create mode 100644 internal/endtoend/testdata/select_star/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/select_star/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/select_star_quoted/mysql/go/db.go create mode 100644 internal/endtoend/testdata/select_star_quoted/mysql/go/models.go create mode 100644 internal/endtoend/testdata/select_star_quoted/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_star_quoted/mysql/query.sql create mode 100644 internal/endtoend/testdata/select_star_quoted/mysql/schema.sql create mode 100644 internal/endtoend/testdata/select_star_quoted/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/select_star_quoted/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/select_star_quoted/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/select_star_quoted/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_star_quoted/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/select_star_quoted/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/select_star_quoted/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/select_subquery/postgresql/issue.md create mode 100644 internal/endtoend/testdata/select_subquery/postgresql/stdlib/exec.json create mode 100644 internal/endtoend/testdata/select_subquery/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/select_subquery/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/select_subquery/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_subquery/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/select_subquery/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/select_subquery/postgresql/stdlib/sqlc.yaml create mode 100644 internal/endtoend/testdata/select_subquery_alias/issue.md create mode 100644 internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/select_subquery_no_alias/mysql/go/db.go create mode 100644 internal/endtoend/testdata/select_subquery_no_alias/mysql/go/models.go create mode 100644 internal/endtoend/testdata/select_subquery_no_alias/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_subquery_no_alias/mysql/query.sql create mode 100644 internal/endtoend/testdata/select_subquery_no_alias/mysql/schema.sql create mode 100644 internal/endtoend/testdata/select_subquery_no_alias/mysql/sqlc.yaml create mode 100644 internal/endtoend/testdata/select_subquery_no_alias/postgres/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/select_subquery_no_alias/postgres/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/select_subquery_no_alias/postgres/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_subquery_no_alias/postgres/stdlib/query.sql create mode 100644 internal/endtoend/testdata/select_subquery_no_alias/postgres/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/select_subquery_no_alias/postgres/stdlib/sqlc.yaml create mode 100644 internal/endtoend/testdata/select_subquery_no_alias/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/select_subquery_no_alias/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/select_subquery_no_alias/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_subquery_no_alias/sqlite/query.sql create mode 100644 internal/endtoend/testdata/select_subquery_no_alias/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/select_subquery_no_alias/sqlite/sqlc.yaml create mode 100644 internal/endtoend/testdata/select_system/issue.md create mode 100644 internal/endtoend/testdata/select_system/pgx/exec.json create mode 100644 internal/endtoend/testdata/select_system/pgx/go/db.go create mode 100644 internal/endtoend/testdata/select_system/pgx/go/models.go create mode 100644 internal/endtoend/testdata/select_system/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_system/pgx/query.sql create mode 100644 internal/endtoend/testdata/select_system/pgx/schema.sql create mode 100644 internal/endtoend/testdata/select_system/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/select_text_array/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/select_text_array/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/select_text_array/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_text_array/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/select_text_array/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/select_text_array/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/select_text_array/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/select_text_array/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/select_text_array/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_text_array/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/select_text_array/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/select_text_array/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/select_text_array/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/select_text_array/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/select_text_array/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_text_array/stdlib/query.sql create mode 100644 internal/endtoend/testdata/select_text_array/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/select_text_array/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/select_union/mysql/go/db.go create mode 100644 internal/endtoend/testdata/select_union/mysql/go/models.go create mode 100644 internal/endtoend/testdata/select_union/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_union/mysql/query.sql create mode 100644 internal/endtoend/testdata/select_union/mysql/schema.sql create mode 100644 internal/endtoend/testdata/select_union/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/select_union/postgres/pgx/v4/exec.json create mode 100644 internal/endtoend/testdata/select_union/postgres/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/select_union/postgres/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/select_union/postgres/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_union/postgres/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/select_union/postgres/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/select_union/postgres/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/select_union/postgres/pgx/v5/exec.json create mode 100644 internal/endtoend/testdata/select_union/postgres/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/select_union/postgres/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/select_union/postgres/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_union/postgres/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/select_union/postgres/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/select_union/postgres/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/select_union/postgres/stdlib/exec.json create mode 100644 internal/endtoend/testdata/select_union/postgres/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/select_union/postgres/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/select_union/postgres/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_union/postgres/stdlib/query.sql create mode 100644 internal/endtoend/testdata/select_union/postgres/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/select_union/postgres/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/select_union/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/select_union/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/select_union/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_union/sqlite/query.sql create mode 100644 internal/endtoend/testdata/select_union/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/select_union/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/select_union_subquery/issue.md create mode 100644 internal/endtoend/testdata/select_union_subquery/mysql/go/db.go create mode 100644 internal/endtoend/testdata/select_union_subquery/mysql/go/models.go create mode 100644 internal/endtoend/testdata/select_union_subquery/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_union_subquery/mysql/query.sql create mode 100644 internal/endtoend/testdata/select_union_subquery/mysql/schema.sql create mode 100644 internal/endtoend/testdata/select_union_subquery/mysql/sqlc.yaml create mode 100644 internal/endtoend/testdata/select_union_subquery/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/select_union_subquery/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/select_union_subquery/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/select_union_subquery/postgresql/query.sql create mode 100644 internal/endtoend/testdata/select_union_subquery/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/select_union_subquery/postgresql/sqlc.yaml create mode 100644 internal/endtoend/testdata/selectstatic/mysql/go/db.go create mode 100644 internal/endtoend/testdata/selectstatic/mysql/go/models.go create mode 100644 internal/endtoend/testdata/selectstatic/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/selectstatic/mysql/query.sql create mode 100644 internal/endtoend/testdata/selectstatic/mysql/schema.sql create mode 100644 internal/endtoend/testdata/selectstatic/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/show_warnings/mysql/go/db.go create mode 100644 internal/endtoend/testdata/show_warnings/mysql/go/models.go create mode 100644 internal/endtoend/testdata/show_warnings/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/show_warnings/mysql/query.sql create mode 100644 internal/endtoend/testdata/show_warnings/mysql/schema.sql create mode 100644 internal/endtoend/testdata/show_warnings/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/single_param_conflict/mysql/go/db.go create mode 100644 internal/endtoend/testdata/single_param_conflict/mysql/go/models.go create mode 100644 internal/endtoend/testdata/single_param_conflict/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/single_param_conflict/mysql/query.sql create mode 100644 internal/endtoend/testdata/single_param_conflict/mysql/schema.sql create mode 100644 internal/endtoend/testdata/single_param_conflict/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/single_param_conflict/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/single_param_conflict/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/single_param_conflict/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/single_param_conflict/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/single_param_conflict/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/single_param_conflict/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/single_param_conflict/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/single_param_conflict/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/single_param_conflict/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/single_param_conflict/sqlite/query.sql create mode 100644 internal/endtoend/testdata/single_param_conflict/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/single_param_conflict/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/sqlc_arg/mysql/go/db.go create mode 100644 internal/endtoend/testdata/sqlc_arg/mysql/go/models.go create mode 100644 internal/endtoend/testdata/sqlc_arg/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/sqlc_arg/mysql/query.sql create mode 100644 internal/endtoend/testdata/sqlc_arg/mysql/schema.sql create mode 100644 internal/endtoend/testdata/sqlc_arg/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/sqlc_arg/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/sqlc_arg/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/sqlc_arg/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/sqlc_arg/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/sqlc_arg/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/sqlc_arg/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/sqlc_arg/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/sqlc_arg/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/sqlc_arg/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/sqlc_arg/sqlite/query.sql create mode 100644 internal/endtoend/testdata/sqlc_arg/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/sqlc_arg/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/sqlc_arg_invalid/mysql/query.sql create mode 100644 internal/endtoend/testdata/sqlc_arg_invalid/mysql/schema.sql create mode 100644 internal/endtoend/testdata/sqlc_arg_invalid/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/sqlc_arg_invalid/mysql/stderr.txt create mode 100644 internal/endtoend/testdata/sqlc_arg_invalid/postgresql/query.sql create mode 100644 internal/endtoend/testdata/sqlc_arg_invalid/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/sqlc_arg_invalid/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/sqlc_arg_invalid/postgresql/stderr.txt create mode 100644 internal/endtoend/testdata/sqlc_arg_invalid/sqlite/query.sql create mode 100644 internal/endtoend/testdata/sqlc_arg_invalid/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/sqlc_arg_invalid/sqlite/stderr.txt create mode 100644 internal/endtoend/testdata/sqlc_embed/mysql/exec.json create mode 100644 internal/endtoend/testdata/sqlc_embed/mysql/go/db.go create mode 100644 internal/endtoend/testdata/sqlc_embed/mysql/go/models.go create mode 100644 internal/endtoend/testdata/sqlc_embed/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/sqlc_embed/mysql/query.sql create mode 100644 internal/endtoend/testdata/sqlc_embed/mysql/schema.sql create mode 100644 internal/endtoend/testdata/sqlc_embed/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/sqlc_embed/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/sqlc_embed/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/sqlc_embed/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/sqlc_embed/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/sqlc_embed/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/sqlc_embed/postgresql/pgx/sqlc.json create mode 100644 internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/sqlc_embed/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/sqlc_embed/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/sqlc_embed/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/sqlc_embed/sqlite/query.sql create mode 100644 internal/endtoend/testdata/sqlc_embed/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/sqlc_embed/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/sqlc_narg/mysql/go/db.go create mode 100644 internal/endtoend/testdata/sqlc_narg/mysql/go/models.go create mode 100644 internal/endtoend/testdata/sqlc_narg/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/sqlc_narg/mysql/query.sql create mode 100644 internal/endtoend/testdata/sqlc_narg/mysql/schema.sql create mode 100644 internal/endtoend/testdata/sqlc_narg/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/go_strict/db.go create mode 100644 internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/go_strict/models.go create mode 100644 internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/go_strict/query.sql.go create mode 100644 internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/sqlc_narg/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/sqlc_narg/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/sqlc_narg/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/sqlc_narg/sqlite/query.sql create mode 100644 internal/endtoend/testdata/sqlc_narg/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/sqlc_narg/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/sqlc_slice/mysql/go/db.go create mode 100644 internal/endtoend/testdata/sqlc_slice/mysql/go/models.go create mode 100644 internal/endtoend/testdata/sqlc_slice/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/sqlc_slice/mysql/query.sql create mode 100644 internal/endtoend/testdata/sqlc_slice/mysql/schema.sql create mode 100644 internal/endtoend/testdata/sqlc_slice/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/sqlc_slice/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/sqlc_slice/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/sqlc_slice/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/sqlc_slice/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/sqlc_slice/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/sqlc_slice/postgresql/pgx/sqlc.json create mode 100644 internal/endtoend/testdata/sqlc_slice/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/sqlc_slice/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/sqlc_slice/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/sqlc_slice/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/sqlc_slice/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/sqlc_slice/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/sqlc_slice/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/sqlc_slice/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/sqlc_slice/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/sqlc_slice/sqlite/query.sql create mode 100644 internal/endtoend/testdata/sqlc_slice/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/sqlc_slice/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/sqlc_slice_prepared/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/sqlc_slice_prepared/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/sqlc_slice_prepared/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/sqlc_slice_prepared/sqlite/query.sql create mode 100644 internal/endtoend/testdata/sqlc_slice_prepared/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/sqlc_slice_prepared/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/sqlite_skip_todo/db/db.go create mode 100644 internal/endtoend/testdata/sqlite_skip_todo/db/models.go create mode 100644 internal/endtoend/testdata/sqlite_skip_todo/db/query.sql.go create mode 100644 internal/endtoend/testdata/sqlite_skip_todo/query.sql create mode 100644 internal/endtoend/testdata/sqlite_skip_todo/schema.sql create mode 100644 internal/endtoend/testdata/sqlite_skip_todo/sqlc.json create mode 100644 internal/endtoend/testdata/sqlite_table_options/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/sqlite_table_options/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/sqlite_table_options/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/sqlite_table_options/sqlite/query.sql create mode 100644 internal/endtoend/testdata/sqlite_table_options/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/sqlite_table_options/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion/mysql/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion/mysql/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion/mysql/query.sql create mode 100644 internal/endtoend/testdata/star_expansion/mysql/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/star_expansion/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion/sqlite/query.sql create mode 100644 internal/endtoend/testdata/star_expansion/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion_core/mysql/exec.json create mode 100644 internal/endtoend/testdata/star_expansion_core/mysql/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion_core/mysql/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion_core/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion_core/mysql/query.sql create mode 100644 internal/endtoend/testdata/star_expansion_core/mysql/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion_core/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion_core/postgresql/exec.json create mode 100644 internal/endtoend/testdata/star_expansion_core/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion_core/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion_core/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion_core/postgresql/query.sql create mode 100644 internal/endtoend/testdata/star_expansion_core/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion_core/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion_core/sqlite/exec.json create mode 100644 internal/endtoend/testdata/star_expansion_core/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion_core/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion_core/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion_core/sqlite/query.sql create mode 100644 internal/endtoend/testdata/star_expansion_core/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion_core/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion_cte/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion_cte/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion_cte/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion_cte/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/star_expansion_cte/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion_cte/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion_cte/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion_cte/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion_cte/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion_cte/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/star_expansion_cte/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion_cte/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion_cte/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion_cte/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion_cte/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion_cte/stdlib/query.sql create mode 100644 internal/endtoend/testdata/star_expansion_cte/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion_cte/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/stderr.txt create mode 100644 internal/endtoend/testdata/star_expansion_from_cte/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion_from_cte/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion_from_cte/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion_from_cte/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/star_expansion_from_cte/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion_from_cte/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion_from_cte/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion_from_cte/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion_from_cte/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion_from_cte/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/star_expansion_from_cte/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion_from_cte/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion_from_cte/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion_from_cte/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion_from_cte/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion_from_cte/stdlib/query.sql create mode 100644 internal/endtoend/testdata/star_expansion_from_cte/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion_from_cte/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion_join/mysql/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion_join/mysql/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion_join/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion_join/mysql/query.sql create mode 100644 internal/endtoend/testdata/star_expansion_join/mysql/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion_join/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion_join/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion_join/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion_join/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion_join/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/star_expansion_join/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion_join/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion_reserved/mysql/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion_reserved/mysql/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion_reserved/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion_reserved/mysql/query.sql create mode 100644 internal/endtoend/testdata/star_expansion_reserved/mysql/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion_reserved/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion_reserved/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion_reserved/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion_reserved/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion_reserved/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/star_expansion_reserved/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion_reserved/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion_series/issue.md create mode 100644 internal/endtoend/testdata/star_expansion_series/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion_series/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion_series/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion_series/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/star_expansion_series/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion_series/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/star_expansion_subquery/mysql/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion_subquery/mysql/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion_subquery/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion_subquery/mysql/query.sql create mode 100644 internal/endtoend/testdata/star_expansion_subquery/mysql/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion_subquery/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/star_expansion_subquery/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/star_expansion_subquery/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/star_expansion_subquery/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/star_expansion_subquery/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/star_expansion_subquery/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/star_expansion_subquery/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/strict_function_checks/postgresql/query.sql create mode 100644 internal/endtoend/testdata/strict_function_checks/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/strict_function_checks/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/strict_function_checks/postgresql/stderr/base.txt create mode 100644 internal/endtoend/testdata/strict_function_checks/postgresql/stderr/managed-db.txt create mode 100644 internal/endtoend/testdata/subquery_calculated_column/mysql/go/db.go create mode 100644 internal/endtoend/testdata/subquery_calculated_column/mysql/go/models.go create mode 100644 internal/endtoend/testdata/subquery_calculated_column/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/subquery_calculated_column/mysql/query.sql create mode 100644 internal/endtoend/testdata/subquery_calculated_column/mysql/schema.sql create mode 100644 internal/endtoend/testdata/subquery_calculated_column/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/subquery_calculated_column/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/subquery_calculated_column/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/subquery_calculated_column/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/subquery_calculated_column/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/subquery_calculated_column/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/subquery_calculated_column/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/subquery_calculated_column/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/subquery_calculated_column/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/subquery_calculated_column/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/subquery_calculated_column/sqlite/query.sql create mode 100644 internal/endtoend/testdata/subquery_calculated_column/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/subquery_calculated_column/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/sum_type/issue.md create mode 100644 internal/endtoend/testdata/sum_type/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/sum_type/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/sum_type/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/sum_type/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/sum_type/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/sum_type/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/sum_type/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/syntax_errors/mysql/query/from.sql create mode 100644 internal/endtoend/testdata/syntax_errors/mysql/query/select.sql create mode 100644 internal/endtoend/testdata/syntax_errors/mysql/query/typo.sql create mode 100644 internal/endtoend/testdata/syntax_errors/mysql/schema.sql create mode 100644 internal/endtoend/testdata/syntax_errors/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/syntax_errors/mysql/stderr.txt create mode 100644 internal/endtoend/testdata/syntax_errors/postgresql/query/from.sql create mode 100644 internal/endtoend/testdata/syntax_errors/postgresql/query/select.sql create mode 100644 internal/endtoend/testdata/syntax_errors/postgresql/query/typo.sql create mode 100644 internal/endtoend/testdata/syntax_errors/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/syntax_errors/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/syntax_errors/postgresql/stderr.txt create mode 100644 internal/endtoend/testdata/table_function/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/table_function/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/table_function/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/table_function/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/table_function/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/table_function/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/table_function/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/table_function/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/table_function/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/table_function/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/table_function/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/table_function/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/table_function/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/table_function/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/table_function/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/table_function/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/table_function/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/table_function/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/table_function/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/table_function/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/table_function/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/table_function/sqlite/query.sql create mode 100644 internal/endtoend/testdata/table_function/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/table_function/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/table_name_case_sensitivity/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/table_name_case_sensitivity/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/table_name_case_sensitivity/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/table_name_case_sensitivity/sqlite/query.sql create mode 100644 internal/endtoend/testdata/table_name_case_sensitivity/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/table_name_case_sensitivity/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/truncate/mysql/go/db.go create mode 100644 internal/endtoend/testdata/truncate/mysql/go/models.go create mode 100644 internal/endtoend/testdata/truncate/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/truncate/mysql/query.sql create mode 100644 internal/endtoend/testdata/truncate/mysql/schema.sql create mode 100644 internal/endtoend/testdata/truncate/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/truncate/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/truncate/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/truncate/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/truncate/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/truncate/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/truncate/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/truncate/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/truncate/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/truncate/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/truncate/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/truncate/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/truncate/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/truncate/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/truncate/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/truncate/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/truncate/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/truncate/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/truncate/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/types_uuid/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/types_uuid/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/types_uuid/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/types_uuid/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/types_uuid/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/types_uuid/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/unknown_func/pganalyze/exec.json create mode 100644 internal/endtoend/testdata/unknown_func/pganalyze/query.sql create mode 100644 internal/endtoend/testdata/unknown_func/pganalyze/schema.sql create mode 100644 internal/endtoend/testdata/unknown_func/pganalyze/sqlc.json create mode 100644 internal/endtoend/testdata/unknown_func/pganalyze/stderr.txt create mode 100644 internal/endtoend/testdata/unknown_func/pgx/v4/exec.json create mode 100644 internal/endtoend/testdata/unknown_func/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/unknown_func/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/unknown_func/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/unknown_func/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/unknown_func/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/unknown_func/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/unknown_func/pgx/v5/exec.json create mode 100644 internal/endtoend/testdata/unknown_func/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/unknown_func/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/unknown_func/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/unknown_func/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/unknown_func/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/unknown_func/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/unknown_func/stdlib/exec.json create mode 100644 internal/endtoend/testdata/unknown_func/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/unknown_func/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/unknown_func/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/unknown_func/stdlib/query.sql create mode 100644 internal/endtoend/testdata/unknown_func/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/unknown_func/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/unnest/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/unnest/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/unnest/postgresql/pgx/v4/go/querier.go create mode 100644 internal/endtoend/testdata/unnest/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/unnest/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/unnest/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/unnest/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/unnest/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/unnest/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/unnest/postgresql/pgx/v5/go/querier.go create mode 100644 internal/endtoend/testdata/unnest/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/unnest/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/unnest/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/unnest/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/unnest/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/unnest/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/unnest/postgresql/stdlib/go/querier.go create mode 100644 internal/endtoend/testdata/unnest/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/unnest/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/unnest/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/unnest/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/unnest_star/issue.md create mode 100644 internal/endtoend/testdata/unnest_star/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/unnest_star/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/unnest_star/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/unnest_star/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/unnest_star/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/unnest_star/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/unnest_star/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/go/querier.go create mode 100644 internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/go/querier.go create mode 100644 internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/go/querier.go create mode 100644 internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/unsigned_params/mysql/go/db.go create mode 100644 internal/endtoend/testdata/unsigned_params/mysql/go/models.go create mode 100644 internal/endtoend/testdata/unsigned_params/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/unsigned_params/mysql/query.sql create mode 100644 internal/endtoend/testdata/unsigned_params/mysql/schema.sql create mode 100644 internal/endtoend/testdata/unsigned_params/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/untyped_columns/sqlite/stdlib/db/db.go create mode 100644 internal/endtoend/testdata/untyped_columns/sqlite/stdlib/db/models.go create mode 100644 internal/endtoend/testdata/untyped_columns/sqlite/stdlib/db/query.sql.go create mode 100644 internal/endtoend/testdata/untyped_columns/sqlite/stdlib/query.sql create mode 100644 internal/endtoend/testdata/untyped_columns/sqlite/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/untyped_columns/sqlite/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/update_array_index/issue.md create mode 100644 internal/endtoend/testdata/update_array_index/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/update_array_index/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/update_array_index/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/update_array_index/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/update_array_index/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/update_array_index/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/update_array_index/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/update_cte/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/update_cte/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/update_cte/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/update_cte/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/update_cte/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/update_cte/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/update_cte/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/update_cte/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/update_cte/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/update_cte/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/update_cte/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/update_cte/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/update_cte/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/update_cte/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/update_cte/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/update_cte/stdlib/query.sql create mode 100644 internal/endtoend/testdata/update_cte/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/update_cte/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/update_inner_join/db/db.go create mode 100644 internal/endtoend/testdata/update_inner_join/db/models.go create mode 100644 internal/endtoend/testdata/update_inner_join/db/query.sql.go create mode 100644 internal/endtoend/testdata/update_inner_join/query.sql create mode 100644 internal/endtoend/testdata/update_inner_join/schema.sql create mode 100644 internal/endtoend/testdata/update_inner_join/sqlc.json create mode 100644 internal/endtoend/testdata/update_join/mysql/db/db.go create mode 100644 internal/endtoend/testdata/update_join/mysql/db/models.go create mode 100644 internal/endtoend/testdata/update_join/mysql/db/query.sql.go create mode 100644 internal/endtoend/testdata/update_join/mysql/query.sql create mode 100644 internal/endtoend/testdata/update_join/mysql/schema.sql create mode 100644 internal/endtoend/testdata/update_join/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/update_join/postgresql/db/db.go create mode 100644 internal/endtoend/testdata/update_join/postgresql/db/models.go create mode 100644 internal/endtoend/testdata/update_join/postgresql/db/query.sql.go create mode 100644 internal/endtoend/testdata/update_join/postgresql/query.sql create mode 100644 internal/endtoend/testdata/update_join/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/update_join/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/update_set/myql/go/db.go create mode 100644 internal/endtoend/testdata/update_set/myql/go/models.go create mode 100644 internal/endtoend/testdata/update_set/myql/go/query.sql.go create mode 100644 internal/endtoend/testdata/update_set/myql/query.sql create mode 100644 internal/endtoend/testdata/update_set/myql/schema.sql create mode 100644 internal/endtoend/testdata/update_set/myql/sqlc.json create mode 100644 internal/endtoend/testdata/update_set/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/update_set/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/update_set/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/update_set/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/update_set/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/update_set/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/update_set/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/update_set/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/update_set/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/update_set/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/update_set/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/update_set/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/update_set/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/update_set/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/update_set/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/update_set/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/update_set/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/update_set/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/update_set/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/update_set/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/update_set/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/update_set/sqlite/query.sql create mode 100644 internal/endtoend/testdata/update_set/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/update_set/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/update_set_multiple/mysql/go/db.go create mode 100644 internal/endtoend/testdata/update_set_multiple/mysql/go/models.go create mode 100644 internal/endtoend/testdata/update_set_multiple/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/update_set_multiple/mysql/query.sql create mode 100644 internal/endtoend/testdata/update_set_multiple/mysql/schema.sql create mode 100644 internal/endtoend/testdata/update_set_multiple/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/update_set_multiple/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/update_set_multiple/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/update_set_multiple/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/update_set_multiple/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/update_set_multiple/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/update_set_multiple/postgresql/stdlib/sqlc.json create mode 100644 internal/endtoend/testdata/update_set_multiple/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/update_set_multiple/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/update_set_multiple/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/update_set_multiple/sqlite/query.sql create mode 100644 internal/endtoend/testdata/update_set_multiple/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/update_set_multiple/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/update_set_on_conflict/issue.md create mode 100644 internal/endtoend/testdata/update_set_on_conflict/postgresql/pgx/exec.json create mode 100644 internal/endtoend/testdata/update_set_on_conflict/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/update_set_on_conflict/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/update_set_on_conflict/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/update_set_on_conflict/postgresql/pgx/stderr.txt create mode 100644 internal/endtoend/testdata/update_two_table/mysql/go/db.go create mode 100644 internal/endtoend/testdata/update_two_table/mysql/go/models.go create mode 100644 internal/endtoend/testdata/update_two_table/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/update_two_table/mysql/query.sql create mode 100644 internal/endtoend/testdata/update_two_table/mysql/schema.sql create mode 100644 internal/endtoend/testdata/update_two_table/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/upsert/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/upsert/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/upsert/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/upsert/sqlite/query.sql create mode 100644 internal/endtoend/testdata/upsert/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/upsert/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/valid_group_by_reference/mysql/go/db.go create mode 100644 internal/endtoend/testdata/valid_group_by_reference/mysql/go/models.go create mode 100644 internal/endtoend/testdata/valid_group_by_reference/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/valid_group_by_reference/mysql/query.sql create mode 100644 internal/endtoend/testdata/valid_group_by_reference/mysql/schema.sql create mode 100644 internal/endtoend/testdata/valid_group_by_reference/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/valid_group_by_reference/pganalyzer/exec.json create mode 100644 internal/endtoend/testdata/valid_group_by_reference/pganalyzer/go/db.go create mode 100644 internal/endtoend/testdata/valid_group_by_reference/pganalyzer/go/models.go create mode 100644 internal/endtoend/testdata/valid_group_by_reference/pganalyzer/go/query.sql.go create mode 100644 internal/endtoend/testdata/valid_group_by_reference/pganalyzer/query.sql create mode 100644 internal/endtoend/testdata/valid_group_by_reference/pganalyzer/schema.sql create mode 100644 internal/endtoend/testdata/valid_group_by_reference/pganalyzer/sqlc.json create mode 100644 internal/endtoend/testdata/valid_group_by_reference/postgresql/exec.json create mode 100644 internal/endtoend/testdata/valid_group_by_reference/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/valid_group_by_reference/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/valid_group_by_reference/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/valid_group_by_reference/postgresql/query.sql create mode 100644 internal/endtoend/testdata/valid_group_by_reference/postgresql/schema.sql create mode 100644 internal/endtoend/testdata/valid_group_by_reference/postgresql/sqlc.json create mode 100644 internal/endtoend/testdata/vet_disable/exec.json create mode 100644 internal/endtoend/testdata/vet_disable/query.sql create mode 100644 internal/endtoend/testdata/vet_disable/sqlc.yaml create mode 100644 internal/endtoend/testdata/vet_disable/stderr.txt create mode 100644 internal/endtoend/testdata/vet_explain/mysql/db/db.go create mode 100644 internal/endtoend/testdata/vet_explain/mysql/db/models.go create mode 100644 internal/endtoend/testdata/vet_explain/mysql/db/query.sql.go create mode 100644 internal/endtoend/testdata/vet_explain/mysql/query.sql create mode 100644 internal/endtoend/testdata/vet_explain/mysql/schema.sql create mode 100644 internal/endtoend/testdata/vet_explain/mysql/sqlc.yaml create mode 100644 internal/endtoend/testdata/vet_failures/exec.json create mode 100644 internal/endtoend/testdata/vet_failures/query.sql create mode 100644 internal/endtoend/testdata/vet_failures/schema.sql create mode 100644 internal/endtoend/testdata/vet_failures/sqlc.yaml create mode 100644 internal/endtoend/testdata/vet_failures/stderr.txt create mode 100644 internal/endtoend/testdata/virtual_table/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/virtual_table/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/virtual_table/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/virtual_table/sqlite/query.sql create mode 100644 internal/endtoend/testdata/virtual_table/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/virtual_table/sqlite/sqlc.yaml create mode 100644 internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/exec.json create mode 100644 internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/query.sql create mode 100644 internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/sqlc.yaml create mode 100644 internal/endtoend/testdata/wasm_plugin_sqlc_gen_greeter/gen/hello.txt create mode 100644 internal/endtoend/testdata/wasm_plugin_sqlc_gen_greeter/query.sql create mode 100644 internal/endtoend/testdata/wasm_plugin_sqlc_gen_greeter/schema.sql create mode 100644 internal/endtoend/testdata/wasm_plugin_sqlc_gen_greeter/sqlc.json create mode 100644 internal/endtoend/testdata/wasm_plugin_sqlc_gen_test/gen/env.json create mode 100644 internal/endtoend/testdata/wasm_plugin_sqlc_gen_test/query.sql create mode 100644 internal/endtoend/testdata/wasm_plugin_sqlc_gen_test/schema.sql create mode 100644 internal/endtoend/testdata/wasm_plugin_sqlc_gen_test/sqlc.json create mode 100644 internal/endtoend/testdata/wasm_plugin_sqlc_gen_unsafe_paths/query.sql create mode 100644 internal/endtoend/testdata/wasm_plugin_sqlc_gen_unsafe_paths/schema.sql create mode 100644 internal/endtoend/testdata/wasm_plugin_sqlc_gen_unsafe_paths/sqlc.json create mode 100644 internal/endtoend/testdata/wasm_plugin_sqlc_gen_unsafe_paths/stderr.txt create mode 100644 internal/endtoend/testdata/wasm_plugin_sqlc_gen_unsafe_paths/stderr_windows.txt create mode 100644 internal/endtoend/testdata/where_collate/sqlite/go/db.go create mode 100644 internal/endtoend/testdata/where_collate/sqlite/go/models.go create mode 100644 internal/endtoend/testdata/where_collate/sqlite/go/query.sql.go create mode 100644 internal/endtoend/testdata/where_collate/sqlite/query.sql create mode 100644 internal/endtoend/testdata/where_collate/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/where_collate/sqlite/sqlc.json create mode 100644 internal/endtoend/testdata/wrap_errors/mysql/db/db.go create mode 100644 internal/endtoend/testdata/wrap_errors/mysql/db/models.go create mode 100644 internal/endtoend/testdata/wrap_errors/mysql/db/query.sql.go create mode 100644 internal/endtoend/testdata/wrap_errors/mysql/query.sql create mode 100644 internal/endtoend/testdata/wrap_errors/mysql/schema.sql create mode 100644 internal/endtoend/testdata/wrap_errors/mysql/sqlc.yaml create mode 100644 internal/endtoend/testdata/wrap_errors/postgresql/pgx/db/db.go create mode 100644 internal/endtoend/testdata/wrap_errors/postgresql/pgx/db/models.go create mode 100644 internal/endtoend/testdata/wrap_errors/postgresql/pgx/db/query.sql.go create mode 100644 internal/endtoend/testdata/wrap_errors/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/wrap_errors/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/wrap_errors/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/wrap_errors/postgresql/stdlib/db/db.go create mode 100644 internal/endtoend/testdata/wrap_errors/postgresql/stdlib/db/models.go create mode 100644 internal/endtoend/testdata/wrap_errors/postgresql/stdlib/db/query.sql.go create mode 100644 internal/endtoend/testdata/wrap_errors/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/wrap_errors/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/wrap_errors/postgresql/stdlib/sqlc.yaml create mode 100644 internal/endtoend/testdata/wrap_errors/sqlite/db/db.go create mode 100644 internal/endtoend/testdata/wrap_errors/sqlite/db/models.go create mode 100644 internal/endtoend/testdata/wrap_errors/sqlite/db/query.sql.go create mode 100644 internal/endtoend/testdata/wrap_errors/sqlite/query.sql create mode 100644 internal/endtoend/testdata/wrap_errors/sqlite/schema.sql create mode 100644 internal/endtoend/testdata/wrap_errors/sqlite/sqlc.yaml create mode 100644 internal/endtoend/testdata/yaml_overrides/go/db.go create mode 100644 internal/endtoend/testdata/yaml_overrides/go/models.go create mode 100644 internal/endtoend/testdata/yaml_overrides/go/query.sql.go create mode 100644 internal/endtoend/testdata/yaml_overrides/sql/query.sql create mode 100644 internal/endtoend/testdata/yaml_overrides/sql/schema.sql create mode 100644 internal/endtoend/testdata/yaml_overrides/sqlc.yaml create mode 100644 internal/endtoend/vet_test.go create mode 100644 internal/engine/clickhouse/catalog.go create mode 100644 internal/engine/clickhouse/convert.go create mode 100644 internal/engine/clickhouse/dialect/dialect.json create mode 100644 internal/engine/clickhouse/dialect/functions.jsonl create mode 100644 internal/engine/clickhouse/dialect/types.jsonl create mode 100644 internal/engine/clickhouse/format.go create mode 100644 internal/engine/clickhouse/parse.go create mode 100644 internal/engine/clickhouse/reserved.go create mode 100644 internal/engine/clickhouse/seed.go create mode 100644 internal/engine/clickhouse/stdlib.go create mode 100644 internal/engine/clickhouse/utils.go create mode 100644 internal/engine/dolphin/CLAUDE.md create mode 100644 internal/engine/dolphin/catalog.go create mode 100644 internal/engine/dolphin/convert.go create mode 100644 internal/engine/dolphin/dialect/dialect.json create mode 100644 internal/engine/dolphin/dialect/functions.jsonl create mode 100644 internal/engine/dolphin/dialect/operators.jsonl create mode 100644 internal/engine/dolphin/dialect/relations.jsonl create mode 100644 internal/engine/dolphin/dialect/types.jsonl create mode 100644 internal/engine/dolphin/fingerprint.go create mode 100644 internal/engine/dolphin/format.go create mode 100644 internal/engine/dolphin/parse.go create mode 100644 internal/engine/dolphin/reserved.go create mode 100644 internal/engine/dolphin/seed.go create mode 100644 internal/engine/dolphin/stdlib.go create mode 100644 internal/engine/dolphin/utils.go create mode 100644 internal/engine/duckdb/convert.go create mode 100644 internal/engine/duckdb/dialect/dialect.json create mode 100644 internal/engine/duckdb/dialect/operators.jsonl create mode 100644 internal/engine/duckdb/dialect/types.jsonl create mode 100644 internal/engine/duckdb/parse.go create mode 100644 internal/engine/duckdb/reserved.go create mode 100644 internal/engine/duckdb/seed.go create mode 100644 internal/engine/duckdb/utils.go create mode 100644 internal/engine/googlesql/catalog.go create mode 100644 internal/engine/googlesql/convert.go create mode 100644 internal/engine/googlesql/dialect/dialect.json create mode 100644 internal/engine/googlesql/dialect/functions.jsonl create mode 100644 internal/engine/googlesql/dialect/operators.jsonl create mode 100644 internal/engine/googlesql/dialect/relations.jsonl create mode 100644 internal/engine/googlesql/dialect/types.jsonl create mode 100644 internal/engine/googlesql/parse.go create mode 100644 internal/engine/googlesql/reserved.go create mode 100644 internal/engine/googlesql/seed.go create mode 100644 internal/engine/googlesql/stdlib.go create mode 100644 internal/engine/googlesql/utils.go create mode 100644 internal/engine/mssql/convert.go create mode 100644 internal/engine/mssql/dialect/dialect.json create mode 100644 internal/engine/mssql/dialect/functions.jsonl create mode 100644 internal/engine/mssql/dialect/types.jsonl create mode 100644 internal/engine/mssql/parse.go create mode 100644 internal/engine/mssql/reserved.go create mode 100644 internal/engine/mssql/seed.go create mode 100644 internal/engine/mssql/utils.go create mode 100644 internal/engine/postgresql/analyzer/analyze.go create mode 100644 internal/engine/postgresql/catalog.go create mode 100644 internal/engine/postgresql/catalog_test.go create mode 100644 internal/engine/postgresql/convert.go create mode 100644 internal/engine/postgresql/dialect/dialect.json create mode 100644 internal/engine/postgresql/dialect/extensions/adminpack/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/amcheck/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/btree_gin/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/btree_gist/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/btree_gist/types.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/citext/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/citext/types.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/cube/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/cube/types.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/dblink/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/dblink/types.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/earthdistance/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/earthdistance/types.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/file_fdw/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/fuzzystrmatch/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/hstore/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/hstore/types.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/intagg/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/intarray/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/intarray/types.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/isn/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/isn/types.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/lo/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/lo/types.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/ltree/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/ltree/types.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/pageinspect/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/pg_buffercache/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/pg_freespacemap/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/pg_prewarm/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/pg_stat_statements/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/pg_trgm/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/pg_trgm/types.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/pg_visibility/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/pgcrypto/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/pgrowlocks/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/pgstattuple/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/postgres_fdw/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/seg/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/seg/types.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/sslinfo/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/tablefunc/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/tablefunc/types.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/tcn/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/unaccent/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/uuid-ossp/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/extensions/xml2/functions.jsonl create mode 100644 internal/engine/postgresql/dialect/operators.jsonl create mode 100644 internal/engine/postgresql/dialect/types.jsonl create mode 100644 internal/engine/postgresql/extension.go create mode 100644 internal/engine/postgresql/parse.go create mode 100644 internal/engine/postgresql/pg_temp.go create mode 100644 internal/engine/postgresql/reserved.go create mode 100644 internal/engine/postgresql/rewrite_test.go create mode 100644 internal/engine/postgresql/seed.go create mode 100644 internal/engine/postgresql/utils.go create mode 100644 internal/engine/sqlite/analyzer/analyze.go create mode 100644 internal/engine/sqlite/catalog.go create mode 100644 internal/engine/sqlite/convert.go create mode 100644 internal/engine/sqlite/dialect/dialect.json create mode 100644 internal/engine/sqlite/dialect/extensions/enable_fts3/functions.jsonl create mode 100644 internal/engine/sqlite/dialect/extensions/enable_fts5/functions.jsonl create mode 100644 internal/engine/sqlite/dialect/extensions/enable_geopoly/functions.jsonl create mode 100644 internal/engine/sqlite/dialect/extensions/enable_offset_sql_func/functions.jsonl create mode 100644 internal/engine/sqlite/dialect/extensions/enable_percentile/functions.jsonl create mode 100644 internal/engine/sqlite/dialect/extensions/enable_rtree/functions.jsonl create mode 100644 internal/engine/sqlite/dialect/extensions/soundex/functions.jsonl create mode 100644 internal/engine/sqlite/dialect/functions.jsonl create mode 100644 internal/engine/sqlite/dialect/operators.jsonl create mode 100644 internal/engine/sqlite/dialect/types.jsonl create mode 100644 internal/engine/sqlite/extension.go create mode 100644 internal/engine/sqlite/format.go create mode 100644 internal/engine/sqlite/parse.go create mode 100644 internal/engine/sqlite/reserved.go create mode 100644 internal/engine/sqlite/seed.go create mode 100644 internal/engine/sqlite/stdlib.go create mode 100644 internal/engine/sqlite/utils.go create mode 100644 internal/ext/handler.go create mode 100644 internal/ext/process/gen.go create mode 100644 internal/ext/wasm/runner.go create mode 100644 internal/ext/wasm/wasm.go create mode 100644 internal/goldeneye/README.md create mode 100644 internal/goldeneye/analysis/analysis.go create mode 100644 internal/goldeneye/clickhouse/analyze.go create mode 100644 internal/goldeneye/clickhouse/check.go create mode 100644 internal/goldeneye/clickhouse/clickhouse.go create mode 100644 internal/goldeneye/clickhouse/clickhouse_test.go create mode 100644 internal/goldeneye/clickhouse/install.go create mode 100644 internal/goldeneye/clickhouse/local.go create mode 100644 internal/goldeneye/clickhouse/queries.go create mode 100644 internal/goldeneye/clickhouse/tree.go create mode 100644 internal/goldeneye/clickhouse/types.go create mode 100644 internal/goldeneye/cmd/goldeneye/main.go create mode 100644 internal/goldeneye/dialect/dialect.go create mode 100644 internal/goldeneye/duckdb/analyze.go create mode 100644 internal/goldeneye/duckdb/duckdb.go create mode 100644 internal/goldeneye/duckdb/duckdb_test.go create mode 100644 internal/goldeneye/duckdb/install.go create mode 100644 internal/goldeneye/duckdb/text.go create mode 100644 internal/goldeneye/duckdb/types.go create mode 100644 internal/goldeneye/endtoend/endtoend.go create mode 100644 internal/goldeneye/endtoend/query.go create mode 100644 internal/goldeneye/go.mod create mode 100644 internal/goldeneye/go.sum create mode 100644 internal/goldeneye/mssql/analyze.go create mode 100644 internal/goldeneye/mssql/mssql.go create mode 100644 internal/goldeneye/mssql/mssql_test.go create mode 100644 internal/goldeneye/mssql/plan.go create mode 100644 internal/goldeneye/mssql/relations.go create mode 100644 internal/goldeneye/mysql/analyze.go create mode 100644 internal/goldeneye/mysql/mysql.go create mode 100644 internal/goldeneye/mysql/mysql_test.go create mode 100644 internal/goldeneye/mysql/relations.go create mode 100644 internal/goldeneye/mysql/text.go create mode 100644 internal/goldeneye/mysql/trace.go create mode 100644 internal/goldeneye/postgresql/postgresql.go create mode 100644 internal/goldeneye/postgresql/postgresql_test.go create mode 100644 internal/goldeneye/postgresql/proc.go create mode 100644 internal/goldeneye/postgresql/relation.go create mode 100644 internal/goldeneye/spanner/analyze.go create mode 100644 internal/goldeneye/spanner/plan.go create mode 100644 internal/goldeneye/spanner/relations.go create mode 100644 internal/goldeneye/spanner/spanner.go create mode 100644 internal/goldeneye/spanner/spanner_test.go create mode 100644 internal/goldeneye/sqlite/analyze.go create mode 100644 internal/goldeneye/sqlite/bytecode.go create mode 100644 internal/goldeneye/sqlite/catalog.go create mode 100644 internal/goldeneye/sqlite/install.go create mode 100644 internal/goldeneye/sqlite/shell.go create mode 100644 internal/goldeneye/sqlite/signatures.go create mode 100644 internal/goldeneye/sqlite/source.go create mode 100644 internal/goldeneye/sqlite/sqlite.go create mode 100644 internal/goldeneye/sqlite/sqlite_test.go create mode 100644 internal/inflection/singular.go create mode 100644 internal/info/facts.go create mode 100644 internal/metadata/meta.go create mode 100644 internal/metadata/meta_test.go create mode 100644 internal/migrations/migrations.go create mode 100644 internal/migrations/migrations_test.go create mode 100644 internal/multierr/error.go create mode 100644 internal/opts/experiment.go create mode 100644 internal/opts/experiment_test.go create mode 100644 internal/opts/parser.go create mode 100644 internal/pattern/match.go create mode 100644 internal/pgx/poolcache/poolcache.go create mode 100644 internal/plugin/codegen.pb.go create mode 100644 internal/plugin/codegen_grpc.pb.go create mode 100644 internal/quickdb/mysql.go create mode 100644 internal/quickdb/rpc.go create mode 100755 internal/quickdb/v1/quickdb.pb.go create mode 100644 internal/quickdb/v1/quickdb_grpc.pb.go create mode 100644 internal/rpc/errors.go create mode 100644 internal/rpc/interceptor.go create mode 100644 internal/shfmt/shfmt.go create mode 100644 internal/shfmt/shfmt_test.go create mode 100644 internal/source/code.go create mode 100644 internal/source/mutate_test.go create mode 100644 internal/sql/ast/CLAUDE.md create mode 100644 internal/sql/ast/a_array_expr.go create mode 100644 internal/sql/ast/a_const.go create mode 100644 internal/sql/ast/a_expr.go create mode 100644 internal/sql/ast/a_expr_kind.go create mode 100644 internal/sql/ast/a_indices.go create mode 100644 internal/sql/ast/a_indirection.go create mode 100644 internal/sql/ast/a_star.go create mode 100644 internal/sql/ast/access_priv.go create mode 100644 internal/sql/ast/agg_split.go create mode 100644 internal/sql/ast/agg_strategy.go create mode 100644 internal/sql/ast/aggref.go create mode 100644 internal/sql/ast/alias.go create mode 100644 internal/sql/ast/alter_collation_stmt.go create mode 100644 internal/sql/ast/alter_database_set_stmt.go create mode 100644 internal/sql/ast/alter_database_stmt.go create mode 100644 internal/sql/ast/alter_default_privileges_stmt.go create mode 100644 internal/sql/ast/alter_domain_stmt.go create mode 100644 internal/sql/ast/alter_enum_stmt.go create mode 100644 internal/sql/ast/alter_event_trig_stmt.go create mode 100644 internal/sql/ast/alter_extension_contents_stmt.go create mode 100644 internal/sql/ast/alter_extension_stmt.go create mode 100644 internal/sql/ast/alter_fdw_stmt.go create mode 100644 internal/sql/ast/alter_foreign_server_stmt.go create mode 100644 internal/sql/ast/alter_function_stmt.go create mode 100644 internal/sql/ast/alter_object_depends_stmt.go create mode 100644 internal/sql/ast/alter_object_schema_stmt.go create mode 100644 internal/sql/ast/alter_op_family_stmt.go create mode 100644 internal/sql/ast/alter_operator_stmt.go create mode 100644 internal/sql/ast/alter_owner_stmt.go create mode 100644 internal/sql/ast/alter_policy_stmt.go create mode 100644 internal/sql/ast/alter_publication_stmt.go create mode 100644 internal/sql/ast/alter_role_set_stmt.go create mode 100644 internal/sql/ast/alter_role_stmt.go create mode 100644 internal/sql/ast/alter_seq_stmt.go create mode 100644 internal/sql/ast/alter_subscription_stmt.go create mode 100644 internal/sql/ast/alter_subscription_type.go create mode 100644 internal/sql/ast/alter_system_stmt.go create mode 100644 internal/sql/ast/alter_table_cmd.go create mode 100644 internal/sql/ast/alter_table_move_all_stmt.go create mode 100644 internal/sql/ast/alter_table_set_schema_stmt.go create mode 100644 internal/sql/ast/alter_table_space_options_stmt.go create mode 100644 internal/sql/ast/alter_table_stmt.go create mode 100644 internal/sql/ast/alter_table_type.go create mode 100644 internal/sql/ast/alter_ts_config_type.go create mode 100644 internal/sql/ast/alter_ts_configuration_stmt.go create mode 100644 internal/sql/ast/alter_ts_dictionary_stmt.go create mode 100644 internal/sql/ast/alter_type_add_value_stmt.go create mode 100644 internal/sql/ast/alter_type_rename_value_stmt.go create mode 100644 internal/sql/ast/alter_type_set_schema_stmt.go create mode 100644 internal/sql/ast/alter_user_mapping_stmt.go create mode 100644 internal/sql/ast/alternative_sub_plan.go create mode 100644 internal/sql/ast/array_coerce_expr.go create mode 100644 internal/sql/ast/array_expr.go create mode 100644 internal/sql/ast/array_ref.go create mode 100644 internal/sql/ast/between_expr.go create mode 100644 internal/sql/ast/bit_string.go create mode 100644 internal/sql/ast/block_id_data.go create mode 100644 internal/sql/ast/bool_expr.go create mode 100644 internal/sql/ast/bool_expr_type.go create mode 100644 internal/sql/ast/bool_test_type.go create mode 100644 internal/sql/ast/boolean.go create mode 100644 internal/sql/ast/boolean_test_expr.go create mode 100644 internal/sql/ast/call_stmt.go create mode 100644 internal/sql/ast/case_expr.go create mode 100644 internal/sql/ast/case_test_expr.go create mode 100644 internal/sql/ast/case_when.go create mode 100644 internal/sql/ast/check_point_stmt.go create mode 100644 internal/sql/ast/close_portal_stmt.go create mode 100644 internal/sql/ast/cluster_stmt.go create mode 100644 internal/sql/ast/cmd_type.go create mode 100644 internal/sql/ast/coalesce_expr.go create mode 100644 internal/sql/ast/coerce_to_domain.go create mode 100644 internal/sql/ast/coerce_to_domain_value.go create mode 100644 internal/sql/ast/coerce_via_io.go create mode 100644 internal/sql/ast/coercion_context.go create mode 100644 internal/sql/ast/coercion_form.go create mode 100644 internal/sql/ast/collate_clause.go create mode 100644 internal/sql/ast/collate_expr.go create mode 100644 internal/sql/ast/column_def.go create mode 100644 internal/sql/ast/column_ref.go create mode 100644 internal/sql/ast/comment.go create mode 100644 internal/sql/ast/comment_on_column_stmt.go create mode 100644 internal/sql/ast/comment_on_schema_stmt.go create mode 100644 internal/sql/ast/comment_on_table_stmt.go create mode 100644 internal/sql/ast/comment_on_type_stmt.go create mode 100644 internal/sql/ast/comment_on_view_stmt.go create mode 100644 internal/sql/ast/comment_stmt.go create mode 100644 internal/sql/ast/common_table_expr.go create mode 100644 internal/sql/ast/composite_type_stmt.go create mode 100644 internal/sql/ast/const.go create mode 100644 internal/sql/ast/constr_type.go create mode 100644 internal/sql/ast/constraint.go create mode 100644 internal/sql/ast/constraints_set_stmt.go create mode 100644 internal/sql/ast/convert_rowtype_expr.go create mode 100644 internal/sql/ast/copy_stmt.go create mode 100644 internal/sql/ast/create_am_stmt.go create mode 100644 internal/sql/ast/create_cast_stmt.go create mode 100644 internal/sql/ast/create_conversion_stmt.go create mode 100644 internal/sql/ast/create_domain_stmt.go create mode 100644 internal/sql/ast/create_enum_stmt.go create mode 100644 internal/sql/ast/create_event_trig_stmt.go create mode 100644 internal/sql/ast/create_extension_stmt.go create mode 100644 internal/sql/ast/create_fdw_stmt.go create mode 100644 internal/sql/ast/create_foreign_server_stmt.go create mode 100644 internal/sql/ast/create_foreign_table_stmt.go create mode 100644 internal/sql/ast/create_function_stmt.go create mode 100644 internal/sql/ast/create_op_class_item.go create mode 100644 internal/sql/ast/create_op_class_stmt.go create mode 100644 internal/sql/ast/create_op_family_stmt.go create mode 100644 internal/sql/ast/create_p_lang_stmt.go create mode 100644 internal/sql/ast/create_policy_stmt.go create mode 100644 internal/sql/ast/create_publication_stmt.go create mode 100644 internal/sql/ast/create_range_stmt.go create mode 100644 internal/sql/ast/create_role_stmt.go create mode 100644 internal/sql/ast/create_schema_stmt.go create mode 100644 internal/sql/ast/create_seq_stmt.go create mode 100644 internal/sql/ast/create_stats_stmt.go create mode 100644 internal/sql/ast/create_stmt.go create mode 100644 internal/sql/ast/create_subscription_stmt.go create mode 100644 internal/sql/ast/create_table_as_stmt.go create mode 100644 internal/sql/ast/create_table_space_stmt.go create mode 100644 internal/sql/ast/create_table_stmt.go create mode 100644 internal/sql/ast/create_transform_stmt.go create mode 100644 internal/sql/ast/create_trig_stmt.go create mode 100644 internal/sql/ast/create_user_mapping_stmt.go create mode 100644 internal/sql/ast/createdb_stmt.go create mode 100644 internal/sql/ast/current_of_expr.go create mode 100644 internal/sql/ast/deallocate_stmt.go create mode 100644 internal/sql/ast/declare_cursor_stmt.go create mode 100644 internal/sql/ast/def_elem.go create mode 100644 internal/sql/ast/def_elem_action.go create mode 100644 internal/sql/ast/define_stmt.go create mode 100644 internal/sql/ast/delete_stmt.go create mode 100644 internal/sql/ast/discard_mode.go create mode 100644 internal/sql/ast/discard_stmt.go create mode 100644 internal/sql/ast/do_stmt.go create mode 100644 internal/sql/ast/drop_behavior.go create mode 100644 internal/sql/ast/drop_function_stmt.go create mode 100644 internal/sql/ast/drop_owned_stmt.go create mode 100644 internal/sql/ast/drop_role_stmt.go create mode 100644 internal/sql/ast/drop_schema_stmt.go create mode 100644 internal/sql/ast/drop_stmt.go create mode 100644 internal/sql/ast/drop_subscription_stmt.go create mode 100644 internal/sql/ast/drop_table_space_stmt.go create mode 100644 internal/sql/ast/drop_table_stmt.go create mode 100644 internal/sql/ast/drop_type_stmt.go create mode 100644 internal/sql/ast/drop_user_mapping_stmt.go create mode 100644 internal/sql/ast/dropdb_stmt.go create mode 100644 internal/sql/ast/execute_stmt.go create mode 100644 internal/sql/ast/explain_stmt.go create mode 100644 internal/sql/ast/expr.go create mode 100644 internal/sql/ast/fetch_direction.go create mode 100644 internal/sql/ast/fetch_stmt.go create mode 100644 internal/sql/ast/field_select.go create mode 100644 internal/sql/ast/field_store.go create mode 100644 internal/sql/ast/float.go create mode 100644 internal/sql/ast/from_expr.go create mode 100644 internal/sql/ast/func_call.go create mode 100644 internal/sql/ast/func_expr.go create mode 100644 internal/sql/ast/func_name.go create mode 100644 internal/sql/ast/func_param.go create mode 100644 internal/sql/ast/func_spec.go create mode 100644 internal/sql/ast/function_parameter.go create mode 100644 internal/sql/ast/function_parameter_mode.go create mode 100644 internal/sql/ast/grant_object_type.go create mode 100644 internal/sql/ast/grant_role_stmt.go create mode 100644 internal/sql/ast/grant_stmt.go create mode 100644 internal/sql/ast/grant_target_type.go create mode 100644 internal/sql/ast/grouping_func.go create mode 100644 internal/sql/ast/grouping_set.go create mode 100644 internal/sql/ast/grouping_set_kind.go create mode 100644 internal/sql/ast/import_foreign_schema_stmt.go create mode 100644 internal/sql/ast/import_foreign_schema_type.go create mode 100644 internal/sql/ast/in.go create mode 100644 internal/sql/ast/index_elem.go create mode 100644 internal/sql/ast/index_stmt.go create mode 100644 internal/sql/ast/infer_clause.go create mode 100644 internal/sql/ast/inference_elem.go create mode 100644 internal/sql/ast/inline_code_block.go create mode 100644 internal/sql/ast/insert_stmt.go create mode 100644 internal/sql/ast/integer.go create mode 100644 internal/sql/ast/interval_expr.go create mode 100644 internal/sql/ast/into_clause.go create mode 100644 internal/sql/ast/join_expr.go create mode 100644 internal/sql/ast/join_type.go create mode 100644 internal/sql/ast/list.go create mode 100644 internal/sql/ast/listen_stmt.go create mode 100644 internal/sql/ast/load_stmt.go create mode 100644 internal/sql/ast/lock_clause_strength.go create mode 100644 internal/sql/ast/lock_stmt.go create mode 100644 internal/sql/ast/lock_wait_policy.go create mode 100644 internal/sql/ast/locking_clause.go create mode 100644 internal/sql/ast/min_max_expr.go create mode 100644 internal/sql/ast/min_max_op.go create mode 100644 internal/sql/ast/multi_assign_ref.go create mode 100644 internal/sql/ast/named_arg_expr.go create mode 100644 internal/sql/ast/next_value_expr.go create mode 100644 internal/sql/ast/node.go create mode 100644 internal/sql/ast/node_tag.go create mode 100644 internal/sql/ast/notify_stmt.go create mode 100644 internal/sql/ast/null.go create mode 100644 internal/sql/ast/null_test_expr.go create mode 100644 internal/sql/ast/null_test_type.go create mode 100644 internal/sql/ast/object_type.go create mode 100644 internal/sql/ast/object_with_args.go create mode 100644 internal/sql/ast/on_commit_action.go create mode 100644 internal/sql/ast/on_conflict_action.go create mode 100644 internal/sql/ast/on_conflict_clause.go create mode 100644 internal/sql/ast/on_conflict_expr.go create mode 100644 internal/sql/ast/on_duplicate_key_update.go create mode 100644 internal/sql/ast/op_expr.go create mode 100644 internal/sql/ast/overriding_kind.go create mode 100644 internal/sql/ast/param.go create mode 100644 internal/sql/ast/param_exec_data.go create mode 100644 internal/sql/ast/param_extern_data.go create mode 100644 internal/sql/ast/param_kind.go create mode 100644 internal/sql/ast/param_list_info_data.go create mode 100644 internal/sql/ast/param_ref.go create mode 100644 internal/sql/ast/paren_expr.go create mode 100644 internal/sql/ast/partition_bound_spec.go create mode 100644 internal/sql/ast/partition_cmd.go create mode 100644 internal/sql/ast/partition_elem.go create mode 100644 internal/sql/ast/partition_range_datum.go create mode 100644 internal/sql/ast/partition_range_datum_kind.go create mode 100644 internal/sql/ast/partition_spec.go create mode 100644 internal/sql/ast/prepare_stmt.go create mode 100644 internal/sql/ast/print.go create mode 100644 internal/sql/ast/printer/printer.go create mode 100644 internal/sql/ast/query.go create mode 100644 internal/sql/ast/query_source.go create mode 100644 internal/sql/ast/range_function.go create mode 100644 internal/sql/ast/range_subselect.go create mode 100644 internal/sql/ast/range_table_func.go create mode 100644 internal/sql/ast/range_table_func_col.go create mode 100644 internal/sql/ast/range_table_sample.go create mode 100644 internal/sql/ast/range_tbl_entry.go create mode 100644 internal/sql/ast/range_tbl_function.go create mode 100644 internal/sql/ast/range_tbl_ref.go create mode 100644 internal/sql/ast/range_var.go create mode 100644 internal/sql/ast/raw_stmt.go create mode 100644 internal/sql/ast/reassign_owned_stmt.go create mode 100644 internal/sql/ast/refresh_mat_view_stmt.go create mode 100644 internal/sql/ast/reindex_object_type.go create mode 100644 internal/sql/ast/reindex_stmt.go create mode 100644 internal/sql/ast/relabel_type.go create mode 100644 internal/sql/ast/rename_column_stmt.go create mode 100644 internal/sql/ast/rename_stmt.go create mode 100644 internal/sql/ast/rename_table_stmt.go create mode 100644 internal/sql/ast/rename_type_stmt.go create mode 100644 internal/sql/ast/replica_identity_stmt.go create mode 100644 internal/sql/ast/res_target.go create mode 100644 internal/sql/ast/returning.go create mode 100644 internal/sql/ast/role_spec.go create mode 100644 internal/sql/ast/role_spec_type.go create mode 100644 internal/sql/ast/role_stmt_type.go create mode 100644 internal/sql/ast/row_compare_expr.go create mode 100644 internal/sql/ast/row_compare_type.go create mode 100644 internal/sql/ast/row_expr.go create mode 100644 internal/sql/ast/row_mark_clause.go create mode 100644 internal/sql/ast/rte_kind.go create mode 100644 internal/sql/ast/rule_stmt.go create mode 100644 internal/sql/ast/scalar_array_op_expr.go create mode 100644 internal/sql/ast/scan_direction.go create mode 100644 internal/sql/ast/sec_label_stmt.go create mode 100644 internal/sql/ast/select_stmt.go create mode 100644 internal/sql/ast/set_op_cmd.go create mode 100644 internal/sql/ast/set_op_strategy.go create mode 100644 internal/sql/ast/set_operation.go create mode 100644 internal/sql/ast/set_operation_stmt.go create mode 100644 internal/sql/ast/set_to_default.go create mode 100644 internal/sql/ast/sort_by.go create mode 100644 internal/sql/ast/sort_by_dir.go create mode 100644 internal/sql/ast/sort_by_nulls.go create mode 100644 internal/sql/ast/sort_group_clause.go create mode 100644 internal/sql/ast/sql_value_function.go create mode 100644 internal/sql/ast/sql_value_function_op.go create mode 100644 internal/sql/ast/statement.go create mode 100644 internal/sql/ast/string.go create mode 100644 internal/sql/ast/sub_link.go create mode 100644 internal/sql/ast/sub_plan.go create mode 100644 internal/sql/ast/table_func.go create mode 100644 internal/sql/ast/table_like_clause.go create mode 100644 internal/sql/ast/table_like_option.go create mode 100644 internal/sql/ast/table_name.go create mode 100644 internal/sql/ast/table_sample_clause.go create mode 100644 internal/sql/ast/target_entry.go create mode 100644 internal/sql/ast/todo.go create mode 100644 internal/sql/ast/transaction_stmt.go create mode 100644 internal/sql/ast/transaction_stmt_kind.go create mode 100644 internal/sql/ast/trigger_transition.go create mode 100644 internal/sql/ast/truncate_stmt.go create mode 100644 internal/sql/ast/type_cast.go create mode 100644 internal/sql/ast/type_name.go create mode 100644 internal/sql/ast/typedefs.go create mode 100644 internal/sql/ast/unlisten_stmt.go create mode 100644 internal/sql/ast/update_stmt.go create mode 100644 internal/sql/ast/vacuum_option.go create mode 100644 internal/sql/ast/vacuum_stmt.go create mode 100644 internal/sql/ast/var.go create mode 100644 internal/sql/ast/variable_expr.go create mode 100644 internal/sql/ast/variable_set_kind.go create mode 100644 internal/sql/ast/variable_set_stmt.go create mode 100644 internal/sql/ast/variable_show_stmt.go create mode 100644 internal/sql/ast/view_check_option.go create mode 100644 internal/sql/ast/view_stmt.go create mode 100644 internal/sql/ast/wco_kind.go create mode 100644 internal/sql/ast/window_clause.go create mode 100644 internal/sql/ast/window_def.go create mode 100644 internal/sql/ast/window_func.go create mode 100644 internal/sql/ast/with_check_option.go create mode 100644 internal/sql/ast/with_clause.go create mode 100644 internal/sql/ast/xml_expr.go create mode 100644 internal/sql/ast/xml_expr_op.go create mode 100644 internal/sql/ast/xml_option_type.go create mode 100644 internal/sql/ast/xml_serialize.go create mode 100644 internal/sql/astutils/CLAUDE.md create mode 100644 internal/sql/astutils/join.go create mode 100644 internal/sql/astutils/rewrite.go create mode 100644 internal/sql/astutils/search.go create mode 100644 internal/sql/astutils/walk.go create mode 100644 internal/sql/catalog/catalog.go create mode 100644 internal/sql/catalog/comment_on.go create mode 100644 internal/sql/catalog/extension.go create mode 100644 internal/sql/catalog/func.go create mode 100644 internal/sql/catalog/public.go create mode 100644 internal/sql/catalog/schema.go create mode 100644 internal/sql/catalog/table.go create mode 100644 internal/sql/catalog/types.go create mode 100644 internal/sql/catalog/view.go create mode 100644 internal/sql/format/format.go create mode 100644 internal/sql/info/info.go create mode 100644 internal/sql/lang/operator.go create mode 100644 internal/sql/named/CLAUDE.md create mode 100644 internal/sql/named/param.go create mode 100644 internal/sql/named/param_set.go create mode 100644 internal/sql/named/param_set_test.go create mode 100644 internal/sql/named/param_test.go create mode 100644 internal/sql/preprocess/CLAUDE.md create mode 100644 internal/sql/preprocess/dialect.go create mode 100644 internal/sql/preprocess/lexer.go create mode 100644 internal/sql/preprocess/preprocess.go create mode 100644 internal/sql/preprocess/preprocess_test.go create mode 100644 internal/sql/preprocess/scan.go create mode 100644 internal/sql/preprocess/testdata/mysql/arg/input.sql create mode 100644 internal/sql/preprocess/testdata/mysql/arg/output.sql create mode 100644 internal/sql/preprocess/testdata/mysql/arg/side_table.json create mode 100644 internal/sql/preprocess/testdata/mysql/dollar_number_is_not_a_placeholder/input.sql create mode 100644 internal/sql/preprocess/testdata/mysql/dollar_number_is_not_a_placeholder/output.sql create mode 100644 internal/sql/preprocess/testdata/mysql/dollar_number_is_not_a_placeholder/side_table.json create mode 100644 internal/sql/preprocess/testdata/mysql/double_quoted_argument/input.sql create mode 100644 internal/sql/preprocess/testdata/mysql/double_quoted_argument/output.sql create mode 100644 internal/sql/preprocess/testdata/mysql/double_quoted_argument/side_table.json create mode 100644 internal/sql/preprocess/testdata/mysql/embed/input.sql create mode 100644 internal/sql/preprocess/testdata/mysql/embed/output.sql create mode 100644 internal/sql/preprocess/testdata/mysql/embed/side_table.json create mode 100644 internal/sql/preprocess/testdata/mysql/error_invalid_calls/input.sql create mode 100644 internal/sql/preprocess/testdata/mysql/error_invalid_calls/output.sql create mode 100644 internal/sql/preprocess/testdata/mysql/error_invalid_calls/side_table.json create mode 100644 internal/sql/preprocess/testdata/mysql/error_invalid_calls/stderr.txt create mode 100644 internal/sql/preprocess/testdata/mysql/existing_placeholders_are_numbered_together/input.sql create mode 100644 internal/sql/preprocess/testdata/mysql/existing_placeholders_are_numbered_together/output.sql create mode 100644 internal/sql/preprocess/testdata/mysql/existing_placeholders_are_numbered_together/side_table.json create mode 100644 internal/sql/preprocess/testdata/mysql/narg_identifier/input.sql create mode 100644 internal/sql/preprocess/testdata/mysql/narg_identifier/output.sql create mode 100644 internal/sql/preprocess/testdata/mysql/narg_identifier/side_table.json create mode 100644 internal/sql/preprocess/testdata/mysql/on_duplicate_key_update/input.sql create mode 100644 internal/sql/preprocess/testdata/mysql/on_duplicate_key_update/output.sql create mode 100644 internal/sql/preprocess/testdata/mysql/on_duplicate_key_update/side_table.json create mode 100644 internal/sql/preprocess/testdata/mysql/skip_backslash_escape/input.sql create mode 100644 internal/sql/preprocess/testdata/mysql/skip_backslash_escape/output.sql create mode 100644 internal/sql/preprocess/testdata/mysql/skip_backslash_escape/side_table.json create mode 100644 internal/sql/preprocess/testdata/mysql/skip_backtick_identifier/input.sql create mode 100644 internal/sql/preprocess/testdata/mysql/skip_backtick_identifier/output.sql create mode 100644 internal/sql/preprocess/testdata/mysql/skip_backtick_identifier/side_table.json create mode 100644 internal/sql/preprocess/testdata/mysql/skip_double_quoted_string/input.sql create mode 100644 internal/sql/preprocess/testdata/mysql/skip_double_quoted_string/output.sql create mode 100644 internal/sql/preprocess/testdata/mysql/skip_double_quoted_string/side_table.json create mode 100644 internal/sql/preprocess/testdata/mysql/skip_hash_comment/input.sql create mode 100644 internal/sql/preprocess/testdata/mysql/skip_hash_comment/output.sql create mode 100644 internal/sql/preprocess/testdata/mysql/skip_hash_comment/side_table.json create mode 100644 internal/sql/preprocess/testdata/mysql/slice/input.sql create mode 100644 internal/sql/preprocess/testdata/mysql/slice/output.sql create mode 100644 internal/sql/preprocess/testdata/mysql/slice/side_table.json create mode 100644 internal/sql/preprocess/testdata/mysql/slice_folds_identifier/input.sql create mode 100644 internal/sql/preprocess/testdata/mysql/slice_folds_identifier/output.sql create mode 100644 internal/sql/preprocess/testdata/mysql/slice_folds_identifier/side_table.json create mode 100644 internal/sql/preprocess/testdata/mysql/string_constant/input.sql create mode 100644 internal/sql/preprocess/testdata/mysql/string_constant/output.sql create mode 100644 internal/sql/preprocess/testdata/mysql/string_constant/side_table.json create mode 100644 internal/sql/preprocess/testdata/mysql/string_constant_keeps_case/input.sql create mode 100644 internal/sql/preprocess/testdata/mysql/string_constant_keeps_case/output.sql create mode 100644 internal/sql/preprocess/testdata/mysql/string_constant_keeps_case/side_table.json create mode 100644 internal/sql/preprocess/testdata/mysql/user_variables_are_not_parameters/input.sql create mode 100644 internal/sql/preprocess/testdata/mysql/user_variables_are_not_parameters/output.sql create mode 100644 internal/sql/preprocess/testdata/mysql/user_variables_are_not_parameters/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/arg/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/arg/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/arg/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/at_sign/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/at_sign/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/at_sign/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/at_sign_cast/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/at_sign_cast/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/at_sign_cast/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/at_sign_in_vet_directive/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/at_sign_in_vet_directive/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/at_sign_in_vet_directive/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/comment_inside_call/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/comment_inside_call/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/comment_inside_call/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/embed/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/embed/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/embed/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/embed_and_user_star/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/embed_and_user_star/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/embed_and_user_star/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/embed_quoted_identifier/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/embed_quoted_identifier/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/embed_quoted_identifier/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/embed_string_constant/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/embed_string_constant/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/embed_string_constant/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/embed_with_args/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/embed_with_args/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/embed_with_args/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/error_is_per_statement/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/error_is_per_statement/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/error_is_per_statement/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/error_is_per_statement/stderr.txt create mode 100644 internal/sql/preprocess/testdata/postgresql/error_nested_call/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/error_nested_call/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/error_nested_call/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/error_nested_call/stderr.txt create mode 100644 internal/sql/preprocess/testdata/postgresql/error_no_arguments/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/error_no_arguments/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/error_no_arguments/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/error_no_arguments/stderr.txt create mode 100644 internal/sql/preprocess/testdata/postgresql/error_numbering_gap/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/error_numbering_gap/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/error_numbering_gap/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/error_numbering_gap/stderr.txt create mode 100644 internal/sql/preprocess/testdata/postgresql/error_placeholder_argument/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/error_placeholder_argument/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/error_placeholder_argument/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/error_placeholder_argument/stderr.txt create mode 100644 internal/sql/preprocess/testdata/postgresql/error_too_many_arguments/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/error_too_many_arguments/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/error_too_many_arguments/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/error_too_many_arguments/stderr.txt create mode 100644 internal/sql/preprocess/testdata/postgresql/error_unknown_function/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/error_unknown_function/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/error_unknown_function/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/error_unknown_function/stderr.txt create mode 100644 internal/sql/preprocess/testdata/postgresql/existing_placeholder/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/existing_placeholder/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/existing_placeholder/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/extra_whitespace/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/extra_whitespace/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/extra_whitespace/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/jsonb_operator_and_path_string/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/jsonb_operator_and_path_string/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/jsonb_operator_and_path_string/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/multiline_call/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/multiline_call/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/multiline_call/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/narg/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/narg/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/narg/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/narg_string_constant/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/narg_string_constant/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/narg_string_constant/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/numbering_restarts_per_statement/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/numbering_restarts_per_statement/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/numbering_restarts_per_statement/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/quoted_names/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/quoted_names/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/quoted_names/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/repeated_name/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/repeated_name/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/repeated_name/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_block_comment/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_block_comment/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_block_comment/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_dollar_quoted/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_dollar_quoted/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_dollar_quoted/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_escape_string/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_escape_string/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_escape_string/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_jsonb_operators/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_jsonb_operators/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_jsonb_operators/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_line_comment/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_line_comment/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_line_comment/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_nested_block_comment/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_nested_block_comment/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_nested_block_comment/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_other_schemas/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_other_schemas/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_other_schemas/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_quoted_identifier/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_quoted_identifier/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_quoted_identifier/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_string_literal/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_string_literal/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_string_literal/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_tagged_dollar_quoted/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_tagged_dollar_quoted/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/skip_tagged_dollar_quoted/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/slice_is_an_array/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/slice_is_an_array/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/slice_is_an_array/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/slice_string_constant/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/slice_string_constant/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/slice_string_constant/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/statement_terminator_in_string/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/statement_terminator_in_string/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/statement_terminator_in_string/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/string_constant_escaped_quote/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/string_constant_escaped_quote/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/string_constant_escaped_quote/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/string_constant_keeps_case/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/string_constant_keeps_case/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/string_constant_keeps_case/side_table.json create mode 100644 internal/sql/preprocess/testdata/postgresql/uppercase/input.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/uppercase/output.sql create mode 100644 internal/sql/preprocess/testdata/postgresql/uppercase/side_table.json create mode 100644 internal/sql/preprocess/testdata/sqlite/arg/input.sql create mode 100644 internal/sql/preprocess/testdata/sqlite/arg/output.sql create mode 100644 internal/sql/preprocess/testdata/sqlite/arg/side_table.json create mode 100644 internal/sql/preprocess/testdata/sqlite/at_sign/input.sql create mode 100644 internal/sql/preprocess/testdata/sqlite/at_sign/output.sql create mode 100644 internal/sql/preprocess/testdata/sqlite/at_sign/side_table.json create mode 100644 internal/sql/preprocess/testdata/sqlite/embed/input.sql create mode 100644 internal/sql/preprocess/testdata/sqlite/embed/output.sql create mode 100644 internal/sql/preprocess/testdata/sqlite/embed/side_table.json create mode 100644 internal/sql/preprocess/testdata/sqlite/error_invalid_calls/input.sql create mode 100644 internal/sql/preprocess/testdata/sqlite/error_invalid_calls/output.sql create mode 100644 internal/sql/preprocess/testdata/sqlite/error_invalid_calls/side_table.json create mode 100644 internal/sql/preprocess/testdata/sqlite/error_invalid_calls/stderr.txt create mode 100644 internal/sql/preprocess/testdata/sqlite/error_mixed_placeholder_styles/input.sql create mode 100644 internal/sql/preprocess/testdata/sqlite/error_mixed_placeholder_styles/output.sql create mode 100644 internal/sql/preprocess/testdata/sqlite/error_mixed_placeholder_styles/side_table.json create mode 100644 internal/sql/preprocess/testdata/sqlite/error_mixed_placeholder_styles/stderr.txt create mode 100644 internal/sql/preprocess/testdata/sqlite/existing_numbered_placeholder/input.sql create mode 100644 internal/sql/preprocess/testdata/sqlite/existing_numbered_placeholder/output.sql create mode 100644 internal/sql/preprocess/testdata/sqlite/existing_numbered_placeholder/side_table.json create mode 100644 internal/sql/preprocess/testdata/sqlite/narg_identifier/input.sql create mode 100644 internal/sql/preprocess/testdata/sqlite/narg_identifier/output.sql create mode 100644 internal/sql/preprocess/testdata/sqlite/narg_identifier/side_table.json create mode 100644 internal/sql/preprocess/testdata/sqlite/repeated_name/input.sql create mode 100644 internal/sql/preprocess/testdata/sqlite/repeated_name/output.sql create mode 100644 internal/sql/preprocess/testdata/sqlite/repeated_name/side_table.json create mode 100644 internal/sql/preprocess/testdata/sqlite/slice/input.sql create mode 100644 internal/sql/preprocess/testdata/sqlite/slice/output.sql create mode 100644 internal/sql/preprocess/testdata/sqlite/slice/side_table.json create mode 100644 internal/sql/preprocess/testdata/sqlite/string_constant/input.sql create mode 100644 internal/sql/preprocess/testdata/sqlite/string_constant/output.sql create mode 100644 internal/sql/preprocess/testdata/sqlite/string_constant/side_table.json create mode 100644 internal/sql/sqlerr/errors.go create mode 100644 internal/sql/sqlfile/split.go create mode 100644 internal/sql/sqlfile/split_test.go create mode 100644 internal/sql/sqlfile/testdata/complex_query/input.sql create mode 100644 internal/sql/sqlfile/testdata/complex_query/output_1.sql create mode 100644 internal/sql/sqlfile/testdata/complex_query/output_2.sql create mode 100644 internal/sql/sqlfile/testdata/complex_query/output_3.sql create mode 100644 internal/sql/sqlfile/testdata/dollar_quote_with_newlines/input.sql create mode 100644 internal/sql/sqlfile/testdata/dollar_quote_with_newlines/output_1.sql create mode 100644 internal/sql/sqlfile/testdata/dollar_quoted_function/input.sql create mode 100644 internal/sql/sqlfile/testdata/dollar_quoted_function/output_1.sql create mode 100644 internal/sql/sqlfile/testdata/dollar_quoted_string/input.sql create mode 100644 internal/sql/sqlfile/testdata/dollar_quoted_string/output_1.sql create mode 100644 internal/sql/sqlfile/testdata/double_quoted_identifier/input.sql create mode 100644 internal/sql/sqlfile/testdata/double_quoted_identifier/output_1.sql create mode 100644 internal/sql/sqlfile/testdata/empty_input/input.sql create mode 100644 internal/sql/sqlfile/testdata/escaped_double_quotes/input.sql create mode 100644 internal/sql/sqlfile/testdata/escaped_double_quotes/output_1.sql create mode 100644 internal/sql/sqlfile/testdata/escaped_quotes/input.sql create mode 100644 internal/sql/sqlfile/testdata/escaped_quotes/output_1.sql create mode 100644 internal/sql/sqlfile/testdata/last_query_no_semicolon/input.sql create mode 100644 internal/sql/sqlfile/testdata/last_query_no_semicolon/output_1.sql create mode 100644 internal/sql/sqlfile/testdata/last_query_no_semicolon/output_2.sql create mode 100644 internal/sql/sqlfile/testdata/multi_line_comment/input.sql create mode 100644 internal/sql/sqlfile/testdata/multi_line_comment/output_1.sql create mode 100644 internal/sql/sqlfile/testdata/multi_line_comment/output_2.sql create mode 100644 internal/sql/sqlfile/testdata/multi_line_comment_with_semicolon/input.sql create mode 100644 internal/sql/sqlfile/testdata/multi_line_comment_with_semicolon/output_1.sql create mode 100644 internal/sql/sqlfile/testdata/multi_line_comment_with_semicolon/output_2.sql create mode 100644 internal/sql/sqlfile/testdata/multiple_queries/input.sql create mode 100644 internal/sql/sqlfile/testdata/multiple_queries/output_1.sql create mode 100644 internal/sql/sqlfile/testdata/multiple_queries/output_2.sql create mode 100644 internal/sql/sqlfile/testdata/multiple_queries/output_3.sql create mode 100644 internal/sql/sqlfile/testdata/nested_dollar_quotes/input.sql create mode 100644 internal/sql/sqlfile/testdata/nested_dollar_quotes/output_1.sql create mode 100644 internal/sql/sqlfile/testdata/no_trailing_semicolon/input.sql create mode 100644 internal/sql/sqlfile/testdata/no_trailing_semicolon/output_1.sql create mode 100644 internal/sql/sqlfile/testdata/only_semicolons/input.sql create mode 100644 internal/sql/sqlfile/testdata/semicolon_in_string/input.sql create mode 100644 internal/sql/sqlfile/testdata/semicolon_in_string/output_1.sql create mode 100644 internal/sql/sqlfile/testdata/single_line_comment/input.sql create mode 100644 internal/sql/sqlfile/testdata/single_line_comment/output_1.sql create mode 100644 internal/sql/sqlfile/testdata/single_line_comment/output_2.sql create mode 100644 internal/sql/sqlfile/testdata/single_line_comment_with_semicolon/input.sql create mode 100644 internal/sql/sqlfile/testdata/single_line_comment_with_semicolon/output_1.sql create mode 100644 internal/sql/sqlfile/testdata/single_line_comment_with_semicolon/output_2.sql create mode 100644 internal/sql/sqlfile/testdata/single_query/input.sql create mode 100644 internal/sql/sqlfile/testdata/single_query/output_1.sql create mode 100644 internal/sql/sqlfile/testdata/tagged_dollar_quoted_string/input.sql create mode 100644 internal/sql/sqlfile/testdata/tagged_dollar_quoted_string/output_1.sql create mode 100644 internal/sql/sqlfile/testdata/whitespace_only/input.sql create mode 100644 internal/sql/sqlpath/read.go create mode 100644 internal/sql/sqlpath/read_test.go create mode 100644 internal/sql/sqlpath/testdata/.hidden.sql create mode 100644 internal/sql/sqlpath/testdata/.hiddendir/file1.sql create mode 100644 internal/sql/sqlpath/testdata/extra.txt create mode 100644 internal/sql/sqlpath/testdata/file1.sql create mode 120000 internal/sql/sqlpath/testdata/file1.symlink.sql create mode 100644 internal/sql/sqlpath/testdata/file2.sql create mode 100644 internal/sql/sqlpath/testdata/file3.down.sql create mode 100644 internal/sql/sqlpath/testdata/file4.SQL create mode 100644 internal/sql/sqlpath/testdata/glob/sub1/queries/file1.sql create mode 100644 internal/sql/sqlpath/testdata/glob/sub2/queries/file2.sql create mode 100644 internal/sql/sqlpath/testdata/glob/sub3/queries/file3.sql create mode 100644 internal/sql/sqlpath/testdata/glob/sub3/queries/file4.sql create mode 100644 internal/sql/sqlpath/testdata/subdir/file2.sql create mode 120000 internal/sql/sqlpath/testdata/symlink create mode 100644 internal/sql/validate/cmd.go create mode 100644 internal/sql/validate/func_call.go create mode 100644 internal/sql/validate/insert_stmt.go create mode 100644 internal/sql/validate/slice.go create mode 100644 internal/sqlcdebug/sqlcdebug.go create mode 100644 internal/sqlcdebug/sqlcdebug_test.go create mode 100644 internal/sqlite3ext/sqlite3ext.go create mode 100644 internal/sqltest/docker/enabled.go create mode 100644 internal/sqltest/docker/mysql.go create mode 100644 internal/sqltest/docker/postgres.go create mode 100644 internal/sqltest/local/id.go create mode 100644 internal/sqltest/local/mysql.go create mode 100644 internal/sqltest/local/postgres.go create mode 100644 internal/sqltest/mysql.go create mode 100644 internal/sqltest/native/enabled.go create mode 100644 internal/sqltest/native/mysql.go create mode 100644 internal/sqltest/native/postgres.go create mode 100644 internal/sqltest/sqlite.go create mode 100644 internal/tracer/trace.go create mode 100644 internal/vet/vet.pb.go create mode 100644 internal/x/expander/expander.go create mode 100644 internal/x/expander/expander_test.go create mode 100644 pkg/cli/cli.go create mode 100644 placeholder.go create mode 100644 protos/analysis/analysis.proto create mode 100644 protos/buf.yaml create mode 100644 protos/plugin/codegen.proto create mode 100644 protos/vet/vet.proto create mode 100755 scripts/build/main.go create mode 100644 scripts/bump-version/main.go create mode 100644 scripts/cleanup-test-dbs/main.go create mode 100644 scripts/mirror-go-plugin/main.go create mode 100755 scripts/release.go create mode 100755 scripts/report.sh create mode 100644 scripts/test-json-process-plugin/main.go diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT.yml b/.github/ISSUE_TEMPLATE/BUG_REPORT.yml new file mode 100644 index 0000000..0c55395 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/BUG_REPORT.yml @@ -0,0 +1,88 @@ +name: Bug Report +description: File a bug report +labels: [bug] +body: + - type: dropdown + id: version + attributes: + label: Version + description: What version of sqlc are you running? If you don't know, run `sqlc version`. + multiple: false + options: + - 1.31.1 + - 1.31.0 + - 1.30.0 + - 1.29.0 + - 1.28.0 + - 1.27.0 + - 1.26.0 + - 1.25.0 + - Other + validations: + required: true + - type: textarea + id: what-happened + attributes: + label: What happened? + description: Also tell us, what did you expect to happen? + placeholder: Tell us what you see! + value: "A bug happened!" + validations: + required: true + - type: textarea + id: logs + attributes: + label: Relevant log output + description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. + render: shell + - type: textarea + id: schema + attributes: + label: Database schema + description: Please include definitions for the relevant database tables. This will be automatically formatted as SQL, so no need for backticks. + render: sql + - type: textarea + id: queries + attributes: + label: SQL queries + description: Please include the SQL queries causing issues. This will be automatically formatted as SQL, so no need for backticks. + render: sql + - type: textarea + id: config + attributes: + label: Configuration + description: Please include the sqlc.(yaml|yml) or sqlc.json file you using in your project. This will be automatically formatted, so no need for backticks. + render: yaml + - type: input + id: playground + attributes: + label: Playground URL + description: "Link to a reproduction of the issue on the sqlc playground" + placeholder: "https://play.sqlc.dev/" + - type: dropdown + id: os + attributes: + label: What operating system are you using? + multiple: true + options: + - Linux + - Windows + - macOS + - type: dropdown + id: engines + attributes: + label: What database engines are you using? + multiple: true + options: + - MySQL + - PostgreSQL + - SQLite + - type: dropdown + id: languages + attributes: + label: What type of code are you generating? + multiple: true + options: + - Go + - Python + - Kotlin diff --git a/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml new file mode 100644 index 0000000..b3dd5b0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml @@ -0,0 +1,30 @@ +name: Feature Request +description: Request a new feature or a change to an existing feature +labels: [enhancement] +body: + - type: textarea + id: feature + attributes: + label: What do you want to change? + placeholder: Tell us what you want + value: "Free unicorns!" + validations: + required: true + - type: dropdown + id: engines + attributes: + label: What database engines need to be changed? + multiple: true + options: + - PostgreSQL + - MySQL + - SQLite + - type: dropdown + id: languages + attributes: + label: What programming language backends need to be changed? + multiple: true + options: + - Go + - Python + - Kotlin diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..69ec223 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,20 @@ +version: 2 +updates: + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "daily" + groups: + production-dependencies: + dependency-type: "production" + development-dependencies: + dependency-type: "development" + - package-ecosystem: "docker" + directory: "/" + schedule: + interval: "daily" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + diff --git a/.github/workflows/buf.yml b/.github/workflows/buf.yml new file mode 100644 index 0000000..c77e9b4 --- /dev/null +++ b/.github/workflows/buf.yml @@ -0,0 +1,18 @@ +name: buf +on: + pull_request: + paths-ignore: + - 'docs/**' +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: bufbuild/buf-setup-action@v1 + with: + # buf-setup-action resolves the release download URL through the + # GitHub API. Without a token that request is anonymous and shares + # a rate limit with every other job on the runner's IP, so setup + # intermittently fails with "API rate limit exceeded". + github_token: ${{ github.token }} + - uses: bufbuild/buf-lint-action@v1 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..ae66e40 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,19 @@ +name: build +on: + workflow_dispatch: +jobs: + build: + strategy: + matrix: + os: [ubuntu-24.04, macos-14, windows-2022] + name: build ${{ matrix.os }} + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-go@v7 + with: + go-version: '1.26.5' + - name: install ./... + run: go build ./... + env: + CGO_ENABLED: "0" diff --git a/.github/workflows/ci-kotlin.yml b/.github/workflows/ci-kotlin.yml new file mode 100644 index 0000000..177787b --- /dev/null +++ b/.github/workflows/ci-kotlin.yml @@ -0,0 +1,31 @@ +name: kotlin +on: + push: + branches: + - main + paths-ignore: + - 'docs/**' + pull_request: + paths-ignore: + - 'docs/**' +jobs: + build: + if: false + name: test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-go@v7 + with: + go-version: '1.26.5' + - name: install ./... + run: go install ./... + - uses: actions/checkout@v7 + with: + repository: sqlc-dev/sqlc-gen-kotlin + path: kotlin + - run: make test + working-directory: kotlin + - run: sqlc diff + working-directory: kotlin/examples + diff --git a/.github/workflows/ci-python.yml b/.github/workflows/ci-python.yml new file mode 100644 index 0000000..47328c7 --- /dev/null +++ b/.github/workflows/ci-python.yml @@ -0,0 +1,30 @@ +name: python +on: + push: + branches: + - main + paths-ignore: + - 'docs/**' + pull_request: + paths-ignore: + - 'docs/**' +jobs: + build: + if: false + name: test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-go@v7 + with: + go-version: '1.26.5' + - name: install ./... + run: go install ./... + - uses: actions/checkout@v7 + with: + repository: sqlc-dev/sqlc-gen-python + path: python + - run: make test + working-directory: python + - run: sqlc diff + working-directory: python/examples diff --git a/.github/workflows/ci-typescript.yml b/.github/workflows/ci-typescript.yml new file mode 100644 index 0000000..e5aac81 --- /dev/null +++ b/.github/workflows/ci-typescript.yml @@ -0,0 +1,30 @@ +name: typescript +on: + push: + branches: + - main + paths-ignore: + - 'docs/**' + pull_request: + paths-ignore: + - 'docs/**' +jobs: + build: + if: false + name: test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-go@v7 + with: + go-version: '1.26.5' + - name: install ./... + run: go install ./... + - uses: actions/checkout@v7 + with: + repository: sqlc-dev/sqlc-gen-typescript + path: typescript + # v0.1.3 + ref: daaf539092421adc15f6c3164279a3470716b560 + - run: sqlc diff + working-directory: typescript/examples diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..b002f97 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,74 @@ +name: go +on: + push: + branches: + - main + pull_request: +jobs: + build: + strategy: + matrix: + goos: [darwin, linux, windows] + goarch: [amd64, arm64] + name: build ${{ matrix.goos }}/${{ matrix.goarch }} + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-go@v7 + with: + go-version: '1.26.5' + - run: go build ./... + env: + CGO_ENABLED: "0" + GOOS: ${{ matrix.goos }} + GOARCH: ${{ matrix.goarch }} + test: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-go@v7 + with: + go-version: '1.26.5' + + - 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 test-json-process-plugin + run: go install ./scripts/test-json-process-plugin/ + + - name: install ./... + run: go install ./... + env: + CGO_ENABLED: "0" + + - name: build internal/endtoend + run: go build ./... + working-directory: internal/endtoend/testdata + env: + CGO_ENABLED: "0" + + - name: install databases + run: go run ./cmd/sqlc-test-setup install + + - name: start databases + run: go run ./cmd/sqlc-test-setup start + + - name: test ./... + run: gotestsum --junitfile junit.xml -- --tags=examples -timeout 20m -failfast ./... + env: + CI_SQLC_PROJECT_ID: ${{ secrets.CI_SQLC_PROJECT_ID }} + CI_SQLC_AUTH_TOKEN: ${{ secrets.CI_SQLC_AUTH_TOKEN }} + SQLC_AUTH_TOKEN: ${{ secrets.CI_SQLC_AUTH_TOKEN }} + POSTGRESQL_SERVER_URI: "postgres://postgres:postgres@127.0.0.1:5432/postgres?sslmode=disable" + MYSQL_SERVER_URI: "root:mysecretpassword@tcp(127.0.0.1:3306)/mysql?multiStatements=true&parseTime=true" + CGO_ENABLED: "0" + + vuln_check: + runs-on: ubuntu-24.04 + timeout-minutes: 5 + + steps: + - uses: golang/govulncheck-action@v1 diff --git a/.github/workflows/gen.yml b/.github/workflows/gen.yml new file mode 100644 index 0000000..169b1dc --- /dev/null +++ b/.github/workflows/gen.yml @@ -0,0 +1,192 @@ +name: gen +on: + workflow_dispatch: +jobs: + postgresql: + name: generate postgresql dialect + runs-on: ubuntu-24.04 + services: + postgres: + image: postgres:16 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + ports: + - 5432:5432 + # needed because the postgres container does not provide a healthcheck + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-go@v7 + with: + go-version-file: internal/goldeneye/go.mod + check-latest: true + - run: go run ./cmd/goldeneye generate postgresql + working-directory: internal/goldeneye + env: + POSTGRESQL_SERVER_URI: postgres://postgres:postgres@localhost:${{ job.services.postgres.ports['5432'] }}/postgres?sslmode=disable + - name: Save results + uses: actions/upload-artifact@v7 + with: + name: dialect-postgresql + path: internal/engine/postgresql/dialect + - name: Fail if the committed dialect differs + run: git add -N internal/engine/postgresql && git diff --exit-code --stat -- internal/engine/postgresql + + mysql: + name: generate mysql dialect + runs-on: ubuntu-24.04 + services: + mysql: + image: mysql:26.7 + env: + MYSQL_ROOT_PASSWORD: mysecretpassword + ports: + - 3306:3306 + options: --health-cmd "mysqladmin ping -h 127.0.0.1 -pmysecretpassword" --health-interval 10s --health-timeout 5s --health-retries 5 + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-go@v7 + with: + go-version-file: internal/goldeneye/go.mod + check-latest: true + - run: go run ./cmd/goldeneye generate mysql + working-directory: internal/goldeneye + env: + MYSQL_SERVER_URI: root:mysecretpassword@tcp(localhost:${{ job.services.mysql.ports['3306'] }})/mysql + - name: Save results + uses: actions/upload-artifact@v7 + with: + name: dialect-mysql + path: internal/engine/dolphin/dialect + - name: Fail if the committed dialect differs + run: git add -N internal/engine/dolphin && git diff --exit-code --stat -- internal/engine/dolphin + + clickhouse: + name: generate clickhouse dialect + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-go@v7 + with: + go-version-file: internal/goldeneye/go.mod + check-latest: true + - run: go run ./cmd/goldeneye install clickhouse + working-directory: internal/goldeneye + - run: go run ./cmd/goldeneye generate clickhouse + working-directory: internal/goldeneye + - name: Save results + uses: actions/upload-artifact@v7 + with: + name: dialect-clickhouse + path: internal/engine/clickhouse/dialect + - name: Fail if the committed dialect differs + run: git add -N internal/engine/clickhouse && git diff --exit-code --stat -- internal/engine/clickhouse + + sqlite: + name: generate sqlite dialect + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-go@v7 + with: + go-version-file: internal/goldeneye/go.mod + check-latest: true + - run: go run ./cmd/goldeneye install sqlite + working-directory: internal/goldeneye + - run: go run ./cmd/goldeneye generate sqlite + working-directory: internal/goldeneye + - name: Save results + uses: actions/upload-artifact@v7 + with: + name: dialect-sqlite + path: internal/engine/sqlite/dialect + - name: Fail if the committed dialect differs + run: git add -N internal/engine/sqlite && git diff --exit-code --stat -- internal/engine/sqlite + + mssql: + name: generate mssql dialect + runs-on: ubuntu-24.04 + services: + mssql: + image: mcr.microsoft.com/mssql/server:2025-latest + env: + ACCEPT_EULA: Y + MSSQL_SA_PASSWORD: Mysecretpassword1! + ports: + - 1433:1433 + options: --health-cmd "/opt/mssql-tools18/bin/sqlcmd -C -S localhost -U sa -P 'Mysecretpassword1!' -Q 'SELECT 1'" --health-interval 10s --health-timeout 5s --health-retries 10 + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-go@v7 + with: + go-version-file: internal/goldeneye/go.mod + check-latest: true + - run: go run ./cmd/goldeneye generate mssql + working-directory: internal/goldeneye + env: + MSSQL_SERVER_URI: sqlserver://sa:Mysecretpassword1!@localhost:${{ job.services.mssql.ports['1433'] }}?encrypt=disable + - name: Save results + uses: actions/upload-artifact@v7 + with: + name: dialect-mssql + path: internal/engine/mssql/dialect + - name: Fail if the committed dialect differs + run: git add -N internal/engine/mssql && git diff --exit-code --stat -- internal/engine/mssql + + spanner: + name: generate googlesql dialect + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-go@v7 + with: + go-version-file: internal/goldeneye/go.mod + check-latest: true + # Spanner Omni is run the way its quickstart runs it, on the host + # network, since a service container cannot be given a command. + - name: Start Spanner Omni + run: | + docker run -d --name spanneromni --network host us-docker.pkg.dev/spanner-omni/images/spanner-omni:2026.r2.1-beta start-single-server + for i in $(seq 1 60); do + if docker exec spanneromni /google/spanner/bin/spanner databases list >/dev/null 2>&1; then exit 0; fi + sleep 5 + done + docker logs spanneromni + exit 1 + - run: go run ./cmd/goldeneye generate spanner + working-directory: internal/goldeneye + env: + SPANNER_SERVER_URI: localhost:15000 + - name: Save results + uses: actions/upload-artifact@v7 + with: + name: dialect-googlesql + path: internal/engine/googlesql/dialect + - name: Fail if the committed dialect differs + run: git add -N internal/engine/googlesql && git diff --exit-code --stat -- internal/engine/googlesql + + duckdb: + name: generate duckdb dialect + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-go@v7 + with: + go-version-file: internal/goldeneye/go.mod + check-latest: true + # The current build of DuckDB's v2.0 preview channel, until 2.0 is + # released: a later build than the dialect was generated from shows up + # as a difference. + - run: go run ./cmd/goldeneye install duckdb + working-directory: internal/goldeneye + - run: go run ./cmd/goldeneye generate duckdb + working-directory: internal/goldeneye + - name: Save results + uses: actions/upload-artifact@v7 + with: + name: dialect-duckdb + path: internal/engine/duckdb/dialect + - name: Fail if the committed dialect differs + run: git add -N internal/engine/duckdb && git diff --exit-code --stat -- internal/engine/duckdb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..39961eb --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +/.idea/ +__pycache__ +.DS_Store +.*.swp + +# Devenv +.envrc +.direnv +.devenv* +devenv.local.nix + diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..d5d0018 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "files.insertFinalNewline": true +} diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..fb53dbb --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,340 @@ +# Claude Code Development Guide for sqlc + +This document provides essential information for working with the sqlc codebase, including testing, development workflow, and code structure. + +## Quick Start + +### Prerequisites + +- **Go 1.26.4+** - Required for building and testing +- **Docker & Docker Compose** - Required for integration tests with databases (local development) +- **Git** - For version control + +## Database Setup with sqlc-test-setup + +The `sqlc-test-setup` tool (`cmd/sqlc-test-setup/`) automates installing and starting PostgreSQL and MySQL for tests. Both commands are idempotent and safe to re-run. + +### Install databases + +```bash +go run ./cmd/sqlc-test-setup install +``` + +This will: +- Configure the apt proxy (if `http_proxy` is set, e.g. in Claude Code remote environments) +- Install PostgreSQL via apt +- Download and install MySQL 26.7 from Oracle's deb bundle +- Resolve all dependencies automatically +- Skip anything already installed + +### Start databases + +```bash +go run ./cmd/sqlc-test-setup start +``` + +This will: +- Start PostgreSQL and configure password auth (`postgres`/`postgres`) +- Start MySQL via `mysqld_safe` and set root password (`mysecretpassword`) +- Verify both connections +- Skip steps that are already done (running services, existing config) + +Connection URIs after start: +- PostgreSQL: `postgres://postgres:postgres@127.0.0.1:5432/postgres?sslmode=disable` +- MySQL: `root:mysecretpassword@tcp(127.0.0.1:3306)/mysql` + +### Run tests + +```bash +# Full test suite (requires databases running) +go test --tags=examples -timeout 20m ./... +``` + +## Running Tests + +### Basic Unit Tests (No Database Required) + +```bash +go test ./... +``` + +### Full Test Suite with Docker (Local Development) + +```bash +docker compose up -d +go test --tags=examples -timeout 20m ./... +``` + +### Full Test Suite without Docker (Remote / CI) + +```bash +go run ./cmd/sqlc-test-setup install +go run ./cmd/sqlc-test-setup start +go test --tags=examples -timeout 20m ./... +``` + +### Running Specific Tests + +```bash +# Test a specific package +go test ./internal/config + +# Run with verbose output +go test -v ./internal/config + +# Run a specific test function +go test -v ./internal/config -run TestConfig + +# Run with race detector (recommended for concurrency changes) +go test -race ./internal/config +``` + +## Testing Strategy + +**Cover new work with end-to-end tests, not unit tests.** A change to the +compiler, an engine, the analysis core or codegen is exercised by running sqlc +the way a user does — a schema, a query file and a committed golden output — +so the test says what sqlc produces rather than what an internal function +returns. Internal APIs move around; the SQL that goes in and the output that +comes out is the contract worth pinning down. + +Adding coverage means adding a directory under `/internal/endtoend/testdata/`, +not a `*_test.go` next to the code. Reach for a unit test only when the +behavior genuinely cannot be reached through the CLI, and say why in the test. + +Some `*_test.go` files predate this and remain; they are not a precedent for +new ones. + +### End-to-End Tests + +- **Location:** `/internal/endtoend/` +- **Requirements:** `--tags=examples` flag and running databases +- **Tests:** + - `TestExamples` - Main end-to-end tests + - `TestReplay` - Replay tests + - `TestFormat` - Code formatting tests + - `TestJsonSchema` - JSON schema validation + - `TestExamplesVet` - Static analysis tests + +A case is a directory holding the inputs and the expected output. `exec.json` +names the command and its arguments — omit it and the case runs `generate`, +comparing the generated files against the ones committed alongside; give it +`{"command": "analyze", "args": [...]}` and the case compares the command's +stdout against `stdout.json` (or `stdout.txt` for a command that does not +print JSON). A case that is expected to fail commits its `stderr.txt`. Regenerate a golden by running the command in its directory and +writing the output back over the committed file. + +`TestReplay` runs the whole corpus once per *context*. `base` runs each case as +committed and `managed-db` reruns it against a live database, so a context can +change the config a case is generated with and the experiments it is generated +under. A case restricts itself to some of them with `"contexts": [...]` in its +`exec.json`, and commits per-context expected errors as `stderr/.txt`. +There is only one set of committed golden files, so every context is expected +to generate identical code. + +The `core` context generates every case through the analysis core +(`SQLCEXPERIMENT=coreanalyzer`). The two paths still disagree, so it is opt-in +and needs no database: + +```bash +SQLC_TEST_CORE=1 go test ./internal/endtoend -run 'TestReplay/core' +``` + +Go aborts a test binary on panic, so a case that panics the core analyzer ends +the run early. Run a subset to get past one (`-run 'TestReplay/core/^select'`). + +### Dialect Checks + +The dialect seeds under `/internal/engine//dialect/` are generated +from a live database by `/internal/goldeneye`, a nested module, and its tests +verify the committed files against one byte for byte. The same module checks +the `analyze_*` cases under `/internal/endtoend/testdata/` against what the +database itself reports for them, so a `fixture.sql` next to a case's schema +gives the queries rows to run against. ClickHouse, DuckDB, MySQL, SQLite, +SQL Server and Spanner have the check today; engines whose database is not +available skip. + +```bash +cd internal/goldeneye +go run ./cmd/goldeneye install clickhouse # download the pinned clickhouse binary once +go run ./cmd/goldeneye install duckdb # download the current DuckDB 2.0 preview build once +go run ./cmd/goldeneye install sqlite # build the pinned sqlite3 shells once; needs a C compiler +POSTGRESQL_SERVER_URI="postgres://postgres:postgres@127.0.0.1:5432/postgres?sslmode=disable" \ +MYSQL_SERVER_URI="root:mysecretpassword@tcp(127.0.0.1:3306)/mysql" \ +MSSQL_SERVER_URI="sqlserver://sa:Mysecretpassword1!@127.0.0.1:1433?encrypt=disable" \ +SPANNER_SERVER_URI="localhost:15000" go test ./... +go run ./cmd/goldeneye generate postgresql # rewrite the files after a change +``` + +The checks are not part of CI. The `gen` workflow +(`.github/workflows/gen.yml`) generates the files on demand and uploads +them as an artifact. + +### Example Tests + +- **Location:** `/examples/` directory +- **Requirements:** Tagged with "examples", requires live databases +- **Databases:** PostgreSQL, MySQL, SQLite examples + +## Database Services + +The `docker-compose.yml` provides test databases: + +- **PostgreSQL 16** - Port 5432 + - User: `postgres` + - Password: `mysecretpassword` + - Database: `postgres` + +- **MySQL 26.7** - Port 3306 + - User: `root` + - Password: `mysecretpassword` + - Database: `dinotest` + +## Makefile Targets + +```bash +make test # Basic unit tests only +make test-examples # Tests with examples tag +make build-endtoend # Build end-to-end test data +make test-ci # Full CI suite (examples + endtoend + vet) +make vet # Run go vet +make start # Start database containers +``` + +## CI/CD Configuration + +### GitHub Actions Workflow + +- **File:** `.github/workflows/ci.yml` +- **Go Version:** 1.26.4 +- **Database Setup:** Uses `sqlc-test-setup` (not Docker) to install and start PostgreSQL and MySQL directly on the runner +- **Test Command:** `gotestsum --junitfile junit.xml -- --tags=examples -timeout 20m ./...` +- **Additional Checks:** `govulncheck` for vulnerability scanning + +## Development Workflow + +### Building Development Versions + +```bash +# Build main sqlc binary for development +go build -o ~/go/bin/sqlc-dev ./cmd/sqlc + +# Build JSON plugin (required for some tests) +go build -o ~/go/bin/sqlc-gen-json ./cmd/sqlc-gen-json +``` + +### Environment Variables for Tests + +You can override database connections via environment variables: + +```bash +POSTGRESQL_SERVER_URI="postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable" +MYSQL_SERVER_URI="root:mysecretpassword@tcp(127.0.0.1:3306)/mysql?multiStatements=true&parseTime=true" +``` + +## Code Structure + +### Key Directories + +- `/cmd/` - Main binaries (sqlc, sqlc-gen-json, sqlc-test-setup) +- `/internal/cmd/` - Command implementations (vet, generate, etc.) +- `/internal/engine/` - Database engine implementations + - `/postgresql/` - PostgreSQL parser and converter + - `/dolphin/` - MySQL parser (uses TiDB parser) + - `/sqlite/` - SQLite parser + - `/duckdb/` - DuckDB 2.0 parser (uses darkwing, the pure Go port of + DuckDB's PEG parser) + - `/dialect/` - The engine's type system and standard library, as + JSONL read by `/internal/core/seed`; the generated parts come from + `/internal/goldeneye` +- `/internal/goldeneye/` - Nested module that generates the dialect seeds + under `/internal/engine//dialect/` from a live database, checks + the committed ones against it, and checks the analyze cases under + `/internal/endtoend/testdata/` against what the database reports, one + package per engine; see its README +- `/internal/core/` - The analysis core: catalog, analyzer and dialect seeds +- `/internal/compiler/` - Query compilation logic +- `/internal/codegen/` - Code generation for different languages +- `/internal/config/` - Configuration file parsing +- `/internal/endtoend/` - End-to-end tests +- `/internal/sqltest/` - Test database setup (Docker, native, local detection) +- `/examples/` - Example projects for testing + +### Important Files + +- `/Makefile` - Build and test targets +- `/docker-compose.yml` - Database services for testing +- `/.github/workflows/ci.yml` - CI configuration + +## Common Issues & Solutions + +### Network Connectivity Issues + +If you see errors about `storage.googleapis.com`, the Go proxy may be unreachable. Use `GOPROXY=direct go mod download` to fetch modules directly from source. + +### Test Timeouts + +End-to-end tests can take a while. Use longer timeouts: +```bash +go test -timeout 20m --tags=examples ./... +``` + +### Race Conditions + +Always run tests with the race detector when working on concurrent code: +```bash +go test -race ./... +``` + +### Database Connection Failures + +If using Docker: +```bash +docker compose ps +docker compose up -d +``` + +If using sqlc-test-setup: +```bash +go run ./cmd/sqlc-test-setup start +``` + +## Tips for Contributors + +1. **Run tests before committing:** `go test --tags=examples -timeout 20m ./...` +2. **Cover new behavior end to end:** Add a case under `/internal/endtoend/testdata/` +3. **Check for race conditions:** Use `-race` flag when testing concurrent code +4. **Iterate on one case:** `go test ./internal/endtoend -run 'TestReplay/base/'` +5. **Read existing cases:** `/internal/endtoend/testdata/` has one per feature + +## Git Workflow + +### Branch Naming + +- Feature branches should start with `claude/` for Claude Code work +- Branch names should be descriptive and end with the session ID + +### Committing Changes + +```bash +git add +git commit -m "Brief description of changes" +git push -u origin +``` + +### Rebasing + +```bash +git checkout main +git pull origin main +git checkout +git rebase main +git push --force-with-lease origin +``` + +## Resources + +- **Main Documentation:** `/docs/` +- **Development Guide:** `/docs/guides/development.md` +- **CI Configuration:** `/.github/workflows/ci.yml` +- **Docker Compose:** `/docker-compose.yml` diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..563c1d7 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,19 @@ +# STEP 1: Build sqlc +FROM golang:1.27.1 AS builder + +COPY . /workspace +WORKDIR /workspace + +ARG github_ref +ARG github_sha +ARG version +ENV GITHUB_REF=$github_ref +ENV GITHUB_SHA=$github_sha +ENV VERSION=$version +RUN go run scripts/release.go -docker + +# STEP 2: Build a tiny image +FROM gcr.io/distroless/base-debian12 + +COPY --from=builder /workspace/sqlc /workspace/sqlc +ENTRYPOINT ["/workspace/sqlc"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..4d86f4d --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Riza, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..52416e1 --- /dev/null +++ b/Makefile @@ -0,0 +1,60 @@ +.PHONY: build build-endtoend test test-ci test-examples test-endtoend test-goldeneye start psql mysqlsh proto + +build: + go build ./... + +install: + go install ./... + +test: + go test ./... + +test-managed: + MYSQL_SERVER_URI="invalid" POSTGRESQL_SERVER_URI="postgres://postgres:mysecretpassword@localhost:5432/postgres" go test -v ./... + +vet: + go vet ./... + +test-examples: + go test --tags=examples ./... + +build-endtoend: + cd ./internal/endtoend/testdata && go build ./... + +test-ci: test-examples build-endtoend vet + +sqlc-dev: + go build -o ~/bin/sqlc-dev ./cmd/sqlc/ + +goldeneye: + cd ./internal/goldeneye && go build -o ~/bin/goldeneye ./cmd/goldeneye + +test-goldeneye: + cd ./internal/goldeneye && go test ./... + +sqlc-gen-json: + go build -o ~/bin/sqlc-gen-json ./cmd/sqlc-gen-json + +test-json-process-plugin: + go build -o ~/bin/test-json-process-plugin ./scripts/test-json-process-plugin/ + +start: + docker compose up -d + +fmt: + go fmt ./... + +psql: + PGPASSWORD=mysecretpassword psql --host=127.0.0.1 --port=5432 --username=postgres dinotest + +mysqlsh: + mysqlsh --sql --user root --password mysecretpassword --database dinotest 127.0.0.1:3306 + +proto: + buf generate + +remote-proto: + protoc \ + --go_out=. --go_opt="Minternal/remote/gen.proto=github.com/sqlc-dev/sqlc/internal/remote" --go_opt=module=github.com/sqlc-dev/sqlc \ + --go-grpc_out=. --go-grpc_opt="Minternal/remote/gen.proto=github.com/sqlc-dev/sqlc/internal/remote" --go-grpc_opt=module=github.com/sqlc-dev/sqlc \ + internal/remote/gen.proto diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..780aa2d --- /dev/null +++ b/NOTICE @@ -0,0 +1,48 @@ +This distribution of sqlc includes software licensed under the Apache +License, Version 2.0, from projects that ship a NOTICE file. As required +by section 4(d) of that license, their attribution notices are reproduced +below. + +================================================================================ +github.com/tetratelabs/wazero +================================================================================ + +wazero +Copyright 2020-2023 wazero authors + +================================================================================ +google.golang.org/grpc +================================================================================ + +Copyright 2014 gRPC authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +================================================================================ +gopkg.in/yaml.v3 +go.yaml.in/yaml/v3 +================================================================================ + +Copyright 2011-2016 Canonical Ltd. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..ba06efa --- /dev/null +++ b/README.md @@ -0,0 +1,59 @@ +# sqlc: A SQL Compiler + +![go](https://github.com/sqlc-dev/sqlc/workflows/go/badge.svg) +[![Go Report Card](https://goreportcard.com/badge/github.com/sqlc-dev/sqlc)](https://goreportcard.com/report/github.com/sqlc-dev/sqlc) + +sqlc generates **type-safe code** from SQL. Here's how it works: + +1. You write queries in SQL. +1. You run sqlc to generate code with type-safe interfaces to those queries. +1. You write application code that calls the generated code. + +Check out [an interactive example](https://play.sqlc.dev/) to see it in action, and the [introductory blog post](https://conroy.org/introducing-sqlc) for the motivation behind sqlc. + +## Overview + +- [Documentation](https://docs.sqlc.dev) +- [Installation](https://docs.sqlc.dev/en/latest/overview/install.html) +- [Playground](https://play.sqlc.dev) +- [Website](https://sqlc.dev) +- [Downloads](https://downloads.sqlc.dev/) +- [Community](https://discord.gg/EcXzGe5SEs) + +## Supported languages + +- [sqlc-gen-go](https://github.com/sqlc-dev/sqlc-gen-go) +- [sqlc-gen-kotlin](https://github.com/sqlc-dev/sqlc-gen-kotlin) +- [sqlc-gen-python](https://github.com/sqlc-dev/sqlc-gen-python) +- [sqlc-gen-typescript](https://github.com/sqlc-dev/sqlc-gen-typescript) + +Additional languages can be added via [plugins](https://docs.sqlc.dev/en/latest/reference/language-support.html#community-language-support). + +## Sponsors + +Development is possible thanks to our sponsors. If you would like to support sqlc, +please consider [sponsoring on GitHub](https://github.com/sponsors/kyleconroy). + +

+ Coder.com + Mint.fun + Mux.com +

+ +

+ Cyberax - + NaNuNaNu - + Stumble - + WestfalNamur - + alecthomas - + cameronnewman - + danielbprice - + davherrmann - + dvob - + gilcrest - + gzuidhof - + jeffreylo - + mmcloughlin - + ryohei1216 - + sgielen +

diff --git a/buf.gen.yaml b/buf.gen.yaml new file mode 100644 index 0000000..3acdb97 --- /dev/null +++ b/buf.gen.yaml @@ -0,0 +1,12 @@ +version: v1 +managed: + enabled: true + go_package_prefix: + default: "github.com/sqlc-dev/sqlc/internal" +plugins: + - plugin: buf.build/protocolbuffers/go:v1.30.0 + out: internal + opt: paths=source_relative + - plugin: buf.build/grpc/go:v1.3.0 + out: internal + opt: paths=source_relative diff --git a/buf.lock b/buf.lock new file mode 100644 index 0000000..c91b581 --- /dev/null +++ b/buf.lock @@ -0,0 +1,2 @@ +# Generated by buf. DO NOT EDIT. +version: v1 diff --git a/buf.work.yaml b/buf.work.yaml new file mode 100644 index 0000000..0ad4353 --- /dev/null +++ b/buf.work.yaml @@ -0,0 +1,3 @@ +version: v1 +directories: + - protos \ No newline at end of file diff --git a/cliff.toml b/cliff.toml new file mode 100644 index 0000000..9b20e5b --- /dev/null +++ b/cliff.toml @@ -0,0 +1,56 @@ +# configuration file for git-cliff (0.1.0) + +[changelog] +# changelog header +header = """ +# Changelog +All notable changes to this project will be documented in this file.\n +""" +# template for the changelog body +# https://tera.netlify.app/docs/#introduction +body = """ +{% if version %}\ + ## [{{ version | trim_start_matches(pat="v") }}](https://github.com/sqlc-dev/sqlc/releases/tag/{{ version }}) +{% else %}\ + ## [unreleased] +{% endif %}\ + +Released {{ timestamp | date(format="%Y-%m-%d") }} + +{% for group, commits in commits | group_by(attribute="group") %} + ### {{ group | upper_first }} + {% for commit in commits %} + - {%if commit.scope %}({{commit.scope}}) {% endif %}{{ commit.message | upper_first }}\ + {% endfor %} +{% endfor %}\n +""" +# remove the leading and trailing whitespaces from the template +trim = true +# changelog footer +footer = """ + +""" + +[git] +# allow only conventional commits +# https://www.conventionalcommits.org +conventional_commits = true +# regex for parsing and grouping commits +commit_parsers = [ + { message = "^feat", group = "Features"}, + { message = "^fix", group = "Bug Fixes"}, + { message = "^doc", group = "Documentation"}, + { message = "^perf", group = "Performance"}, + { message = "^refactor", group = "Refactor"}, + { message = "^style", group = "Styling"}, + { message = "^test", group = "Testing"}, + { message = "^chore\\(release\\): prepare for", skip = true}, + { message = "^chore", group = "Miscellaneous Tasks"}, + { body = ".*security", group = "Security"}, +] +# filter out the commits that are not matched by commit parsers +filter_commits = false +# glob pattern for matching git tags +tag_pattern = "v[0-9]*" +# regex for skipping tags +skip_tags = "v*beta" diff --git a/cmd/sqlc-gen-json/main.go b/cmd/sqlc-gen-json/main.go new file mode 100644 index 0000000..05c804d --- /dev/null +++ b/cmd/sqlc-gen-json/main.go @@ -0,0 +1,47 @@ +package main + +import ( + "bufio" + "context" + "fmt" + "io" + "os" + + "github.com/sqlc-dev/sqlc/internal/codegen/json" + "github.com/sqlc-dev/sqlc/internal/plugin" + "google.golang.org/protobuf/proto" +) + +func main() { + if err := run(); err != nil { + fmt.Fprintf(os.Stderr, "error generating JSON: %s", err) + os.Exit(2) + } +} + +func run() error { + var req plugin.GenerateRequest + reqBlob, err := io.ReadAll(os.Stdin) + if err != nil { + return err + } + if err := proto.Unmarshal(reqBlob, &req); err != nil { + return err + } + resp, err := json.Generate(context.Background(), &req) + if err != nil { + return err + } + respBlob, err := proto.Marshal(resp) + if err != nil { + return err + } + w := bufio.NewWriter(os.Stdout) + if _, err := w.Write(respBlob); err != nil { + return err + } + if err := w.Flush(); err != nil { + return err + } + return nil +} diff --git a/cmd/sqlc-test-setup/main.go b/cmd/sqlc-test-setup/main.go new file mode 100644 index 0000000..2aef6fd --- /dev/null +++ b/cmd/sqlc-test-setup/main.go @@ -0,0 +1,717 @@ +package main + +import ( + "crypto/sha256" + "encoding/hex" + "fmt" + "io" + "log" + "net/http" + "os" + "os/exec" + "path/filepath" + "runtime" + "strconv" + "strings" + "time" +) + +const ( + // pgVersion is the PostgreSQL version to install. + pgVersion = "18.2.0" +) + +// pgBinary contains the download information for a PostgreSQL binary release. +type pgBinary struct { + URL string + SHA256 string +} + +// pgBinaries maps "/" to the corresponding binary download info. +var pgBinaries = map[string]pgBinary{ + "linux/amd64": { + URL: "https://github.com/theseus-rs/postgresql-binaries/releases/download/" + pgVersion + "/postgresql-" + pgVersion + "-x86_64-unknown-linux-gnu.tar.gz", + SHA256: "cc2674e1641aa2a62b478971a22c131a768eb783f313e6a3385888f58a604074", + }, + "linux/arm64": { + URL: "https://github.com/theseus-rs/postgresql-binaries/releases/download/" + pgVersion + "/postgresql-" + pgVersion + "-aarch64-unknown-linux-gnu.tar.gz", + SHA256: "8b415a11c7a5484e5fbf7a57fca71554d2d1d7acd34faf066606d2fee1261854", + }, +} + +func main() { + log.SetFlags(log.Ltime) + log.SetPrefix("[sqlc-test-setup] ") + + if len(os.Args) < 2 { + fmt.Fprintln(os.Stderr, "usage: sqlc-test-setup ") + os.Exit(1) + } + + switch os.Args[1] { + case "install": + if err := runInstall(); err != nil { + log.Fatalf("install failed: %s", err) + } + case "start": + if err := runStart(); err != nil { + log.Fatalf("start failed: %s", err) + } + default: + fmt.Fprintf(os.Stderr, "unknown command: %s\nusage: sqlc-test-setup \n", os.Args[1]) + os.Exit(1) + } +} + +// run executes a command with verbose logging, streaming output to stderr. +func run(name string, args ...string) error { + log.Printf("exec: %s %s", name, strings.Join(args, " ")) + cmd := exec.Command(name, args...) + cmd.Stdout = os.Stderr + cmd.Stderr = os.Stderr + cmd.Stdin = os.Stdin + return cmd.Run() +} + +// runOutput executes a command and returns its combined output. +func runOutput(name string, args ...string) (string, error) { + log.Printf("exec: %s %s", name, strings.Join(args, " ")) + cmd := exec.Command(name, args...) + out, err := cmd.CombinedOutput() + return string(out), err +} + +// commandExists checks if a binary is available in PATH. +func commandExists(name string) bool { + _, err := exec.LookPath(name) + return err == nil +} + +// The MySQL release the tests run against. Everything that names a MySQL +// version — the docker-compose service, the goldeneye dialect generator and +// its gen workflow — is pinned to the same release. +const ( + mysqlMajor = 26 + mysqlVersion = "26.7.0" +) + +// isMySQLVersionOK checks if the mysqld --version output indicates the +// pinned major release or a later one. +// Example version string: "/usr/sbin/mysqld Ver 8.0.44-0ubuntu0.24.04.2 ..." +func isMySQLVersionOK(versionOutput string) bool { + // Look for "Ver X.Y.Z" pattern + fields := strings.Fields(versionOutput) + for i, f := range fields { + if strings.EqualFold(f, "Ver") && i+1 < len(fields) { + ver := strings.Split(fields[i+1], ".") + if len(ver) > 0 { + major, err := strconv.Atoi(ver[0]) + if err != nil { + return false + } + return major >= mysqlMajor + } + } + } + return false +} + +// pgBaseDir returns the sqlc-specific directory where PostgreSQL is installed, +// using the user's cache directory (~/.cache/sqlc/postgresql on Linux). +func pgBaseDir() string { + cacheDir, err := os.UserCacheDir() + if err != nil { + cacheDir = filepath.Join(os.Getenv("HOME"), ".cache") + } + return filepath.Join(cacheDir, "sqlc", "postgresql") +} + +// pgBinDir returns the path to the PostgreSQL bin directory. +func pgBinDir() string { + return filepath.Join(pgBaseDir(), "bin") +} + +// pgDataDir returns the path to the PostgreSQL data directory. +func pgDataDir() string { + return filepath.Join(pgBaseDir(), "data") +} + +// pgBin returns the full path to a PostgreSQL binary. +func pgBin(name string) string { + return filepath.Join(pgBinDir(), name) +} + +// ---- install ---- + +func runInstall() error { + log.Println("=== Installing PostgreSQL and MySQL for test setup ===") + + if err := installAptProxy(); err != nil { + return fmt.Errorf("configuring apt proxy: %w", err) + } + + if err := installPostgreSQL(); err != nil { + return fmt.Errorf("installing postgresql: %w", err) + } + + if err := installMySQL(); err != nil { + return fmt.Errorf("installing mysql: %w", err) + } + + log.Println("=== Install complete ===") + return nil +} + +func installAptProxy() error { + proxy := os.Getenv("http_proxy") + if proxy == "" { + log.Println("http_proxy is not set, skipping apt proxy configuration") + return nil + } + + const confPath = "/etc/apt/apt.conf.d/99proxy" + if _, err := os.Stat(confPath); err == nil { + log.Printf("apt proxy config already exists at %s, skipping", confPath) + return nil + } + + log.Printf("configuring apt proxy to use %s", proxy) + proxyConf := fmt.Sprintf("Acquire::http::Proxy \"%s\";", proxy) + cmd := fmt.Sprintf("echo '%s' | sudo tee /etc/apt/apt.conf.d/99proxy", proxyConf) + return run("bash", "-c", cmd) +} + +func installPostgreSQL() error { + log.Println("--- Installing PostgreSQL ---") + + // Install runtime dependencies needed by PostgreSQL extensions (e.g. + // uuid-ossp requires libossp-uuid16). + if err := installPgDeps(); err != nil { + return fmt.Errorf("installing postgresql dependencies: %w", err) + } + + // Check if already installed in our directory + if _, err := os.Stat(pgBin("postgres")); err == nil { + out, err := runOutput(pgBin("postgres"), "--version") + if err == nil { + log.Printf("postgresql is already installed: %s", strings.TrimSpace(out)) + log.Println("skipping postgresql installation") + return nil + } + } + + platform := runtime.GOOS + "/" + runtime.GOARCH + bin, ok := pgBinaries[platform] + if !ok { + return fmt.Errorf("unsupported platform: %s (supported: %s)", platform, supportedPlatforms()) + } + + // Download to a temp file + tarball := filepath.Join(os.TempDir(), fmt.Sprintf("postgresql-%s.tar.gz", pgVersion)) + + if _, err := os.Stat(tarball); err != nil { + log.Printf("downloading PostgreSQL %s from %s", pgVersion, bin.URL) + if err := downloadFile(tarball, bin.URL); err != nil { + os.Remove(tarball) + return fmt.Errorf("downloading postgresql: %w", err) + } + } else { + log.Printf("postgresql tarball already downloaded at %s", tarball) + } + + // Verify SHA256 checksum + log.Printf("verifying SHA256 checksum") + actualHash, err := sha256File(tarball) + if err != nil { + return fmt.Errorf("computing sha256: %w", err) + } + if actualHash != bin.SHA256 { + os.Remove(tarball) + return fmt.Errorf("SHA256 mismatch: expected %s, got %s", bin.SHA256, actualHash) + } + log.Printf("SHA256 checksum verified: %s", actualHash) + + baseDir := pgBaseDir() + + // Create the base directory in the user cache + if err := os.MkdirAll(baseDir, 0o755); err != nil { + return fmt.Errorf("creating %s: %w", baseDir, err) + } + + // Extract the tarball - it contains a top-level directory like + // postgresql-18.2.0-x86_64-unknown-linux-gnu/ with bin/, lib/, share/ inside. + // We strip that top-level directory and extract directly into the base dir. + log.Printf("extracting postgresql to %s", baseDir) + if err := run("tar", "-xzf", tarball, "-C", baseDir, "--strip-components=1"); err != nil { + return fmt.Errorf("extracting postgresql: %w", err) + } + + // Verify the binary works + out, err := runOutput(pgBin("postgres"), "--version") + if err != nil { + return fmt.Errorf("postgres --version failed after install: %w", err) + } + log.Printf("postgresql installed successfully: %s", strings.TrimSpace(out)) + return nil +} + +// installPgDeps installs shared libraries required by PostgreSQL extensions at +// runtime (e.g. libossp-uuid16 for uuid-ossp). +func installPgDeps() error { + log.Println("installing postgresql runtime dependencies") + if err := run("sudo", "apt-get", "install", "-y", "--no-install-recommends", "libossp-uuid16"); err != nil { + return fmt.Errorf("apt-get install libossp-uuid16: %w", err) + } + return nil +} + +// supportedPlatforms returns a comma-separated list of supported platforms. +func supportedPlatforms() string { + platforms := make([]string, 0, len(pgBinaries)) + for p := range pgBinaries { + platforms = append(platforms, p) + } + return strings.Join(platforms, ", ") +} + +// downloadFile downloads a URL to a local file path. +func downloadFile(filepath string, url string) error { + resp, err := http.Get(url) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("HTTP %d: %s", resp.StatusCode, resp.Status) + } + + out, err := os.Create(filepath) + if err != nil { + return err + } + defer out.Close() + + _, err = io.Copy(out, resp.Body) + return err +} + +// sha256File computes the SHA256 hash of a file and returns the hex string. +func sha256File(path string) (string, error) { + f, err := os.Open(path) + if err != nil { + return "", err + } + defer f.Close() + + h := sha256.New() + if _, err := io.Copy(h, f); err != nil { + return "", err + } + return hex.EncodeToString(h.Sum(nil)), nil +} + +func installMySQL() error { + log.Printf("--- Installing MySQL %s ---", mysqlVersion) + + if commandExists("mysqld") { + out, err := runOutput("mysqld", "--version") + if err == nil { + version := strings.TrimSpace(out) + log.Printf("mysql is already installed: %s", version) + if isMySQLVersionOK(version) { + log.Printf("mysql version is %d+, skipping installation", mysqlMajor) + return nil + } + log.Printf("mysql version is too old, upgrading to MySQL %s", mysqlVersion) + // Stop existing MySQL before upgrading + _ = exec.Command("sudo", "service", "mysql", "stop").Run() + _ = exec.Command("sudo", "pkill", "-f", "mysqld").Run() + time.Sleep(2 * time.Second) + // Remove old MySQL packages to avoid conflicts + log.Println("removing old mysql packages") + _ = run("sudo", "apt-get", "remove", "-y", "mysql-server", "mysql-client", "mysql-common", + "mysql-server-core-*", "mysql-client-core-*") + // Clear old data directory so the new release can initialize fresh + log.Println("clearing old mysql data directory") + _ = run("sudo", "rm", "-rf", "/var/lib/mysql") + _ = run("sudo", "mkdir", "-p", "/var/lib/mysql") + _ = run("sudo", "chown", "mysql:mysql", "/var/lib/mysql") + } + } + + major, minor, _ := strings.Cut(mysqlVersion, ".") + minor, _, _ = strings.Cut(minor, ".") + bundleURL := fmt.Sprintf("https://dev.mysql.com/get/Downloads/MySQL-%s.%s/mysql-server_%s-1ubuntu24.04_amd64.deb-bundle.tar", major, minor, mysqlVersion) + bundleTar := fmt.Sprintf("/tmp/mysql-server-%s-bundle.tar", mysqlVersion) + extractDir := "/tmp/mysql-server-" + mysqlVersion + + if _, err := os.Stat(bundleTar); err != nil { + log.Printf("downloading MySQL %s bundle from %s", mysqlVersion, bundleURL) + if err := run("curl", "-L", "-o", bundleTar, bundleURL); err != nil { + return fmt.Errorf("downloading mysql bundle: %w", err) + } + } else { + log.Printf("mysql bundle already downloaded at %s, skipping download", bundleTar) + } + + log.Printf("extracting bundle to %s", extractDir) + if err := os.MkdirAll(extractDir, 0o755); err != nil { + return fmt.Errorf("creating extract dir: %w", err) + } + if err := run("tar", "-xf", bundleTar, "-C", extractDir); err != nil { + return fmt.Errorf("extracting mysql bundle: %w", err) + } + + // Install packages in dependency order using dpkg. + // Some packages may fail due to missing dependencies, which is expected. + // We fix them all at the end with apt-get install -f. + packages := []string{ + "mysql-common_*.deb", + "mysql-community-client-plugins_*.deb", + "mysql-community-client-core_*.deb", + "mysql-community-client_*.deb", + "mysql-client_*.deb", + "mysql-community-server-core_*.deb", + "mysql-community-server_*.deb", + "mysql-server_*.deb", + } + + for _, pkg := range packages { + log.Printf("installing %s (dependency errors will be fixed afterwards)", pkg) + cmd := fmt.Sprintf("sudo dpkg -i %s/%s", extractDir, pkg) + if err := run("bash", "-c", cmd); err != nil { + log.Printf("dpkg reported errors for %s (will fix with apt-get install -f)", pkg) + } + } + + log.Println("fixing missing dependencies with apt-get install -f") + if err := run("sudo", "apt-get", "install", "-f", "-y"); err != nil { + return fmt.Errorf("apt-get install -f: %w", err) + } + + log.Printf("mysql %s installed successfully", mysqlVersion) + return nil +} + +// ---- start ---- + +func runStart() error { + log.Println("=== Starting PostgreSQL and MySQL ===") + + if err := startPostgreSQL(); err != nil { + return fmt.Errorf("starting postgresql: %w", err) + } + + if err := startMySQL(); err != nil { + return fmt.Errorf("starting mysql: %w", err) + } + + log.Println("=== Both databases are running and configured ===") + log.Println("PostgreSQL: postgres://postgres:postgres@127.0.0.1:5432/postgres?sslmode=disable") + log.Println("MySQL: root:mysecretpassword@tcp(127.0.0.1:3306)/mysql") + return nil +} + +func startPostgreSQL() error { + log.Println("--- Starting PostgreSQL ---") + + dataDir := pgDataDir() + logFile := filepath.Join(pgBaseDir(), "postgresql.log") + + // Check if already running + if pgIsReady() { + log.Println("postgresql is already running and accepting connections") + return nil + } + + // Initialize data directory if needed + if _, err := os.Stat(filepath.Join(dataDir, "PG_VERSION")); os.IsNotExist(err) { + log.Println("initializing postgresql data directory") + if err := os.MkdirAll(dataDir, 0o700); err != nil { + return fmt.Errorf("creating data directory: %w", err) + } + if err := run(pgBin("initdb"), + "-D", dataDir, + "--username=postgres", + "--auth=trust", + ); err != nil { + return fmt.Errorf("initdb: %w", err) + } + + // Configure pg_hba.conf for md5 password authentication on TCP + hbaPath := filepath.Join(dataDir, "pg_hba.conf") + if err := configurePgHBA(hbaPath); err != nil { + return fmt.Errorf("configuring pg_hba.conf: %w", err) + } + + // Configure postgresql.conf to listen on localhost + confPath := filepath.Join(dataDir, "postgresql.conf") + if err := appendToFile(confPath, + "\n# sqlc-test-setup configuration\n"+ + "listen_addresses = '127.0.0.1'\n"+ + "port = 5432\n", + ); err != nil { + return fmt.Errorf("configuring postgresql.conf: %w", err) + } + } else { + log.Println("postgresql data directory already initialized") + } + + // Start PostgreSQL using pg_ctl + log.Println("starting postgresql") + if err := run(pgBin("pg_ctl"), + "-D", dataDir, + "-l", logFile, + "-o", fmt.Sprintf("-k %s", dataDir), + "start", + ); err != nil { + return fmt.Errorf("pg_ctl start: %w", err) + } + + // Wait for PostgreSQL to be ready + log.Println("waiting for postgresql to accept connections") + if err := waitForPostgreSQL(30 * time.Second); err != nil { + return fmt.Errorf("postgresql did not start in time: %w", err) + } + + // Set the postgres user password + log.Println("setting password for postgres user") + if err := run(pgBin("psql"), + "-h", "127.0.0.1", + "-U", "postgres", + "-c", "ALTER USER postgres PASSWORD 'postgres';", + ); err != nil { + return fmt.Errorf("setting postgres password: %w", err) + } + + // Update pg_hba.conf to require md5 auth now that password is set + hbaPath := filepath.Join(dataDir, "pg_hba.conf") + if err := configurePgHBAWithMD5(hbaPath); err != nil { + return fmt.Errorf("updating pg_hba.conf for md5: %w", err) + } + + // Reload configuration + log.Println("reloading postgresql configuration") + if err := run(pgBin("pg_ctl"), "-D", dataDir, "reload"); err != nil { + return fmt.Errorf("pg_ctl reload: %w", err) + } + + // Verify connection with password + log.Println("verifying postgresql connection") + cmd := exec.Command(pgBin("psql"), + "-h", "127.0.0.1", + "-U", "postgres", + "-c", "SELECT 1;", + ) + cmd.Env = append(os.Environ(), "PGPASSWORD=postgres") + cmd.Stdout = os.Stderr + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return fmt.Errorf("postgresql connection test failed: %w", err) + } + + log.Println("postgresql is running and configured") + return nil +} + +// configurePgHBA writes a pg_hba.conf that allows trust auth initially (for +// setting the password), then we switch to md5. +func configurePgHBA(hbaPath string) error { + content := `# pg_hba.conf - generated by sqlc-test-setup +# TYPE DATABASE USER ADDRESS METHOD +local all all trust +host all all 127.0.0.1/32 trust +host all all ::1/128 trust +` + return os.WriteFile(hbaPath, []byte(content), 0o600) +} + +// configurePgHBAWithMD5 rewrites pg_hba.conf to use md5 for TCP connections. +func configurePgHBAWithMD5(hbaPath string) error { + content := `# pg_hba.conf - generated by sqlc-test-setup +# TYPE DATABASE USER ADDRESS METHOD +local all all trust +host all all 127.0.0.1/32 md5 +host all all ::1/128 md5 +` + return os.WriteFile(hbaPath, []byte(content), 0o600) +} + +// appendToFile appends text to a file. +func appendToFile(path, text string) error { + f, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY, 0o644) + if err != nil { + return err + } + defer f.Close() + _, err = f.WriteString(text) + return err +} + +// pgIsReady checks if PostgreSQL is running and accepting connections. +func pgIsReady() bool { + cmd := exec.Command(pgBin("pg_isready"), "-h", "127.0.0.1", "-p", "5432") + return cmd.Run() == nil +} + +// waitForPostgreSQL polls until PostgreSQL accepts connections or times out. +func waitForPostgreSQL(timeout time.Duration) error { + deadline := time.Now().Add(timeout) + for time.Now().Before(deadline) { + if pgIsReady() { + return nil + } + time.Sleep(500 * time.Millisecond) + } + return fmt.Errorf("timed out after %s waiting for postgresql", timeout) +} + +func startMySQL() error { + log.Println("--- Starting MySQL ---") + + // Check if MySQL is already running and accessible with the expected password + if mysqlReady() { + log.Println("mysql is already running and accepting connections") + return verifyMySQL() + } + + // Stop any existing MySQL service that might be running (e.g. pre-installed + // on GitHub Actions runners) to avoid port conflicts. + log.Println("stopping any existing mysql service") + _ = exec.Command("sudo", "service", "mysql", "stop").Run() + _ = exec.Command("sudo", "mysqladmin", "shutdown").Run() + // Give MySQL time to fully shut down + time.Sleep(2 * time.Second) + + if err := ensureMySQLDirs(); err != nil { + return err + } + + // Check if data directory already exists and has been initialized + needsPasswordReset := false + if mysqlInitialized() { + log.Println("mysql data directory already initialized, skipping initialization") + // Existing data dir may have an unknown root password (e.g. pre-installed + // MySQL on GitHub Actions). We'll need to use --skip-grant-tables to reset it. + needsPasswordReset = true + } else { + log.Println("initializing mysql data directory") + if err := run("sudo", "mysqld", "--initialize-insecure", "--user=mysql"); err != nil { + return fmt.Errorf("mysqld --initialize-insecure: %w", err) + } + } + + if needsPasswordReset { + // Start with --skip-grant-tables to reset the unknown root password. + if err := startMySQLDaemon("--skip-grant-tables"); err != nil { + return err + } + + log.Println("resetting root password via --skip-grant-tables") + resetSQL := "FLUSH PRIVILEGES; ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'mysecretpassword';" + if err := run("mysql", "-u", "root", "-e", resetSQL); err != nil { + return fmt.Errorf("resetting mysql root password: %w", err) + } + + // Restart without --skip-grant-tables + log.Println("restarting mysql normally") + if err := run("sudo", "mysqladmin", "-u", "root", "-pmysecretpassword", "shutdown"); err != nil { + // If mysqladmin fails, try killing the process directly + _ = run("sudo", "pkill", "-f", "mysqld") + } + time.Sleep(2 * time.Second) + + if err := startMySQLDaemon(); err != nil { + return err + } + } else { + // Fresh initialization — start normally and set password + if err := startMySQLDaemon(); err != nil { + return err + } + + log.Println("setting mysql root password") + alterSQL := "ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'mysecretpassword'; FLUSH PRIVILEGES;" + if err := run("mysql", "-u", "root", "-e", alterSQL); err != nil { + return fmt.Errorf("setting mysql root password: %w", err) + } + } + + return verifyMySQL() +} + +// ensureMySQLDirs creates the directories MySQL needs at runtime. +func ensureMySQLDirs() error { + if err := run("sudo", "mkdir", "-p", "/var/run/mysqld"); err != nil { + return fmt.Errorf("creating /var/run/mysqld: %w", err) + } + if err := run("sudo", "chown", "mysql:mysql", "/var/run/mysqld"); err != nil { + return fmt.Errorf("chowning /var/run/mysqld: %w", err) + } + return nil +} + +// startMySQLDaemon starts mysqld_safe in the background and waits for it to +// accept connections. Extra args (e.g. "--skip-grant-tables") are appended. +func startMySQLDaemon(extraArgs ...string) error { + args := append([]string{"mysqld_safe", "--user=mysql"}, extraArgs...) + log.Printf("starting mysql via mysqld_safe %v", extraArgs) + cmd := exec.Command("sudo", args...) + cmd.Stdout = os.Stderr + cmd.Stderr = os.Stderr + if err := cmd.Start(); err != nil { + return fmt.Errorf("starting mysqld_safe: %w", err) + } + + log.Println("waiting for mysql to accept connections") + if err := waitForMySQL(30 * time.Second); err != nil { + return fmt.Errorf("mysql did not start in time: %w", err) + } + log.Println("mysql is accepting connections") + return nil +} + +// mysqlReady checks if MySQL is running and accepting connections with the expected password. +func mysqlReady() bool { + err := exec.Command("mysqladmin", "-h", "127.0.0.1", "-u", "root", "-pmysecretpassword", "ping").Run() + return err == nil +} + +// waitForMySQL polls until MySQL accepts connections or the timeout expires. +func waitForMySQL(timeout time.Duration) error { + deadline := time.Now().Add(timeout) + for time.Now().Before(deadline) { + // Try connecting without password (fresh) or with password (already configured) + if exec.Command("mysqladmin", "-u", "root", "ping").Run() == nil { + return nil + } + if exec.Command("mysqladmin", "-h", "127.0.0.1", "-u", "root", "-pmysecretpassword", "ping").Run() == nil { + return nil + } + time.Sleep(500 * time.Millisecond) + } + return fmt.Errorf("timed out after %s waiting for mysql", timeout) +} + +func verifyMySQL() error { + log.Println("verifying mysql connection") + if err := run("mysql", "-h", "127.0.0.1", "-u", "root", "-pmysecretpassword", "-e", "SELECT VERSION();"); err != nil { + return fmt.Errorf("mysql connection test failed: %w", err) + } + log.Println("mysql is running and configured") + return nil +} + +// mysqlInitialized checks if the MySQL data directory has been initialized. +// We use sudo ls because /var/lib/mysql is typically only readable by the +// mysql user, so filepath.Glob from a non-root process would silently fail. +func mysqlInitialized() bool { + out, err := exec.Command("sudo", "ls", "/var/lib/mysql").CombinedOutput() + if err != nil { + return false + } + // If the directory has any contents, consider it initialized. + // mysqld --initialize-insecure requires an empty directory. + return strings.TrimSpace(string(out)) != "" +} diff --git a/cmd/sqlc/main.go b/cmd/sqlc/main.go new file mode 100644 index 0000000..f003db4 --- /dev/null +++ b/cmd/sqlc/main.go @@ -0,0 +1,11 @@ +package main + +import ( + "os" + + "github.com/sqlc-dev/sqlc/internal/cmd" +) + +func main() { + os.Exit(cmd.Do(os.Args[1:], os.Stdin, os.Stdout, os.Stderr)) +} diff --git a/devenv.lock b/devenv.lock new file mode 100644 index 0000000..ff48a49 --- /dev/null +++ b/devenv.lock @@ -0,0 +1,100 @@ +{ + "nodes": { + "devenv": { + "locked": { + "dir": "src/modules", + "lastModified": 1742659231, + "owner": "cachix", + "repo": "devenv", + "rev": "c651cb04013be972767aaecb3e9a98fc930d080e", + "type": "github" + }, + "original": { + "dir": "src/modules", + "owner": "cachix", + "repo": "devenv", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1733328505, + "owner": "edolstra", + "repo": "flake-compat", + "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1742707865, + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "dd613136ee91f67e5dba3f3f41ac99ae89c5406b", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "pre-commit-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1742649964, + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "dcf5072734cb576d2b0c59b2ac44f5050b5eac82", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, + "root": { + "inputs": { + "devenv": "devenv", + "nixpkgs": "nixpkgs", + "pre-commit-hooks": "pre-commit-hooks" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/devenv.nix b/devenv.nix new file mode 100644 index 0000000..8a25b78 --- /dev/null +++ b/devenv.nix @@ -0,0 +1,17 @@ +{ pkgs, ... }: + +{ + # https://devenv.sh/packages/ + packages = [ + pkgs.buf + pkgs.go_1_24 + pkgs.git + pkgs.git-cliff + pkgs.govulncheck + pkgs.gopls + pkgs.golint + pkgs.mysql-shell + pkgs.postgresql_15 + pkgs.python311 + ]; +} diff --git a/devenv.yaml b/devenv.yaml new file mode 100644 index 0000000..c7cb5ce --- /dev/null +++ b/devenv.yaml @@ -0,0 +1,3 @@ +inputs: + nixpkgs: + url: github:NixOS/nixpkgs/nixpkgs-unstable diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..2af58e1 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,39 @@ +version: "3.8" +services: + mysql: + image: "mysql:26.7" + ports: + - "3306:3306" + restart: always + environment: + MYSQL_DATABASE: dinotest + MYSQL_ROOT_PASSWORD: mysecretpassword + MYSQL_ROOT_HOST: '%' + + postgresql: + image: "postgres:16" + ports: + - "5432:5432" + restart: always + environment: + POSTGRES_DB: postgres + POSTGRES_PASSWORD: mysecretpassword + POSTGRES_USER: postgres + + mssql: + image: "mcr.microsoft.com/mssql/server:2025-latest" + ports: + - "1433:1433" + restart: always + environment: + ACCEPT_EULA: "Y" + MSSQL_SA_PASSWORD: "Mysecretpassword1!" + + # Spanner Omni, the downloadable Spanner, serves plaintext gRPC on port + # 15000 and its console on 15026; its quickstart runs it on the host + # network. + spanner: + image: "us-docker.pkg.dev/spanner-omni/images/spanner-omni:2026.r2.1-beta" + command: start-single-server + network_mode: host + restart: always diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..7812132 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,2 @@ +_venv +_build diff --git a/docs/guides/development.md b/docs/guides/development.md new file mode 100644 index 0000000..f819657 --- /dev/null +++ b/docs/guides/development.md @@ -0,0 +1,61 @@ +# Developing sqlc + +## Building + +For local development, install `sqlc` under an alias. We suggest `sqlc-dev`. + +``` +go build -o ~/go/bin/sqlc-dev ./cmd/sqlc +``` + +Install `sqlc-gen-json` to avoid test failure. + +``` +go build -o ~/go/bin/sqlc-gen-json ./cmd/sqlc-gen-json +``` + +## Running Tests + +``` +go test ./... +``` + +To run the tests in the examples folder, use the `examples` tag. + +``` +go test --tags=examples ./... +``` + +These tests require locally-running database instances. Run these databases +using [Docker Compose](https://docs.docker.com/compose/). + +``` +docker compose up -d +``` + +The tests use the following environment variables to connect to the +database + +### For PostgreSQL + +``` +Variable Default Value +------------------------- +PG_HOST 127.0.0.1 +PG_PORT 5432 +PG_USER postgres +PG_PASSWORD mysecretpassword +PG_DATABASE dinotest +``` + +### For MySQL + +``` +Variable Default Value +------------------------- +MYSQL_HOST 127.0.0.1 +MYSQL_PORT 3306 +MYSQL_USER root +MYSQL_ROOT_PASSWORD mysecretpassword +MYSQL_DATABASE dinotest +``` diff --git a/docs/guides/migrating-off-hosted-managed-databases.md b/docs/guides/migrating-off-hosted-managed-databases.md new file mode 100644 index 0000000..7951a1c --- /dev/null +++ b/docs/guides/migrating-off-hosted-managed-databases.md @@ -0,0 +1,71 @@ +# Migrating off hosted managed databases + +Starting in sqlc 1.27.0, [managed databases](../howto/managed-databases.md) will require a database server URI in the configuration file. + +This guide walks you through migrating to a locally running database server. + +## Run a database server locally + +There are many options for running a database server locally, but this guide +will use [Docker Compose](https://docs.docker.com/compose/), as it can support +both MySQL and PostgreSQL. + +If you're using macOS and PostgreSQL, [Postgres.app](https://postgresapp.com/) is also a good option. + +For MySQL, create a `docker-compose.yml` file with the following contents: + +```yaml +version: "3.8" +services: + mysql: + image: "mysql/mysql-server:8.0" + ports: + - "3306:3306" + restart: always + environment: + MYSQL_DATABASE: dinotest + MYSQL_ROOT_PASSWORD: mysecretpassword + MYSQL_ROOT_HOST: '%' +``` + +For PostgreSQL, create a `docker-compose.yml` file with the following contents: + +```yaml +version: "3.8" +services: + postgresql: + image: "postgres:16" + ports: + - "5432:5432" + restart: always + environment: + POSTGRES_DB: postgres + POSTGRES_PASSWORD: mysecretpassword + POSTGRES_USER: postgres +``` + +```sh +docker compose up -d +``` + +## Upgrade sqlc + +You must be running sqlc v1.31.1 or greater to have access to the `servers` +configuration. + +## Add servers to configuration + +```diff +version: '2' +cloud: + project: '' ++ servers: ++ - name: mysql ++ uri: mysql://localhost:3306 ++ - name: postgres ++ uri: postgres://localhost:5432/postgres?sslmode=disable +``` + +## Re-generate the code + +Run `sqlc generate`. A database with the `sqlc_managed_` prefix will be automatically created and used for query analysis. diff --git a/docs/guides/migrating-to-sqlc-gen-kotlin.md b/docs/guides/migrating-to-sqlc-gen-kotlin.md new file mode 100644 index 0000000..17660aa --- /dev/null +++ b/docs/guides/migrating-to-sqlc-gen-kotlin.md @@ -0,0 +1,119 @@ +# Migrating to sqlc-gen-kotlin + +Starting in sqlc 1.16.0, built-in Kotlin support has been deprecated. It will +be fully removed in 1.17.0 in favor of sqlc-gen-kotlin. + +This guide will walk you through migrating to the [sqlc-gen-kotlin](https://github.com/sqlc-dev/sqlc-gen-kotlin) plugin, +which involves three steps. + +1. Add the sqlc-gen-kotlin plugin +2. Migrate each package +3. Re-generate the code + +## Add the sqlc-gen-kotlin plugin + +In your configuration file, add a `plugins` array if you don't have one +already. Add the following configuration for the plugin: + +```json +{ + "version": "2", + "plugins": [ + { + "name": "kt", + "wasm": { + "url": "https://downloads.sqlc.dev/plugin/sqlc-gen-kotlin_1.0.0.wasm", + "sha256": "7620dc5d462de41fdc90e2011232c842117b416c98fd5c163d27c5738431a45c" + } + } + ] +} +``` + +```yaml +version: "2" +plugins: +- name: "kt" + wasm: + url: "https://downloads.sqlc.dev/plugin/sqlc-gen-kotlin_1.0.0.wasm" + sha256: "7620dc5d462de41fdc90e2011232c842117b416c98fd5c163d27c5738431a45c" +``` + +## Migrate each package + +Your package configuration should currently looks something like this for JSON. + +```json + "sql": [ + { + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql", + "gen": { + "kotlin": { + "out": "src/main/kotlin/com/example/foo", + "package": "com.example.foo" + } + } + } + ] +``` + +Or this if you're using YAML. + +```yaml + sql: + - schema: "schema.sql" + queries: "query.sql" + engine: "postgresql" + gen: + kotlin: + out: "src/main/kotlin/com/example/foo" + package: "com.example.foo" +``` + +To use the plugin, you'll need to replace the `gen` mapping with the `codegen` +collection. Add the `plugin` field, setting it to `kt`. All fields other than +`out` need to be moved into the `options` mapping. + +After you're done, it should look like this for JSON. + +```json + "sql": [ + { + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql", + "codegen": [ + { + "out": "src/main/kotlin/com/example/foo", + "plugin": "kt", + "options": { + "package": "com.example.foo" + } + } + ] + } + ] +``` + +Or this for YAML. + +```yaml + sql: + - schema: "schema.sql" + queries: "query.sql" + engine: "postgresql" + codegen: + - plugin: "kt" + out: "src/main/kotlin/com/example/foo" + options: + package: "com.example.foo" +``` + +## Re-generate the code + +Run `sqlc generate`. The plugin will produce the same output, so you shouldn't +see any changes. The first time `sqlc generate` is run, the plugin must be +downloaded and compiled, resulting in a slightly longer runtime. Subsequent +`generate` calls will be fast. diff --git a/docs/guides/migrating-to-sqlc-gen-python.md b/docs/guides/migrating-to-sqlc-gen-python.md new file mode 100644 index 0000000..e139ad0 --- /dev/null +++ b/docs/guides/migrating-to-sqlc-gen-python.md @@ -0,0 +1,131 @@ +# Migrating to sqlc-gen-python + +Starting in sqlc 1.16.0, built-in Python support has been deprecated. It will +be fully removed in 1.17.0 in favor of sqlc-gen-python. + +This guide will walk you through migrating to the [sqlc-gen-python](https://github.com/sqlc-dev/sqlc-gen-python) plugin, +which involves three steps. + +1. Add the sqlc-gen-python plugin +2. Migrate each package +3. Re-generate the code + +## Add the sqlc-gen-python plugin + +In your configuration file, add a `plugins` array if you don't have one +already. Add the following configuration for the plugin: + +```json +{ + "version": "2", + "plugins": [ + { + "name": "py", + "wasm": { + "url": "https://downloads.sqlc.dev/plugin/sqlc-gen-python_1.0.0.wasm", + "sha256": "aca83e1f59f8ffdc604774c2f6f9eb321a2b23e07dc83fc12289d25305fa065b" + } + } + ] +} +``` + +```yaml +version: "2" +plugins: + - name: "py" + wasm: + url: "https://downloads.sqlc.dev/plugin/sqlc-gen-python_1.0.0.wasm" + sha256: "aca83e1f59f8ffdc604774c2f6f9eb321a2b23e07dc83fc12289d25305fa065b" +``` + +## Migrate each package + +Your package configuration should currently looks something like this for JSON. + +```json + "sql": [ + { + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql", + "gen": { + "python": { + "out": "src", + "package": "foo", + "emit_sync_querier": true, + "emit_async_querier": true, + "query_parameter_limit": 5 + } + } + } + ] +``` + +Or this if you're using YAML. + +```yaml + sql: + - schema: "schema.sql" + queries: "query.sql" + engine: "postgresql" + gen: + python: + out: "src" + package: "foo" + emit_sync_querier: true + emit_async_querier: true + query_parameter_limit: 5 +``` + +To use the plugin, you'll need to replace the `gen` mapping with the `codegen` +collection. Add the `plugin` field, setting it to `py`. All fields other than +`out` need to be moved into the `options` mapping. + +After you're done, it should look like this for JSON. + +```json + "sql": [ + { + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql", + "codegen": [ + { + "out": "src", + "plugin": "py", + "options": { + "package": "authors", + "emit_sync_querier": true, + "emit_async_querier": true, + "query_parameter_limit": 5 + } + } + ] + } + ] +``` + +Or this for YAML. + +```yaml + sql: + - schema: "schema.sql" + queries: "query.sql" + engine: "postgresql" + codegen: + - plugin: "py" + out: "src" + options: + package: "foo" + emit_sync_querier: true + emit_async_querier: true + query_parameter_limit: 5 +``` + +## Re-generate the code + +Run `sqlc generate`. The plugin will produce the same output, so you shouldn't +see any changes. The first time `sqlc generate` is run, the plugin must be +downloaded and compiled, resulting in a slightly longer runtime. Subsequent +`generate` calls will be fast. diff --git a/docs/guides/plugins.md b/docs/guides/plugins.md new file mode 100644 index 0000000..b229f91 --- /dev/null +++ b/docs/guides/plugins.md @@ -0,0 +1,104 @@ +# Using plugins + +To use plugins, you must be using [Version 2](../reference/config.md#version-2) of +the configuration file. The top-level `plugins` array defines the available +plugins. + +## WASM plugins + +> WASM plugins are fully sandboxed; they do not have access to the network, +> filesystem, or environment variables. + +In the `codegen` section, the `out` field dictates what directory will contain +the new files. The `plugin` key must reference a plugin defined in the +top-level `plugins` map. Any `options` are serialized to a string as JSON and +passed on to the plugin itself. + + +```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 + options: + lang: en-US +``` + +For a complete working example see the following files: +- [sqlc-gen-greeter](https://github.com/sqlc-dev/sqlc-gen-greeter) + - A WASM plugin (written in Rust) that outputs a friendly message +- [wasm_plugin_sqlc_gen_greeter](https://github.com/sqlc-dev/sqlc/tree/main/internal/endtoend/testdata/wasm_plugin_sqlc_gen_greeter) + - An example project showing how to use a WASM plugin + +## Process plugins + +> Process-based plugins offer minimal security. Only use plugins that you +> trust. Better yet, only use plugins that you've written yourself. + +In the `codegen` section, the `out` field dictates what directory will contain +the new files. The `plugin` key must reference a plugin defined in the +top-level `plugins` map. Any `options` are serialized to a string as JSON and +passed on to the plugin itself. + +```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: +- [sqlc-gen-json](https://github.com/sqlc-dev/sqlc/tree/main/cmd/sqlc-gen-json) + - 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 +- [process_plugin_sqlc_gen_json](https://github.com/sqlc-dev/sqlc/tree/main/internal/endtoend/testdata/process_plugin_format_json/) + - An example project showing how to use a process-based plugin using json + +## Environment variables + +By default, plugins do not inherit access to environment variables. Instead, +you can configure access on a per-variable basis. For example, if your plugin +needs the `PATH` environment variable, add `PATH` to the `env` list 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 +``` + +A variable named `SQLC_VERSION` is always included in the plugin's +environment, set to the version of the `sqlc` executable invoking it. diff --git a/docs/guides/privacy.md b/docs/guides/privacy.md new file mode 100644 index 0000000..da29fd8 --- /dev/null +++ b/docs/guides/privacy.md @@ -0,0 +1,55 @@ +# Privacy and data collection + +These days, it feels like every piece of software is tracking you. From your +browser, to your phone, to your terminal, programs collect as much data about +you as possible and send it off to the cloud for analysis. + +We believe the best way to keep data safe is to never collect it in the first +place. + +## Our Privacy Pledge + +The `sqlc` command line tool does not collect any information. It +does not send crash reports to a third-party. It does not gather anonymous +aggregate user behaviour analytics. + +No analytics. +No finger-printing. +No tracking. + +Not now and not in the future. + +### Distribution Channels + +We distribute sqlc using popular package managers such as +[Homebrew](https://brew.sh/) and [Snapcraft](https://snapcraft.io/). These +package managers and their associated command-line tools do collect usage +metrics. + +We use these services to make it easy to for users to install sqlc. There will +always be an option to download sqlc from a stable URL. + +## Hosted Services + +We provide a few hosted services in addition to the sqlc command line tool. + +### sqlc.dev + +* Hosted on [GitHub Pages](https://pages.github.com/) +* Analytics with [Plausible](https://plausible.io/privacy-focused-web-analytics) + +### docs.sqlc.dev + +* Hosted on [Read the Docs](https://readthedocs.org/) +* Analytics with [Plausible](https://plausible.io/privacy-focused-web-analytics) + +### play.sqlc.dev + +* Hosted on [Heroku](https://heroku.com) +* Playground data stored in [Google Cloud Storage](https://cloud.google.com/storage) + * Automatically deleted after 30 days + +### app.sqlc.dev / api.sqlc.dev + +* Hosted on [Heroku](https://heroku.com) +* Error tracking and tracing with [Sentry](https://sentry.io) diff --git a/docs/guides/using-go-and-pgx.md b/docs/guides/using-go-and-pgx.md new file mode 100644 index 0000000..c5b9db7 --- /dev/null +++ b/docs/guides/using-go-and-pgx.md @@ -0,0 +1,125 @@ +# Using Go and pgx + +> [!NOTE] +> `pgx/v5` is supported starting from v1.18.0. + +pgx is a pure Go driver and toolkit for PostgreSQL. It's become the default +PostgreSQL package for many Gophers since lib/pq was put into maintenance mode. + +## Getting started + +To start generating code that uses pgx, set the `sql_package` field in +your `sqlc.yaml` configuration file. Valid options are `pgx/v4` or +`pgx/v5` + +```yaml +version: "2" +sql: + - engine: "postgresql" + queries: "query.sql" + schema: "query.sql" + gen: + go: + package: "db" + sql_package: "pgx/v5" + out: "db" +``` + +If you don't have an existing sqlc project on hand, create a directory with the +configuration file above and the following `query.sql` file. + +```sql +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); + +-- 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; +``` + +Generating the code will now give you pgx-compatible database access methods. + +```bash +sqlc generate +``` + +## Generated code walkthrough + +The generated code is very similar to the code generated when using +`lib/pq`. However, instead of using `database/sql`, the code uses +pgx types directly. + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/jackc/pgx/v5" + + "example.com/sqlc-tutorial/db" +) + +func main() { + // urlExample := "postgres://username:password@localhost:5432/database_name" + conn, err := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL")) + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err) + os.Exit(1) + } + defer conn.Close(context.Background()) + + q := db.New(conn) + + author, err := q.GetAuthor(context.Background(), 1) + if err != nil { + fmt.Fprintf(os.Stderr, "GetAuthor failed: %v\n", err) + os.Exit(1) + } + + fmt.Println(author.Name) +} +``` + +> [!NOTE] +> For production applications, consider using pgxpool for connection pooling: +> +> ```go +> import ( +> "github.com/jackc/pgx/v5/pgxpool" +> "example.com/sqlc-tutorial/db" +> ) +> +> func main() { +> pool, err := pgxpool.New(context.Background(), os.Getenv("DATABASE_URL")) +> if err != nil { +> fmt.Fprintf(os.Stderr, "Unable to create connection pool: %v\n", err) +> os.Exit(1) +> } +> defer pool.Close() +> +> q := db.New(pool) +> // Use q the same way as with single connections +> } +> ``` diff --git a/docs/howto/analyze.md b/docs/howto/analyze.md new file mode 100644 index 0000000..09784d2 --- /dev/null +++ b/docs/howto/analyze.md @@ -0,0 +1,129 @@ +# `analyze` - Analyzing query result types + +> [!NOTE] +> `analyze` is in beta. Its flags and JSON output may change in a +> future release, and the types it reports can differ from the ones +> `generate` produces. + +`sqlc analyze` analyzes a query against a schema and prints the inferred result +columns and parameters as a single JSON document. + +Unlike [`generate`](generate.md), this command does not require a configuration +file and does not connect to a database. It uses sqlc's native static analysis +to infer types directly from the provided schema. + +Every dialect is analyzed by the same engine-neutral analysis core: the schema +is loaded into a catalog seeded with the dialect's types, operators and +functions, and each query is resolved against it. `generate` still uses each +engine's own analysis path, so the two can report a type differently — most +visibly, `analyze` reports type names as the catalog stores them, in lower +case. + +## Usage + +```sh +sqlc analyze --dialect --schema [query-file] +``` + +The query is read from the given file, or from standard input when no file is +provided. The schema is always read from the `--schema` file. + +## Flags + +- `--dialect`, `-d` - The SQL dialect to use. One of `postgresql`, `mysql`, + `sqlite`, `clickhouse`, `googlesql`, `mssql`, or `duckdb`. Required. +- `--schema`, `-s` - Path to the schema (DDL) file. Required. +- `--ast` - Include each statement's AST in the output. Defaults to `false`. + +## Examples + +Given a schema in `schema.sql`: + +```sql +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); +``` + +and a query in `query.sql`: + +```sql +-- name: GetAuthor :one +SELECT * FROM authors WHERE id = $1; +``` + +Running: + +```sh +sqlc analyze --dialect postgresql --schema schema.sql query.sql +``` + +reports the result columns and parameters: + +```json +[ + { + "name": "GetAuthor", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "authors" + }, + { + "name": "name", + "type": { + "name": "text" + }, + "table": "authors" + }, + { + "name": "bio", + "type": { + "name": "text", + "nullable": true + }, + "table": "authors" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "authors" + } + } + ] + } +] +``` + +A column's `type` is written as a call expression: a `name` applied to +`args`, each of which carries an optional `label` and exactly one of `type`, +`int`, `bool`, `string` or `ident`, with `nullable` set at whatever depth it +applies. A `numeric(10,2)` column is `numeric` applied to `10` and `2`; an +array of text is `array` applied to `text`, and an array of arrays nests +one `array` per dimension; a `Map(String, Nullable(UInt8))` in ClickHouse is +`map` applied to `string` and a nullable `uint8`; a `STRUCT` in +GoogleSQL is `struct` applied to an `int64` labelled `a`; the `MAX` of SQL +Server's `nvarchar(max)` is the identifier `max`. + +Types are reported the way the engine itself stores and reports them rather +than the way the schema spelled them: PostgreSQL's `int` and `bigserial` are +`integer` and `bigint`, as `format_type` prints them; MySQL's `BOOLEAN` is +`tinyint(1)`; ClickHouse's `Decimal32(4)` is `decimal(9, 4)`; DuckDB's +`TEXT` is `varchar`; SQL Server's `FLOAT(24)` is `real`. SQLite, which +keeps a declared type as written, is reported as written. + +Pass `--ast` to also include each statement's parsed AST under an `ast` key. It +has the same shape as the output of [`parse`](parse.md), with every node tagged +by type. diff --git a/docs/howto/ci-cd.md b/docs/howto/ci-cd.md new file mode 100644 index 0000000..8dc81c6 --- /dev/null +++ b/docs/howto/ci-cd.md @@ -0,0 +1,159 @@ +# Using sqlc in CI/CD + +If your project has more than a single developer, we suggest running `sqlc` as +part of your CI/CD pipeline. The four subcommands you'll want to run are `diff`, +`vet`, `verify` and `push` + +`sqlc diff` ensures that your generated code is up to date. New developers to a +project may forget to run `sqlc generate` after adding a query or updating a +schema. They also might edit generated code. `sqlc diff` will catch both errors +by comparing the expected output from `sqlc generate` to what's on disk. + +```diff +% sqlc diff +--- a/postgresql/query.sql.go ++++ b/postgresql/query.sql.go +@@ -55,7 +55,7 @@ + + const listAuthors = `-- name: ListAuthors :many + SELECT id, name, bio FROM authors +-ORDER BY name ++ORDER BY bio + ` +``` + +`sqlc vet` runs a set of lint rules against your SQL queries. These rules are +helpful in catching anti-patterns before they make it into production. Please +see the [vet](vet.md) documentation for a complete guide to adding lint rules +for your project. + +`sqlc verify` ensures that schema changes do not break production. Existing +queries are checked against new schema changes for correctness. Please see the +[verify](verify.md) documentation for a complete guide. + + +`sqlc push` pushes your database schema, queries and configuration to sqlc +Cloud. These archives are used by `verify` to catch breaking changes to your +database schema. Learn more about uploading projects [here](push.md) + +## General setup + +Install `sqlc` using the [suggested instructions](../overview/install.md). + +Create three steps in your pipeline for `sqlc diff`, `sqlc vet`, and `sqlc +verify`. Run `sqlc push` after merge on your `main` branch. + +## GitHub Actions + +We provide the [setup-sqlc](https://github.com/marketplace/actions/setup-sqlc) +GitHub Action to install `sqlc`. The action uses the built-in +[tool-cache](https://github.com/actions/toolkit/blob/main/packages/tool-cache/README.md) +to speed up the installation process. + +### diff + +The following GitHub Workflow configuration runs `sqlc diff` on every push. + +```yaml +name: sqlc +on: [push] +jobs: + diff: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: sqlc-dev/setup-sqlc@v3 + with: + sqlc-version: '1.31.1' + - run: sqlc diff +``` + +### vet + +The following GitHub Workflow configuration runs [sqlc vet](vet.md) on every push. +You can use `sqlc vet` without a database connection, but you'll need one if your +`sqlc` configuration references the built-in `sqlc/db-prepare` lint rule. + +```yaml +name: sqlc +on: [push] +jobs: + vet: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: sqlc-dev/setup-sqlc@v3 + with: + sqlc-version: '1.31.1' + # Start a PostgreSQL server + - uses: sqlc-dev/action-setup-postgres@master + with: + postgres-version: "16" + id: postgres + - run: sqlc vet + env: + POSTGRESQL_SERVER_URI: ${{ steps.postgres.outputs.connection-uri }}?sslmode=disable + +``` + +### push + +> [!NOTE] +> Pushing a project is powered by [sqlc Cloud](https://dashboard.sqlc.dev). Sign up for [free](https://dashboard.sqlc.dev) today. + +The following GitHub Workflow configuration runs [sqlc push](push.md) on +every push to `main`. Create an auth token via the +[dashboard](https://dashboard.sqlc.dev). + +```yaml +name: sqlc +on: [push] +jobs: + push: + runs-on: ubuntu-latest + if: ${{ github.ref == 'refs/heads/main' }} + steps: + - uses: actions/checkout@v3 + - uses: sqlc-dev/setup-sqlc@v3 + with: + sqlc-version: '1.31.1' + - run: sqlc push + env: + SQLC_AUTH_TOKEN: ${{ secrets.SQLC_AUTH_TOKEN }} +``` + +### verify + +> [!NOTE] +> Verify database migrations is powered by [sqlc Cloud](https://dashboard.sqlc.dev). Sign up for [free](https://dashboard.sqlc.dev) today. + +```yaml +name: sqlc +on: [push] +jobs: + verify: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: sqlc-dev/setup-sqlc@v3 + with: + sqlc-version: '1.31.1' + - uses: sqlc-dev/action-setup-postgres@master + with: + postgres-version: "16" + id: postgres + - run: sqlc verify + env: + POSTGRESQL_SERVER_URI: ${{ steps.postgres.outputs.connection-uri }}?sslmode=disable + SQLC_AUTH_TOKEN: ${{ secrets.SQLC_AUTH_TOKEN }} + push: + runs-on: ubuntu-latest + if: ${{ github.ref == 'refs/heads/main' }} + steps: + - uses: sqlc-dev/setup-sqlc@v3 + with: + sqlc-version: '1.31.1' + - run: sqlc push + env: + SQLC_AUTH_TOKEN: ${{ secrets.SQLC_AUTH_TOKEN }} +`````` diff --git a/docs/howto/ddl.md b/docs/howto/ddl.md new file mode 100644 index 0000000..2d51af7 --- /dev/null +++ b/docs/howto/ddl.md @@ -0,0 +1,232 @@ +# Modifying the database schema + +sqlc parses `CREATE TABLE` and `ALTER TABLE` statements in order to generate +the necessary code. + +```sql +CREATE TABLE authors ( + id SERIAL PRIMARY KEY, + birth_year int NOT NULL +); + +ALTER TABLE authors ADD COLUMN bio text NOT NULL; +ALTER TABLE authors DROP COLUMN birth_year; +ALTER TABLE authors RENAME TO writers; +``` + +```go +package db + +type Writer struct { + ID int + Bio string +} +``` + +## Handling SQL migrations + +sqlc does not perform database migrations for you. However, sqlc is able to +differentiate between up and down migrations. sqlc ignores down migrations when +parsing SQL files. + +sqlc supports parsing migrations from the following tools: + +- [atlas](https://github.com/ariga/atlas) +- [dbmate](https://github.com/amacneil/dbmate) +- [golang-migrate](https://github.com/golang-migrate/migrate) +- [goose](https://github.com/pressly/goose) +- [sql-migrate](https://github.com/rubenv/sql-migrate) +- [tern](https://github.com/jackc/tern) + +To enable migration parsing, specify the migration directory instead of a schema file: + +```yaml +version: "2" +sql: + - engine: "postgresql" + queries: "query.sql" + schema: "db/migrations" + gen: + go: + package: "tutorial" + out: "tutorial" +``` + +### atlas + +```sql +-- Create "post" table +CREATE TABLE "public"."post" ("id" integer NOT NULL, "title" text NULL, "body" text NULL, PRIMARY KEY ("id")); +``` + +```go +package db + +type Post struct { + ID int + Title sql.NullString + Body sql.NullString +} +``` + +### dbmate + +```sql +-- migrate:up +CREATE TABLE foo (bar INT NOT NULL); + +-- migrate:down +DROP TABLE foo; +``` + +```go +package db + +type Foo struct { + Bar int32 +} +``` + +### golang-migrate + +**Warning:** +[golang-migrate interprets](https://github.com/golang-migrate/migrate/blob/master/MIGRATIONS.md#migration-filename-format) +migration filenames numerically. However, sqlc parses migration files in +lexicographic order. If you choose to have sqlc enumerate your migration files, +make sure their numeric ordering matches their lexicographic ordering to avoid +unexpected behavior. This can be done by prepending enough zeroes to the +migration filenames. + +This doesn't work as intended. + +``` +1_initial.up.sql +... +9_foo.up.sql +# this migration file will be parsed BEFORE 9_foo +10_bar.up.sql +``` + +This worked as intended. + +``` +001_initial.up.sql +... +009_foo.up.sql +010_bar.up.sql +``` + +In `20060102.up.sql`: + +```sql +CREATE TABLE post ( + id int NOT NULL, + title text, + body text, + PRIMARY KEY(id) +); +``` + +In `20060102.down.sql`: + +```sql +DROP TABLE post; +``` + +```go +package db + +type Post struct { + ID int + Title sql.NullString + Body sql.NullString +} +``` + +### goose + +**Warning:** +sqlc parses migration files in lexicographic order. **If you are using numeric filenames for migrations in Goose and you choose to have sqlc enumerate your migration files**, +make sure their numeric ordering matches their lexicographic ordering to avoid +unexpected behavior. This can be done by prepending enough zeroes to the +migration filenames. + +This doesn't work as intended. + +``` +1_initial.sql +... +9_foo.sql +# this migration file will be parsed BEFORE 9_foo +10_bar.sql +``` + +This worked as intended. + +``` +001_initial.sql +... +009_foo.sql +010_bar.sql +``` + +```sql +-- +goose Up +CREATE TABLE post ( + id int NOT NULL, + title text, + body text, + PRIMARY KEY(id) +); + +-- +goose Down +DROP TABLE post; +``` + +```go +package db + +type Post struct { + ID int + Title sql.NullString + Body sql.NullString +} +``` + +### sql-migrate + +```sql +-- +migrate Up +-- SQL in section 'Up' is executed when this migration is applied +CREATE TABLE people (id int); + + +-- +migrate Down +-- SQL section 'Down' is executed when this migration is rolled back +DROP TABLE people; +``` + +```go +package db + +type People struct { + ID int32 +} +``` + +### tern + +```sql +CREATE TABLE comment (id int NOT NULL, text text NOT NULL); +---- create above / drop below ---- +DROP TABLE comment; +``` + +```go +package db + +type Comment struct { + ID int32 + Text string +} +``` diff --git a/docs/howto/delete.md b/docs/howto/delete.md new file mode 100644 index 0000000..4dc0d61 --- /dev/null +++ b/docs/howto/delete.md @@ -0,0 +1,52 @@ +# Deleting rows + +```sql +CREATE TABLE authors ( + id SERIAL PRIMARY KEY, + bio text NOT NULL +); +``` + +The parameter syntax varies by database engine: + +**PostgreSQL:** +```sql +-- name: DeleteAuthor :exec +DELETE FROM authors WHERE id = $1; +``` + +**MySQL and SQLite:** +```sql +-- name: DeleteAuthor :exec +DELETE FROM authors WHERE id = ?; +``` + +```go +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +const deleteAuthor = `-- name: DeleteAuthor :exec +DELETE FROM authors WHERE id = $1 +` + +func (q *Queries) DeleteAuthor(ctx context.Context, id int) error { + _, err := q.db.ExecContext(ctx, deleteAuthor, id) + return err +} +``` diff --git a/docs/howto/embedding.md b/docs/howto/embedding.md new file mode 100644 index 0000000..d9e95ba --- /dev/null +++ b/docs/howto/embedding.md @@ -0,0 +1,61 @@ +# Embedding structs + +Embedding allows you to reuse existing model structs in more queries, resulting +in less manual serialization work. First, imagine we have the following schema +with students and test scores. + +```sql +CREATE TABLE students ( + id bigserial PRIMARY KEY, + name text NOT NULL, + age integer NOT NULL +); + +CREATE TABLE test_scores ( + student_id bigint NOT NULL, + score integer NOT NULL, + grade text NOT NULL +); +``` + +We want to select the student record and the scores they got on a test. +Here's how we'd usually do that: + +```sql +-- name: ScoreAndTests :many +SELECT students.*, test_scores.* +FROM students +JOIN test_scores ON test_scores.student_id = students.id +WHERE students.id = $1; +``` + +When using Go, sqlc will produce a struct like this: + +```go +type ScoreAndTestsRow struct { + ID int64 + Name string + Age int32 + StudentID int64 + Score int32 + Grade string +} +``` + +With embedding, the struct will contain a model for both tables instead of a +flattened list of columns. + +```sql +-- name: ScoreAndTests :many +SELECT sqlc.embed(students), sqlc.embed(test_scores) +FROM students +JOIN test_scores ON test_scores.student_id = students.id +WHERE students.id = $1; +``` + +``` +type ScoreAndTestsRow struct { + Student Student + TestScore TestScore +} +``` \ No newline at end of file diff --git a/docs/howto/fmt.md b/docs/howto/fmt.md new file mode 100644 index 0000000..5501d15 --- /dev/null +++ b/docs/howto/fmt.md @@ -0,0 +1,74 @@ +# `fmt` - Formatting queries + +> [!NOTE] +> `fmt` is in beta. It rewrites your query files in place, so commit +> or back them up first. The formatting it produces may change in a +> future release. + +`sqlc fmt` rewrites the query files referenced by your configuration file in a +canonical format. Each query is parsed with the engine's parser and printed +back from the syntax tree, so formatting never depends on how the query was +written — only on what it means. PostgreSQL, MySQL and SQLite are supported; +query files for other engines are left unchanged. + +Like `gofmt`, the formatter does not impose a maximum line width. A statement +written on a single line stays on a single line, and a statement the author +broke across lines keeps its breaks: the printer notices which clause +boundaries (`FROM`, `WHERE`, `ORDER BY`, ...) and list boundaries the author +broke at and preserves them, normalizing indentation and spacing around them. + +Comments inside a statement are formatted along with it: each comment is +anchored to the code around it by source position and printed back there — +a comment trailing a select-list item stays with that item, a comment above +a clause stays above its keyword — and a comment that runs to the end of its +line breaks the statement open around it. Any statement that cannot be +proven to survive formatting unchanged is left exactly as written. + +## Usage + +```sh +sqlc fmt [--diff] +``` + +Without flags, the query files are rewritten in place. With `--diff`, the +changes are printed to standard output instead and no files are modified. + +## Examples + +Given this query file: + +```sql +-- name: GetAuthor :one +select id,name , bio +from authors +where id = ? limit 1; + +-- name: SearchAuthors :many +SELECT id, -- the primary key + name, bio, created_at FROM authors WHERE name LIKE ? AND bio IS NOT NULL AND id > ? AND created_at > ? AND name <> ? ORDER BY name; +``` + +running `sqlc fmt` rewrites it to: + +```sql +-- name: GetAuthor :one +SELECT id, name, bio +FROM authors +WHERE id = ? +LIMIT 1; + +-- name: SearchAuthors :many +SELECT + id, -- the primary key + name, + bio, + created_at +FROM authors +WHERE name LIKE ? AND bio IS NOT NULL AND id > ? AND created_at > ? AND name <> ? +ORDER BY name; +``` + +`GetAuthor` keeps the line breaks its author wrote; had it been written on +one line, it would stay on one line. In `SearchAuthors`, the line comment +cannot share a line with the code after it, so the statement breaks open +around it, while the `WHERE` chain — written on one line — stays on one. diff --git a/docs/howto/generate.md b/docs/howto/generate.md new file mode 100644 index 0000000..288fb1a --- /dev/null +++ b/docs/howto/generate.md @@ -0,0 +1,76 @@ +# `generate` - Generating code + +`sqlc generate` parses SQL, analyzes the results, and outputs code. Your schema and queries are stored in separate SQL files. The paths to these files live in a `sqlc.yaml` configuration file. + +```yaml +version: "2" +sql: + - engine: "postgresql" + queries: "query.sql" + schema: "schema.sql" + gen: + go: + package: "tutorial" + out: "tutorial" + sql_package: "pgx/v5" +``` + +We've written extensive docs on [retrieving](select.md), [inserting](insert.md), +[updating](update.md), and [deleting](delete.md) rows. + +By default, sqlc runs its analysis using a built-in query analysis engine. While fast, this engine can't handle some complex queries and type-inference. + +You can configure sqlc to use a database connection for enhanced analysis using metadata from that database. + +The database-backed analyzer currently supports PostgreSQL, with [MySQL](https://github.com/sqlc-dev/sqlc/issues/2902) and [SQLite](https://github.com/sqlc-dev/sqlc/issues/2903) +support planned in the future. + +## Enhanced analysis with managed databases + +With [managed databases](managed-databases.md) configured, `generate` will automatically create a hosted ephemeral database with your +schema and use that database to improve its query analysis. And sqlc will cache its analysis locally +on a per-query basis to speed up future `generate` runs. This saves you the trouble of running and maintaining a database with +an up-to-date schema. Here's a minimal working configuration: + +```yaml +version: "2" +servers: +- engine: postgresql + uri: "postgres://locahost:5432/postgres?sslmode=disable" +sql: + - engine: "postgresql" + queries: "query.sql" + schema: "schema.sql" + database: + managed: true + gen: + go: + out: "db" + sql_package: "pgx/v5" +``` + +## Enhanced analysis using your own database + +You can opt-in to database-backed analysis using your own database, by providing a `uri` in your sqlc +[database](../reference/config.md#database) configuration. + +The `uri` string can contain references to environment variables using the `${...}` +syntax. In the following example, the connection string will have the value of +the `PG_PASSWORD` environment variable set as its password. + +```yaml +version: "2" +sql: + - engine: "postgresql" + queries: "query.sql" + schema: "schema.sql" + database: + uri: "postgres://postgres:${PG_PASSWORD}@localhost:5432/postgres" + gen: + go: + out: "db" + sql_package: "pgx/v5" +``` + +Databases configured with a `uri` must have an up-to-date schema for query analysis to work correctly, and `sqlc` does not apply schema migrations your database. Use your migration tool of choice to create the necessary +tables and objects before running `sqlc generate`. diff --git a/docs/howto/insert.md b/docs/howto/insert.md new file mode 100644 index 0000000..1129a46 --- /dev/null +++ b/docs/howto/insert.md @@ -0,0 +1,238 @@ +# Inserting rows + +```sql +CREATE TABLE authors ( + id SERIAL PRIMARY KEY, + bio text NOT NULL +); +``` + +The parameter syntax varies by database engine: + +**PostgreSQL:** +```sql +-- name: CreateAuthor :exec +INSERT INTO authors (bio) VALUES ($1); +``` + +**MySQL and SQLite:** +```sql +-- name: CreateAuthor :exec +INSERT INTO authors (bio) VALUES (?); +``` + +```go +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +const createAuthor = `-- name: CreateAuthor :exec +INSERT INTO authors (bio) VALUES ($1) +` + +func (q *Queries) CreateAuthor(ctx context.Context, bio string) error { + _, err := q.db.ExecContext(ctx, createAuthor, bio) + return err +} +``` + +## Returning columns from inserted rows + +sqlc has full support for the `RETURNING` statement. + +```sql +-- Example queries for sqlc +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); +``` + +**PostgreSQL:** +```sql +-- name: CreateAuthor :one +INSERT INTO authors ( + name, bio +) VALUES ( + $1, $2 +) +RETURNING *; + +-- name: CreateAuthorAndReturnId :one +INSERT INTO authors ( + name, bio +) VALUES ( + $1, $2 +) +RETURNING id; +``` + +**SQLite (with RETURNING support):** +```sql +-- name: CreateAuthor :one +INSERT INTO authors ( + name, bio +) VALUES ( + ?, ? +) +RETURNING *; + +-- name: CreateAuthorAndReturnId :one +INSERT INTO authors ( + name, bio +) VALUES ( + ?, ? +) +RETURNING id; +``` + +Note: MySQL does not support the `RETURNING` clause. Use `:execresult` instead to get the last insert ID. + +```go +package db + +import ( + "context" + "database/sql" +) + +const createAuthor = `-- name: CreateAuthor :one +INSERT INTO authors ( + name, bio +) VALUES ( + $1, $2 +) +RETURNING id, name, bio +` + +type CreateAuthorParams struct { + Name string + Bio sql.NullString +} + +func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (Author, error) { + row := q.db.QueryRowContext(ctx, createAuthor, arg.Name, arg.Bio) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const createAuthorAndReturnId = `-- name: CreateAuthorAndReturnId :one +INSERT INTO authors ( + name, bio +) VALUES ( + $1, $2 +) +RETURNING id +` + +type CreateAuthorAndReturnIdParams struct { + Name string + Bio sql.NullString +} + +func (q *Queries) CreateAuthorAndReturnId(ctx context.Context, arg CreateAuthorAndReturnIdParams) (int64, error) { + row := q.db.QueryRowContext(ctx, createAuthorAndReturnId, arg.Name, arg.Bio) + var id int64 + err := row.Scan(&id) + return id, err +} +``` + +## Using CopyFrom + +### PostgreSQL + +PostgreSQL supports the [COPY protocol](https://www.postgresql.org/docs/current/sql-copy.html) that can insert rows a lot faster than sequential inserts. You can use this easily with sqlc: + +```sql +CREATE TABLE authors ( + id SERIAL PRIMARY KEY, + name text NOT NULL, + bio text NOT NULL +); + +-- name: CreateAuthors :copyfrom +INSERT INTO authors (name, bio) VALUES ($1, $2); +``` + +```go +type CreateAuthorsParams struct { + Name string + Bio string +} + +func (q *Queries) CreateAuthors(ctx context.Context, arg []CreateAuthorsParams) (int64, error) { + ... +} +``` + +The `:copyfrom` command requires either `pgx/v4` or `pgx/v5`. + +```yaml +version: "2" +sql: + - engine: "postgresql" + queries: "query.sql" + schema: "query.sql" + gen: + go: + package: "db" + sql_package: "pgx/v5" + out: "db" +``` + +### MySQL + +MySQL supports a similar feature using [LOAD DATA](https://dev.mysql.com/doc/refman/8.0/en/load-data.html). + +Errors and duplicate keys are treated as warnings and insertion will +continue, even without an error for some cases. Use this in a transaction +and use SHOW WARNINGS to check for any problems and roll back if necessary. + +Check the [error handling](https://dev.mysql.com/doc/refman/8.0/en/load-data.html#load-data-error-handling) documentation for more information. + +```sql +CREATE TABLE foo (a text, b integer, c DATETIME, d DATE); + +-- name: InsertValues :copyfrom +INSERT INTO foo (a, b, c, d) VALUES (?, ?, ?, ?); +``` + +```go +func (q *Queries) InsertValues(ctx context.Context, arg []InsertValuesParams) (int64, error) { + ... +} +``` + +The `:copyfrom` command requires setting the `sql_package` and `sql_driver` options. + +```yaml +version: "2" +sql: + - engine: "mysql" + queries: "query.sql" + schema: "query.sql" + gen: + go: + package: "db" + sql_package: "database/sql" + sql_driver: "github.com/go-sql-driver/mysql" + out: "db" +``` \ No newline at end of file diff --git a/docs/howto/managed-databases.md b/docs/howto/managed-databases.md new file mode 100644 index 0000000..6b20816 --- /dev/null +++ b/docs/howto/managed-databases.md @@ -0,0 +1,101 @@ +# Managed databases + +*Added in v1.22.0* + +`sqlc` can automatically create read-only databases to power query analysis, +linting and verification. These databases are immediately useful for powering +sqlc's database-connected query analyzer, an opt-in feature that improves upon +sqlc's built-in query analysis engine. PostgreSQL support is available today, +with MySQL on the way. + +Once configured, `sqlc` will also use managed databases when linting queries +with [`sqlc vet`](vet.md) in cases where your lint rules require a connection +to a running database. + +Managed databases are under active development, and we're interested in +supporting other use-cases. + +## Configuring managed databases + +To configure `sqlc` to use managed databases, remove the `uri` key from your +`database` configuration and replace it with the `managed` key set to `true`. +Access to a running database server is required. Add a connection string to the `servers` mapping. + +```yaml +version: '2' +servers: +- engine: postgresql + uri: "postgres://localhost:5432/postgres?sslmode=disable" +sql: +- schema: schema.sql + queries: query.sql + engine: postgresql + database: + managed: true +``` + +An environment variable can also be used via the `${}` syntax. + +```yaml +version: '2' +servers: +- engine: postgresql + uri: ${DATABASE_URI} +sql: +- schema: schema.sql + queries: query.sql + engine: postgresql + database: + managed: true +``` + +## Improving codegen + +Without a database connection, sqlc does its best to parse, analyze and compile your queries just using +the schema you pass it and what it knows about the various database engines it supports. In many cases +this works just fine, but for more advanced queries sqlc might not have enough information to produce good code. + +With managed databases configured, `sqlc generate` will automatically create a hosted ephemeral database with your +schema and use that database to improve its query analysis. And sqlc will cache its analysis locally +on a per-query basis to speed up future codegen runs. Here's a minimal working configuration: + +```yaml +version: '2' +servers: +- engine: postgresql + uri: "postgres://localhost:5432/postgres?sslmode=disable" +sql: +- schema: schema.sql + queries: query.sql + engine: postgresql + database: + managed: true + gen: + go: + out: "db" +``` + +## Linting queries + +With managed databases configured, `sqlc vet` will automatically create a hosted ephemeral database with your +schema and use that database when running lint rules that require a +database connection, e.g. any [rule relying on `EXPLAIN ...` output](vet.md#rules-using-explain--output). + +If you don't yet have any vet rules, the [built-in sqlc/db-prepare rule](vet.md#sqlcdb-prepare) +is a good place to start. It prepares each of your queries against the database +to ensure the query is valid. Here's a minimal working configuration: + +```yaml +version: '2' +servers: +- engine: postgresql + uri: "postgres://localhost:5432/postgres?sslmode=disable" +sql: +- schema: schema.sql + queries: query.sql + engine: postgresql + database: + managed: true + rules: + - sqlc/db-prepare +``` diff --git a/docs/howto/named_parameters.md b/docs/howto/named_parameters.md new file mode 100644 index 0000000..b09b969 --- /dev/null +++ b/docs/howto/named_parameters.md @@ -0,0 +1,93 @@ +# Naming parameters + +sqlc tries to generate good names for positional parameters, but sometimes it +lacks enough context. The following SQL generates parameters with less than +ideal names: + +```sql +-- name: UpsertAuthorName :one +UPDATE author +SET + name = CASE WHEN $1::bool + THEN $2::text + ELSE name + END +RETURNING *; +``` + +```go +type UpdateAuthorNameParams struct { + Column1 bool `json:""` + Column2_2 string `json:"_2"` +} +``` + +In these cases, named parameters give you the control over field names on the +Params struct. + +```sql +-- name: UpsertAuthorName :one +UPDATE author +SET + name = CASE WHEN sqlc.arg(set_name)::bool + THEN sqlc.arg(name)::text + ELSE name + END +RETURNING *; +``` + +```go +type UpdateAuthorNameParams struct { + SetName bool `json:"set_name"` + Name string `json:"name"` +} +``` + +If the `sqlc.arg()` syntax is too verbose for your taste, you can use the `@` +operator as a shortcut. + +> [!NOTE] +> The `@` operator as a shortcut for `sqlc.arg()` is not supported in MySQL. + +```sql +-- name: UpsertAuthorName :one +UPDATE author +SET + name = CASE WHEN @set_name::bool + THEN @name::text + ELSE name + END +RETURNING *; +``` + +## Nullable parameters + +sqlc infers the nullability of any specified parameters, and often does exactly +what you want. If you want finer control over the nullability of your +parameters, you may use `sqlc.narg()` (**n**ullable arg) to override the default +behavior. Using `sqlc.narg` tells sqlc to ignore whatever nullability it has +inferred and generate a nullable parameter instead. There is no nullable +equivalent of the `@` syntax. + +Here is an example that uses a single query to allow updating an author's +name, bio or both. + +```sql +-- name: UpdateAuthor :one +UPDATE author +SET + name = coalesce(sqlc.narg('name'), name), + bio = coalesce(sqlc.narg('bio'), bio) +WHERE id = sqlc.arg('id') +RETURNING *; +``` + +The following code is generated: + +```go +type UpdateAuthorParams struct { + Name sql.NullString + Bio sql.NullString + ID int64 +} +``` diff --git a/docs/howto/overrides.md b/docs/howto/overrides.md new file mode 100644 index 0000000..b525994 --- /dev/null +++ b/docs/howto/overrides.md @@ -0,0 +1,184 @@ +# Overriding types + +> [!NOTE] +> Type overrides and field renaming are only fully-supported for Go. + +In many cases it's useful to tell `sqlc` explicitly what Go type you want it to +use for a query input or output. For instance, by default when you use +`pgx/v5`, `sqlc` will map a PostgreSQL UUID type to `UUID` from `github.com/jackc/pgx/pgtype`. +But you may want `sqlc` to use `UUID` from `github.com/google/uuid` instead. + +To tell `sqlc` to use a different Go type, add an entry to the `overrides` list in your +configuration. + +`sqlc` offers two kinds of Go type overrides: +* `db_type` overrides, which override the Go type for a specific database type. +* `column` overrides, which override the Go type for a column or columns by name. + +Here's an example including one of each kind: + +```yaml +version: "2" +sql: +- schema: "postgresql/schema.sql" + queries: "postgresql/query.sql" + engine: "postgresql" + gen: + go: + package: "authors" + out: "db" + sql_package: "pgx/v5" + overrides: + - db_type: "uuid" + nullable: true + go_type: + import: "github.com/google/uuid" + type: "UUID" + - column: "users.birthday" + go_type: "time.Time" +``` + +> [!TIP] +> A single `db_type` override configuration applies to either nullable or non-nullable +> columns, but not both. If you want the same Go type to override regardless of +> nullability, you'll need to configure two overrides: one with `nullable: true` and one without. + +## The `overrides` list + +Each element in the `overrides` list has the following keys: + +- `db_type`: + - A database type to override. Find the full list of supported types in [postgresql_type.go](https://github.com/sqlc-dev/sqlc/blob/main/internal/codegen/golang/postgresql_type.go#L12) or [mysql_type.go](https://github.com/sqlc-dev/sqlc/blob/main/internal/codegen/golang/mysql_type.go#L12). Note that for Postgres you must use pg_catalog-prefixed names where available. `db_type` and `column` are mutually exclusive. +- `column`: + - A column name to override. The value should be of the form `table.column` but you can also specify `schema.table.column` or `catalog.schema.table.column`. `column` and `db_type` are mutually exclusive. +- `go_type`: + - The fully-qualified name of a Go type to use in generated code. This is usually a string but can also be [a map](#the-go_type-map) for more complex configurations. +- `go_struct_tag`: + - A reflect-style struct tag to use in generated code, e.g. `a:"b" x:"y,z"`. + If you want `json` or `db` tags for all fields, configure `emit_json_tags` or `emit_db_tags` instead. +- `unsigned`: + - If `true`, sqlc will apply this override when a numeric column is unsigned. + Note that this only applies to `db_type` overrides and has no effect on `column` overrides. + Defaults to `false`. +- `nullable`: + - If `true`, sqlc will apply this override when a column is nullable. + Otherwise `sqlc` will apply this override when a column is non-nullable. + Note that this only applies to `db_type` overrides and has no effect on `column` overrides. + Defaults to `false`. + +> [!TIP] +> A single `db_type` override configuration applies to either nullable or non-nullable +> columns, but not both. If you want the same Go type to override regardless of nullability, you'll +> need to configure two overrides: one with `nullable: true` and one without. + +> [!NOTE] +> When generating code, `column` override configurations take precedence over `db_type` configurations. + +### The `go_type` map + +Some overrides may require more detailed configuration. If necessary, `go_type` +can be a map with the following keys: + +- `import`: + - The import path for the package where the type is defined. +- `package`: + - The package name where the type is defined. This should only be necessary when your import path doesn't end with the desired package name. +- `type`: + - The type name itself, without any package prefix. +- `pointer`: + - If `true`, generated code will use a pointer to the type rather than the type itself. +- `slice`: + - If `true`, generated code will use a slice of the type rather than the type itself. + +An example: + +```yaml +version: "2" +sql: +- schema: "postgresql/schema.sql" + queries: "postgresql/query.sql" + engine: "postgresql" + gen: + go: + package: "authors" + out: "db" + sql_package: "pgx/v5" + overrides: + - db_type: "uuid" + go_type: + import: "a/b/v2" + package: "b" + type: "MyType" + pointer: true +``` + +## Global overrides + +To override types in all packages that `sqlc` generates, add an override +configuration to the top-level `overrides` section of your `sqlc` config: + +```yaml +version: "2" +overrides: + go: + overrides: + - db_type: "pg_catalog.timestamptz" + nullable: true + engine: "postgresql" + go_type: + import: "gopkg.in/guregu/null.v4" + package: "null" + type: "Time" +sql: +- schema: "service1/schema.sql" + queries: "service1/query.sql" + engine: "postgresql" + gen: + go: + package: "service1" + out: "service1" +- schema: "service2/schema.sql" + queries: "service2/query.sql" + engine: "postgresql" + gen: + go: + package: "service2" + out: "service2" +``` + +Using this configuration, whenever there is a nullable `timestamp with time zone` +column in a Postgres table, `sqlc` will generate Go code using `null.Time`. + +Note that the mapping for global type overrides has a field called `engine` that +is absent in per-package type overrides. This field is only used when there are +multiple `sql` sections using different engines. If you're only generating code +for a single database engine you can omit it. + +#### Version 1 configuration + +If you are using the older version 1 of the `sqlc` configuration format, override +configurations themselves are unchanged but are nested differently. + +Per-package configurations are nested under the `overrides` key within an item +in the `packages` list: + +```yaml +version: "1" +packages: + - name: "db" + path: "internal/db" + queries: "./sql/query/" + schema: "./sql/schema/" + engine: "postgresql" + overrides: [...] +``` + +And global configurations are nested under the top-level `overrides` key: + +```yaml +version: "1" +packages: [...] +overrides: + - db_type: "uuid" + go_type: "github.com/gofrs/uuid.UUID" +``` diff --git a/docs/howto/parse.md b/docs/howto/parse.md new file mode 100644 index 0000000..d46d35f --- /dev/null +++ b/docs/howto/parse.md @@ -0,0 +1,111 @@ +# `parse` - Parsing SQL into an AST + +> [!NOTE] +> `parse` is in beta. Its flags and the shape of the JSON AST it +> prints may change in a future release. + +`sqlc parse` parses SQL from a file or standard input and prints the abstract +syntax tree (AST) as a single JSON document. It does not require a configuration +file or a database connection. + +Each statement is reported with its sqlc query name and command (when the +statement carries a [`-- name:`](../reference/query-annotations.md) annotation) +alongside its AST. + +## Usage + +```sh +sqlc parse --dialect [file] +``` + +The SQL is read from the given file, or from standard input when no file is +provided. + +## Flags + +- `--dialect`, `-d` - The SQL dialect to use. One of `postgresql`, `mysql`, + `sqlite`, `clickhouse`, `googlesql`, `mssql`, or `duckdb`. Required. + +## Examples + +Parse a query file: + +```sh +sqlc parse --dialect postgresql query.sql +``` + +Parse SQL piped via standard input: + +```sh +echo "SELECT 1;" | sqlc parse --dialect mysql +``` + +The output is a JSON array with one object per statement: + +```json +[ + { + "name": "GetAuthor", + "cmd": ":one", + "ast": { + "tag": "RawStmt", + "stmt": { + "...": "..." + }, + "stmt_location": 0, + "stmt_len": 42 + } + } +] +``` + +Statements without a `-- name:` annotation (for example schema DDL) omit the +`name` and `cmd` fields. Field names are `snake_case` versions of the AST node +field names. + +## Node types + +Every node in the AST carries a `tag` naming its type. Some nodes have no +fields of their own, so without it a star, a null literal and an untranslated +clause would all print as `{}`. + +```json +"val": { + "tag": "ColumnRef", + "name": "", + "fields": { + "tag": "List", + "items": [ + { + "tag": "A_Star" + } + ] + }, + "location": 93 +} +``` + +A `tag` of `TODO` marks a clause the dialect's converter does not translate +yet. It means the clause was parsed but is not represented in the AST, not that +the clause was absent from the query. + +## Absent fields + +A field the statement does not use is left out rather than printed as `null`. +An `A_Const` carrying an integer reports only what it has: + +```json +"val": { + "tag": "A_Const", + "val": { + "tag": "Integer", + "ival": 1 + }, + "location": 30 +} +``` + +Only absent fields — and empty lists, which engines construct differently for +the same SQL — are omitted. A zero keeps its place, because zero is a value the +parser can find: `stmt_location` is 0 for the first statement in a file, and +`LIMIT 0` parses to an `ival` of 0. diff --git a/docs/howto/prepared_query.md b/docs/howto/prepared_query.md new file mode 100644 index 0000000..83e62b5 --- /dev/null +++ b/docs/howto/prepared_query.md @@ -0,0 +1,89 @@ +# Preparing queries + +If you're using `pgx/v5` you get its +[implicit support](https://github.com/jackc/pgx/wiki/Automatic-Prepared-Statement-Caching) +for prepared statements. No additional `sqlc` configuration is required. + +For other drivers, `sqlc` can give you the option to explicitly use prepared +queries. These prepared queries also work with transactions. + +You'll need to set `emit_prepared_queries` to `true` in your `sqlc` configuration +to generate code similar to the example below. + +```sql +CREATE TABLE records ( + id SERIAL PRIMARY KEY +); + +-- name: GetRecord :one +SELECT * FROM records +WHERE id = $1; +``` + +```go +package db + +import ( + "context" + "database/sql" + "fmt" +) + +type Record struct { + ID int32 +} + +type DBTX interface { + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryRowContext(context.Context, string, ...any) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +func Prepare(ctx context.Context, db DBTX) (*Queries, error) { + q := Queries{db: db} + var err error + if q.getRecordStmt, err = db.PrepareContext(ctx, getRecord); err != nil { + return nil, fmt.Errorf("error preparing query GetRecord: %w", err) + } + return &q, nil +} + +func (q *Queries) queryRow(ctx context.Context, stmt *sql.Stmt, query string, args ...any) *sql.Row { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).QueryRowContext(ctx, args...) + case stmt != nil: + return stmt.QueryRowContext(ctx, args...) + default: + return q.db.QueryRowContext(ctx, query, args...) + } +} + +type Queries struct { + db DBTX + tx *sql.Tx + getRecordStmt *sql.Stmt +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + tx: tx, + getRecordStmt: q.getRecordStmt, + } +} + +const getRecord = `-- name: GetRecord :one +SELECT id FROM records +WHERE id = $1 +` + +func (q *Queries) GetRecord(ctx context.Context, id int32) (int32, error) { + row := q.queryRow(ctx, q.getRecordStmt, getRecord, id) + err := row.Scan(&id) + return id, err +} +``` diff --git a/docs/howto/push.md b/docs/howto/push.md new file mode 100644 index 0000000..0da4e07 --- /dev/null +++ b/docs/howto/push.md @@ -0,0 +1,70 @@ +# `push` - Uploading projects + +> [!NOTE] +> `push` is powered by [sqlc Cloud](https://dashboard.sqlc.dev). Sign up for [free](https://dashboard.sqlc.dev) today. + +*Added in v1.24.0* + +We've renamed the `upload` sub-command to `push`. We've also changed the data sent along in a push request. Upload used to include the configuration file, migrations, queries, and all generated code. Push drops the generated code in favor of including the [plugin.GenerateRequest](https://buf.build/sqlc/sqlc/docs/main:plugin#plugin.GenerateRequest), which is the protocol buffer message we pass to codegen plugins. + +## Add configuration + +After creating a project, add the project ID to your sqlc configuration file. + +```yaml +version: "2" +cloud: + project: "" +``` + +You'll also need to create an auth token and make it available via the +`SQLC_AUTH_TOKEN` environment variable. + +```shell +export SQLC_AUTH_TOKEN=sqlc_xxxxxxxx +``` + +## Dry run + +You can see what's included when uploading your project by using using the +`--dry-run` flag: + +```shell +$ sqlc push --dry-run +2023/11/21 10:39:51 INFO config file=sqlc.yaml bytes=912 +2023/11/21 10:39:51 INFO codegen_request queryset=app file=codegen_request.pb +2023/11/21 10:39:51 INFO schema queryset=app file=migrations/00001_initial.sql bytes=3033 +2023/11/21 10:39:51 INFO query queryset=app file=queries/app.sql bytes=1150 +``` + +The output is the files `sqlc` would have sent without the `--dry-run` flag. + +## Push + +Once you're ready to push, remove the `--dry-run` flag. + +```shell +$ sqlc push +``` + +### Tags + +You can provide tags to associate with a push, primarily as a convenient reference when using `sqlc verify` with the `against` argument. + +Tags only refer to a single push, so if you pass an existing tag to `push` it will overwrite the previous reference. + +```shell +$ sqlc push --tag main +``` + +### Annotations + +Annotations are added to each push request. By default, we include these environment variables (if they are present). + +``` +GITHUB_REPOSITORY +GITHUB_REF +GITHUB_REF_NAME +GITHUB_REF_TYPE +GITHUB_SHA +``` diff --git a/docs/howto/query_count.md b/docs/howto/query_count.md new file mode 100644 index 0000000..687d98a --- /dev/null +++ b/docs/howto/query_count.md @@ -0,0 +1,83 @@ +# Counting rows + +```sql +CREATE TABLE authors ( + id SERIAL PRIMARY KEY, + hometown text NOT NULL +); + +-- name: CountAuthors :one +SELECT count(*) FROM authors; + +-- name: CountAuthorsByTown :many +SELECT hometown, count(*) FROM authors +GROUP BY 1 +ORDER BY 1; +``` + +```go +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +const countAuthors = `-- name: CountAuthors :one +SELECT count(*) FROM authors +` + +func (q *Queries) CountAuthors(ctx context.Context) (int, error) { + row := q.db.QueryRowContext(ctx, countAuthors) + var i int + err := row.Scan(&i) + return i, err +} + +const countAuthorsByTown = `-- name: CountAuthorsByTown :many +SELECT hometown, count(*) FROM authors +GROUP BY 1 +ORDER BY 1 +` + +type CountAuthorsByTownRow struct { + Hometown string + Count int +} + +func (q *Queries) CountAuthorsByTown(ctx context.Context) ([]CountAuthorsByTownRow, error) { + rows, err := q.db.QueryContext(ctx, countAuthorsByTown) + if err != nil { + return nil, err + } + defer rows.Close() + items := []CountAuthorsByTownRow{} + for rows.Next() { + var i CountAuthorsByTownRow + if err := rows.Scan(&i.Hometown, &i.Count); 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/docs/howto/rename.md b/docs/howto/rename.md new file mode 100644 index 0000000..47ee05c --- /dev/null +++ b/docs/howto/rename.md @@ -0,0 +1,122 @@ +# Renaming fields + +Struct field names are generated from column names using a simple algorithm: +split the column name on underscores and capitalize the first letter of each +part. + +``` +account -> Account +spotify_url -> SpotifyUrl +app_id -> AppID +``` + +If you're not happy with a field's generated name, use the `rename` mapping +to pick a new name. The keys are column names and the values are the struct +field name to use. + +```yaml +version: "2" +sql: +- schema: "postgresql/schema.sql" + queries: "postgresql/query.sql" + engine: "postgresql" + gen: + go: + package: "authors" + out: "postgresql" + rename: + spotify_url: "SpotifyURL" +``` + +## Tables + +The output structs associated with tables can also be renamed. By default, +the struct name will be the singular version of the table name. For example, +the `authors` table will generate an `Author` struct and the `book_publishers` +table will generate a `BookPublisher` struct. + +```sql +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); + +CREATE TABLE book_publishers ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL +); +``` + +```go +package db + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} + +type Publisher struct { + ID int64 + Name string +} +``` + +To rename these structs, you must use the generated struct name. In this +example, that would be `author` and `book_publisher`. Use the `rename` map to +change the name of these struct to `Writer` and `BookPublisher` (note the +camel-casing and the underscore for multi-worded tables). + +```yaml +version: '1' +packages: +- path: db + engine: postgresql + schema: query.sql + queries: query.sql +rename: + author: Writer + book_publisher: Publisher +``` + +```yaml +version: "2" +sql: + - engine: postgresql + queries: query.sql + schema: query.sql +overrides: + go: + rename: + author: Writer + book_publisher: Publisher +``` + +```go +package db + +import ( + "database/sql" +) + +type Writer struct { + ID int64 + Name string + Bio sql.NullString +} + +type Publisher struct { + ID int64 + Name string +} +``` + +## Limitations + +Rename mappings apply to an entire package. Therefore, a column named `foo` and +a table name `foo` can't map to different rename values. diff --git a/docs/howto/select.md b/docs/howto/select.md new file mode 100644 index 0000000..998a134 --- /dev/null +++ b/docs/howto/select.md @@ -0,0 +1,393 @@ +# Retrieving rows + +To generate a database access method, annotate a query with a specific comment. + +```sql +CREATE TABLE authors ( + id SERIAL PRIMARY KEY, + bio text NOT NULL, + birth_year int NOT NULL +); +``` + +The parameter syntax varies by database engine: + +**PostgreSQL:** +```sql +-- name: GetAuthor :one +SELECT * FROM authors +WHERE id = $1; + +-- name: ListAuthors :many +SELECT * FROM authors +ORDER BY id; +``` + +**MySQL and SQLite:** +```sql +-- name: GetAuthor :one +SELECT * FROM authors +WHERE id = ?; + +-- name: ListAuthors :many +SELECT * FROM authors +ORDER BY id; +``` + +A few new pieces of code are generated beyond the `Author` struct. An interface +for the underlying database is generated. The `*sql.DB` and `*sql.Tx` types +satisfy this interface. + +The database access methods are added to a `Queries` struct, which is created +using the `New` method. + +Note that the `*` in our query has been replaced with explicit column names. +This change ensures that the query will never return unexpected data. + +Our query was annotated with `:one`, meaning that it should only return a +single row. We scan the data from that one into a `Author` struct. + +Since the get query has a single parameter, the `GetAuthor` method takes a single +`int` as an argument. + +Since the list query has no parameters, the `ListAuthors` method accepts no +arguments. + + +```go +package db + +import ( + "context" + "database/sql" +) + +type Author struct { + ID int + Bio string + BirthYear int +} + +type DBTX interface { + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +const getAuthor = `-- name: GetAuthor :one +SELECT id, bio, birth_year FROM authors +WHERE id = $1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Author + err := row.Scan(&i.ID, &i.Bio, &i.BirthYear) + return i, err +} + +const listAuthors = `-- name: ListAuthors :many +SELECT id, bio, birth_year FROM authors +ORDER BY id +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Bio, &i.BirthYear); 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 +} +``` + +## Selecting columns + +```sql +CREATE TABLE authors ( + id SERIAL PRIMARY KEY, + bio text NOT NULL, + birth_year int NOT NULL +); + +-- name: GetBioForAuthor :one +SELECT bio FROM authors +WHERE id = $1; + +-- name: GetInfoForAuthor :one +SELECT bio, birth_year FROM authors +WHERE id = $1; +``` + +When selecting a single column, only that value is returned. The `GetBioForAuthor` +method takes a single `int` as an argument and returns a `string` and an +`error`. + +When selecting multiple columns, a row record (method-specific struct) is +returned. In this case, `GetInfoForAuthor` returns a struct with two fields: +`Bio` and `BirthYear`. + +If a query result has no row records, a zero value and an `ErrNoRows` error are +returned instead of a zero value and `nil`. For instance, when the `GetBioForAuthor` +result has no rows, it will return `""` and `ErrNoRows`. + +```go +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + QueryRowContext(context.Context, string, ...any) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +const getBioForAuthor = `-- name: GetBioForAuthor :one +SELECT bio FROM authors +WHERE id = $1 +` + +func (q *Queries) GetBioForAuthor(ctx context.Context, id int) (string, error) { + row := q.db.QueryRowContext(ctx, getBioForAuthor, id) + var i string + err := row.Scan(&i) + return i, err +} + +const getInfoForAuthor = `-- name: GetInfoForAuthor :one +SELECT bio, birth_year FROM authors +WHERE id = $1 +` + +type GetInfoForAuthorRow struct { + Bio string + BirthYear int +} + +func (q *Queries) GetInfoForAuthor(ctx context.Context, id int) (GetInfoForAuthorRow, error) { + row := q.db.QueryRowContext(ctx, getInfoForAuthor, id) + var i GetInfoForAuthorRow + err := row.Scan(&i.Bio, &i.BirthYear) + return i, err +} +``` + +## Passing a slice as a parameter to a query + +### PostgreSQL + +In PostgreSQL, +[ANY](https://www.postgresql.org/docs/current/functions-comparisons.html#id-1.5.8.28.16) +allows you to check if a value exists in an array expression. Queries using ANY +with a single parameter will generate method signatures with slices as +arguments. Use the postgres data types, eg: int, varchar, etc. + +```sql +CREATE TABLE authors ( + id SERIAL PRIMARY KEY, + bio text NOT NULL, + birth_year int NOT NULL +); + +-- name: ListAuthorsByIDs :many +SELECT * FROM authors +WHERE id = ANY($1::int[]); +``` + +The above SQL will generate the following code: + +```go +package db + +import ( + "context" + "database/sql" + + "github.com/lib/pq" +) + +type Author struct { + ID int + Bio string + BirthYear int +} + +type DBTX interface { + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +const listAuthors = `-- name: ListAuthorsByIDs :many +SELECT id, bio, birth_year FROM authors +WHERE id = ANY($1::int[]) +` + +func (q *Queries) ListAuthorsByIDs(ctx context.Context, ids []int) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthors, pq.Array(ids)) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Bio, &i.BirthYear); 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 +} +``` + +### MySQL and SQLite + +MySQL and SQLite differ from PostgreSQL in that placeholders must be generated based on +the number of elements in the slice you pass in. Though trivial it is still +something of a nuisance. The passed in slice must not be nil or empty or an +error will be returned (ie not a panic). The placeholder insertion location is +marked by the meta-function `sqlc.slice()` (which is similar to `sqlc.arg()` +that you see documented under [Naming parameters](named_parameters.md)). + +To rephrase, the `sqlc.slice('param')` behaves identically to `sqlc.arg()` it +terms of how it maps the explicit argument to the function signature, eg: + + * `sqlc.slice('ids')` maps to `ids []GoType` in the function signature + * `sqlc.slice(cust_ids)` maps to `custIds []GoType` in the function signature + (like `sqlc.arg()`, the parameter does not have to be quoted) + +This feature is not compatible with `emit_prepared_queries` statement found in the +[Configuration file](../reference/config.md). + +```sql +CREATE TABLE authors ( + id SERIAL PRIMARY KEY, + bio text NOT NULL, + birth_year int NOT NULL +); + +-- name: ListAuthorsByIDs :many +SELECT * FROM authors +WHERE id IN (sqlc.slice('ids')); +``` + +The above SQL will generate the following code: + +```go +package db + +import ( + "context" + "database/sql" + "fmt" + "strings" +) + +type Author struct { + ID int + Bio string + BirthYear int +} + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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, + } +} + +const listAuthorsByIDs = `-- name: ListAuthorsByIDs :many +SELECT id, bio, birth_year FROM authors +WHERE id IN (/*SLICE:ids*/?) +` + +func (q *Queries) ListAuthorsByIDs(ctx context.Context, ids []int64) ([]Author, error) { + sql := listAuthorsByIDs + var queryParams []any + if len(ids) == 0 { + return nil, fmt.Errorf("slice ids must have at least one element") + } + for _, v := range ids { + queryParams = append(queryParams, v) + } + sql = strings.Replace(sql, "/*SLICE:ids*/?", strings.Repeat(",?", len(ids))[1:], 1) + rows, err := q.db.QueryContext(ctx, sql, queryParams...) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Bio, &i.BirthYear); 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/docs/howto/structs.md b/docs/howto/structs.md new file mode 100644 index 0000000..c0b203d --- /dev/null +++ b/docs/howto/structs.md @@ -0,0 +1,53 @@ +# Configuring generated structs + +## Naming scheme + +Structs generated from tables will attempt to use the singular form of a table +name if the table name is pluralized. + +```sql +CREATE TABLE authors ( + id SERIAL PRIMARY KEY, + name text NOT NULL +); +``` + +```go +package db + +// Struct names use the singular form of table names +type Author struct { + ID int + Name string +} +``` + +## JSON tags + +```sql +CREATE TABLE authors ( + id SERIAL PRIMARY KEY, + created_at timestamp NOT NULL +); +``` + +sqlc can generate structs with JSON tags by adding the `emit_json_tags` key to the configuration file as it shows on [configuration reference](../reference/config.md). +The JSON name for a field matches +the column name in the database. + +```go +package db + +import ( + "time" +) + +type Author struct { + ID int `json:"id"` + CreatedAt time.Time `json:"created_at"` +} +``` + +## More control + +See the guide to [Overriding types](./overrides.md) for fine-grained control over struct field types and tags. diff --git a/docs/howto/transactions.md b/docs/howto/transactions.md new file mode 100644 index 0000000..b80aee7 --- /dev/null +++ b/docs/howto/transactions.md @@ -0,0 +1,101 @@ +# Using transactions +In the code generated by sqlc, the `WithTx` method allows a `Queries` instance to be associated with a transaction. + +For example, with the following SQL structure: + +`schema.sql`: +```sql +CREATE TABLE records ( + id SERIAL PRIMARY KEY, + counter INT NOT NULL +); +``` + +`query.sql` +```sql +-- name: GetRecord :one +SELECT * FROM records +WHERE id = $1; + +-- name: UpdateRecord :exec +UPDATE records SET counter = $2 +WHERE id = $1; +``` + +And the generated code from sqlc in `db.go`: +```go +package tutorial + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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, + } +} + +``` + +You'd use it like this: + +```go +// Using `github/lib/pq` as the driver. +func bumpCounter(ctx context.Context, db *sql.DB, queries *tutorial.Queries, id int32) error { + tx, err := db.Begin() + if err != nil { + return err + } + defer tx.Rollback() + qtx := queries.WithTx(tx) + r, err := qtx.GetRecord(ctx, id) + if err != nil { + return err + } + if err := qtx.UpdateRecord(ctx, tutorial.UpdateRecordParams{ + ID: r.ID, + Counter: r.Counter + 1, + }); err != nil { + return err + } + return tx.Commit() +} + +// Using `github.com/jackc/pgx/v5` as the driver. +func bumpCounter(ctx context.Context, db *pgx.Conn, queries *tutorial.Queries, id int32) error { + tx, err := db.Begin(ctx) + if err != nil { + return err + } + defer tx.Rollback(ctx) + qtx := queries.WithTx(tx) + r, err := qtx.GetRecord(ctx, id) + if err != nil { + return err + } + if err := qtx.UpdateRecord(ctx, tutorial.UpdateRecordParams{ + ID: r.ID, + Counter: r.Counter + 1, + }); err != nil { + return err + } + return tx.Commit(ctx) +} +``` \ No newline at end of file diff --git a/docs/howto/update.md b/docs/howto/update.md new file mode 100644 index 0000000..52b4ac1 --- /dev/null +++ b/docs/howto/update.md @@ -0,0 +1,115 @@ +# Updating rows + +```sql +CREATE TABLE authors ( + id SERIAL PRIMARY KEY, + bio text NOT NULL +); +``` + +## Single parameter + +If your query has a single parameter, your Go method will also have a single +parameter. + +The parameter syntax varies by database engine: + +**PostgreSQL:** +```sql +-- name: UpdateAuthorBios :exec +UPDATE authors SET bio = $1; +``` + +**MySQL and SQLite:** +```sql +-- name: UpdateAuthorBios :exec +UPDATE authors SET bio = ?; +``` + +```go +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +const updateAuthorBios = `-- name: UpdateAuthorBios :exec +UPDATE authors SET bio = $1 +` + +func (q *Queries) UpdateAuthorBios(ctx context.Context, bio string) error { + _, err := q.db.ExecContext(ctx, updateAuthorBios, bio) + return err +} +``` + +## Multiple parameters + +If your query has more than one parameter, your Go method will accept a +`Params` struct. + +**PostgreSQL:** +```sql +-- name: UpdateAuthor :exec +UPDATE authors SET bio = $2 +WHERE id = $1; +``` + +**MySQL and SQLite:** +```sql +-- name: UpdateAuthor :exec +UPDATE authors SET bio = ? +WHERE id = ?; +``` + +Note: For MySQL and SQLite, parameters are bound in the order they appear in the query, regardless of the order in the function signature. + +```go +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +const updateAuthor = `-- name: UpdateAuthor :exec +UPDATE authors SET bio = $2 +WHERE id = $1 +` + +type UpdateAuthorParams struct { + ID int32 + Bio string +} + +func (q *Queries) UpdateAuthor(ctx context.Context, arg UpdateAuthorParams) error { + _, err := q.db.ExecContext(ctx, updateAuthor, arg.ID, arg.Bio) + return err +} +``` + diff --git a/docs/howto/verify.md b/docs/howto/verify.md new file mode 100644 index 0000000..62da440 --- /dev/null +++ b/docs/howto/verify.md @@ -0,0 +1,105 @@ +# `verify` - Verifying schema changes + +*Added in v1.24.0* + +Schema updates and poorly-written queries often bring down production databases. That’s bad. + +Out of the box, `sqlc generate` catches some of these issues. Running `sqlc vet` with the `sqlc/db-prepare` rule catches more subtle problems. But there is a large class of issues that sqlc can’t prevent by looking at current schema and queries alone. + +For instance, when a schema change is proposed, existing queries and code running in production might fail when the schema change is applied. Enter `sqlc verify`, which analyzes existing queries against new schema changes and errors if there are any issues. + +Let's look at an example. Assume you have these two tables in production. + +```sql +CREATE TABLE users ( + id UUID PRIMARY KEY +); + +CREATE TABLE user_actions ( + id UUID PRIMARY KEY, + user_id UUID NOT NULL, + action TEXT, + created_at TIMESTAMP +); +``` + +Your application contains the following query to join user actions against the users table. + +```sql +-- name: GetUserActions :many +SELECT * FROM users u +JOIN user_actions ua ON u.id = ua.user_id +ORDER BY created_at; +``` + +So far, so good. Then assume you propose this schema change: + +```sql +ALTER TABLE users ADD COLUMN created_at TIMESTAMP; +``` + +Running `sqlc generate` fails with this change, returning a `column reference "created_at" is ambiguous` error. You update your query to fix the issue. + +```sql +-- name: GetUserActions :many +SELECT * FROM users u +JOIN user_actions ua ON u.id = ua.user_id +ORDER BY u.created_at; +``` + +While that change fixes the issue, there's a production outage waiting to happen. When the schema change is applied, the existing `GetUserActions` query will begin to fail. The correct way to fix this is to deploy the updated query before applying the schema migration. + +It ensures migrations are safe to deploy by sending your current schema and queries to sqlc cloud. There, we run the queries for your latest push against your new schema changes. This check catches backwards incompatible schema changes for existing queries. + +Here `sqlc verify` alerts you to the fact that ORDER BY "created_at" is ambiguous. + +```sh +$ sqlc verify +FAIL: app query.sql + +=== Failed +=== FAIL: app query.sql GetUserActions + ERROR: column reference "created_at" is ambiguous (SQLSTATE 42702) +``` + +By the way, this scenario isn't made up! It happened to us a few weeks ago. We've been happily testing early versions of `verify` for the last two weeks and haven't had any issues since. + +This type of verification is only the start. If your application is deployed on-prem by your customers, `verify` could tell you if it's safe for your customers to rollback to an older version of your app, even after schema migrations have been run. + +Using `verify` requires that you push your queries and schema when you tag a release of your application. We run it on every push to main, as we continuously deploy those commits. + +## Authentication + +`sqlc` expects to find a valid auth token in the value of the `SQLC_AUTH_TOKEN` +environment variable. You can create an auth token via the [dashboard](https://dashboard.sqlc.dev). + +```shell +export SQLC_AUTH_TOKEN=sqlc_xxxxxxxx +``` + +## Expected workflow + +Using `sqlc verify` requires pushing your queries and schema to sqlc Cloud. When +you release a new version of your application, you should push your schema and +queries as well. For example, we run `sqlc push` after any change has been +merged into our `main` branch on Github, as we deploy every commit to +production. + +```shell +$ sqlc push --tag main +``` + +Locally or in pull requests, run `sqlc verify` to check that existing queries +continue to work with your current database schema. + +```shell +$ sqlc verify --against main +``` + +## Picking a tag + +Without an `against` argument, `verify` will run its analysis of the provided schema using your most-recently pushed queries. We suggest using the `against` argument to explicitly select a set of queries for comparison. + +```shell +$ sqlc verify --against [tag] +``` diff --git a/docs/howto/vet.md b/docs/howto/vet.md new file mode 100644 index 0000000..3909c61 --- /dev/null +++ b/docs/howto/vet.md @@ -0,0 +1,286 @@ +# `vet` - Linting queries + +*Added in v1.19.0* + +`sqlc vet` runs queries through a set of lint rules. + +Rules are defined in the `sqlc` [configuration](../reference/config.md) file. They +consist of a name, message, and a [Common Expression Language +(CEL)](https://github.com/google/cel-spec) expression. Expressions are evaluated +using [cel-go](https://github.com/cel-expr/cel-go). If an expression evaluates to +`true`, `sqlc vet` will report an error using the given message. + +## Defining lint rules + +Each lint rule's CEL expression has access to information from your sqlc +configuration and queries via variables defined in the following proto messages. + +```proto +message Config +{ + string version = 1; + string engine = 2 ; + repeated string schema = 3; + repeated string queries = 4; +} + +message Query +{ + // SQL body + string sql = 1; + // Name of the query + string name = 2; + // One of "many", "one", "exec", etc. + string cmd = 3; + // Query parameters, if any + repeated Parameter params = 4; +} + +message Parameter +{ + int32 number = 1; +} +``` + +In addition to this basic information, when you have a PostgreSQL or MySQL +[database connection configured](../reference/config.md#database) +each CEL expression has access to the output from running `EXPLAIN ...` on your query +via the `postgresql.explain` and `mysql.explain` variables. +This output is quite complex and depends on the structure of your query but sqlc attempts +to parse and provide as much information as it can. See +[Rules using `EXPLAIN ...` output](#rules-using-explain--output) for more information. + +Here are a few example rules just using the basic configuration and query information available +to the CEL expression environment. While these examples are simplistic, they give you a flavor +of the types of rules you can write. + +```yaml +version: 2 +sql: + - schema: "query.sql" + queries: "query.sql" + engine: "postgresql" + gen: + go: + package: "authors" + out: "db" + rules: + - no-pg + - no-delete + - only-one-param + - no-exec +rules: + - name: no-pg + message: "invalid engine: postgresql" + rule: | + config.engine == "postgresql" + - name: no-delete + message: "don't use delete statements" + rule: | + query.sql.contains("DELETE") + - name: only-one-param + message: "too many parameters" + rule: | + query.params.size() > 1 + - name: no-exec + message: "don't use exec" + rule: | + query.cmd == "exec" +``` + +### Rules using `EXPLAIN ...` output + +*Added in v1.20.0* + +The CEL expression environment has two variables containing `EXPLAIN ...` output, +`postgresql.explain` and `mysql.explain`. `sqlc` only populates the variable associated with +your configured database engine, and only when you have a +[database connection configured](../reference/config.md#database). + +For the `postgresql` engine, `sqlc` runs + +```sql +EXPLAIN (ANALYZE false, VERBOSE, COSTS, SETTINGS, BUFFERS, FORMAT JSON) ... +``` + +where `"..."` is your query string, and parses the output into a [`PostgreSQLExplain`](https://buf.build/sqlc/sqlc/docs/v1.20.0:vet#vet.PostgreSQLExplain) proto message. + +For the `mysql` engine, `sqlc` runs + +```sql +EXPLAIN FORMAT=JSON ... +``` + +where `"..."` is your query string, and parses the output into a [`MySQLExplain`](https://buf.build/sqlc/sqlc/docs/v1.20.0:vet#vet.MySQLExplain) proto message. + +These proto message definitions are too long to include here, but you can find them in the `protos` +directory within the `sqlc` source tree. + +The output from `EXPLAIN ...` depends on the structure of your query so it's a bit difficult +to offer generic examples. Refer to the +[PostgreSQL documentation](https://www.postgresql.org/docs/current/using-explain.html) and +[MySQL documentation](https://dev.mysql.com/doc/refman/en/explain-output.html) for more +information. + +```yaml +... +rules: +- name: postgresql-query-too-costly + message: "Query cost estimate is too high" + rule: "postgresql.explain.plan.total_cost > 1.0" +- name: postgresql-no-seq-scan + message: "Query plan results in a sequential scan" + rule: "postgresql.explain.plan.node_type == 'Seq Scan'" +- name: mysql-query-too-costly + message: "Query cost estimate is too high" + rule: "has(mysql.explain.query_block.cost_info) && double(mysql.explain.query_block.cost_info.query_cost) > 2.0" +- name: mysql-must-use-primary-key + message: "Query plan doesn't use primary key" + rule: "has(mysql.explain.query_block.table.key) && mysql.explain.query_block.table.key != 'PRIMARY'" +``` + +When building rules that depend on `EXPLAIN ...` output, it may be helpful to see the actual JSON +returned from the database. `sqlc` will print it When you set the environment variable +`SQLCDEBUG=dumpexplain=1`. Use this environment variable together with a dummy rule to see +`EXPLAIN ...` output for all of your queries. + +```yaml +version: 2 +sql: + - schema: "query.sql" + queries: "query.sql" + engine: "postgresql" + database: + uri: "postgresql://postgres:postgres@localhost:5432/postgres" + gen: + go: + package: "db" + out: "db" + rules: + - debug +rules: +- name: debug + rule: "!has(postgresql.explain)" # A dummy rule to trigger explain +``` + +Please note that databases configured with a `uri` must have an up-to-date +schema for `vet` to work correctly, and `sqlc` does not apply schema migrations +to your database. Use your migration tool of choice to create the necessary +tables and objects before running `sqlc vet` with rules that depend on +`EXPLAIN ...` output. + +Alternatively, configure [managed databases](managed-databases.md) to have +`sqlc` create hosted ephemeral databases with the correct schema automatically. + +## Built-in rules + +### sqlc/db-prepare + +When a [database](../reference/config.md#database) connection is configured, you can +run the built-in `sqlc/db-prepare` rule. This rule will attempt to prepare +each of your queries against the connected database and report any failures. + +```yaml +version: 2 +sql: + - schema: "schema.sql" + queries: "query.sql" + engine: "postgresql" + gen: + go: + package: "authors" + out: "db" + database: + uri: "postgresql://postgres:password@localhost:5432/postgres" + rules: + - sqlc/db-prepare +``` + +Please note that databases configured with a `uri` must have an up-to-date +schema for `vet` to work correctly, and `sqlc` does not apply schema migrations +to your database. Use your migration tool of choice to create the necessary +tables and objects before running `sqlc vet` with the `sqlc/db-prepare` rule. + +Alternatively, configure [managed databases](managed-databases.md) to have +`sqlc` create hosted ephemeral databases with the correct schema automatically. + +```yaml +version: 2 +cloud: + project: "" +sql: + - schema: "schema.sql" + queries: "query.sql" + engine: "postgresql" + gen: + go: + package: "authors" + out: "db" + database: + managed: true + rules: + - sqlc/db-prepare +``` + +To see this in action, check out the [authors +example](https://github.com/sqlc-dev/sqlc/blob/main/examples/authors/sqlc.yaml). + +## Running lint rules + +When you add the name of a defined rule to the rules list +for a [sql package](../reference/config.md#sql), +`sqlc vet` will evaluate that rule against every query in the package. + +In the example below, two rules are defined but only one is enabled. + +```yaml +version: 2 +sql: + - schema: "query.sql" + queries: "query.sql" + engine: "postgresql" + gen: + go: + package: "authors" + out: "db" + rules: + - no-delete +rules: + - name: no-pg + message: "invalid engine: postgresql" + rule: | + config.engine == "postgresql" + - name: no-delete + message: "don't use delete statements" + rule: | + query.sql.contains("DELETE") +``` + +### Opting-out of lint rules + +For any query, you can tell `sqlc vet` not to evaluate lint rules using the +`@sqlc-vet-disable` query annotation. The annotation accepts a list of rules to ignore. + +```sql +/* name: GetAuthor :one */ +/* @sqlc-vet-disable sqlc/db-prepare no-pg */ +SELECT * FROM authors +WHERE id = ? LIMIT 1; +``` +The rules can also be split across lines. +```sql +/* name: GetAuthor :one */ +/* @sqlc-vet-disable sqlc/db-prepare */ +/* @sqlc-vet-disable no-pg */ +SELECT * FROM authors +WHERE id = ? LIMIT 1; +``` + +To skip all rules for a query, you can provide the `@sqlc-vet-disable` annotation without any parameters. + +```sql +/* name: GetAuthor :one */ +/* @sqlc-vet-disable */ +SELECT * FROM authors +WHERE id = ? LIMIT 1; +``` diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..4b7f203 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,22 @@ +# sqlc Documentation + +> And lo, the Great One looked down upon the people and proclaimed: +> "SQL is actually pretty great" + +sqlc generates **fully type-safe idiomatic Go code** from SQL. Here's how it +works: + +1. You write SQL queries +2. You run sqlc to generate Go code that presents type-safe interfaces to those + queries +3. You write application code that calls the methods sqlc generated + +Seriously, it's that easy. You don't have to write any boilerplate SQL querying +code ever again. + +## Getting started + +- [Installing sqlc](overview/install.md) +- [Getting started with MySQL](tutorials/getting-started-mysql.md) +- [Getting started with PostgreSQL](tutorials/getting-started-postgresql.md) +- [Getting started with SQLite](tutorials/getting-started-sqlite.md) diff --git a/docs/overview/install.md b/docs/overview/install.md new file mode 100644 index 0000000..1ab41e9 --- /dev/null +++ b/docs/overview/install.md @@ -0,0 +1,51 @@ +# Installing sqlc + +sqlc is distributed as a single binary with zero dependencies. + +## macOS + +``` +brew install sqlc +``` + +## Ubuntu + +``` +sudo snap install sqlc +``` + +## go install + +Installing recent versions of sqlc requires Go 1.21+. + +``` +go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest +``` + +## Docker + +``` +docker pull sqlc/sqlc +``` + +Run `sqlc` using `docker run`: + +``` +docker run --rm -v $(pwd):/src -w /src sqlc/sqlc generate +``` + +Run `sqlc` using `docker run` in the Command Prompt on Windows (`cmd`): + +``` +docker run --rm -v "%cd%:/src" -w /src sqlc/sqlc generate +``` + +## Downloads + +Get pre-built binaries for *v1.31.1*: + +- [Linux](https://downloads.sqlc.dev/sqlc_1.31.1_linux_amd64.tar.gz) +- [macOS](https://downloads.sqlc.dev/sqlc_1.31.1_darwin_amd64.zip) +- [Windows](https://downloads.sqlc.dev/sqlc_1.31.1_windows_amd64.zip) + +See [downloads.sqlc.dev](https://downloads.sqlc.dev/) for older versions. diff --git a/docs/reference/changelog.md b/docs/reference/changelog.md new file mode 100644 index 0000000..af42c03 --- /dev/null +++ b/docs/reference/changelog.md @@ -0,0 +1,2936 @@ +# Changelog +All notable changes to this project will be documented in this file. + +(v1-31-1)= +## [1.31.1](https://github.com/sqlc-dev/sqlc/releases/tag/v1.31.1) +Released 2026-04-22 + +### Bug Fixes + +- Remove go.mod replace directive that breaks `go install ...@latest` (#4401) +- Downgrade github.com/ncruces/go-sqlite3 to v0.32.0 (#4400) + +### Build + +- (deps) Bump github.com/jackc/pgx/v5 (#4398) + +(v1-31-0)= +## [1.31.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.31.0) +Released 2026-04-19 + +### Bug Fixes + +- Strip psql meta-commands from schema files (#4390) +- Emit pointers for nullable enum columns when `emit_pointers_for_null_types` is set (#4388) +- Map xid8 to pgtype.Uint64 for pgx/v5 (#4387) +- Rename `:one` return variable when it conflicts with a parameter (#4383) +- Coerce SQLite JSONB output regardless of type casing (#4385) +- Dedupe `sqlc.arg` parameters wrapped in a type cast for MySQL (#4384) +- Preserve MySQL optimizer hints in generated query text (#4382) +- Catch invalid `ON CONFLICT DO UPDATE` column references (#4366) +- Replace manual loop with `copy()` builtin (#4166) +- (native) Make MySQL connection check immediate on first attempt (#4254) + +### Documentation + +- Add link to community python plugin (#4157) +- Add Claude Code remote environment setup instructions (#4246) +- Add sqlc-gen-sqlx to community language support (#4371) +- Add GitHub Topic to the plugins page (#4258) + +### Features + +- (sqlfile) Add `sqlfile.Split` (#4146) +- (sqlite) Add database analyzer using ncruces/go-sqlite3 (#4199) +- (ast) Implement comprehensive SQL AST formatting (#4205) +- (mysql) Improve AST formatting and add DELETE JOIN support (#4206) +- (sqlite) Add SQLite support to format tests (#4207) +- (expander) Add star expander for `SELECT *` and `RETURNING *` (PostgreSQL, MySQL, SQLite) (#4203) +- Add `SQLCEXPERIMENT` environment variable for experimental features (#4228) +- Add native database support for e2e tests without Docker (#4236) +- (postgresql) Add analyzerv2 experiment for database-only analysis (#4237) +- Graduate parsecmd experiment (#4253) +- Add parse subcommand with AST JSON output (#4240) +- Add ClickHouse support to `sqlc parse` (#4267) +- Add `sqlc-test-setup` command for database test environment setup (#4304) + +### Refactor + +- (ast) Rename Formatter interface to Dialect (#4208) + +### Build + +- Upgrade Go toolchain to 1.26.2 (#4378) +- Upgrade Go version to 1.26.0 (#4312) +- Remove github.com/jackc/pgx/v4 dependency (#4379) +- Upgrade github.com/pingcap/tidb/pkg/parser (#4389) +- Install PostgreSQL from theseus-rs/postgresql-binaries instead of apt (#4310) +- Skip CI/RTD builds when the change is irrelevant (#4381) +- (deps) 35 dependabot bumps (collapsed from individual entries) + +(v1-30-0)= +## [1.30.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.30.0) +Released 2025-09-01 + +### Bug Fixes + +- (compiler/mysql) Prevent panic in convertSetOprSelectList() (#4042) +- Range subselect alias pointer dereference (#3711) +- (codegen/golang) Don't omit enums used as arrays (#4058) +- (codegen/golang) Handle `go_struct_tag` for `db_type` overrides (#4055) +- (engine/dolphin) Remove references to deprecated `pcast.ChangeStmt` (#4057) +- Normalize identifier usage for table names (#4045) +- (engine/sqlite) Fix parsing of INSERT DEFAULT VALUES syntax (#4010) + +### Documentation + +- Fix parameter syntax inconsistency for MySQL and SQLite (#4036) +- Use correct configuration to generate the given output for JSON type override (#4049) +- Clean up and add to docs regarding type overrides (#4060) +- Try a different admonition format (#4061) +- Use the correct admonition format (#4062) +- Add multi-worded table example for renaming (#4067) + +### Features + +- (docs) Add link to Gleam/parrot (#4038) +- (engine/dolphin) Implement MATCH_AGAINST conversion in SQL AST (#1192, #3091) (#4070) +- (engine/sqlite) Coerce jsonb columns to json before returning to Go code (#3968) + +### Testing + +- (endtoend) Skip process_plugin_sqlc_gen_json (#4075) +- (endtoend) Use Docker to start database servers (#4076) + +### Build + +- (deps) Bump the production-dependencies group across 1 directory with 2 updates (#3941) +- (deps) Bump packaging (#3940) +- (deps) Bump golang from 1.24.2 to 1.24.4 (#3983) +- (deps) Bump golang from 1.24.4 to 1.24.5 (#4014) +- (deps) Bump urllib3 from 2.4.0 to 2.5.0 in /docs (#3994) +- (deps) Bump the production-dependencies group across 1 directory with 5 updates (#3989) +- (deps) Bump the production-dependencies group across 1 directory with 4 updates (#4027) +- (deps) Bump modernc.org/sqlite (#4032) +- (deps) Bump the production-dependencies group across 1 directory with 4 updates (#4018) +- (deps) Bump certifi in /docs in the production-dependencies group (#4041) +- (deps) Bump google.golang.org/protobuf (#4043) +- (deps) Bump actions/checkout from 4 to 5 (#4059) +- (deps) Bump the production-dependencies group across 1 directory with 2 updates (#4071) +- (deps) Bump requests in /docs in the production-dependencies group (#4068) +- Upgrade to Go 1.25 (#4074) +- (deps) Bump golang from 1.24.5 to 1.25.0 (#4063) +- (deps) Bump github.com/google/cel-go (#4080) + +(v1-29-0)= +## [1.29.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.29.0) +Released 2025-04-14 + +### Bug Fixes + +- (docs) Correct spelling and grammar (#3645) +- (dbmanager) Use correct SQL to drop databases (#3640) +- (compiler) Don't crash on WHERE x IN (... UNION ...) (#3652) +- (golang) Escape q field name (#3647) +- Postgresql alter materialized view is not registered to statements (#3728) +- Do not close wazero module on error (#3758) (#3759) +- (pgx) Do not wrap nil error (#3913) +- (migrations) Normalize case for migration statement for all cases (#3919) + +### Documentation + +- Add missing documentation about copyfrom (#3583) +- Add sqlc-gen-from-template (#3601) +- Add changelog for 1.28.0 (#3797) +- Add PHP DBAL plugin (#3813) +- Fix PostGIS function name (#3829) +- Add Zig plugin (#3824) +- Add link to tandemdude/sqlc-gen-java (#3819) + +### Features + +- (docs) How-to use transactions with pgx (#3557) +- (quickdb) Remove unused func (#3576) +- (vet) Allow selective disabling of rules per query (#3620) +- (dolphin) Upgrade to latest TiDB parser (#3733) +- (mysql) Add a test for VECTOR column type (#3734) +- (cli) Bump version from 1.27.0 to 1.28.0 (#3798) +- (codegen/golang) Add an option to wrap query errors that includes query name (#3876) + +### Miscellaneous Tasks + +- Remove the triage label (#3527) +- Upgrade to Go 1.22.8 to silence vulncheck (#3646) +- Update sqlc-gen-java supported engines (#3843) + +### Build + +- (deps) Bump myst-parser (#3530) +- (deps) Bump golang from 1.22.5 to 1.22.6 (#3532) +- (deps) Bump modernc.org/sqlite (#3537) +- (deps) Bump the production-dependencies group across 1 directory with 4 updates (#3566) +- (deps) Bump the production-dependencies group across 1 directory with 2 updates (#3565) +- (deps) Bump golang from 1.22.6 to 1.23.0 (#3546) +- (deps) Bump golang from 1.23.0 to 1.23.1 (#3586) +- (deps) Bump the production-dependencies group across 1 directory with 5 updates (#3644) +- (deps) Bump the production-dependencies group across 1 directory with 5 updates (#3642) +- (deps) Bump sphinx-rtd-theme (#3648) +- (deps) Bump pyparsing (#3653) +- (deps) Bump markupsafe (#3666) +- (deps) Bump the production-dependencies group across 1 directory with 2 updates (#3707) +- (deps) Bump golang from 1.23.2 to 1.23.3 (#3691) +- (deps) Bump the production-dependencies group across 1 directory with 5 updates (#3721) +- (deps) Bump the production-dependencies group across 1 directory with 2 updates (#3731) +- (deps) Bump certifi in /docs in the production-dependencies group (#3748) +- (deps) Bump golang.org/x/crypto from 0.27.0 to 0.31.0 (#3740) +- (deps) Bump golang from 1.23.3 to 1.23.4 (#3735) +- (deps) Bump the production-dependencies group across 1 directory with 2 updates (#3749) +- (deps) Bump the production-dependencies group with 2 updates (#3753) +- (deps) Bump the production-dependencies group across 1 directory with 3 updates (#3764) +- (deps) Bump the production-dependencies group (#3761) +- (deps) Bump jinja2 from 3.1.4 to 3.1.5 in /docs (#3762) +- (deps) Bump google.golang.org/protobuf (#3776) +- (deps) Bump the production-dependencies group across 1 directory with 2 updates (#3777) +- (deps) Bump google.golang.org/grpc (#3784) +- (deps) Bump golang from 1.23.4 to 1.23.5 (#3791) +- (deps) Bump the production-dependencies group with 2 updates (#3789) +- Upgrade to Go 1.23.5 (#3795) +- (deps) Bump golang.org/x/net from 0.30.0 to 0.33.0 (#3796) +- (deps) Bump golang from 1.23.5 to 1.23.6 (#3822) +- Use govulncheck action (#3831) +- (deps) Bump the production-dependencies group across 1 directory with 3 updates (#3817) +- (deps) Bump the production-dependencies group across 1 directory with 5 updates (#3826) +- (deps) Bump golang from 1.23.6 to 1.24.0 (#3842) +- (deps) Bump myst-parser (#3841) +- (deps) Bump modernc.org/sqlite (#3846) +- (deps) Bump golang from 1.24.0 to 1.24.1 (#3870) +- (deps) Bump jinja2 in /docs in the production-dependencies group (#3872) +- Upgrade to wazero@v1.9.0 (#3887) +- Upgrade to Go 1.24.1 (#3892) +- Upgrade to latest version of MySQL parser (#3893) +- (deps) Bump pyparsing (#3890) +- (deps) Bump golang.org/x/net from 0.33.0 to 0.37.0 (#3894) +- (deps) Bump the production-dependencies group across 1 directory with 8 updates (#3896) +- (deps) Bump github.com/jackc/pgx/v5 (#3898) +- (deps) Bump the production-dependencies group (#3899) +- (deps) Bump modernc.org/sqlite (#3905) +- (deps) Bump the production-dependencies group across 1 directory with 2 updates (#3914) +- (deps) Bump urllib3 in /docs in the production-dependencies group (#3926) +- (deps) Bump golang from 1.24.1 to 1.24.2 (#3915) +- (deps) Bump the production-dependencies group across 1 directory with 3 updates (#3923) +- (deps) Upgrade github.com/wasilibs/go-pgquery (#3927) + +(v1-28-0)= +## [1.28.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.28.0) +Released 2025-01-20 + +### Features + +- (mysql) Add a test for VECTOR column type (#3734) +- (quickdb) Remove unused func (#3576) +- (vet) Allow selective disabling of rules per query (#3620) +- (dolphin) Upgrade to latest TiDB parser (#3733) + +### Bug Fixes + +- (dbmanager) Use correct SQL to drop databases (#3640) +- (compiler) Don't crash on WHERE x IN (... UNION ...) (#3652) +- (golang) Escape q field name (#3647) +- Postgresql alter materialized view is not registered to statements (#3728) +- Do not close wazero module on error (#3758) (#3759) + +### Documentation + +- How-to use transactions with pgx (#3557) +- Add missing documentation about copyfrom (#3583) +- Add sqlc-gen-from-template (#3601) +- Correct spelling and grammar (#3645) + +### Miscellaneous Tasks + +- Remove the triage label (#3527) +- Upgrade to Go 1.22.8 to silence vulncheck (#3646) + +### Build + +- (deps) Bump myst-parser (#3530) +- (deps) Bump golang from 1.22.5 to 1.22.6 (#3532) +- (deps) Bump modernc.org/sqlite (#3537) +- (deps) Bump the production-dependencies group across 1 directory with 4 updates (#3566) +- (deps) Bump the production-dependencies group across 1 directory with 2 updates (#3565) +- (deps) Bump golang from 1.22.6 to 1.23.0 (#3546) +- (deps) Bump golang from 1.23.0 to 1.23.1 (#3586) +- (deps) Bump the production-dependencies group across 1 directory with 5 updates (#3644) +- (deps) Bump the production-dependencies group across 1 directory with 5 updates (#3642) +- (deps) Bump sphinx-rtd-theme (#3648) +- (deps) Bump pyparsing (#3653) +- (deps) Bump markupsafe (#3666) +- (deps) Bump the production-dependencies group across 1 directory with 2 updates (#3707) +- (deps) Bump golang from 1.23.2 to 1.23.3 (#3691) +- (deps) Bump the production-dependencies group across 1 directory with 5 updates (#3721) +- (deps) Bump the production-dependencies group across 1 directory with 2 updates (#3731) +- (deps) Bump certifi in /docs in the production-dependencies group (#3748) +- (deps) Bump golang.org/x/crypto from 0.27.0 to 0.31.0 (#3740) +- (deps) Bump golang from 1.23.3 to 1.23.4 (#3735) +- (deps) Bump the production-dependencies group across 1 directory with 2 updates (#3749) +- (deps) Bump the production-dependencies group with 2 updates (#3753) +- (deps) Bump the production-dependencies group across 1 directory with 3 updates (#3764) +- (deps) Bump the production-dependencies group (#3761) +- (deps) Bump jinja2 from 3.1.4 to 3.1.5 in /docs (#3762) +- (deps) Bump google.golang.org/protobuf (#3776) +- (deps) Bump the production-dependencies group across 1 directory with 2 updates (#3777) +- (deps) Bump google.golang.org/grpc (#3784) +- (deps) Bump golang from 1.23.4 to 1.23.5 (#3791) +- (deps) Bump the production-dependencies group with 2 updates (#3789) +- Upgrade to Go 1.23.5 (#3795) + +(v1-27-0)= +## [1.27.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.27.0) +Released 2024-08-05 + +### Bug Fixes + +- (dbmanager) Add leading slash to db uri path rewrite (#3493) +- (verify) Include database engine in request (#3522) + +### Features + +- (golang) Add initialisms configuration (#3308) +- (compiler) Support subqueries in the FROM clause (second coming) (#3310) +- Managed databases with any accessible server (#3421) +- (vet) Use new dbmanager client (#3423) +- (verify) Update verify to work with managed databases (#3425) + +### Documentation + +- Fix typo in config (#3358) +- Resolve a typo in configuration keys (#3349) +- Add sponsorship information to README (#3413) +- Update the language-support to include C# (#3408) +- Add migration guide for hosted managed databases (#3417) +- Fix readme links (#3424) +- Update the managed db and verify documentation (#3426) +- Add sponsor image (#3428) +- Add Ruby as supported language (#3487) +- Update migrating-to-sqlc-gen-kotlin.md (#3454) +- Fix typo in comment (#3316) +- Fix deprecated build tag format (#3361) + +### Testing + +- (endtoend) Re-use databases when possible (#3315) +- Enabled MySQL database (#3318) +- Remove internal/sqltest/hosted package (#3521) + +(v1-26-0)= +## [1.26.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.26.0) +Released 2024-03-28 + +### Release notes + +This release is mainly a bug fix release. It also includes an [important security fix](https://github.com/sqlc-dev/sqlc/issues/3194) for users using output plugins. + +### Changes + +#### Bug Fixes + +- (docker) Use distroless base image instead of scratch (#3111) +- (generate) Ensure files are created inside output directory (#3195) +- (mysql) BREAKING: Use `int16` for MySQL `SMALLINT` and `YEAR` (#3106) +- (mysql) BREAKING: Use `int8` for MySQL TINYINT (#3298) +- (mysql) Variables not resolving in ORDER BY statements (#3115) +- (opts) Validate SQL package and driver options (#3241) +- (postgres/batch) Ignore query_parameter_limit for batches +- (scripts) Remove deprecated test output regeneration script (#3105) +- (sqlite) Correctly skip unknown statements (#3239) + +#### Documentation + +- (postgres) Add instructions for PostGIS/GEOS (#3182) +- Improve details on TEXT (#3247) + +#### Features + +- (generate) Avoid generating empty Go imports (#3135) +- (mysql) Add NEXTVAL() to the MySQL catalog (#3147) +- (mysql) Support json.RawMessage for LOAD DATA INFILE (#3099) + +#### Build + +- (deps) Bump github.com/jackc/pgx/v5 to 5.5.5 (#3259) +- (deps) Bump modernc.org/sqlite to 1.29.5 (#3200) +- (deps) Bump github.com/go-sql-driver/mysql to 1.8.0 (#3257) +- (deps) Bump github.com/tetratelabs/wazero to 1.7.0 (#3096) +- (deps) Bump github.com/pganalyze/pg_query_go to v5 (#3096) + + +(v1-25-0)= +## [1.25.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.25.0) +Released 2024-01-03 + +### Release notes + +#### Add tags to push and verify + +You can add tags when [pushing](../howto/push.md) schema and queries to [sqlc Cloud](https://dashboard.sqlc.dev). Tags operate like git tags, meaning you can overwrite previously-pushed tag values. We suggest tagging pushes to associate them with something relevant from your environment, e.g. a git tag or branch name. + +``` +$ sqlc push --tag v1.0.0 +``` + +Once you've created a tag, you can refer to it when [verifying](../howto/verify.md) changes, allowing you +to compare the existing schema against a known set of previous queries. + +``` +$ sqlc verify --against v1.0.0 +``` + +#### C-ya, `cgo` + +Over the last month, we've switched out a few different modules to remove our reliance on [cgo](https://go.dev/blog/cgo). Previously, we needed cgo for three separate functions: + +- Parsing PostgreSQL queries with [pganalyze/pg_query_go](https://github.com/pganalyze/pg_query_go) +- Running SQLite databases with [mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) +- Executing WASM / WASI code with [bytecodealliance/wasmtime-go](https://github.com/bytecodealliance/wasmtime-go) + +With the help of the community, we found cgo-free alternatives for each module: + +- Parsing PostgreSQL queries, now using [wasilibs/go-pgquery](https://github.com/wasilibs/go-pgquery) +- Running SQLite databases, now using [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) +- Executing WASM / WASI code, now using [tetratelabs/wazero](https://github.com/tetratelabs/wazero) + +For the first time, Windows users can enjoy full PostgreSQL support without using [WSL](https://learn.microsoft.com/en-us/windows/wsl/about). It's a Christmas miracle! + +If you run into any issues with the updated dependencies, please [open an issue](https://github.com/sqlc-dev/sqlc/issues). + +### Changes + +#### Bug Fixes + +- (codegen) Wrong yaml annotation in go codegen options for output_querier_file_name (#3006) +- (codegen) Use derived ArrayDims instead of deprecated attndims (#3032) +- (codegen) Take the maximum array dimensions (#3034) +- (compiler) Skip analysis of queries without a `name` annotation (#3072) +- (codegen/golang) Don't import `"strings"` for `sqlc.slice()` with pgx (#3073) + +### Documentation + +- Add name to query set configuration (#3011) +- Add a sidebar link for `push`, add Go plugin link (#3023) +- Update banner for sqlc-gen-typescript (#3036) +- Add strict_order_by in doc (#3044) +- Re-order the migration tools list (#3064) + +### Features + +- (analyzer) Return zero values when encountering unexpected ast nodes (#3069) +- (codegen/go) add omit_sqlc_version to Go code generation (#3019) +- (codgen/go) Add `emit_sql_as_comment` option to Go code plugin (#2735) +- (plugins) Use wazero instead of wasmtime (#3042) +- (push) Add tag support (#3074) +- (sqlite) Support emit_pointers_for_null_types (#3026) + +### Testing + +- (endtoend) Enable for more build targets (#3041) +- (endtoend) Run MySQL and PostgreSQL locally on the runner (#3095) +- (typescript) Test against sqlc-gen-typescript (#3046) +- Add tests for omit_sqlc_version (#3020) +- Split schema and query for test (#3094) + +### Build + +- (deps) Bump idna from 3.4 to 3.6 in /docs (#3010) +- (deps) Bump sphinx-rtd-theme from 1.3.0 to 2.0.0 in /docs (#3016) +- (deps) Bump golang from 1.21.4 to 1.21.5 (#3043) +- (deps) Bump actions/setup-go from 4 to 5 (#3047) +- (deps) Bump github.com/jackc/pgx/v5 from 5.5.0 to 5.5.1 (#3050) +- (deps) Upgrade to latest version of github.com/wasilibs/go-pgquery (#3052) +- (deps) Bump google.golang.org/grpc from 1.59.0 to 1.60.0 (#3053) +- (deps) Bump babel from 2.13.1 to 2.14.0 in /docs (#3055) +- (deps) Bump actions/upload-artifact from 3 to 4 (#3061) +- (deps) Bump modernc.org/sqlite from 1.27.0 to 1.28.0 (#3062) +- (deps) Bump golang.org/x/crypto from 0.14.0 to 0.17.0 (#3068) +- (deps) Bump google.golang.org/grpc from 1.60.0 to 1.60.1 (#3070) +- (deps) Bump google.golang.org/protobuf from 1.31.0 to 1.32.0 (#3079) +- (deps) Bump github.com/tetratelabs/wazero from 1.5.0 to 1.6.0 (#3096) +- (sqlite) Update to antlr 4.13.1 (#3086) +- (sqlite) Disable modernc for WASM (#3048) +- (sqlite) Switch from mattn/go-sqlite3 to modernc.org/sqlite (#3040) + +(v1-24-0)= +## [1.24.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.24.0) +Released 2023-11-22 + +### Release notes + +#### Verifying database schema changes + +Schema updates and poorly-written queries often bring down production databases. That’s bad. + +Out of the box, `sqlc generate` catches some of these issues. Running `sqlc vet` with the `sqlc/db-prepare` rule catches more subtle problems. But there is a large class of issues that sqlc can’t prevent by looking at current schema and queries alone. + +For instance, when a schema change is proposed, existing queries and code running in production might fail when the schema change is applied. Enter `sqlc verify`, which analyzes existing queries against new schema changes and errors if there are any issues. + +Let's look at an example. Assume you have these two tables in production. + +```sql +CREATE TABLE users ( + id UUID PRIMARY KEY +); + +CREATE TABLE user_actions ( + id UUID PRIMARY KEY, + user_id UUID NOT NULL, + action TEXT, + created_at TIMESTAMP +); +``` + +Your application contains the following query to join user actions against the users table. + +```sql +-- name: GetUserActions :many +SELECT * FROM users u +JOIN user_actions ua ON u.id = ua.user_id +ORDER BY created_at; +``` + +So far, so good. Then assume you propose this schema change: + +```sql +ALTER TABLE users ADD COLUMN created_at TIMESTAMP; +``` + +Running `sqlc generate` fails with this change, returning a `column reference "created_at" is ambiguous` error. You update your query to fix the issue. + +```sql +-- name: GetUserActions :many +SELECT * FROM users u +JOIN user_actions ua ON u.id = ua.user_id +ORDER BY u.created_at; +``` + +While that change fixes the issue, there's a production outage waiting to happen. When the schema change is applied, the existing `GetUserActions` query will begin to fail. The correct way to fix this is to deploy the updated query before applying the schema migration. + +It ensures migrations are safe to deploy by sending your current schema and queries to sqlc cloud. There, we run the queries for your latest push against your new schema changes. This check catches backwards incompatible schema changes for existing queries. + +Here `sqlc verify` alerts you to the fact that ORDER BY "created_at" is ambiguous. + +```sh +$ sqlc verify +FAIL: app query.sql + +=== Failed +=== FAIL: app query.sql GetUserActions + ERROR: column reference "created_at" is ambiguous (SQLSTATE 42702) +``` + +By the way, this scenario isn't made up! It happened to us a few weeks ago. We've been happily testing early versions of `verify` for the last two weeks and haven't had any issues since. + +This type of verification is only the start. If your application is deployed on-prem by your customers, `verify` could tell you if it's safe for your customers to rollback to an older version of your app, even after schema migrations have been run. + +#### Rename `upload` command to `push` + +We've renamed the `upload` sub-command to `push`. We changed the data sent along in a push request. Upload used to include the configuration file, migrations, queries, and all generated code. Push drops the generated code in favor of including the [plugin.GenerateRequest](https://buf.build/sqlc/sqlc/docs/main:plugin#plugin.GenerateRequest), which is the protocol buffer message we pass to codegen plugins. + +We also add annotations to each push. By default, we include these environment variables if they are present: + +``` +GITHUB_REPOSITORY +GITHUB_REF +GITHUB_REF_NAME +GITHUB_REF_TYPE +GITHUB_SHA +``` + +Like upload, `push` should be run when you tag a release of your application. We run it on every push to main, as we continuously deploy those commits. + +#### MySQL support in `createdb` + +The `createdb` command, added in the last release, now supports MySQL. If you have a cloud project configured, you can use `sqlc createdb` to spin up a new ephemeral database with your schema and print its connection string to standard output. This is useful for integrating with other tools. Read more in the [managed databases](../howto/managed-databases.md) documentation. + +#### Plugin interface refactor + +This release includes a refactored plugin interface to better support future functionality. Plugins now support different methods via a gRPC service interface, allowing plugins to support different functionality in a backwards-compatible way. + +By using gRPC interfaces, we can even (theoretically) support [remote plugins](https://github.com/sqlc-dev/sqlc/pull/2938), but that's something for another day. + +### Changes + +#### Bug Fixes + +- (engine/sqlite) Support CASE expr (#2926) +- (engine/sqlite) Support -> and ->> operators (#2927) +- (vet) Add a nil pointer check to prevent db/prepare panic (#2934) +- (compiler) Prevent panic when compiler is nil (#2942) +- (codegen/golang) Move more Go-specific config validation into the plugin (#2951) +- (compiler) No panic on full-qualified column names (#2956) +- (docs) Better discussion of type override nuances (#2972) +- (codegen) Never generate return structs for :exec (#2976) +- (generate) Update help text for generate to be more generic (#2981) +- (generate) Return an error instead of generating duplicate Go names (#2962) +- (codegen/golang) Pull opts into its own package (#2920) +- (config) Make some struct and field names less confusing (#2922) + +#### Features + +- (codegen) Remove Go specific overrides from codegen proto (#2929) +- (plugin) Use gRPC interface for codegen plugin communication (#2930) +- (plugin) Calculate SHA256 if it does not exist (#2935) +- (sqlc-gen-go) Add script to mirror code to sqlc-gen-go (#2952) +- (createdb) Add support for MySQL (#2980) +- (verify) Add new command to verify queries and migrations (#2986) + +#### Testing + +- (ci) New workflow for sqlc-gen-python (#2936) +- (ci) Rely on go.mod to determine which Go version to use (#2971) +- (tests) Add glob pattern tests to sqlpath.Glob (#2995) +- (examples) Use hosted MySQL databases for tests (#2982) +- (docs) Clean up a little, update LICENSE and README (#2941) + +#### Build + +- (deps) Bump babel from 2.13.0 to 2.13.1 in /docs (#2911) +- (deps) Bump github.com/spf13/cobra from 1.7.0 to 1.8.0 (#2944) +- (deps) Bump github.com/mattn/go-sqlite3 from 1.14.17 to 1.14.18 (#2945) +- (deps) Bump golang.org/x/sync from 0.4.0 to 0.5.0 (#2946) +- (deps) Bump github.com/jackc/pgx/v5 from 5.4.3 to 5.5.0 (#2947) +- (deps) Change github.com/pingcap/tidb/parser to github.com/pingcap/tidb/pkg/parser +- (deps) Bump github.com/google/cel-go from 0.18.1 to 0.18.2 (#2969) +- (deps) Bump urllib3 from 2.0.7 to 2.1.0 in /docs (#2975) +- (buf) Change root of Buf module (#2987) +- (deps) Bump certifi from 2023.7.22 to 2023.11.17 in /docs (#2993) +- (ci) Bump Go version from 1.21.3 to 1.21.4 in workflows and Dockerfile (#2961) + +(v1-23-0)= +## [1.23.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.23.0) +Released 2023-10-24 + +### Release notes + +#### Database-backed query analysis + +With a [database connection](config.md#database) configured, `sqlc generate` +will gather metadata from that database to support its query analysis. +Turning this on resolves a [large number of +issues](https://github.com/sqlc-dev/sqlc/issues?q=is%3Aissue+label%3Aanalyzer) +in the backlog related to type inference and more complex queries. The easiest +way to try it out is with [managed databases](../howto/managed-databases.md). + +The database-backed analyzer currently supports PostgreSQL, with [MySQL](https://github.com/sqlc-dev/sqlc/issues/2902) and [SQLite](https://github.com/sqlc-dev/sqlc/issues/2903) +support planned in the future. + +#### New `createdb` command + +When you have a cloud project configured, you can use the new `sqlc createdb` +command to spin up a new ephemeral database with your schema and print its +connection string to standard output. This is useful for integrating with other +tools. Read more in the [managed +databases](../howto/managed-databases.md) documentation. + +#### Support for pgvector + +If you're using [pgvector](https://github.com/pgvector/pgvector), say goodbye to custom overrides! sqlc now generates code using [pgvector-go](https://github.com/pgvector/pgvector-go#pgx) as long as you're using `pgx`. The pgvector extension is also available in [managed databases](../howto/managed-databases.md). + +#### Go build tags + +With the new `emit_build_tags` configuration parameter you can set build tags +for sqlc to add at the top of generated source files. + +### Changes + +#### Bug Fixes + +- (codegen) Correct column names in :copyfrom (#2838) +- (compiler) Search SELECT and UPDATE the same way (#2841) +- (dolphin) Support more UNIONs for MySQL (#2843) +- (compiler) Account for parameters without parents (#2844) +- (postgresql) Remove temporary pool config (#2851) +- (golang) Escape reserved keywords (#2849) +- (mysql) Handle simplified CASE statements (#2852) +- (engine/dolphin) Support enum in ALTER definition (#2680) +- (mysql) Add, drop, rename and change enum values (#2853) +- (config) Validate `database` config in all cases (#2856) +- (compiler) Use correct func signature for `CommentSyntax` on windows (#2867) +- (codegen/go) Prevent filtering of embedded struct fields (#2868) +- (compiler) Support functions with OUT params (#2865) +- (compiler) Pull in array information from analyzer (#2864) +- (analyzer) Error on unexpanded star expression (#2882) +- (vet) Remove rollback statements from DDL (#2895) + +#### Documentation + +- Add stable anchors to changelog (#2784) +- Fix typo in v1.22.0 changelog (#2796) +- Add sqlc upload to CI / CD guide (#2797) +- Fix broken link, add clarity to plugins doc (#2813) +- Add clarity and reference to JSON tags (#2819) +- Replace form with dashboard link (#2840) +- (examples) Update examples to use pgx/v5 (#2863) +- Use docker compose v2 and update MYSQL_DATABASE env var (#2870) +- Update getting started guides, use pgx for Postgres guide (#2891) +- Use managed databases in PostgreSQL getting started guide (#2892) +- Update managed databases doc to discuss codegen (#2897) +- Add managed dbs to CI/CD and vet guides (#2896) +- Document database-backed query analyzer (#2904) + +#### Features + +- (codegen) Support setting Go build tags (#2012) (#2807) +- (generate) Reorder codegen handlers to prefer plugins (#2814) +- (devenv) Add vscode settings.json with auto newline (#2834) +- (cmd) Support sqlc.yml configuration file (#2828) +- (analyzer) Analyze queries using a running PostgreSQL database (#2805) +- (sql/ast) Render AST to SQL (#2815) +- (codegen) Include plugin information (#2846) +- (postgresql) Add ALTER VIEW ... SET SCHEMA (#2855) +- (compiler) Parse query parameter metadata from comments (#2850) +- (postgresql) Support system columns on tables (#2871) +- (compiler) Support LEFT JOIN on aliased table (#2873) +- Improve messaging for common cloud config and rpc errors (#2885) +- Abort compiler when rpc fails as unauthenticated (#2887) +- (codegen) Add support for pgvector and pgvector-go (#2888) +- (analyzer) Cache query analysis (#2889) +- (createdb) Create ephemeral databases (#2894) +- (debug) Add databases=managed debug option (#2898) +- (config) Remove managed database validation (#2901) + +#### Miscellaneous Tasks + +- (endtoend) Fix test output for do tests (#2782) + +#### Refactor + +- (codegen) Remove golang and json settings from plugin proto (#2822) +- (codegen) Removed deprecated code and improved speed (#2899) + +#### Testing + +- (endtoend) Split shema and queries (#2803) +- Fix a few incorrect testcases (#2804) +- (analyzer) Add more database analyzer test cases (#2854) +- Add more analyzer test cases (#2866) +- Add more test cases for new analyzer (#2879) +- (endtoend) Enabled managed-db tests in CI (#2883) +- Enabled pgvector tests for managed dbs (#2893) + +#### Build + +- (deps) Bump packaging from 23.1 to 23.2 in /docs (#2791) +- (deps) Bump urllib3 from 2.0.5 to 2.0.6 in /docs (#2798) +- (deps) Bump babel from 2.12.1 to 2.13.0 in /docs (#2799) +- (deps) Bump golang.org/x/sync from 0.3.0 to 0.4.0 (#2810) +- (deps) Bump golang from 1.21.1 to 1.21.2 (#2811) +- (deps) Bump github.com/google/go-cmp from 0.5.9 to 0.6.0 (#2826) +- (deps) Bump golang from 1.21.2 to 1.21.3 (#2824) +- (deps) Bump google.golang.org/grpc from 1.58.2 to 1.58.3 (#2825) +- (deps) Bump golang.org/x/net from 0.12.0 to 0.17.0 (#2836) +- (deps) Bump urllib3 from 2.0.6 to 2.0.7 in /docs (#2872) +- (deps) Bump google.golang.org/grpc from 1.58.3 to 1.59.0 (#2876) +- (deps) Upgrade wasmtime-go from 13.0.0 to 14.0.0 (#2900) + +#### Ci + +- Bump go version in workflows (#2835) + + +(v1-22-0)= +## [1.22.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.22.0) +Released 2023-09-26 + +### Release notes + +#### Managed databases for `sqlc vet` + +If you're using [sqlc vet](../howto/vet.md) to write rules that require access to a running +database, `sqlc` can now start and manage that database for you. PostgreSQL +support is available today, with MySQL on the way. + +When you turn on managed databases, `sqlc` will use your schema to create a +template database that it can copy to make future runs of `sqlc vet` very +performant. + +This feature relies on configuration obtained via [sqlc +Cloud](https://dashboard.sqlc.dev). + +Read more in the [managed databases](../howto/managed-databases.md) documentation. + +### Changes + +#### Bug Fixes + +- (codegen/golang) Refactor imports code to match templates (#2709) +- (codegen/golang) Support name type (#2715) +- (wasm) Move Runner struct to shared file (#2725) +- (engine/sqlite) Fix grammer to avoid missing join_constraint (#2732) +- (convert) Support YAML anchors in plugin options (#2733) +- (mysql) Disallow time.Time in mysql :copyfrom queries, not all queries (#2768) +- (engine/sqlite) Fix convert process for VALUES (#2737) + +#### Documentation + +- Clarify nullable override behavior (#2753) +- Add managed databases to sidebar (#2764) +- Pull renaming and type overrides into separate sections (#2774) +- Update the docs banner for managed dbs (#2775) + +#### Features + +- (config) Enables the configuration of copyfrom.go similar to quierer and friends (#2727) +- (vet) Run rules against a managed database (#2751) +- (upload) Point upload command at new endpoint (#2772) +- (compiler) Support DO statements (#2777) + +#### Miscellaneous Tasks + +- (endtoend) Skip tests missing secrets (#2763) +- Skip certain tests on PRs (#2769) + +#### Testing + +- (endtoend) Verify all schemas in endtoend (#2744) +- (examples) Use a hosted database for example testing (#2749) +- (endtoend) Pull region from environment (#2750) + +#### Build + +- (deps) Bump golang from 1.21.0 to 1.21.1 (#2711) +- (deps) Bump google.golang.org/grpc from 1.57.0 to 1.58.1 (#2743) +- (deps) Bump wasmtime-go from v12 to v13 (#2756) +- (windows) Downgrade to mingw 11.2.0 (#2757) +- (deps) Bump urllib3 from 2.0.4 to 2.0.5 in /docs (#2747) +- (deps) Bump google.golang.org/grpc from 1.58.1 to 1.58.2 (#2758) +- (deps) Bump github.com/google/cel-go from 0.18.0 to 0.18.1 (#2778) + +#### Ci + +- Bump go version to latest in ci workflows (#2722) + + +(v1-21-0)= +## [1.21.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.21.0) +Released 2023-09-06 + +### Release notes + +This is primarily a bugfix release, along with some documentation and testing improvements. + +#### MySQL engine improvements + +`sqlc` previously didn't know how to parse a `CALL` statement when using the MySQL engine, +which meant it was impossible to use sqlc with stored procedures in MySQL databases. + +Additionally, `sqlc` now supports `IS [NOT] NULL` in queries. And `LIMIT` and `OFFSET` clauses +now work with `UNION`. + +#### SQLite engine improvements + +GitHub user [@orisano](https://github.com/orisano) continues to bring bugfixes and +improvements to `sqlc`'s SQLite engine. See the "Changes" section below for the +full list. + +#### Plugin access to environment variables + +If you're authoring a [sqlc plugin](../guides/plugins.md), you can now configure +sqlc to pass your plugin the values of specific environment variables. + +For example, if your plugin +needs the `PATH` environment variable, add `PATH` to the `env` list 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 +``` + +A variable named `SQLC_VERSION` is always included in the plugin's +environment, set to the version of the `sqlc` executable invoking it. + +### Changes + +#### Bug Fixes + +- Myriad string formatting changes (#2558) +- (engine/sqlite) Support quoted identifier (#2556) +- (engine/sqlite) Fix compile error (#2564) +- (engine/sqlite) Fixed detection of column alias without AS (#2560) +- (ci) Bump go version to 1.20.7 (#2568) +- Remove references to deprecated `--experimental` flag (#2567) +- (postgres) Fixed a problem with array dimensions disappearing when using "ALTER TABLE ADD COLUMN" (#2572) +- Remove GitHub sponsor integration (#2574) +- (docs) Improve discussion of prepared statements support (#2604) +- (docs) Remove multidimensional array qualification in datatypes.md (#2619) +- (config) Go struct tag parsing (#2606) +- (compiler) Fix to not scan children under ast.RangeSubselect when retrieving table listing (#2573) +- (engine/sqlite) Support NOT IN (#2587) +- (codegen/golang) Fixed detection of the used package (#2597) +- (engine/dolphin) Fixed problem that LIMIT OFFSET cannot be used with `UNION ALL` (#2613) +- (compiler) Support identifiers with schema (#2579) +- (compiler) Fix column expansion to work with quoted non-keyword identifiers (#2576) +- (codegen/go) Compare define type in codegen (#2263) (#2578) +- (engine/sqlite) Fix ast when using compound operator (#2673) +- (engine/sqlite) Fix to handle join clauses correctly (#2674) +- (codegen) Use correct Go types for bit strings and cid/oid/tid/xid with pgx/v4 (#2668) +- (endtoend) Ensure all SQL works against PostgreSQL (#2684) + +#### Documentation + +- Update Docker installation instructions (#2552) +- Missing emit_pointers_for_null_types configuration option in version 2 (#2682) (#2683) +- Fix typo (#2697) +- Document sqlc.* macros (#2698) +- (mysql) Document parseTimet=true requirement (#2699) +- Add atlas to the list of supported migration frameworks (#2700) +- Minor updates to insert howto (#2701) + +#### Features + +- (endtoend/testdata) Added two sqlite `CAST` tests and rearranged postgres tests for same (#2551) +- (docs) Add a reference to type overriding in datatypes.md (#2557) +- (engine/sqlite) Support COLLATE for sqlite WHERE clause (#2554) +- (mysql) Add parser support for IS [NOT] NULL (#2651) +- (engine/dolphin) Support CALL statement (#2614) +- (codegen) Allow plugins to access environment variables (#2669) +- (config) Add JSON schema files for configs (#2703) + +#### Miscellaneous Tasks + +- Ignore Vim swap files (#2616) +- Fix typo (#2696) + +#### Refactor + +- (astutils) Remove redundant nil check in `Walk` (#2660) + +#### Build + +- (deps) Bump wasmtime from v8.0.0 to v11.0.0 (#2553) +- (deps) Bump golang from 1.20.6 to 1.20.7 (#2563) +- (deps) Bump chardet from 5.1.0 to 5.2.0 in /docs (#2562) +- (deps) Bump github.com/pganalyze/pg_query_go/v4 (#2583) +- (deps) Bump golang from 1.20.7 to 1.21.0 (#2596) +- (deps) Bump github.com/jackc/pgx/v5 from 5.4.2 to 5.4.3 (#2582) +- (deps) Bump pygments from 2.15.1 to 2.16.1 in /docs (#2584) +- (deps) Bump sphinxcontrib-applehelp from 1.0.4 to 1.0.7 in /docs (#2620) +- (deps) Bump sphinxcontrib-qthelp from 1.0.3 to 1.0.6 in /docs (#2622) +- (deps) Bump github.com/google/cel-go from 0.17.1 to 0.17.6 (#2650) +- (deps) Bump sphinxcontrib-serializinghtml in /docs (#2641) +- Upgrade from Go 1.20 to Go 1.21 (#2665) +- (deps) Bump sphinxcontrib-devhelp from 1.0.2 to 1.0.5 in /docs (#2621) +- (deps) Bump github.com/bytecodealliance/wasmtime-go from v11.0.0 to v12.0.0 (#2666) +- (deps) Bump sphinx-rtd-theme from 1.2.2 to 1.3.0 in /docs (#2670) +- (deps) Bump sphinxcontrib-htmlhelp from 2.0.1 to 2.0.4 in /docs (#2671) +- (deps) Bump github.com/google/cel-go from 0.17.6 to 0.18.0 (#2691) +- (deps) Bump actions/checkout from 3 to 4 (#2694) +- (deps) Bump pytz from 2023.3 to 2023.3.post1 in /docs (#2695) +- (devenv) Bump go from 1.20.7 to 1.21.0 (#2702) + +(v1-20-0)= +## [1.20.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.20.0) +Released 2023-07-31 + +### Release notes + +#### `kyleconroy/sqlc` is now `sqlc-dev/sqlc` + +We've completed our migration to the [sqlc-dev/sqlc](https://github.com/sqlc-dev/sqlc) repository. All existing links and installation instructions will continue to work. If you're using the `go` tool to install `sqlc`, you'll need to use the new import path to get v1.20.0 (and all future versions). + +```sh +# INCORRECT: old import path +go install github.com/kyleconroy/sqlc/cmd/sqlc@v1.20.0 + +# CORRECT: new import path +go install github.com/sqlc-dev/sqlc/cmd/sqlc@v1.20.0 +``` + +We designed the upgrade process to be as smooth as possible. If you run into any issues, please [file a bug report](https://github.com/sqlc-dev/sqlc/issues/new?assignees=&labels=bug%2Ctriage&projects=&template=BUG_REPORT.yml) via GitHub. + +#### Use `EXPLAIN ...` output in lint rules + +`sqlc vet` can now run `EXPLAIN` on your queries and include the results for use in your lint rules. For example, this rule checks that `SELECT` queries use an index. + +```yaml +version: 2 +sql: + - schema: "query.sql" + queries: "query.sql" + engine: "postgresql" + database: + uri: "postgresql://postgres:postgres@localhost:5432/postgres" + gen: + go: + package: "db" + out: "db" + rules: + - has-index +rules: +- name: has-index + rule: > + query.sql.startsWith("SELECT") && + !(postgresql.explain.plan.plans.all(p, has(p.index_name) || p.plans.all(p, has(p.index_name)))) +``` + +The expression environment has two variables containing `EXPLAIN ...` output, `postgresql.explain` and `mysql.explain`. `sqlc` only populates the variable associated with your configured database engine, and only when you have a [database connection configured](../reference/config.md#database). + +For the `postgresql` engine, `sqlc` runs + +```sql +EXPLAIN (ANALYZE false, VERBOSE, COSTS, SETTINGS, BUFFERS, FORMAT JSON) ... +``` + +where `"..."` is your query string, and parses the output into a [`PostgreSQLExplain`](https://buf.build/sqlc/sqlc/docs/v1.20.0:vet#vet.PostgreSQLExplain) proto message. + +For the `mysql` engine, `sqlc` runs + +```sql +EXPLAIN FORMAT=JSON ... +``` + +where `"..."` is your query string, and parses the output into a [`MySQLExplain`](https://buf.build/sqlc/sqlc/docs/v1.20.0:vet#vet.MySQLExplain) proto message. + +These proto message definitions are too long to include here, but you can find them in the `protos` directory within the `sqlc` source tree. + +The output from `EXPLAIN ...` depends on the structure of your query so it's a bit difficult to offer generic examples. Refer to the [PostgreSQL documentation](https://www.postgresql.org/docs/current/using-explain.html) and [MySQL documentation](https://dev.mysql.com/doc/refman/en/explain-output.html) for more information. + +```yaml +... +rules: +- name: postgresql-query-too-costly + message: "Query cost estimate is too high" + rule: "postgresql.explain.plan.total_cost > 1.0" +- name: postgresql-no-seq-scan + message: "Query plan results in a sequential scan" + rule: "postgresql.explain.plan.node_type == 'Seq Scan'" +- name: mysql-query-too-costly + message: "Query cost estimate is too high" + rule: "has(mysql.explain.query_block.cost_info) && double(mysql.explain.query_block.cost_info.query_cost) > 2.0" +- name: mysql-must-use-primary-key + message: "Query plan doesn't use primary key" + rule: "has(mysql.explain.query_block.table.key) && mysql.explain.query_block.table.key != 'PRIMARY'" +``` + +When building rules that depend on `EXPLAIN ...` output, it may be helpful to see the actual JSON returned from the database. `sqlc` will print it When you set the environment variable `SQLCDEBUG=dumpexplain=1`. Use this environment variable together with a dummy rule to see `EXPLAIN ...` output for all of your queries. + +#### Opting-out of lint rules + +For any query, you can tell `sqlc vet` not to evaluate lint rules using the `@sqlc-vet-disable` query annotation. + +```sql +/* name: GetAuthor :one */ +/* @sqlc-vet-disable */ +SELECT * FROM authors +WHERE id = ? LIMIT 1; +``` + +#### Bulk insert for MySQL + +_Developed by [@Jille](https://github.com/Jille)_ + +MySQL now supports the `:copyfrom` query annotation. The generated code uses the [LOAD DATA](https://dev.mysql.com/doc/refman/8.0/en/load-data.html) command to insert data quickly and efficiently. + +Use caution with this feature. Errors and duplicate keys are treated as warnings and insertion will continue, even without an error for some cases. Use this in a transaction and use `SHOW WARNINGS` to check for any problems and roll back if necessary. + +Check the [error handling](https://dev.mysql.com/doc/refman/8.0/en/load-data.html#load-data-error-handling) documentation for more information. + +```sql +CREATE TABLE foo (a text, b integer, c DATETIME, d DATE); + +-- name: InsertValues :copyfrom +INSERT INTO foo (a, b, c, d) VALUES (?, ?, ?, ?); +``` + +```go +func (q *Queries) InsertValues(ctx context.Context, arg []InsertValuesParams) (int64, error) { + ... +} +``` + +`LOAD DATA` support must be enabled in the MySQL server. + +#### CAST support for MySQL + +_Developed by [@ryanpbrewster](https://github.com/ryanpbrewster) and [@RadhiFadlillah](https://github.com/RadhiFadlillah)_ + +`sqlc` now understands `CAST` calls in MySQL queries, offering greater flexibility when generating code for complex queries. + +```sql +CREATE TABLE foo (bar BOOLEAN NOT NULL); + +-- name: SelectColumnCast :many +SELECT CAST(bar AS BIGINT) FROM foo; +``` + +```go +package querytest + +import ( + "context" +) + +const selectColumnCast = `-- name: SelectColumnCast :many +SELECT CAST(bar AS BIGINT) FROM foo +` + +func (q *Queries) SelectColumnCast(ctx context.Context) ([]int64, error) { + ... +} +``` + +#### SQLite improvements + +A slew of fixes landed for our SQLite implementation, bringing it closer to parity with MySQL and PostgreSQL. We want to thank [@orisano](https://github.com/orisano) for their continued dedication to improving `sqlc`'s SQLite support. + +### Changes + +#### Features + +- (debug) Add debug flag and docs for dumping vet rule variables (#2521) +- (mysql) :copyfrom support via LOAD DATA INFILE (#2545) +- (mysql) Implement cast function parser (#2473) +- (postgresql) Add support for PostgreSQL multi-dimensional arrays (#2338) +- (sql/catalog) Support ALTER TABLE IF EXISTS (#2542) +- (sqlite) Virtual tables and fts5 supported (#2531) +- (vet) Add default query parameters for explain queries (#2543) +- (vet) Add output from `EXPLAIN ...` for queries to the CEL program environment (#2489) +- (vet) Introduce a query annotation to opt out of sqlc vet rules (#2474) +- Parse comment lines starting with `@symbol` as boolean flags associated with a query (#2464) + +#### Bug Fixes + +- (codegen/golang) Fix sqlc.embed to work with pq.Array (#2544) +- (compiler) Correctly validate alias in order/group by clauses for joins (#2537) +- (engine/sqlite) Added function to convert cast node (#2470) +- (engine/sqlite) Fix join_operator rule (#2434) +- (engine/sqlite) Fix table_alias rules (#2465) +- (engine/sqlite) Fixed IN operator precedence (#2428) +- (engine/sqlite) Fixed to be able to find relation from WITH clause (#2444) +- (engine/sqlite) Lowercase ast.ResTarget.Name (#2433) +- (engine/sqlite) Put logging statement behind debug flag (#2488) +- (engine/sqlite) Support for repeated table_option (#2482) +- (mysql) Generate unsigned param (#2522) +- (sql/catalog) Support pg_dump output (#2508) +- (sqlite) Code generation for sqlc.slice (#2431) +- (vet) Clean up unnecessary `prepareable()` func and a var name (#2509) +- (vet) Query.cmd was always set to ":" (#2525) +- (vet) Report an error when a query is unpreparable, close prepared statement connection (#2486) +- (vet) Split vet messages out of codegen.proto (#2511) + +#### Documentation + +- Add a description to the document for cases when a query result has no rows (#2462) +- Update copyright and author (#2490) +- Add example sqlc.yaml for migration parsing (#2479) +- Small updates (#2506) +- Point GitHub links to new repository location (#2534) + +#### Miscellaneous Tasks + +- Rename kyleconroy/sqlc to sqlc-dev/sqlc (#2523) +- (proto) Reformat protos using `buf format -w` (#2536) +- Update FEATURE_REQUEST.yml to include SQLite engine option +- Finish migration to sqlc-dev/sqlc (#2548) +- (compiler) Remove some duplicate code (#2546) + +#### Testing + +- Add profiles to docker compose (#2503) + +#### Build + +- Run all supported versions of MySQL / PostgreSQL (#2463) +- (deps) Bump pygments from 2.7.4 to 2.15.0 in /docs (#2485) +- (deps) Bump github.com/jackc/pgconn from 1.14.0 to 1.14.1 (#2483) +- (deps) Bump github.com/google/cel-go from 0.16.0 to 0.17.1 (#2484) +- (docs) Check Python dependencies via dependabot (#2497) +- (deps) Bump idna from 2.10 to 3.4 in /docs (#2499) +- (deps) Bump packaging from 20.9 to 23.1 in /docs (#2498) +- (deps) Bump pygments from 2.15.0 to 2.15.1 in /docs (#2500) +- (deps) Bump certifi from 2022.12.7 to 2023.7.22 in /docs (#2504) +- (deps) Bump sphinx from 4.4.0 to 6.1.0 in /docs (#2505) +- Add psql and mysqlsh to devenv (#2507) +- (deps) Bump urllib3 from 1.26.5 to 2.0.4 in /docs (#2516) +- (deps) Bump chardet from 4.0.0 to 5.1.0 in /docs (#2517) +- (deps) Bump snowballstemmer from 2.1.0 to 2.2.0 in /docs (#2519) +- (deps) Bump pytz from 2021.1 to 2023.3 in /docs (#2520) +- (deps) Bump sphinxcontrib-htmlhelp from 2.0.0 to 2.0.1 in /docs (#2518) +- (deps) Bump pyparsing from 2.4.7 to 3.1.0 in /docs (#2530) +- (deps) Bump alabaster from 0.7.12 to 0.7.13 in /docs (#2526) +- (docs) Ignore updates for sphinx (#2532) +- (deps) Bump babel from 2.9.1 to 2.12.1 in /docs (#2527) +- (deps) Bump sphinxcontrib-applehelp from 1.0.2 to 1.0.4 in /docs (#2533) +- (deps) Bump google.golang.org/grpc from 1.56.2 to 1.57.0 (#2535) +- (deps) Bump pyparsing from 3.1.0 to 3.1.1 in /docs (#2547) + + +## [1.19.1](https://github.com/sqlc-dev/sqlc/releases/tag/v1.19.1) +Released 2023-07-13 + +### Bug Fixes + +- Fix to traverse Sel in ast.In (#2414) +- (compiler) Validate UNION ... ORDER BY (#2446) +- (golang) Prevent duplicate enum output (#2447) + +### Miscellaneous Tasks + +- Replace codegen, test and docs references to github.com/tabbed repos (#2418) + +### Build + +- (deps) Bump google.golang.org/grpc from 1.56.1 to 1.56.2 (#2415) +- (deps) Bump golang from 1.20.5 to 1.20.6 (#2437) +- Pin Go to 1.20.6 (#2441) +- (deps) Bump github.com/jackc/pgx/v5 from 5.4.1 to 5.4.2 (#2436) + +## [1.19.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.19.0) +Released 2023-07-06 + +### Release notes + +#### sqlc vet + +[`sqlc vet`](../howto/vet.md) runs queries through a set of lint rules. + +Rules are defined in the `sqlc` [configuration](config.md) file. They consist +of a name, message, and a [Common Expression Language (CEL)](https://github.com/google/cel-spec) +expression. Expressions are evaluated using [cel-go](https://github.com/cel-expr/cel-go). +If an expression evaluates to `true`, an error is reported using the given message. + +While these examples are simplistic, they give you a flavor of the types of +rules you can write. + +```yaml +version: 2 +sql: + - schema: "query.sql" + queries: "query.sql" + engine: "postgresql" + gen: + go: + package: "authors" + out: "db" + rules: + - no-pg + - no-delete + - only-one-param + - no-exec +rules: + - name: no-pg + message: "invalid engine: postgresql" + rule: | + config.engine == "postgresql" + - name: no-delete + message: "don't use delete statements" + rule: | + query.sql.contains("DELETE") + - name: only-one-param + message: "too many parameters" + rule: | + query.params.size() > 1 + - name: no-exec + message: "don't use exec" + rule: | + query.cmd == "exec" +``` + +##### Database connectivity + +`vet` also marks the first time that `sqlc` can connect to a live, running +database server. We'll expand this functionality over time, but for now it +powers the `sqlc/db-prepare` built-in rule. + +When a [database](config.md#database) is configured, the +`sqlc/db-preapre` rule will attempt to prepare each of your +queries against the connected database and report any failures. + +```yaml +version: 2 +sql: + - schema: "query.sql" + queries: "query.sql" + engine: "postgresql" + gen: + go: + package: "authors" + out: "db" + database: + uri: "postgresql://postgres:password@localhost:5432/postgres" + rules: + - sqlc/db-prepare +``` + +To see this in action, check out the [authors +example](https://github.com/sqlc-dev/sqlc/blob/main/examples/authors/sqlc.yaml). + +Please note that `sqlc` does not manage or migrate your database. Use your +migration tool of choice to create the necessary database tables and objects +before running `sqlc vet`. + +#### Omit unused structs + +Added a new configuration parameter `omit_unused_structs` which, when set to +true, filters out table and enum structs that aren't used in queries for a given +package. + +#### Suggested CI/CD setup + +With the addition of `sqlc diff` and `sqlc vet`, we encourage users to run sqlc +in your CI/CD pipelines. See our [suggested CI/CD setup](../howto/ci-cd.md) for +more information. + +#### Simplified plugin development + +The [sqlc-gen-kotlin](https://github.com/sqlc-dev/sqlc-gen-kotlin) and +[sqlc-gen-python](https://github.com/sqlc-dev/sqlc-gen-python) plugins have been +updated use the upcoming [WASI](https://wasi.dev/) support in [Go +1.21](https://tip.golang.org/doc/go1.21#wasip1). Building these plugins no +longer requires [TinyGo](https://tinygo.org/). + +### Changes + +#### Bug Fixes + +- Pointers overrides skip imports in generated query files (#2240) +- CASE-ELSE clause is not properly parsed when a value is constant (#2238) +- Fix toSnakeCase to handle input in CamelCase format (#2245) +- Add location info to sqlite ast (#2298) +- Add override tags to result struct (#1867) (#1887) +- Override types of aliased columns and named parameters (#1884) +- Resolve duplicate fields generated when inheriting multiple tables (#2089) +- Check column references in ORDER BY (#1411) (#1915) +- MySQL slice shadowing database/sql import (#2332) +- Don't defer rows.Close() if pgx.BatchResults.Query() failed (#2362) +- Fix type overrides not working with sqlc.slice (#2351) +- Type overrides on columns for parameters inside an IN clause (#2352) +- Broken interaction between query_parameter_limit and pq.Array() (#2383) +- (codegen/golang) Bring :execlastid in line with the rest (#2378) + +#### Documentation + +- Update changelog.md with some minor edits (#2235) +- Add F# community plugin (#2295) +- Add a ReadTheDocs config file (#2327) +- Update query_parameter_limit documentation (#2374) +- Add launch announcement banner + +#### Features +- PostgreSQL capture correct line and column numbers for parse error (#2289) +- Add supporting COMMENT ON VIEW (#2249) +- To allow spaces between function name and arguments of functions to be rewritten (#2250) +- Add support for pgx/v5 emit_pointers_for_null_types flag (#2269) +- (mysql) Support unsigned integers (#1746) +- Allow use of table and column aliases for table functions returning unknown types (#2156) +- Support "LIMIT ?" in UPDATE and DELETE for MySQL (#2365) +- (internal/codegen/golang) Omit unused structs from output (#2369) +- Improve default names for BETWEEN ? AND ? to have prefixes from_ and to_ (#2366) +- (cmd/sqlc) Add the vet subcommand (#2344) +- (sqlite) Add support for UPDATE/DELETE with a LIMIT clause (#2384) +- Add support for BETWEEN sqlc.arg(min) AND sqlc.arg(max) (#2373) +- (cmd/vet) Prepare queries against a database (#2387) +- (cmd/vet) Prepare queries for MySQL (#2388) +- (cmd/vet) Prepare SQLite queries (#2389) +- (cmd/vet) Simplify environment variable substiution (#2393) +- (cmd/vet) Add built-in db-prepare rule +- Add compiler support for NOTIFY and LISTEN (PostgreSQL) (#2363) + +#### Miscellaneous Tasks + +- A few small staticcheck fixes (#2361) +- Remove a bunch of dead code (#2360) +- (scripts/regenerate) Should also update stderr.txt (#2379) + +#### Build + +- (deps) Bump requests from 2.25.1 to 2.31.0 in /docs (#2283) +- (deps) Bump golang from 1.20.3 to 1.20.4 (#2256) +- (deps) Bump google.golang.org/grpc from 1.54.0 to 1.55.0 (#2265) +- (deps) Bump github.com/mattn/go-sqlite3 from 1.14.16 to 1.14.17 (#2293) +- (deps) Bump golang.org/x/sync from 0.1.0 to 0.2.0 (#2266) +- (deps) Bump golang from 1.20.4 to 1.20.5 (#2301) +- Configure dependencies via devenv.sh (#2319) +- Configure dependencies via devenv.sh (#2326) +- (deps) Bump golang.org/x/sync from 0.2.0 to 0.3.0 (#2328) +- (deps) Bump google.golang.org/grpc from 1.55.0 to 1.56.0 (#2333) +- (deps) Bump google.golang.org/protobuf from 1.30.0 to 1.31.0 (#2370) +- (deps) Bump actions/checkout from 2 to 3 (#2357) +- Run govulncheck on all builds (#2372) +- (deps) Bump google.golang.org/grpc from 1.56.0 to 1.56.1 (#2358) + +#### Cmd/sqlc + +- Show helpful output on missing subcommand (#2345) + +#### Codegen + +- Use catalog's default schema (#2310) +- (go) Add tests for tables with dashes (#2312) +- (go) Strip invalid characters from table and column names (#2314) +- (go) Support JSON tags for nullable enum structs (#2121) + +#### Internal/config + +- Support golang overrides for slices (#2339) + +#### Kotlin + +- Use latest version of sqlc-gen-kotlin (#2356) + +#### Postgres + +- Column merging for table inheritence (#2315) + +#### Protos + +- Add missing field name (#2354) + +#### Python + +- Use latest version of sqlc-gen-python (#2355) + +#### Remote + +- Use user-id/password auth (#2262) + +#### Sqlite + +- Fixed sqlite column type override (#1986) + + +## [1.18.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.18.0) +Released 2023-04-27 + +### Release notes + +#### Remote code generation + +_Developed by [@andrewmbenton](https://github.com/andrewmbenton)_ + +At its core, sqlc is powered by SQL engines, which include parsers, formatters, +analyzers and more. While our goal is to support each engine on each operating +system, it's not always possible. For example, the PostgreSQL engine does not +work on Windows. + +To bridge that gap, we're announcing remote code generation, currently in +private alpha. To join the private alpha, [sign up for the waitlist](https://docs.google.com/forms/d/e/1FAIpQLScDWrGtTgZWKt3mdlF5R2XCX6tL1pMkB4yuZx5yq684tTNN1Q/viewform?usp=sf_link). + +Remote code generation works like local code generation, except the heavy +lifting is performed in a consistent cloud environment. WASM-based plugins are +supported in the remote environment, but process-based plugins are not. + +To configure remote generation, add a `cloud` block in `sqlc.json`. + +```json +{ + "version": "2", + "cloud": { + "organization": "", + "project": "", + }, + ... +} +``` + +You'll also need to set the `SQLC_AUTH_TOKEN` environment variable. + +```bash +export SQLC_AUTH_TOKEN= +``` + +When the `cloud` configuration block exists, `sqlc generate` will default to remote +code generation. If you'd like to generate code locally without removing the `cloud` +block from your config, pass the `--no-remote` option. + + +```bash +sqlc generate --no-remote +``` + +Remote generation is off by default and requires an opt-in to use. + +#### sqlc.embed + +_Developed by [@nickjackson](https://github.com/nickjackson)_ + +Embedding allows you to reuse existing model structs in more queries, resulting +in less manual serialization work. First, imagine we have the following schema +with students and test scores. + + +```sql +CREATE TABLE students ( + id bigserial PRIMARY KEY, + name text, + age integer +) + +CREATE TABLE test_scores ( + student_id bigint, + score integer, + grade text +) +``` + +We want to select the student record and the highest score they got on a test. +Here's how we'd usually do that: + +```sql +-- name: HighScore :many +WITH high_scores AS ( + SELECT student_id, max(score) as high_score + FROM test_scores + GROUP BY 1 +) +SELECT students.*, high_score::integer +FROM students +JOIN high_scores ON high_scores.student_id = students.id; +``` + +When using Go, sqlc will produce a struct like this: + +``` +type HighScoreRow struct { + ID int64 + Name sql.NullString + Age sql.NullInt32 + HighScore int32 +} +``` + +With embedding, the struct will contain a model for the table instead of a +flattened list of columns. + +```sql +-- name: HighScoreEmbed :many +WITH high_scores AS ( + SELECT student_id, max(score) as high_score + FROM test_scores + GROUP BY 1 +) +SELECT sqlc.embed(students), high_score::integer +FROM students +JOIN high_scores ON high_scores.student_id = students.id; +``` + +``` +type HighScoreRow struct { + Student Student + HighScore int32 +} +``` + +#### sqlc.slice + +_Developed by Paul Cameron and Jille Timmermans_ + +The MySQL Go driver does not support passing slices to the IN operator. The +`sqlc.slice` function generates a dynamic query at runtime with the correct +number of parameters. + +```sql +/* name: SelectStudents :many */ +SELECT * FROM students +WHERE age IN (sqlc.slice("ages")) +``` + +```go +func (q *Queries) SelectStudents(ctx context.Context, ages []int32) ([]Student, error) { +``` + +This feature is only supported in MySQL and cannot be used with prepared +queries. + +#### Batch operation improvements + +When using batches with pgx, the error returned when a batch is closed is +exported by the generated package. This change allows for cleaner error +handling using `errors.Is`. + +```go +errors.Is(err, generated_package.ErrBatchAlreadyClosed) +``` + +Previously, you would have had to check match on the error message itself. + +``` +err.Error() == "batch already closed" +``` + +The generated code for batch operations always lived in `batch.go`. This file +name can now be configured via the `output_batch_file_name` configuration +option. + +#### Configurable query parameter limits for Go + +By default, sqlc will limit Go functions to a single parameter. If a query +includes more than one parameter, the generated method will use an argument +struct instead of positional arguments. This behavior can now be changed via +the `query_parameter_limit` configuration option. If set to `0`, every +genreated method will use a argument struct. + +### Changes + +#### Bug Fixes + +- Prevent variable redeclaration in single param conflict for pgx (#2058) +- Retrieve Larg/Rarg join query after inner join (#2051) +- Rename argument when conflicted to imported package (#2048) +- Pgx closed batch return pointer if need #1959 (#1960) +- Correct singularization of "waves" (#2194) +- Honor Package level renames in v2 yaml config (#2001) +- (mysql) Prevent UPDATE ... JOIN panic #1590 (#2154) +- Mysql delete join panic (#2197) +- Missing import with pointer overrides, solves #2168 #2125 (#2217) + +#### Documentation + +- (config.md) Add `sqlite` as engine option (#2164) +- Add first pass at pgx documentation (#2174) +- Add missed configuration option (#2188) +- `specifies parameter ":one" without containing a RETURNING clause` (#2173) + +#### Features + +- Add `sqlc.embed` to allow model re-use (#1615) +- (Go) Add query_parameter_limit conf to codegen (#1558) +- Add remote execution for codegen (#2214) + +#### Testing + +- Skip tests if required plugins are missing (#2104) +- Add tests for reanme fix in v2 (#2196) +- Regenerate batch output for filename tests +- Remove remote test (#2232) +- Regenerate test output + +#### Bin/sqlc + +- Add SQLCTMPDIR environment variable (#2189) + +#### Build + +- (deps) Bump github.com/antlr/antlr4/runtime/Go/antlr (#2109) +- (deps) Bump github.com/jackc/pgx/v4 from 4.18.0 to 4.18.1 (#2119) +- (deps) Bump golang from 1.20.1 to 1.20.2 (#2135) +- (deps) Bump google.golang.org/protobuf from 1.28.1 to 1.29.0 (#2137) +- (deps) Bump google.golang.org/protobuf from 1.29.0 to 1.29.1 (#2143) +- (deps) Bump golang from 1.20.2 to 1.20.3 (#2192) +- (deps) Bump actions/setup-go from 3 to 4 (#2150) +- (deps) Bump google.golang.org/protobuf from 1.29.1 to 1.30.0 (#2151) +- (deps) Bump github.com/spf13/cobra from 1.6.1 to 1.7.0 (#2193) +- (deps) Bump github.com/lib/pq from 1.10.7 to 1.10.8 (#2211) +- (deps) Bump github.com/lib/pq from 1.10.8 to 1.10.9 (#2229) +- (deps) Bump github.com/go-sql-driver/mysql from 1.7.0 to 1.7.1 (#2228) + +#### Cmd/sqlc + +- Remove --experimental flag (#2170) +- Add option to disable process-based plugins (#2180) +- Bump version to v1.18.0 + +#### Codegen + +- Correctly generate CopyFrom columns for single-column copyfroms (#2185) + +#### Config + +- Add top-level cloud configuration (#2204) + +#### Engine/postgres + +- Upgrade to pg_query_go/v4 (#2114) + +#### Ext/wasm + +- Check exit code on returned error (#2223) + +#### Parser + +- Generate correct types for `SELECT NOT EXISTS` (#1972) + +#### Sqlite + +- Add support for CREATE TABLE ... STRICT (#2175) + +#### Wasm + +- Upgrade to wasmtime v8.0.0 (#2222) + +## [1.17.2](https://github.com/sqlc-dev/sqlc/releases/tag/v1.17.2) +Released 2023-02-22 + +### Bug Fixes + +- Fix build on Windows (#2102) + +## [1.17.1](https://github.com/sqlc-dev/sqlc/releases/tag/v1.17.1) +Released 2023-02-22 + +### Bug Fixes + +- Prefer to use []T over pgype.Array[T] (#2090) +- Revert changes to Dockerfile (#2091) +- Do not throw error when IF NOT EXISTS is used on ADD COLUMN (#2092) + +### MySQL + +- Add `float` support to MySQL (#2097) + +### Build + +- (deps) Bump golang from 1.20.0 to 1.20.1 (#2082) + +## [1.17.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.17.0) +Released 2023-02-13 + +### Bug Fixes + +- Initialize generated code outside function (#1850) +- (engine/mysql) Take into account column's charset to distinguish text/blob, (var)char/(var)binary (#776) (#1895) +- The enum Value method returns correct type (#1996) +- Documentation for Inserting Rows (#2034) +- Add import statements even if only pointer types exist (#2046) +- Search from Rexpr if not found from Lexpr (#2056) + +### Documentation + +- Change ENTRYPOINT to CMD (#1943) +- Update samples for HOW-TO GUIDES (#1953) + +### Features + +- Add the diff command (#1963) + +### Build + +- (deps) Bump github.com/mattn/go-sqlite3 from 1.14.15 to 1.14.16 (#1913) +- (deps) Bump github.com/spf13/cobra from 1.6.0 to 1.6.1 (#1909) +- Fix devcontainer (#1942) +- Run sqlc-pg-gen via GitHub Actions (#1944) +- Move large arrays out of functions (#1947) +- Fix conflicts from pointer configuration (#1950) +- (deps) Bump github.com/go-sql-driver/mysql from 1.6.0 to 1.7.0 (#1988) +- (deps) Bump github.com/jackc/pgtype from 1.12.0 to 1.13.0 (#1978) +- (deps) Bump golang from 1.19.3 to 1.19.4 (#1992) +- (deps) Bump certifi from 2020.12.5 to 2022.12.7 in /docs (#1993) +- (deps) Bump golang from 1.19.4 to 1.19.5 (#2016) +- (deps) Bump golang from 1.19.5 to 1.20.0 (#2045) +- (deps) Bump github.com/jackc/pgtype from 1.13.0 to 1.14.0 (#2062) +- (deps) Bump github.com/jackc/pgx/v4 from 4.17.2 to 4.18.0 (#2063) + +### Cmd + +- Generate packages in parallel (#2026) + +### Cmd/sqlc + +- Bump version to v1.17.0 + +### Codegen + +- Remove built-in Kotlin support (#1935) +- Remove built-in Python support (#1936) + +### Internal/codegen + +- Cache pattern matching compilations (#2028) + +### Mysql + +- Add datatype tests (#1948) +- Fix blob tests (#1949) + +### Plugins + +- Upgrade to wasmtime 3.0.1 (#2009) + +### Sqlite + +- Supported between expr (#1958) (#1967) + +### Tools + +- Regenerate scripts skips dirs that contains diff exec command (#1987) + +### Wasm + +- Upgrade to wasmtime 5.0.0 (#2065) + +## [1.16.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.16.0) +Released 2022-11-09 + + +### Bug Fixes + +- (validate) Sqlc.arg & sqlc.narg are not "missing" (#1814) +- Emit correct comment for nullable enums (#1819) +- 🐛 Correctly switch `coalesce()` result `.NotNull` value (#1664) +- Prevent batch infinite loop with arg length (#1794) +- Support version 2 in error message (#1839) +- Handle empty column list in postgresql (#1843) +- Batch imports filter queries, update cmds having ret type (#1842) +- Named params contribute to batch parameter count (#1841) + +### Documentation + +- Add a getting started guide for SQLite (#1798) +- Various readability improvements (#1854) +- Add documentation for codegen plugins (#1904) +- Update migration guides with links (#1933) + +### Features + +- Add HAVING support to MySQL (#1806) + +### Miscellaneous Tasks + +- Upgrade wasmtime version (#1827) +- Bump wasmtime version to v1.0.0 (#1869) + +### Build + +- (deps) Bump github.com/jackc/pgconn from 1.12.1 to 1.13.0 (#1785) +- (deps) Bump github.com/mattn/go-sqlite3 from 1.14.13 to 1.14.15 (#1799) +- (deps) Bump github.com/jackc/pgx/v4 from 4.16.1 to 4.17.0 (#1786) +- (deps) Bump github.com/jackc/pgx/v4 from 4.17.0 to 4.17.1 (#1825) +- (deps) Bump github.com/bytecodealliance/wasmtime-go (#1826) +- (deps) Bump github.com/jackc/pgx/v4 from 4.17.1 to 4.17.2 (#1831) +- (deps) Bump golang from 1.19.0 to 1.19.1 (#1834) +- (deps) Bump github.com/google/go-cmp from 0.5.8 to 0.5.9 (#1838) +- (deps) Bump github.com/lib/pq from 1.10.6 to 1.10.7 (#1835) +- (deps) Bump github.com/bytecodealliance/wasmtime-go (#1857) +- (deps) Bump github.com/spf13/cobra from 1.5.0 to 1.6.0 (#1893) +- (deps) Bump golang from 1.19.1 to 1.19.3 (#1920) + +### Cmd/sqlc + +- Bump to v1.16.0 + +### Codgen + +- Include serialized codegen options (#1890) + +### Compiler + +- Move Kotlin parameter logic into codegen (#1910) + +### Examples + +- Port Python examples to WASM plugin (#1903) + +### Pg-gen + +- Make sqlc-pg-gen the complete source of truth for pg_catalog.go (#1809) +- Implement information_schema shema (#1815) + +### Python + +- Port all Python tests to sqlc-gen-python (#1907) +- Upgrade to sqlc-gen-python v1.0.0 (#1932) + +## [1.15.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.15.0) +Released 2022-08-07 + +### Bug Fixes + +- (mysql) Typo (#1700) +- (postgresql) Add quotes for CamelCase columns (#1729) +- Cannot parse SQLite upsert statement (#1732) +- (sqlite) Regenerate test output for builtins (#1735) +- (wasm) Version modules by wasmtime version (#1734) +- Missing imports (#1637) +- Missing slice import for querier (#1773) + +### Documentation + +- Add process-based plugin docs (#1669) +- Add links to downloads.sqlc.dev (#1681) +- Update transactions how to example (#1775) + +### Features + +- More SQL Syntax Support for SQLite (#1687) +- (sqlite) Promote SQLite support to beta (#1699) +- Codegen plugins, powered by WASM (#1684) +- Set user-agent for plugin downloads (#1707) +- Null enums types (#1485) +- (sqlite) Support stdlib functions (#1712) +- (sqlite) Add support for returning (#1741) + +### Miscellaneous Tasks + +- Add tests for quoting columns (#1733) +- Remove catalog tests (#1762) + +### Testing + +- Add tests for fixing slice imports (#1736) +- Add test cases for returning (#1737) + +### Build + +- Upgrade to Go 1.19 (#1780) +- Upgrade to go-wasmtime 0.39.0 (#1781) + +### Plugins + +- (wasm) Change default cache location (#1709) +- (wasm) Change the SHA-256 config key (#1710) + +## [1.14.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.14.0) +Released 2022-06-09 + +### Bug Fixes + +- (postgresql) Remove extra newline with db argument (#1417) +- (sqlite) Fix DROP TABLE (#1443) +- (compiler) Fix left join nullability with table aliases (#1491) +- Regenerate testdata for CREATE TABLE AS (#1516) +- (bundler) Only close multipart writer once (#1528) +- (endtoend) Regenerate testdata for exex_lastid +- (pgx) Copyfrom imports (#1626) +- Validate sqlc function arguments (#1633) +- Fixed typo `sql.narg` in doc (#1668) + +### Features + +- (golang) Add Enum.Valid and AllEnumValues (#1613) +- (sqlite) Start expanding support (#1410) +- (pgx) Add support for batch operations (#1437) +- (sqlite) Add support for delete statements (#1447) +- (codegen) Insert comments in interfaces (#1458) +- (sdk) Add the plugin SDK package (#1463) +- Upload projects (#1436) +- Add sqlc version to generated Kotlin code (#1512) +- Add sqlc version to generated Go code (#1513) +- Pass sqlc version in codegen request (#1514) +- (postgresql) Add materialized view support (#1509) +- (python) Graduate Python support to beta (#1520) +- Run sqlc with docker on windows cmd (#1557) +- Add JSON "codegen" output (#1565) +- Add sqlc.narg() for nullable named params (#1536) +- Process-based codegen plugins (#1578) + +### Miscellaneous Tasks + +- Fix extra newline in comments for copyfrom (#1438) +- Generate marshal/unmarshal with vtprotobuf (#1467) + +### Refactor + +- (codegen) Port Kotlin codegen package to use plugin types (#1416) +- (codegen) Port Go to plugin types (#1460) +- (cmd) Simplify codegen selection logic (#1466) +- (sql/catalog) Improve Readability (#1595) +- Add basic fuzzing for config / overrides (#1500) + +## [1.13.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.13.0) +Released 2022-03-31 + +### Bug Fixes + +- (compiler) Fix left join nullability with table aliases (#1491) +- (postgresql) Remove extra newline with db argument (#1417) +- (sqlite) Fix DROP TABLE (#1443) + +### Features + +- (cli) Upload projects (#1436) +- (codegen) Add sqlc version to generated Go code (#1513) +- (codegen) Add sqlc version to generated Kotlin code (#1512) +- (codegen) Insert comments in interfaces (#1458) +- (codegen) Pass sqlc version in codegen request (#1514) +- (pgx) Add support for batch operations (#1437) +- (postgresql) Add materialized view support (#1509) +- (python) Graduate Python support to beta (#1520) +- (sdk) Add the plugin SDK package (#1463) +- (sqlite) Add support for delete statements (#1447) +- (sqlite) Start expanding support (#1410) + +### Miscellaneous Tasks + +- Fix extra newline in comments for copyfrom (#1438) +- Generate marshal/unmarshal with vtprotobuf (#1467) + +### Refactor + +- (codegen) Port Kotlin codegen package to use plugin types (#1416) +- (codegen) Port Go to plugin types (#1460) +- (cmd) Simplify codegen selection logic (#1466) + +### Config + +- Add basic fuzzing for config / overrides (#1500) + +## [1.12.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.12.0) +Released 2022-02-05 + +### Bug + +- ALTER TABLE SET SCHEMA (#1409) + +### Bug Fixes + +- Update ANTLR v4 go.mod entry (#1336) +- Check delete statements for CTEs (#1329) +- Fix validation of GROUP BY on field aliases (#1348) +- Fix imports when non-copyfrom queries needed imports that copyfrom queries didn't (#1386) +- Remove extra comment newline (#1395) +- Enable strict function checking (#1405) + +### Documentation + +- Bump version to 1.11.0 (#1308) + +### Features + +- Inheritance (#1339) +- Generate query code using ASTs instead of templates (#1338) +- Add support for CREATE TABLE a ( LIKE b ) (#1355) +- Add support for sql.NullInt16 (#1376) + +### Miscellaneous Tasks + +- Add tests for :exec{result,rows} (#1344) +- Delete template-based codegen (#1345) + +### Build + +- Bump github.com/jackc/pgx/v4 from 4.14.0 to 4.14.1 (#1316) +- Bump golang from 1.17.3 to 1.17.4 (#1331) +- Bump golang from 1.17.4 to 1.17.5 (#1337) +- Bump github.com/spf13/cobra from 1.2.1 to 1.3.0 (#1343) +- Remove devel Docker build +- Bump golang from 1.17.5 to 1.17.6 (#1369) +- Bump github.com/google/go-cmp from 0.5.6 to 0.5.7 (#1382) +- Format all Go code (#1387) + +## [1.11.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.11.0) +Released 2021-11-24 + + +### Bug Fixes + +- Update incorrect signatures (#1180) +- Correct aggregate func sig (#1182) +- Jsonb_build_object (#1211) +- Case-insensitive identifiers (#1216) +- Incorrect handling of meta (#1228) +- Detect invalid INSERT expression (#1231) +- Respect alias name for coalesce (#1232) +- Mark nullable when casting NULL (#1233) +- Support nullable fields in joins for MySQL engine (#1249) +- Fix between expression handling of table references (#1268) +- Support nullable fields in joins on same table (#1270) +- Fix missing binds in ORDER BY (#1273) +- Set RV for TargetList items on updates (#1252) +- Fix MySQL parser for query without trailing semicolon (#1282) +- Validate table alias references (#1283) +- Add support for MySQL ON DUPLICATE KEY UPDATE (#1286) +- Support references to columns in joined tables in UPDATE statements (#1289) +- Add validation for GROUP BY clause column references (#1285) +- Prevent variable redeclaration in single param conflict (#1298) +- Use common params struct field for same named params (#1296) + +### Documentation + +- Replace deprecated go get with go install (#1181) +- Fix package name referenced in tutorial (#1202) +- Add environment variables (#1264) +- Add go.17+ install instructions (#1280) +- Warn about golang-migrate file order (#1302) + +### Features + +- Instrument compiler via runtime/trace (#1258) +- Add MySQL support for BETWEEN arguments (#1265) + +### Refactor + +- Move from io/ioutil to io and os package (#1164) + +### Styling + +- Apply gofmt to sample code (#1261) + +### Build + +- Bump golang from 1.17.0 to 1.17.1 (#1173) +- Bump eskatos/gradle-command-action from 1 to 2 (#1220) +- Bump golang from 1.17.1 to 1.17.2 (#1227) +- Bump github.com/pganalyze/pg_query_go/v2 (#1234) +- Bump actions/checkout from 2.3.4 to 2.3.5 (#1238) +- Bump babel from 2.9.0 to 2.9.1 in /docs (#1245) +- Bump golang from 1.17.2 to 1.17.3 (#1272) +- Bump actions/checkout from 2.3.5 to 2.4.0 (#1267) +- Bump github.com/lib/pq from 1.10.3 to 1.10.4 (#1278) +- Bump github.com/jackc/pgx/v4 from 4.13.0 to 4.14.0 (#1303) + +### Cmd/sqlc + +- Bump version to v1.11.0 + +## [1.10.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.10.0) +Released 2021-09-07 + + +### Documentation + +- Fix invalid language support table (#1161) +- Add a getting started guide for MySQL (#1163) + +### Build + +- Bump golang from 1.16.7 to 1.17.0 (#1129) +- Bump github.com/lib/pq from 1.10.2 to 1.10.3 (#1160) + +### Ci + +- Upgrade Go to 1.17 (#1130) + +### Cmd/sqlc + +- Bump version to v1.10.0 (#1165) + +### Codegen/golang + +- Consolidate import logic (#1139) +- Add pgx support for range types (#1146) +- Use pgtype for hstore when using pgx (#1156) + +### Codgen/golang + +- Use p[gq]type for network address types (#1142) + +### Endtoend + +- Run `go test` in CI (#1134) + +### Engine/mysql + +- Add support for LIKE (#1162) + +### Golang + +- Output NullUUID when necessary (#1137) + +## [1.9.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.9.0) +Released 2021-08-13 + + +### Documentation + +- Update documentation (a bit) for v1.9.0 (#1117) + +### Build + +- Bump golang from 1.16.6 to 1.16.7 (#1107) + +### Cmd/sqlc + +- Bump version to v1.9.0 (#1121) + +### Compiler + +- Add tests for COALESCE behavior (#1112) +- Handle subqueries in SELECT statements (#1113) + +## [1.8.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.8.0) +Released 2021-05-03 + + +### Documentation + +- Add language support Matrix (#920) + +### Features + +- Add case style config option (#905) + +### Python + +- Eliminate runtime package and use sqlalchemy (#939) + +### Build + +- Bump github.com/google/go-cmp from 0.5.4 to 0.5.5 (#926) +- Bump github.com/lib/pq from 1.9.0 to 1.10.0 (#931) +- Bump golang from 1.16.0 to 1.16.1 (#935) +- Bump golang from 1.16.1 to 1.16.2 (#942) +- Bump github.com/jackc/pgx/v4 from 4.10.1 to 4.11.0 (#956) +- Bump github.com/go-sql-driver/mysql from 1.5.0 to 1.6.0 (#961) +- Bump github.com/pganalyze/pg_query_go/v2 (#965) +- Bump urllib3 from 1.26.3 to 1.26.4 in /docs (#968) +- Bump golang from 1.16.2 to 1.16.3 (#963) +- Bump github.com/lib/pq from 1.10.0 to 1.10.1 (#980) + +### Cmd + +- Add the --experimental flag (#929) +- Fix sqlc init (#959) + +### Cmd/sqlc + +- Bump version to v1.7.1-devel (#913) +- Bump version to v1.8.0 + +### Codegen + +- Generate valid enum names for symbols (#972) + +### Postgresql + +- Support generated columns +- Add test for PRIMARY KEY INCLUDE +- Add tests for CREATE TABLE PARTITION OF +- CREATE TRIGGER EXECUTE FUNCTION +- Add support for renaming types (#971) + +### Sql/ast + +- Resolve return values from functions (#964) + +### Workflows + +- Only run tests once (#924) + +## [1.7.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.7.0) +Released 2021-02-28 + + +### Bug Fixes + +- Struct tag formatting (#833) + +### Documentation + +- Include all the existing Markdown files (#877) +- Split docs into four sections (#882) +- Reorganize and consolidate documentation +- Add link to Windows download (#888) +- Shorten the README (#889) + +### Features + +- Adding support for pgx/v4 +- Adding support for pgx/v4 + +### README + +- Add Go Report Card badge (#891) + +### Build + +- Bump github.com/google/go-cmp from 0.5.3 to 0.5.4 (#813) +- Bump github.com/lib/pq from 1.8.0 to 1.9.0 (#820) +- Bump golang from 1.15.5 to 1.15.6 (#822) +- Bump github.com/jackc/pgx/v4 from 4.9.2 to 4.10.0 (#823) +- Bump github.com/jackc/pgx/v4 from 4.10.0 to 4.10.1 (#839) +- Bump golang from 1.15.6 to 1.15.7 (#855) +- Bump golang from 1.15.7 to 1.15.8 (#881) +- Bump github.com/spf13/cobra from 1.1.1 to 1.1.2 (#892) +- Bump golang from 1.15.8 to 1.16.0 (#897) +- Bump github.com/lfittl/pg_query_go from 1.0.1 to 1.0.2 (#901) +- Bump github.com/spf13/cobra from 1.1.2 to 1.1.3 (#893) + +### Catalog + +- Improve alter column type (#818) + +### Ci + +- Uprade to Go 1.15 (#887) + +### Cmd + +- Allow config file location to be specified (#863) + +### Cmd/sqlc + +- Bump to version v1.6.1-devel (#807) +- Bump version to v1.7.0 (#912) + +### Codegen/golang + +- Make sure to import net package (#858) + +### Compiler + +- Support UNION query + +### Dolphin + +- Generate bools for tinyint(1) +- Support joins in update statements (#883) +- Add support for union query + +### Endtoend + +- Add tests for INTERSECT and EXCEPT + +### Go.mod + +- Update to go 1.15 and run 'go mod tidy' (#808) + +### Mysql + +- Compile tinyint(1) to bool (#873) + +### Sql/ast + +- Add enum values for SetOperation + +## [1.6.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.6.0) +Released 2020-11-23 + + +### Dolphin + +- Implement Rename (#651) +- Skip processing view drops (#653) + +### README + +- Update language / database support (#698) + +### Astutils + +- Fix Params rewrite call (#674) + +### Build + +- Bump golang from 1.14 to 1.15.3 (#765) +- Bump docker/build-push-action from v1 to v2.1.0 (#764) +- Bump github.com/google/go-cmp from 0.4.0 to 0.5.2 (#766) +- Bump github.com/spf13/cobra from 1.0.0 to 1.1.1 (#767) +- Bump github.com/jackc/pgx/v4 from 4.6.0 to 4.9.2 (#768) +- Bump github.com/lfittl/pg_query_go from 1.0.0 to 1.0.1 (#773) +- Bump github.com/google/go-cmp from 0.5.2 to 0.5.3 (#783) +- Bump golang from 1.15.3 to 1.15.5 (#782) +- Bump github.com/lib/pq from 1.4.0 to 1.8.0 (#769) + +### Catalog + +- Improve variadic argument support (#804) + +### Cmd/sqlc + +- Bump to version v1.6.0 (#806) + +### Codegen + +- Fix errant database/sql imports (#789) + +### Compiler + +- Use engine-specific reserved keywords (#677) + +### Dolphi + +- Add list of builtin functions (#795) + +### Dolphin + +- Update to the latest MySQL parser (#665) +- Add ENUM() support (#676) +- Add test for table aliasing (#684) +- Add MySQL ddl_create_table test (#685) +- Implete TRUNCATE table (#697) +- Represent tinyint as int32 (#797) +- Add support for coalesce (#802) +- Add function signatures (#796) + +### Endtoend + +- Add MySQL json test (#692) +- Add MySQL update set multiple test (#696) + +### Examples + +- Use generated enum constants in db_test (#678) +- Port ondeck to MySQL (#680) +- Add MySQL authors example (#682) + +### Internal/cmd + +- Print correct config file on parse failure (#749) + +### Kotlin + +- Remove runtime dependency (#774) + +### Metadata + +- Support multiple comment prefixes (#683) + +### Postgresql + +- Support string concat operator (#701) + +### Sql/catalog + +- Add support for variadic functions (#798) + +## [1.5.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.5.0) +Released 2020-08-05 + + +### Documentation + +- Build sqlc using Go 1.14 (#549) + +### Cmd + +- Add debugging support (#573) + +### Cmd/sqlc + +- Bump version to v1.4.1-devel (#548) +- Bump version to v1.5.0 + +### Compiler + +- Support calling functions with defaults (#635) +- Skip func args without a paramRef (#636) +- Return a single column from coalesce (#639) + +### Config + +- Add emit_empty_slices to version one (#552) + +### Contrib + +- Add generated code for contrib + +### Dinosql + +- Remove deprecated package (#554) + +### Dolphin + +- Add support for column aliasing (#566) +- Implement star expansion for subqueries (#619) +- Implement exapansion with reserved words (#620) +- Implement parameter refs (#621) +- Implement limit and offest (#622) +- Implement inserts (#623) +- Implement delete (#624) +- Implement simple update statements (#625) +- Implement INSERT ... SELECT (#626) +- Use test driver instead of TiDB driver (#629) +- Implement named parameters via sqlc.arg() (#632) + +### Endtoend + +- Add MySQL test for SELECT * JOIN (#565) +- Add MySQL test for inflection (#567) + +### Engine + +- Create engine package (#556) + +### Equinox + +- Use the new equinox-io/setup action (#586) + +### Examples + +- Run tests for MySQL booktest (#627) + +### Golang + +- Add support for the money type (#561) +- Generate correct types for int2 and int8 (#579) + +### Internal + +- Rm catalog, pg, postgres packages (#555) + +### Mod + +- Downgrade TiDB package to fix build (#603) + +### Mysql + +- Upgrade to the latest vitess commit (#562) +- Support to infer type of a duplicated arg (#615) +- Allow some builtin functions to be nullable (#616) + +### Postgresql + +- Generate all functions in pg_catalog (#550) +- Remove pg_catalog schema from tests (#638) +- Move contrib code to a package + +### Sql/catalog + +- Fix comparison of pg_catalog types (#637) + +### Tools + +- Generate functions for all of contrib + +### Workflow + +- Migrate to equinox-io/setup-release-tool (#614) + +## [1.4.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.4.0) +Released 2020-06-17 + + +### Dockerfile + +- Add version build argument (#487) + +### MySQL + +- Prevent Panic when WHERE clause contains parenthesis. (#531) + +### README + +- Document emit_exact_table_names (#486) + +### All + +- Remove the exp build tag (#507) + +### Catalog + +- Support functions with table parameters (#541) + +### Cmd + +- Bump to version 1.3.1-devel (#485) + +### Cmd/sqlc + +- Bump version to v1.4.0 (#547) + +### Codegen + +- Add the new codegen packages (#513) +- Add the :execresult query annotation (#542) + +### Compiler + +- Validate function calls (#505) +- Port bottom of parseQuery (#510) +- Don't mutate table name (#517) +- Enable experimental parser by default (#518) +- Apply rename rules to enum constants (#523) +- Temp fix for typecast function parameters (#530) + +### Endtoend + +- Standardize JSON formatting (#490) +- Add per-test configuration files (#521) +- Read expected stderr failures from disk (#527) + +### Internal/dinosql + +- Check parameter style before ref (#488) +- Remove unneeded column suffix (#492) +- Support named function arguments (#494) + +### Internal/postgresql + +- Fix NamedArgExpr rewrite (#491) + +### Multierr + +- Move dinosql.ParserErr to a new package (#496) + +### Named + +- Port parameter style validation to SQL (#504) + +### Parser + +- Support columns from subselect statements (#489) + +### Rewrite + +- Move parameter rewrite to package (#499) + +### Sqlite + +- Use convert functions instead of the listener (#519) + +### Sqlpath + +- Move ReadSQLFiles into a separate package (#495) + +### Validation + +- Move query validation to separate package (#498) + +## [1.3.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.3.0) +Released 2020-05-12 + + +### Makefile + +- Update target (#449) + +### README + +- Add Myles as a sponsor (#469) + +### Testing + +- Make sure all Go examples build (#480) + +### Cmd + +- Bump version to v1.3.0 (#484) + +### Cmd/sqlc + +- Bump version to v1.2.1-devel (#442) + +### Dinosql + +- Inline addFile (#446) +- Add PostgreSQL support for TRUNCATE (#448) + +### Gen + +- Emit json.RawMessage for JSON columns (#461) + +### Go.mod + +- Use latest lib/pq (#471) + +### Parser + +- Use same function to load SQL files (#483) + +### Postgresql + +- Fix panic walking CreateTableAsStmt (#475) + +## [1.2.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.2.0) +Released 2020-04-07 + + +### Documentation + +- Publish to Docker Hub (#422) + +### README + +- Docker installation docs (#424) + +### Cmd/sqlc + +- Bump version to v1.1.1-devel (#407) +- Bump version to v1.2.0 (#441) + +### Gen + +- Add special case for "campus" (#435) +- Properly quote reserved keywords on expansion (#436) + +### Migrations + +- Move migration parsing to new package (#427) + +### Parser + +- Generate correct types for SELECT EXISTS (#411) + +## [1.1.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.1.0) +Released 2020-03-17 + + +### README + +- Add installation instructions (#350) +- Add section on running tests (#357) +- Fix typo (#371) + +### Ast + +- Add AST for ALTER TABLE ADD / DROP COLUMN (#376) +- Add support for CREATE TYPE as ENUM (#388) +- Add support for CREATE / DROP SCHEMA (#389) + +### Astutils + +- Apply changes to the ValuesList slice (#372) + +### Cmd + +- Return v1.0.0 (#348) +- Return next bug fix version (#349) + +### Cmd/sqlc + +- Bump version to v1.1.0 (#406) + +### Compiler + +- Wire up the experimental parsers + +### Config + +- Remove "emit_single_file" option (#367) + +### Dolphin + +- Add experimental parser for MySQL + +### Gen + +- Add option to emit single file for Go (#366) +- Add support for the ltree extension (#385) + +### Go.mod + +- Add packages for MySQL and SQLite parsers + +### Internal/dinosql + +- Support Postgres macaddr type in Go (#358) + +### Internal/endtoend + +- Remove %w (#354) + +### Kotlin + +- Add Query class to support timeout and cancellation (#368) + +### Postgresql + +- Add experimental parser for MySQL + +### Sql + +- Add generic SQL AST + +### Sql/ast + +- Port support for COMMENT ON (#391) +- Implement DROP TYPE (#397) +- Implement ALTER TABLE RENAME (#398) +- Implement ALTER TABLE RENAME column (#399) +- Implement ALTER TABLE SET SCHEMA (#400) + +### Sql/catalog + +- Port tests over from catalog pkg (#402) + +### Sql/errors + +- Add a new errors package (#390) + +### Sqlite + +- Add experimental parser for SQLite + +## [1.0.0](https://github.com/sqlc-dev/sqlc/releases/tag/v1.0.0) +Released 2020-02-18 + + +### Documentation + +- Add documentation for query commands (#270) +- Add named parameter documentation (#332) + +### README + +- Add sponsors section (#333) + +### Cmd + +- Remove parse subcommand (#322) + +### Config + +- Parse V2 config format +- Add support for YAML (#336) + +### Examples + +- Add the jets and booktest examples (#237) +- Move sqlc.json into examples folder (#238) +- Add the authors example (#241) +- Add build tag to authors tests (#319) + +### Internal + +- Allow CTE to be used with UPDATE (#268) +- Remove the PackageMap from settings (#295) + +### Internal/config + +- Create new config package (#313) + +### Internal/dinosql + +- Emit Querier interface (#240) +- Strip leading "go-" or trailing "-go" from import (#262) +- Overrides can now be basic types (#271) +- Import needed types for Querier (#285) +- Handle schema-scoped enums (#310) +- Ignore golang-migrate rollbacks (#320) + +### Internal/endtoend + +- Move more tests to the record/replay framework +- Add update test for named params (#329) + +### Internal/mysql + +- Fix flaky test (#242) +- Port tests to endtoend package (#315) + +### Internal/parser + +- Resolve nested CTEs (#324) +- Error if last query is missing (#325) +- Support joins with aliases (#326) +- Remove print statement (#327) + +### Internal/sqlc + +- Add support for composite types (#311) + +### Kotlin + +- Support primitives +- Arrays, enums, and dates +- Generate examples +- README for examples +- Factor out db setup extension +- Fix enums, use List instead of Array +- Port Go tests for examples +- Rewrite numbered params to positional params +- Always use use, fix indents +- Unbox query params + +### Parser + +- Attach range vars to insert params +- Attach range vars to insert params (#342) +- Remove dead code (#343) + +## [0.1.0](https://github.com/sqlc-dev/sqlc/releases/tag/v0.1.0) +Released 2020-01-07 + + +### Documentation + +- Replace remaining references to DinoSQL with sqlc (#149) + +### README + +- Fix download links (#66) +- Add LIMIT 1 to query that should return one (#99) + +### Catalog + +- Support "ALTER TABLE ... DROP CONSTRAINT ..." (#34) +- Differentiate functions with different argument types (#51) + +### Ci + +- Enable tests on pull requests + +### Cmd + +- Include filenames in error messages (#69) +- Do not output any changes on error (#72) + +### Dinosql/internal + +- Add lower and upper functions (#215) +- Ignore alter sequence commands (#219) + +### Gen + +- Add DO NOT EDIT comments to generated code (#50) +- Include all schemas when generating models (#90) +- Prefix structs with schema name (#91) +- Generate single import for uuid package (#98) +- Use same import logic for all Go files +- Pick correct struct to return for queries (#107) +- Create consistent JSON tags (#110) +- Add Close method to Queries struct (#127) +- Ignore empty override settings (#128) +- Turn SQL comments into Go comments (#136) + +### Internal/catalog + +- Parse unnamed function arguments (#166) + +### Internal/dinosql + +- Prepare() with no GoQueries still valid (#95) +- Fix multiline comment rendering (#142) +- Dereference alias nodes on walk (#158) +- Ignore sql-migrate rollbacks (#160) +- Sort imported packages (#165) +- Add support for timestamptz (#169) +- Error on missing queries (#180) +- Use more database/sql null types (#182) +- Support the pg_temp schema (#183) +- Override columns with array type (#184) +- Implement robust expansion +- Implement robust expansion (#186) +- Add COMMENT ON support (#191) +- Add DATE support +- Add DATE support (#196) +- Filter out invalid characters (#198) +- Quote reserved keywords (#205) +- Return parser errors first (#207) +- Implement advisory locks (#212) +- Error on duplicate query names (#221) +- Fix incorrect enum names (#223) +- Add support for numeric types +- Add support for numeric types (#228) + +### Internal/dinosql/testdata/ondeck + +- Add Makefile (#156) + +### Ondeck + +- Move all tests to GitHub CI (#58) + +### ParseQuery + +- Return either a query or an error (#178) + +### Parser + +- Use schema when resolving catalog refs (#82) +- Support function calls in expressions (#104) +- Correctly handle single files (#119) +- Return error if missing RETURNING (#131) +- Add support for mathmatical operators (#132) +- Add support for simple case expressions (#134) +- Error on mismatched INSERT input (#135) +- Set IsArray on joined columns (#139) + +### Pg + +- Store functions in the catalog (#41) +- Add location to errors (#73) + + diff --git a/docs/reference/cli.md b/docs/reference/cli.md new file mode 100644 index 0000000..286467a --- /dev/null +++ b/docs/reference/cli.md @@ -0,0 +1,29 @@ +# CLI + +```sh +Usage: + sqlc [command] + +Available Commands: + analyze Analyze a query against a schema and output the result columns and parameters + compile Statically check SQL for syntax and type errors + completion Generate the autocompletion script for the specified shell + createdb Create an ephemeral database + diff Compare the generated files to the existing files + fmt Format SQL queries + generate Generate source code from SQL + help Help about any command + init Create an empty sqlc.yaml settings file + parse Parse SQL and output the AST as JSON + push Push the schema, queries, and configuration for this project + verify Verify schema, queries, and configuration for this project + version Print the sqlc version number + vet Vet examines queries + +Flags: + -f, --file string specify an alternate config file (default: sqlc.yaml) + -h, --help help for sqlc + --no-database disable database connections (default: false) + +Use "sqlc [command] --help" for more information about a command. +``` diff --git a/docs/reference/config.md b/docs/reference/config.md new file mode 100644 index 0000000..15fdb7c --- /dev/null +++ b/docs/reference/config.md @@ -0,0 +1,501 @@ +# Configuration + +The `sqlc` tool is configured via a `sqlc.(yaml|yml)` or `sqlc.json` file. This +file must be in the directory where the `sqlc` command is run. + +## Version 2 + +```yaml +version: "2" +cloud: + project: "" +sql: +- schema: "postgresql/schema.sql" + queries: "postgresql/query.sql" + engine: "postgresql" + gen: + go: + package: "authors" + out: "postgresql" + database: + managed: true + rules: + - sqlc/db-prepare +- schema: "mysql/schema.sql" + queries: "mysql/query.sql" + engine: "mysql" + gen: + go: + package: "authors" + out: "mysql" +``` + +### sql + +Each mapping in the `sql` collection has the following keys: + +- `name`: + - An human-friendly identifier for this query set. Optional. +- `engine`: + - One of `postgresql`, `mysql` or `sqlite`. +- `schema`: + - Directory of SQL migrations or path to single SQL file; or a list of paths. +- `queries`: + - Directory of SQL queries or path to single SQL file; or a list of paths. +- `codegen`: + - A collection of mappings to configure code generators. See [codegen](#codegen) for the supported keys. +- `gen`: + - A mapping to configure built-in code generators. See [gen](#gen) for the supported keys. +- `database`: + - A mapping to configure database connections. See [database](#database) for the supported keys. +- `rules`: + - A collection of rule names to run via `sqlc vet`. See [rules](#rules) for configuration options. +- `analyzer`: + - A mapping to configure query analysis. See [analyzer](#analyzer) for the supported keys. +- `strict_function_checks` + - If true, return an error if a called SQL function does not exist. Defaults to `false`. +- `strict_order_by` + - If true, return an error if a order by column is ambiguous. Defaults to `true`. + +### codegen + +The `codegen` mapping supports the following keys: + +- `out`: + - Output directory for generated code. +- `plugin`: + - The name of the plugin. Must be defined in the `plugins` collection. +- `options`: + - A mapping of plugin-specific options. + +```yaml +version: '2' +plugins: +- name: py + wasm: + url: https://github.com/sqlc-dev/sqlc-gen-python/releases/download/v0.16.0-alpha/sqlc-gen-python.wasm + sha256: 428476c7408fd4c032da4ec74e8a7344f4fa75e0f98a5a3302f238283b9b95f2 +sql: +- schema: "schema.sql" + queries: "query.sql" + engine: postgresql + codegen: + - out: src/authors + plugin: py + options: + package: authors + emit_sync_querier: true + emit_async_querier: true + query_parameter_limit: 5 +``` + +### database + +The `database` mapping supports the following keys: + +- `managed`: + - If true, connect to a [managed database](../howto/managed-databases.md). Defaults to `false`. +- `uri`: + - Database connection URI + +The `uri` string can contain references to environment variables using the `${...}` +syntax. In the following example, the connection string will have the value of +the `PG_PASSWORD` environment variable set as its password. + +```yaml +version: '2' +sql: +- schema: schema.sql + queries: query.sql + engine: postgresql + database: + uri: postgresql://postgres:${PG_PASSWORD}@localhost:5432/authors + gen: + go: + package: authors + out: postgresql +``` + +### analyzer + +The `analyzer` mapping supports the following keys: + +- `database`: + - If false, do not use the configured database for query analysis. Defaults to `true`. + +### gen + +The `gen` mapping supports the following keys: + +#### go + +- `package`: + - The package name to use for the generated code. Defaults to `out` basename. +- `out`: + - Output directory for generated code. +- `sql_package`: + - Either `pgx/v4`, `pgx/v5` or `database/sql`. Defaults to `database/sql`. +- `sql_driver`: + - Either `github.com/jackc/pgx/v4`, `github.com/jackc/pgx/v5`, `github.com/lib/pq` or `github.com/go-sql-driver/mysql`. No defaults. Required if query annotation `:copyfrom` is used. +- `emit_db_tags`: + - If true, add DB tags to generated structs. Defaults to `false`. +- `emit_prepared_queries`: + - If true, include support for prepared queries. Defaults to `false`. +- `emit_interface`: + - If true, output a `Querier` interface in the generated package. Defaults to `false`. +- `emit_exact_table_names`: + - If true, struct names will mirror table names. Otherwise, sqlc attempts to singularize plural table names. Defaults to `false`. +- `emit_empty_slices`: + - If true, slices returned by `:many` queries will be empty instead of `nil`. Defaults to `false`. +- `emit_exported_queries`: + - If true, autogenerated SQL statement can be exported to be accessed by another package. +- `emit_json_tags`: + - If true, add JSON tags to generated structs. Defaults to `false`. +- `emit_result_struct_pointers`: + - If true, query results are returned as pointers to structs. Queries returning multiple results are returned as slices of pointers. Defaults to `false`. +- `emit_params_struct_pointers`: + - If true, parameters are passed as pointers to structs. Defaults to `false`. +- `emit_methods_with_db_argument`: + - If true, generated methods will accept a DBTX argument instead of storing a DBTX on the `*Queries` struct. Defaults to `false`. +- `emit_pointers_for_null_types`: + - If true, generated types for nullable columns are emitted as pointers (ie. `*string`) instead of `database/sql` null types (ie. `NullString`). Currently only supported for PostgreSQL if `sql_package` is `pgx/v4` or `pgx/v5`, and for SQLite. Defaults to `false`. Nullable enum columns also follow this setting unless `emit_pointers_for_null_enum_types` is set. +- `emit_pointers_for_null_enum_types`: + - Overrides `emit_pointers_for_null_types` for nullable enum columns only. When `true`, nullable enum columns are emitted as pointers (ie. `*UserRole`). When `false`, nullable enum columns use the generated `NullUserRole` wrapper struct even if `emit_pointers_for_null_types` is true. Set this to `false` to keep the pre-v1.31 behavior when upgrading. Only applies to PostgreSQL with `sql_package` `pgx/v4` or `pgx/v5`. +- `emit_enum_valid_method`: + - If true, generate a Valid method on enum types, + indicating whether a string is a valid enum value. +- `emit_all_enum_values`: + - If true, emit a function per enum type + that returns all valid enum values. +- `emit_sql_as_comment`: + - If true, emits the SQL statement as a code-block comment above the generated function, appending to any existing comments. Defaults to `false`. +- `build_tags`: + - If set, add a `//go:build ` directive at the beginning of each generated Go file. +- `initialisms`: + - An array of [initialisms](https://google.github.io/styleguide/go/decisions.html#initialisms) to upper-case. For example, `app_id` becomes `AppID`. Defaults to `["id"]`. +- `json_tags_id_uppercase`: + - If true, "Id" in json tags will be uppercase. If false, will be camelcase. Defaults to `false` +- `json_tags_case_style`: + - `camel` for camelCase, `pascal` for PascalCase, `snake` for snake_case or `none` to use the column name in the DB. Defaults to `none`. +- `omit_unused_structs`: + - If `true`, sqlc won't generate table and enum structs that aren't used in queries for a given package. Defaults to `false`. +- `output_batch_file_name`: + - Customize the name of the batch file. Defaults to `batch.go`. +- `output_db_file_name`: + - Customize the name of the db file. Defaults to `db.go`. +- `output_models_file_name`: + - Customize the name of the models file. Defaults to `models.go`. +- `output_querier_file_name`: + - Customize the name of the querier file. Defaults to `querier.go`. +- `output_copyfrom_file_name`: + - Customize the name of the copyfrom file. Defaults to `copyfrom.go`. +- `output_files_suffix`: + - If specified the suffix will be added to the name of the generated files. +- `query_parameter_limit`: + - The number of positional arguments that will be generated for Go functions. To always emit a parameter struct, set this to `0`. Defaults to `1`. +- `rename`: + - Customize the name of generated struct fields. See [Renaming fields](../howto/rename.md) for usage information. +- `overrides`: + - A collection of configurations to override sqlc's default Go type choices. See [Overriding types](../howto/overrides.md) for usage information. + +##### overrides + +See [Overriding types](../howto/overrides.md) for an in-depth guide to using type overrides. + +#### kotlin + +> Removed in v1.17.0 and replaced by the [sqlc-gen-kotlin](https://github.com/sqlc-dev/sqlc-gen-kotlin) plugin. Follow the [migration guide](../guides/migrating-to-sqlc-gen-kotlin.md) to switch. + +- `package`: + - The package name to use for the generated code. +- `out`: + - Output directory for generated code. +- `emit_exact_table_names`: + - If true, use the exact table name for generated models. Otherwise, guess a singular form. Defaults to `false`. + +#### python + +> Removed in v1.17.0 and replaced by the [sqlc-gen-python](https://github.com/sqlc-dev/sqlc-gen-python) plugin. Follow the [migration guide](../guides/migrating-to-sqlc-gen-python.md) to switch. + +- `package`: + - The package name to use for the generated code. +- `out`: + - Output directory for generated code. +- `emit_exact_table_names`: + - If true, use the exact table name for generated models. Otherwise, guess a singular form. Defaults to `false`. +- `emit_sync_querier`: + - If true, generate a class with synchronous methods. Defaults to `false`. +- `emit_async_querier`: + - If true, generate a class with asynchronous methods. Defaults to `false`. +- `emit_pydantic_models`: + - If true, generate classes that inherit from `pydantic.BaseModel`. Otherwise, define classes using the `dataclass` decorator. Defaults to `false`. + +#### json + +- `out`: + - Output directory for the generated JSON. +- `filename`: + - Filename for the generated JSON document. Defaults to `codegen_request.json`. +- `indent`: + - Indent string to use in the JSON document. Defaults to ` `. + +### plugins + +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 + - `format`: + - The format expected. Supports `json` and `protobuf` formats. Defaults to `protobuf`. +- `wasm`: A mapping with a two keys `url` and `sha256` + - `url`: + - The URL to fetch the WASM file. Supports the `https://` or `file://` schemes. + - `sha256` + - The SHA256 checksum for the downloaded file. + +```yaml +version: "2" +plugins: +- name: "py" + wasm: + 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" +``` + +### rules + +Each mapping in the `rules` collection has the following keys: + +- `name`: + - The name of this rule. Required +- `rule`: + - A [Common Expression Language (CEL)](https://github.com/google/cel-spec) expression. Required. +- `message`: + - An optional message shown when this rule evaluates to `true`. + +See the [vet](../howto/vet.md) documentation for a list of built-in rules and +help writing custom rules. + +```yaml +version: "2" +sql: + - schema: "query.sql" + queries: "query.sql" + engine: "postgresql" + gen: + go: + package: "authors" + out: "db" + rules: + - no-pg + - no-delete + - only-one-param + - no-exec +rules: + - name: no-pg + message: "invalid engine: postgresql" + rule: | + config.engine == "postgresql" + - name: no-delete + message: "don't use delete statements" + rule: | + query.sql.contains("DELETE") + - name: only-one-param + message: "too many parameters" + rule: | + query.params.size() > 1 + - name: no-exec + message: "don't use exec" + rule: | + query.cmd == "exec" +``` + +### Global overrides + +Sometimes, the same configuration must be done across various specifications of +code generation. Then a global definition for type overriding and field +renaming can be done using the `overrides` mapping the following manner: + +```yaml +version: "2" +overrides: + go: + rename: + id: "Identifier" + overrides: + - db_type: "pg_catalog.timestamptz" + nullable: true + engine: "postgresql" + go_type: + import: "gopkg.in/guregu/null.v4" + package: "null" + type: "Time" +sql: +- schema: "postgresql/schema.sql" + queries: "postgresql/query.sql" + engine: "postgresql" + gen: + go: + package: "authors" + out: "postgresql" +- schema: "mysql/schema.sql" + queries: "mysql/query.sql" + engine: "mysql" + gen: + go: + package: "authors" + out: "mysql" +``` + +With the previous configuration, whenever a struct field is generated from a +table column that is called `id`, it will generated as `Identifier`. + +Also, whenever there is a nullable `timestamp with time zone` column in a +Postgres table, it will be generated as `null.Time`. Note that the mapping for +global type overrides has a field called `engine` that is absent in the regular +type overrides. This field is only used when there are multiple definitions +using multiple engines. Otherwise, the value of the `engine` key +defaults to the engine that is currently being used. + +Currently, type overrides and field renaming, both global and regular, are only +fully supported in Go. + +## Version 1 + +```yaml +version: "1" +packages: + - name: "db" + path: "internal/db" + queries: "./sql/query/" + schema: "./sql/schema/" + engine: "postgresql" + emit_db_tags: false + emit_prepared_queries: true + emit_interface: false + emit_exact_table_names: false + emit_empty_slices: false + emit_exported_queries: false + emit_json_tags: true + emit_result_struct_pointers: false + emit_params_struct_pointers: false + emit_methods_with_db_argument: false + emit_pointers_for_null_types: false + emit_enum_valid_method: false + emit_all_enum_values: false + build_tags: "some_tag" + json_tags_case_style: "camel" + omit_unused_structs: false + output_batch_file_name: "batch.go" + output_db_file_name: "db.go" + output_models_file_name: "models.go" + output_querier_file_name: "querier.go" + output_copyfrom_file_name: "copyfrom.go" + query_parameter_limit: 1 +``` + +### packages + +Each mapping in the `packages` collection has the following keys: + +- `name`: + - The package name to use for the generated code. Defaults to `path` basename. +- `path`: + - Output directory for generated code. +- `queries`: + - Directory of SQL queries or path to single SQL file; or a list of paths. +- `schema`: + - Directory of SQL migrations or path to single SQL file; or a list of paths. +- `engine`: + - Either `postgresql` or `mysql`. Defaults to `postgresql`. +- `sql_package`: + - Either `pgx/v4`, `pgx/v5` or `database/sql`. Defaults to `database/sql`. +- `overrides`: + - A list of type override configurations. See the [Overriding types](../howto/overrides.md) guide for details. +- `emit_db_tags`: + - If true, add DB tags to generated structs. Defaults to `false`. +- `emit_prepared_queries`: + - If true, include support for prepared queries. Defaults to `false`. +- `emit_interface`: + - If true, output a `Querier` interface in the generated package. Defaults to `false`. +- `emit_exact_table_names`: + - If true, struct names will mirror table names. Otherwise, sqlc attempts to singularize plural table names. Defaults to `false`. +- `emit_empty_slices`: + - If true, slices returned by `:many` queries will be empty instead of `nil`. Defaults to `false`. +- `emit_exported_queries`: + - If true, autogenerated SQL statement can be exported to be accessed by another package. +- `emit_json_tags`: + - If true, add JSON tags to generated structs. Defaults to `false`. +- `emit_result_struct_pointers`: + - If true, query results are returned as pointers to structs. Queries returning multiple results are returned as slices of pointers. Defaults to `false`. +- `emit_params_struct_pointers`: + - If true, parameters are passed as pointers to structs. Defaults to `false`. +- `emit_methods_with_db_argument`: + - If true, generated methods will accept a DBTX argument instead of storing a DBTX on the `*Queries` struct. Defaults to `false`. +- `emit_pointers_for_null_types`: + - If true and `sql_package` is set to `pgx/v4` or `pgx/v5`, generated types for nullable columns are emitted as pointers (ie. `*string`) instead of `database/sql` null types (ie. `NullString`). Defaults to `false`. Nullable enum columns also follow this setting unless `emit_pointers_for_null_enum_types` is set. +- `emit_pointers_for_null_enum_types`: + - Overrides `emit_pointers_for_null_types` for nullable enum columns only. When `true`, nullable enum columns are emitted as pointers (ie. `*UserRole`). When `false`, nullable enum columns use the generated `NullUserRole` wrapper struct even if `emit_pointers_for_null_types` is true. Set this to `false` to keep the pre-v1.31 behavior when upgrading. Only applies to PostgreSQL with `sql_package` `pgx/v4` or `pgx/v5`. +- `emit_enum_valid_method`: + - If true, generate a Valid method on enum types, + indicating whether a string is a valid enum value. +- `emit_all_enum_values`: + - If true, emit a function per enum type + that returns all valid enum values. +- `build_tags`: + - If set, add a `//go:build ` directive at the beginning of each generated Go file. +- `json_tags_case_style`: + - `camel` for camelCase, `pascal` for PascalCase, `snake` for snake_case or `none` to use the column name in the DB. Defaults to `none`. +- `omit_unused_structs`: + - If `true`, sqlc won't generate table and enum structs that aren't used in queries for a given package. Defaults to `false`. +- `output_batch_file_name`: + - Customize the name of the batch file. Defaults to `batch.go`. +- `output_db_file_name`: + - Customize the name of the db file. Defaults to `db.go`. +- `output_models_file_name`: + - Customize the name of the models file. Defaults to `models.go`. +- `output_querier_file_name`: + - Customize the name of the querier file. Defaults to `querier.go`. +- `output_copyfrom_file_name`: + - Customize the name of the copyfrom file. Defaults to `copyfrom.go`. +- `output_files_suffix`: + - If specified the suffix will be added to the name of the generated files. +- `query_parameter_limit`: + - Positional arguments that will be generated in Go functions (`>= 0`). To always emit a parameter struct, you would need to set it to `0`. Defaults to `1`. + +### overrides + +See the version 1 configuration section of the [Overriding types](../howto/overrides.md#version-1-configuration) guide for details. + +### rename + +Struct field names are generated from column names using a simple algorithm: +split the column name on underscores and capitalize the first letter of each +part. + +``` +account -> Account +spotify_url -> SpotifyUrl +app_id -> AppID +``` + +If you're not happy with a field's generated name, use the `rename` mapping +to pick a new name. The keys are column names and the values are the struct +field name to use. + +```yaml +version: "1" +packages: [...] +rename: + spotify_url: "SpotifyURL" +``` diff --git a/docs/reference/datatypes.md b/docs/reference/datatypes.md new file mode 100644 index 0000000..651e1c0 --- /dev/null +++ b/docs/reference/datatypes.md @@ -0,0 +1,388 @@ +# Datatypes + +`sqlc` attempts to make reasonable default choices when mapping internal +database types to Go types. Choices for more complex types are described below. + +If you're unsatisfied with the default, you can override any type using the +[overrides list](config.md#overrides) in your `sqlc` config file. + +## Arrays + +PostgreSQL [arrays](https://www.postgresql.org/docs/current/arrays.html) are +materialized as Go slices. + +```sql +CREATE TABLE places ( + name text not null, + tags text[] +); +``` + +```go +package db + +type Place struct { + Name string + Tags []string +} +``` + +## Dates and times + +All date and time types are returned as `time.Time` structs. For +null time or date values, the `NullTime` type from `database/sql` is used. + +The `pgx/v5` sql package uses the appropriate pgx types. + +For MySQL users relying on `github.com/go-sql-driver/mysql`, ensure that +`parseTime=true` is added to your database connection string. + +```sql +CREATE TABLE authors ( + id SERIAL PRIMARY KEY, + created_at timestamp NOT NULL DEFAULT NOW(), + updated_at timestamp +); +``` + +```go +package db + +import ( + "database/sql" + "time" +) + +type Author struct { + ID int + CreatedAt time.Time + UpdatedAt sql.NullTime +} +``` + +## Enums + +PostgreSQL [enums](https://www.postgresql.org/docs/current/datatype-enum.html) are +mapped to an aliased string type. + +```sql +CREATE TYPE status AS ENUM ( + 'open', + 'closed' +); + +CREATE TABLE stores ( + name text PRIMARY KEY, + status status NOT NULL +); +``` + +```go +package db + +type Status string + +const ( + StatusOpen Status = "open" + StatusClosed Status = "closed" +) + +type Store struct { + Name string + Status Status +} +``` + +## Null + +For structs, null values are represented using the appropriate type from the +`database/sql` or `pgx` package. + +```sql +CREATE TABLE authors ( + id SERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); +``` + +```go +package db + +import ( + "database/sql" +) + +type Author struct { + ID int + Name string + Bio sql.NullString +} +``` + +## UUIDs + +For UUID support, sqlc uses the `github.com/google/uuid` package by default. +The pgx/v5 sql package uses `pgtype.UUID`. + +```sql +CREATE TABLE records ( + id uuid PRIMARY KEY +); +``` + +```go +package db + +import ( + "github.com/google/uuid" +) + +type Author struct { + ID uuid.UUID +} +``` + +### Using the standard library uuid package + +Go 1.27 added a [`uuid`](https://pkg.go.dev/uuid) package to the standard +library. sqlc will use this package by default in a future release. Until +then, use it today with type overrides +(see [Overriding types](../howto/overrides.md) for details). + +Two overrides are required: one for non-nullable columns and one for nullable +columns. The standard library does not include a `NullUUID` type, so nullable +columns map to `*uuid.UUID` instead. + +```yaml +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "db" + out: "db" + sql_package: "pgx/v5" + overrides: + - db_type: "uuid" + go_type: "uuid.UUID" + - db_type: "uuid" + nullable: true + go_type: + import: "uuid" + type: "UUID" + pointer: true +``` + +With this configuration, a table with both nullable and non-nullable `uuid` +columns: + +```sql +CREATE TABLE records ( + id uuid PRIMARY KEY, + external_id uuid +); +``` + +generates: + +```go +package db + +import ( + "uuid" +) + +type Record struct { + ID uuid.UUID + ExternalID *uuid.UUID +} +``` + +These overrides work with both the `pgx/v5` and `database/sql` sql packages. +pgx supports any type whose underlying type is `[16]byte`, and as of Go 1.27 +`database/sql` converts `uuid.UUID` values in both directions: parameters are +bound via `driver.DefaultParameterConverter` and results are scanned into +`uuid.UUID` and `*uuid.UUID` destinations, with `nil` representing `NULL`. + +For MySQL, there is no native `uuid` data type. When using `UUID_TO_BIN` to store a `UUID()`, the underlying field type is `BINARY(16)` which by default sqlc would map to `sql.NullString`. To have sqlc automatically convert these fields to a `uuid.UUID` type, use an overide on the column storing the `uuid` +(see [Overriding types](../howto/overrides.md) for details). + +```json +{ + "overrides": [ + { + "column": "*.uuid", + "go_type": "github.com/google/uuid.UUID" + } + ] +} +``` + +## JSON + +By default, sqlc will generate the `[]byte`, `pgtype.JSON` or `json.RawMessage` for JSON column type. +But if you use the `pgx/v5` sql package then you can specify a struct instead of the default type +(see [Overriding types](../howto/overrides.md) for details). +The `pgx` implementation will marshal/unmarshal the struct automatically. + +```go +package dto + +type BookData struct { + Genres []string `json:"genres"` + Title string `json:"title"` + Published bool `json:"published"` +} +``` + +```sql +CREATE TABLE books ( + data jsonb +); +``` + +```json +{ + "overrides": [ + { + "column": "books.data", + "go_type": { + "import":"example.com/db", + "package": "dto", + "type":"BookData", + "pointer": true + } + } + ] +} +``` + +```go +package db + +import ( + "example.com/db/dto" +) + +type Book struct { + Data *dto.BookData +} +``` + +## TEXT + +In PostgreSQL, when you have a column with the TEXT type, sqlc will map it to a Go string by default. This default mapping applies to `TEXT` columns that are not nullable. However, for nullable `TEXT` columns, sqlc maps them to `pgtype.Text` when using the pgx/v5 driver. This distinction is crucial for developers looking to handle null values appropriately in their Go applications. + +To accommodate nullable strings and map them to `*string` in Go, you can use the `emit_pointers_for_null_types` option in your sqlc configuration. This option ensures that nullable SQL columns are represented as pointer types in Go, allowing for a clear distinction between null and non-null values. Another way to do this is by passing the option `pointer: true` when you are overriding the `TEXT` datatype in your sqlc config file (see [Overriding types](../howto/overrides.md) for details). + +## Geometry + +### PostGIS + +#### Using `github.com/twpayne/go-geos` (pgx/v5 only) + +sqlc can be configured to use the [geos](https://github.com/twpayne/go-geos) +package for working with PostGIS geometry types in [GEOS](https://libgeos.org/). + +There are three steps: + +1. Configure sqlc to use `*github.com/twpayne/go-geos.Geom` for geometry types (see [Overriding types](../howto/overrides.md) for details). +2. Call `github.com/twpayne/pgx-geos.Register` on each + `*github.com/jackc/pgx/v5.Conn`. +3. Annotate your SQL with `::geometry` typecasts, if needed. + +```sql +-- Multipolygons in British National Grid (epsg:27700) +create table shapes( + id serial, + name varchar, + geom geometry(Multipolygon, 27700) +); + +-- name: GetCentroids :many +SELECT id, name, ST_Centroid(geom)::geometry FROM shapes; +``` + +```json +{ + "version": 2, + "gen": { + "go": { + "overrides": [ + { + "db_type": "geometry", + "go_type": { + "import": "github.com/twpayne/go-geos", + "package": "geos", + "pointer": true, + "type": "Geom" + }, + "nullable": true + } + ] + } + } +} +``` + +```go +import ( + "github.com/twpayne/go-geos" + pgxgeos "github.com/twpayne/pgx-geos" +) + +// ... + +config.AfterConnect = func(ctx context.Context, conn *pgx.Conn) error { + if err := pgxgeos.Register(ctx, conn, geos.NewContext()); err != nil { + return err + } + return nil +} +``` + + +#### Using `github.com/twpayne/go-geom` + +sqlc can be configured to use the [geom](https://github.com/twpayne/go-geom) +package for working with PostGIS geometry types. See [Overriding types](../howto/overrides.md) for more information. + +```sql +-- Multipolygons in British National Grid (epsg:27700) +create table shapes( + id serial, + name varchar, + geom geometry(Multipolygon, 27700) +); + +-- name: GetShapes :many +SELECT * FROM shapes; +``` + +```json +{ + "version": "1", + "packages": [ + { + "path": "db", + "engine": "postgresql", + "schema": "query.sql", + "queries": "query.sql" + } + ], + "overrides": [ + { + "db_type": "geometry", + "go_type": "github.com/twpayne/go-geom.MultiPolygon" + }, + { + "db_type": "geometry", + "go_type": "github.com/twpayne/go-geom.MultiPolygon", + "nullable": true + } + ] +} +``` diff --git a/docs/reference/environment-variables.md b/docs/reference/environment-variables.md new file mode 100644 index 0000000..dde6b40 --- /dev/null +++ b/docs/reference/environment-variables.md @@ -0,0 +1,190 @@ +# Environment variables + +## SQLCEXPERIMENT + +The `SQLCEXPERIMENT` variable controls experimental features within sqlc. It is +a comma-separated list of experiment names. This is modeled after Go's +[GOEXPERIMENT](https://pkg.go.dev/internal/goexperiment) environment variable. + +Experiment names can be prefixed with `no` to explicitly disable them. + +``` +SQLCEXPERIMENT=foo,bar # enable foo and bar experiments +SQLCEXPERIMENT=nofoo # explicitly disable foo experiment +SQLCEXPERIMENT=foo,nobar # enable foo, disable bar +``` + +The following experiments are defined: + +### coreanalyzer + +Routes `sqlc generate` through the core catalog and analyzer instead of each +engine's own analysis path. This is the same analysis used by `sqlc analyze`, +and the only analysis path for the ClickHouse and GoogleSQL engines. + +``` +SQLCEXPERIMENT=coreanalyzer +``` + +## SQLCCACHE + +The `SQLCCACHE` environment variable dictates where `sqlc` will store cached +data. By default `sqlc` follows the [XDG Base Directory +Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html). + +The cache is designed after Bazel's local disk cache and has three parts: + +- `cas/` — a content-addressable store holding blobs (query analysis + results, WASM plugin binaries, compiled WASM machine code) keyed by the + SHA-256 hash of their contents. A remotely fetched plugin's address is + exactly the checksum declared in the configuration file, so it is loaded + directly by that address. +- `ac/` — an action cache mapping the digest of a unit of cacheable work and + its inputs (analyzing a query against a schema, compiling a WASM module to + machine code) to the CAS digests of its outputs. +- `exec/` — per-action directories where cached output trees are + materialized for tools that read them from disk, such as the + [wazero](https://wazero.io) runtime's compilation cache. + +The entire directory is safe to delete at any time; sqlc will rebuild it as +needed. + +## SQLCDEBUG + +The `SQLCDEBUG` variable controls debugging variables within the runtime. It is +a comma-separated list of name=val pairs settings. + +### dumpast + +The `dumpast` command shows the SQL AST that was generated by the parser. Note +that this is the generic SQL AST, not the engine-specific SQL AST. + +``` +SQLCDEBUG=dumpast=1 +``` + +``` +([]interface {}) (len=1 cap=1) { + (*catalog.Catalog)(0xc0004f48c0)({ + Comment: (string) "", + DefaultSchema: (string) (len=6) "public", + Name: (string) "", + Schemas: ([]*catalog.Schema) (len=3 cap=4) { + (*catalog.Schema)(0xc0004f4930)({ + Name: (string) (len=6) "public", + Tables: ([]*catalog.Table) (len=1 cap=1) { + (*catalog.Table)(0xc00052ff20)({ + Rel: (*ast.TableName)(0xc00052fda0)({ + Catalog: (string) "", + Schema: (string) "", + Name: (string) (len=7) "authors" + }), +``` + +### dumpcatalog + +The `dumpcatalog` command outputs the entire catalog. If you're using MySQL or +PostgreSQL, this can be a bit overwhelming. Expect this output to change in +future versions. + +``` +SQLCDEBUG=dumpcatalog=1 +``` + +``` +([]interface {}) (len=1 cap=1) { + (*catalog.Catalog)(0xc00050d1f0)({ + Comment: (string) "", + DefaultSchema: (string) (len=6) "public", + Name: (string) "", + Schemas: ([]*catalog.Schema) (len=3 cap=4) { + (*catalog.Schema)(0xc00050d260)({ + Name: (string) (len=6) "public", + Tables: ([]*catalog.Table) (len=1 cap=1) { + (*catalog.Table)(0xc0000c0840)({ + Rel: (*ast.TableName)(0xc0000c06c0)({ + Catalog: (string) "", + Schema: (string) "", + Name: (string) (len=7) "authors" + }), +``` + +### trace + +The `trace` command is helpful for tracking down performance issues. + +`SQLCDEBUG=trace=1` + +By default, the trace output is written to `trace.out` in the current working +directory. You can configure a different path if needed. + +`SQLCDEBUG=trace=name.out` + +View the execution trace using the Go `trace` tool. + +``` +go tool trace trace.out +``` + +There's a ton of different views for the trace output, but here's an example +log showing the execution time for each package. + +``` +0.000043897 . 1 task sqlc (id 1, parent 0) created +0.000144923 . 101026 1 region generate started (duration: 47.619781ms) +0.001048975 . 904052 1 region package started (duration: 14.588456ms) +0.001054616 . 5641 1 name=authors dir=/Users/kyle/projects/sqlc/examples/python language=python +0.001071257 . 16641 1 region parse started (duration: 7.966549ms) +0.009043960 . 7972703 1 region codegen started (duration: 6.587086ms) +0.009171704 . 127744 1 new goroutine 35: text/template/parse.lex·dwrap·1 +0.010361654 . 1189950 1 new goroutine 36: text/template/parse.lex·dwrap·1 +0.015641815 . 5280161 1 region package started (duration: 10.904938ms) +0.015644943 . 3128 1 name=booktest dir=/Users/kyle/projects/sqlc/examples/python language=python +0.015647431 . 2488 1 region parse started (duration: 4.207749ms) +0.019860308 . 4212877 1 region codegen started (duration: 6.681624ms) +0.020028488 . 168180 1 new goroutine 37: text/template/parse.lex·dwrap·1 +0.021020310 . 991822 1 new goroutine 8: text/template/parse.lex·dwrap·1 +0.026551163 . 5530853 1 region package started (duration: 9.217294ms) +0.026554368 . 3205 1 name=jets dir=/Users/kyle/projects/sqlc/examples/python language=python +0.026556804 . 2436 1 region parse started (duration: 3.491005ms) +0.030051911 . 3495107 1 region codegen started (duration: 5.711931ms) +0.030213937 . 162026 1 new goroutine 20: text/template/parse.lex·dwrap·1 +0.031099938 . 886001 1 new goroutine 38: text/template/parse.lex·dwrap·1 +0.035772637 . 4672699 1 region package started (duration: 10.267039ms) +0.035775688 . 3051 1 name=ondeck dir=/Users/kyle/projects/sqlc/examples/python language=python +0.035778150 . 2462 1 region parse started (duration: 4.094518ms) +0.039877181 . 4099031 1 region codegen started (duration: 6.156341ms) +0.040010771 . 133590 1 new goroutine 39: text/template/parse.lex·dwrap·1 +0.040894567 . 883796 1 new goroutine 40: text/template/parse.lex·dwrap·1 +0.046042779 . 5148212 1 region writefiles started (duration: 1.718259ms) +0.047767781 . 1725002 1 task end +``` + +### processplugins + +Setting this value to `0` disables process-based plugins. If a process-based +plugin is declared in the configuration file, running any `sqlc` command will +return an error. + +`SQLCDEBUG=processplugins=0` + +### dumpvetenv + +The `dumpvetenv` command prints the variables available to a `sqlc vet` rule +during evaluation. + +`SQLCDEBUG=dumpvetenv=1` + +### dumpexplain + +The `dumpexplain` command prints the JSON-formatted result from running +`EXPLAIN ...` on a query when a `sqlc vet` rule evaluation requires its output. + +`SQLCDEBUG=dumpexplain=1` + +## SQLCTMPDIR + +If specified, use the given directory as the base for temporary folders. Only +applies when using WASM-based codegen plugins. When not specified, this +defaults to passing an empty string to +[`os.MkdirTemp`](https://pkg.go.dev/os#MkdirTemp). diff --git a/docs/reference/language-support.md b/docs/reference/language-support.md new file mode 100644 index 0000000..0f7a6f3 --- /dev/null +++ b/docs/reference/language-support.md @@ -0,0 +1,34 @@ +# Database and language support + +| Language | Plugin | MySQL | PostgreSQL | SQLite | +| ---------- | ---------------------------------------------------------------------- | ------ | ---------- | --------------- | +| Go | (built-in) | Stable | Stable | Beta | +| Go | [sqlc-gen-go](https://github.com/sqlc-dev/sqlc-gen-go) | Stable | Stable | Beta | +| Kotlin | [sqlc-gen-kotlin](https://github.com/sqlc-dev/sqlc-gen-kotlin) | Beta | Beta | Not implemented | +| Python | [sqlc-gen-python](https://github.com/sqlc-dev/sqlc-gen-python) | Beta | Beta | Not implemented | +| TypeScript | [sqlc-gen-typescript](https://github.com/sqlc-dev/sqlc-gen-typescript) | Beta | Beta | Not implemented | + +## Community language support + +New languages can be added via [plugins](../guides/plugins.md). + +| Language | Plugin | MySQL | PostgreSQL | SQLite | +| -------- | ------------------------------------------------------------------------------------- | ------ | ---------- | ------ | +| C# | [DaredevilOSS/sqlc-gen-csharp](https://github.com/DaredevilOSS/sqlc-gen-csharp) | Stable | Stable | Stable | +| F# | [kaashyapan/sqlc-gen-fsharp](https://github.com/kaashyapan/sqlc-gen-fsharp) | N/A | Beta | Beta | +| Java | [tandemdude/sqlc-gen-java](https://github.com/tandemdude/sqlc-gen-java) | Beta | Beta | N/A | +| PHP | [lcarilla/sqlc-plugin-php-dbal](https://github.com/lcarilla/sqlc-plugin-php-dbal) | Beta | N/A | N/A | +| Ruby | [DaredevilOSS/sqlc-gen-ruby](https://github.com/DaredevilOSS/sqlc-gen-ruby) | Beta | Beta | Beta | +| Zig | [tinyzimmer/sqlc-gen-zig](https://github.com/tinyzimmer/sqlc-gen-zig) | N/A | Beta | Beta | +| Python | [rayakame/sqlc-gen-better-python](https://github.com/rayakame/sqlc-gen-better-python) | Beta | Stable | Stable | +| Rust | [mathematic-inc/sqlc-gen-sqlx](https://github.com/mathematic-inc/sqlc-gen-sqlx) | N/A | Beta | N/A | +| \[Any\] | [fdietze/sqlc-gen-from-template](https://github.com/fdietze/sqlc-gen-from-template) | Stable | Stable | Stable | + +Plugins developed by our Community can also be found using our +[github topic](https://github.com/topics/sqlc-plugin). + +## Community projects + +| Language | Project | MySQL | PostgreSQL | SQLite | +| -------- | ----------------------------------------------------------------- | ------ | ---------- | ------ | +| Gleam | [daniellionel01/parrot](https://github.com/daniellionel01/parrot) | Stable | Stable | Stable | diff --git a/docs/reference/macros.md b/docs/reference/macros.md new file mode 100644 index 0000000..54d44ed --- /dev/null +++ b/docs/reference/macros.md @@ -0,0 +1,119 @@ +# Macros + +## `sqlc.arg` + +Attach a name to a parameter in a SQL query. This macro expands to an +engine-specific parameter placeholder. The name of the parameter is noted and +used during code generation. + +```sql +-- name: GetAuthorByName :one +SELECT * +FROM authors +WHERE lower(name) = sqlc.arg(name); + +-- >>> EXPANDS TO >>> + +-- name: GetAuthorByName :one +SELECT * +FROM authors +WHERE lower(name) = ?; +``` + +See more examples in [Naming parameters](../howto/named_parameters.md). + +## `sqlc.embed` + +Embedding allows you to reuse existing model structs in more queries, resulting +in less manual serialization work. First, imagine we have the following schema +with students and test scores. + +```sql +CREATE TABLE students ( + id bigserial PRIMARY KEY, + name text, + age integer +); + +CREATE TABLE test_scores ( + student_id bigint, + score integer, + grade text +); +``` + +```sql +-- name: GetStudentAndScore :one +SELECT sqlc.embed(students), sqlc.embed(test_scores) +FROM students +JOIN test_scores ON test_scores.student_id = students.id +WHERE students.id = $1; + +-- >>> EXPANDS TO >>> + +-- name: GetStudentAndScore :one +SELECT students.*, test_scores.* +FROM students +JOIN test_scores ON test_scores.student_id = students.id +WHERE students.id = $1; +``` + +The Go method will return a struct with a field for the `Student` and field for +the test `TestScore` instead of each column existing on the struct. + +```go +type GetStudentAndScoreRow struct { + Student Student + TestScore TestScore +} + +func (q *Queries) GetStudentAndScore(ctx context.Context, id int64) (GetStudentAndScoreRow, error) { + // ... +} +``` + +See a full example in [Embedding structs](../howto/embedding.md). + +## `sqlc.narg` + +The same as `sqlc.arg`, but always marks the parameter as nullable. + +```sql +-- name: GetAuthorByName :one +SELECT * +FROM authors +WHERE lower(name) = sqlc.narg(name); + +-- >>> EXPANDS TO >>> + +-- name: GetAuthorByName :one +SELECT * +FROM authors +WHERE LOWER(name) = ?; +``` + +See more examples in [Naming parameters](../howto/named_parameters.md). + +## `sqlc.slice` + +For drivers that do not support passing slices to the IN operator, the +`sqlc.slice` macro generates a dynamic query at runtime with the correct +number of parameters. + +```sql +/* name: SelectStudents :many */ +SELECT * FROM students +WHERE age IN (sqlc.slice("ages")) + +-- >>> EXPANDS TO >>> + +/* name: SelectStudents :many */ +SELECT id, name, age FROM authors +WHERE age IN (/*SLICE:ages*/?) +``` + +Since the `/*SLICE:ages*/` placeholder is dynamically replaced on a per-query +basis, this macro can't be used with prepared statements. + +See a full example in [Passing a slice as a parameter to a +query](../howto/select.md#mysql-and-sqlite). diff --git a/docs/reference/query-annotations.md b/docs/reference/query-annotations.md new file mode 100644 index 0000000..4fabe05 --- /dev/null +++ b/docs/reference/query-annotations.md @@ -0,0 +1,230 @@ +# Query annotations + +sqlc requires each query to have a small comment indicating the name and +command. The format of this comment is as follows: + +```sql +-- name: +``` + +## `:exec` + +The generated method will return the error from +[ExecContext](https://golang.org/pkg/database/sql/#DB.ExecContext). + +```sql +-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = $1; +``` + +```go +func (q *Queries) DeleteAuthor(ctx context.Context, id int64) error { + _, err := q.db.ExecContext(ctx, deleteAuthor, id) + return err +} +``` + +## `:execresult` + +The generated method will return the [sql.Result](https://golang.org/pkg/database/sql/#Result) returned by +[ExecContext](https://golang.org/pkg/database/sql/#DB.ExecContext). + +```sql +-- name: DeleteAllAuthors :execresult +DELETE FROM authors; +``` + +```go +func (q *Queries) DeleteAllAuthors(ctx context.Context) (sql.Result, error) { + return q.db.ExecContext(ctx, deleteAllAuthors) +} +``` + +## `:execrows` + +The generated method will return the number of affected rows from the +[result](https://golang.org/pkg/database/sql/#Result) returned by +[ExecContext](https://golang.org/pkg/database/sql/#DB.ExecContext). + +```sql +-- name: DeleteAllAuthors :execrows +DELETE FROM authors; +``` + +```go +func (q *Queries) DeleteAllAuthors(ctx context.Context) (int64, error) { + _, err := q.db.ExecContext(ctx, deleteAllAuthors) + // ... +} +``` + +## `:execlastid` + +The generated method will return the number generated by the database from the +[result](https://golang.org/pkg/database/sql/#Result) returned by +[ExecContext](https://golang.org/pkg/database/sql/#DB.ExecContext). + +```sql +-- name: InsertAuthor :execlastid +INSERT INTO authors (name) VALUES (?); +``` + +```go +func (q *Queries) InsertAuthor(ctx context.Context, name string) (int64, error) { + _, err := q.db.ExecContext(ctx, insertAuthor, name) + // ... +} +``` + +## `:many` + +The generated method will return a slice of records via +[QueryContext](https://golang.org/pkg/database/sql/#DB.QueryContext). + +```sql +-- name: ListAuthors :many +SELECT * FROM authors +ORDER BY name; +``` + +```go +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + // ... +} +``` + +## `:one` + +The generated method will return a single record via +[QueryRowContext](https://golang.org/pkg/database/sql/#DB.QueryRowContext). + +```sql +-- name: GetAuthor :one +SELECT * FROM authors +WHERE id = $1 LIMIT 1; +``` + +```go +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + // ... +} +``` + +## `:batchexec` + +__NOTE: This command only works with PostgreSQL using the `pgx/v4` and `pgx/v5` drivers and outputting Go code.__ + +The generated method will return a batch object. The batch object will have +the following methods: +- `Exec`, that takes a `func(int, error)` parameter, +- `Close`, to close the batch operation early. + +```sql +-- name: DeleteBook :batchexec +DELETE FROM books +WHERE book_id = $1; +``` + +```go +type DeleteBookBatchResults struct { + br pgx.BatchResults + ind int +} + +func (q *Queries) DeleteBook(ctx context.Context, bookID []int32) *DeleteBookBatchResults { + //... +} +func (b *DeleteBookBatchResults) Exec(f func(int, error)) { + //... +} +func (b *DeleteBookBatchResults) Close() error { + //... +} +``` + +## `:batchmany` + +__NOTE: This command only works with PostgreSQL using the `pgx/v4` and `pgx/v5` drivers and outputting Go code.__ + +The generated method will return a batch object. The batch object will have +the following methods: +- `Query`, that takes a `func(int, []T, error)` parameter, where `T` is your query's return type +- `Close`, to close the batch operation early. + +```sql +-- name: BooksByTitleYear :batchmany +SELECT * FROM books +WHERE title = $1 AND year = $2; +``` + +```go +type BooksByTitleYearBatchResults struct { + br pgx.BatchResults + ind int +} +type BooksByTitleYearParams struct { + Title string `json:"title"` + Year int32 `json:"year"` +} + +func (q *Queries) BooksByTitleYear(ctx context.Context, arg []BooksByTitleYearParams) *BooksByTitleYearBatchResults { + //... +} +func (b *BooksByTitleYearBatchResults) Query(f func(int, []Book, error)) { + //... +} +func (b *BooksByTitleYearBatchResults) Close() error { + //... +} +``` + +## `:batchone` + +__NOTE: This command only works with PostgreSQL using the `pgx/v4` and `pgx/v5` drivers and outputting Go code.__ + +The generated method will return a batch object. The batch object will have +the following methods: +- `QueryRow`, that takes a `func(int, T, error)` parameter, where `T` is your query's return type +- `Close`, to close the batch operation early. + +```sql +-- name: CreateBook :batchone +INSERT INTO books ( + author_id, + isbn +) VALUES ( + $1, + $2 +) +RETURNING book_id, author_id, isbn +``` + +```go +type CreateBookBatchResults struct { + br pgx.BatchResults + ind int +} +type CreateBookParams struct { + AuthorID int32 `json:"author_id"` + Isbn string `json:"isbn"` +} + +func (q *Queries) CreateBook(ctx context.Context, arg []CreateBookParams) *CreateBookBatchResults { + //... +} +func (b *CreateBookBatchResults) QueryRow(f func(int, Book, error)) { + //... +} +func (b *CreateBookBatchResults) Close() error { + //... +} +``` + +## `:copyfrom` + +__NOTE: This command is driver and package specific, see [how to insert](../howto/insert.md#using-copyfrom) + +This command is used to insert rows a lot faster than sequential inserts. diff --git a/docs/toc.yaml b/docs/toc.yaml new file mode 100644 index 0000000..464fe33 --- /dev/null +++ b/docs/toc.yaml @@ -0,0 +1,72 @@ +# Navigation for the sqlc documentation site. +# +# Every page in docs/ must appear exactly once, either in a section or in +# the unlisted set. Unlisted pages are published but do not appear in the +# sidebar. + +index: index.md + +sections: + - title: Overview + pages: + - overview/install.md + + - title: Tutorials + pages: + - tutorials/getting-started-mysql.md + - tutorials/getting-started-postgresql.md + - tutorials/getting-started-sqlite.md + + - title: Commands + pages: + - howto/analyze.md + - howto/fmt.md + - howto/generate.md + - howto/parse.md + - howto/push.md + - howto/verify.md + - howto/vet.md + + - title: How-to Guides + pages: + - howto/select.md + - howto/query_count.md + - howto/insert.md + - howto/update.md + - howto/delete.md + - howto/prepared_query.md + - howto/transactions.md + - howto/named_parameters.md + - howto/ddl.md + - howto/structs.md + - howto/embedding.md + - howto/overrides.md + - howto/rename.md + + - title: sqlc Cloud + pages: + - howto/managed-databases.md + + - title: Reference + pages: + - reference/changelog.md + - reference/cli.md + - reference/config.md + - reference/datatypes.md + - reference/environment-variables.md + - reference/language-support.md + - reference/macros.md + - reference/query-annotations.md + + - title: Conceptual Guides + pages: + - howto/ci-cd.md + - guides/using-go-and-pgx.md + - guides/plugins.md + - guides/development.md + - guides/privacy.md + +unlisted: + - guides/migrating-off-hosted-managed-databases.md + - guides/migrating-to-sqlc-gen-kotlin.md + - guides/migrating-to-sqlc-gen-python.md diff --git a/docs/tutorials/getting-started-mysql.md b/docs/tutorials/getting-started-mysql.md new file mode 100644 index 0000000..25e7d61 --- /dev/null +++ b/docs/tutorials/getting-started-mysql.md @@ -0,0 +1,221 @@ +# Getting started with MySQL + +This tutorial assumes that the latest version of sqlc is +[installed](../overview/install.md) and ready to use. + +We'll generate Go code here, but other +[language plugins](../reference/language-support.md) are available. You'll +naturally need the Go toolchain if you want to build and run a program with the +code sqlc generates, but sqlc itself has no dependencies. + +At the end, you'll push your SQL queries to [sqlc Cloud](https://dashboard.sqlc.dev/) for further insights and analysis. + +## Setting up + +Create a new directory called `sqlc-tutorial` and open it up. + +Initialize a new Go module named `tutorial.sqlc.dev/app` + +```shell +go mod init tutorial.sqlc.dev/app +``` + +sqlc looks for either a `sqlc.(yaml|yml)` or `sqlc.json` file in the current +directory. In our new directory, create a file named `sqlc.yaml` with the +following contents: + +```yaml +version: "2" +sql: + - engine: "mysql" + queries: "query.sql" + schema: "schema.sql" + gen: + go: + package: "tutorial" + out: "tutorial" +``` + +## Schema and queries + +sqlc needs to know your database schema and queries in order to generate code. +In the same directory, create a file named `schema.sql` with the following +content: + +```sql +CREATE TABLE authors ( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + name text NOT NULL, + bio text +); +``` + +Next, create a `query.sql` file with the following four queries: + +```sql +-- name: GetAuthor :one +SELECT * FROM authors +WHERE id = ? LIMIT 1; + +-- name: ListAuthors :many +SELECT * FROM authors +ORDER BY name; + +-- name: CreateAuthor :execresult +INSERT INTO authors ( + name, bio +) VALUES ( + ?, ? +); + +-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = ?; +``` + +## Generating code + +You are now ready to generate code. You shouldn't see any output when you run +the `generate` subcommand, unless something goes wrong: + +```shell +sqlc generate +``` + +You should now have a `tutorial` subdirectory with three files containing Go +source code. These files comprise a Go package named `tutorial`: + +``` +├── go.mod +├── query.sql +├── schema.sql +├── sqlc.yaml +└── tutorial + ├── db.go + ├── models.go + └── query.sql.go +``` + +## Using generated code + +You can use your newly-generated `tutorial` package from any Go program. +Create a file named `tutorial.go` and add the following contents: + +```go +package main + +import ( + "context" + "database/sql" + "log" + "reflect" + + _ "github.com/go-sql-driver/mysql" + + "tutorial.sqlc.dev/app/tutorial" +) + +func run() error { + ctx := context.Background() + + db, err := sql.Open("mysql", "user:password@/dbname?parseTime=true") + if err != nil { + return err + } + + queries := tutorial.New(db) + + // list all authors + authors, err := queries.ListAuthors(ctx) + if err != nil { + return err + } + log.Println(authors) + + // create an author + result, err := queries.CreateAuthor(ctx, tutorial.CreateAuthorParams{ + Name: "Brian Kernighan", + Bio: sql.NullString{String: "Co-author of The C Programming Language and The Go Programming Language", Valid: true}, + }) + if err != nil { + return err + } + + insertedAuthorID, err := result.LastInsertId() + if err != nil { + return err + } + log.Println(insertedAuthorID) + + // get the author we just inserted + fetchedAuthor, err := queries.GetAuthor(ctx, insertedAuthorID) + if err != nil { + return err + } + + // prints true + log.Println(reflect.DeepEqual(insertedAuthorID, fetchedAuthor.ID)) + return nil +} + +func main() { + if err := run(); err != nil { + log.Fatal(err) + } +} +``` + +Before this code will compile you'll need to fetch the relevant MySQL driver: + +```shell +go get github.com/go-sql-driver/mysql +go build . +``` + +The program should compile without errors. To make that possible, sqlc generates +readable, **idiomatic** Go code that you otherwise would've had to write +yourself. Take a look in `tutorial/query.sql.go`. + +Of course for this program to run successfully you'll need +to compile after replacing the database connection parameters in the call to +`sql.Open()` with the correct parameters for your database. And your +database must have the `authors` table as defined in `schema.sql`. + +You should now have a working program using sqlc's generated Go source code, +and hopefully can see how you'd use sqlc in your own real-world applications. + +## Query verification + +[sqlc Cloud](https://dashboard.sqlc.dev) provides additional verification, catching subtle bugs. To get started, create a +[dashboard account](https://dashboard.sqlc.dev). Once you've signed in, create a +project and generate an auth token. Add your project's ID to the `cloud` block +to your sqlc.yaml. + + +```yaml +version: "2" +cloud: + # Replace with your project ID from the sqlc Cloud dashboard + project: "" +sql: + - engine: "mysql" + queries: "query.sql" + schema: "schema.sql" + gen: + go: + package: "tutorial" + out: "tutorial" +``` + +Replace `` with your project ID from the sqlc Cloud dashboard. It +will look something like `01HA8SZH31HKYE9RR3N3N3TSJM`. + +And finally, set the `SQLC_AUTH_TOKEN` environment variable: + +```shell +export SQLC_AUTH_TOKEN="" +``` + +```shell +$ sqlc push --tag tutorial +``` diff --git a/docs/tutorials/getting-started-postgresql.md b/docs/tutorials/getting-started-postgresql.md new file mode 100644 index 0000000..d6045cf --- /dev/null +++ b/docs/tutorials/getting-started-postgresql.md @@ -0,0 +1,248 @@ +# Getting started with PostgreSQL + +This tutorial assumes that the latest version of sqlc is +[installed](../overview/install.md) and ready to use. + +We'll generate Go code here, but other +[language plugins](../reference/language-support.md) are available. You'll +naturally need the Go toolchain if you want to build and run a program with the +code sqlc generates, but sqlc itself has no dependencies. + +At the end, you'll push your SQL queries to [sqlc +Cloud](https://dashboard.sqlc.dev/) for further insights and analysis. + +## Setting up + +Create a new directory called `sqlc-tutorial` and open it up. + +Initialize a new Go module named `tutorial.sqlc.dev/app`: + +```shell +go mod init tutorial.sqlc.dev/app +``` + +sqlc looks for either a `sqlc.(yaml|yml)` or `sqlc.json` file in the current +directory. In our new directory, create a file named `sqlc.yaml` with the +following contents: + +```yaml +version: "2" +sql: + - engine: "postgresql" + queries: "query.sql" + schema: "schema.sql" + gen: + go: + package: "tutorial" + out: "tutorial" + sql_package: "pgx/v5" +``` + +## Schema and queries + +sqlc needs to know your database schema and queries in order to generate code. +In the same directory, create a file named `schema.sql` with the following +content: + +```sql +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); +``` + +Next, create a `query.sql` file with the following five queries: + +```sql +-- 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: UpdateAuthor :exec +UPDATE authors + set name = $2, + bio = $3 +WHERE id = $1; + +-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = $1; +``` + +If you prefer, you can alter the `UpdateAuthor` query to return the updated +record: + +```sql +-- name: UpdateAuthor :one +UPDATE authors + set name = $2, + bio = $3 +WHERE id = $1 +RETURNING *; +``` + +## Generating code + +You are now ready to generate code. You shouldn't see any output when you run +the `generate` subcommand, unless something goes wrong: + +```shell +sqlc generate +``` + +You should now have a `tutorial` subdirectory with three files containing Go +source code. These files comprise a Go package named `tutorial`: + +``` +├── go.mod +├── query.sql +├── schema.sql +├── sqlc.yaml +└── tutorial + ├── db.go + ├── models.go + └── query.sql.go +``` + +## Using generated code + +You can use your newly-generated `tutorial` package from any Go program. +Create a file named `tutorial.go` and add the following contents: + +```go +package main + +import ( + "context" + "log" + "reflect" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgtype" + + "tutorial.sqlc.dev/app/tutorial" +) + +func run() error { + ctx := context.Background() + + conn, err := pgx.Connect(ctx, "user=pqgotest dbname=pqgotest sslmode=verify-full") + if err != nil { + return err + } + defer conn.Close(ctx) + + queries := tutorial.New(conn) + + // list all authors + authors, err := queries.ListAuthors(ctx) + if err != nil { + return err + } + log.Println(authors) + + // create an author + insertedAuthor, err := queries.CreateAuthor(ctx, tutorial.CreateAuthorParams{ + Name: "Brian Kernighan", + Bio: pgtype.Text{String: "Co-author of The C Programming Language and The Go Programming Language", Valid: true}, + }) + if err != nil { + return err + } + log.Println(insertedAuthor) + + // get the author we just inserted + fetchedAuthor, err := queries.GetAuthor(ctx, insertedAuthor.ID) + if err != nil { + return err + } + + // prints true + log.Println(reflect.DeepEqual(insertedAuthor, fetchedAuthor)) + return nil +} + +func main() { + if err := run(); err != nil { + log.Fatal(err) + } +} +``` + +Before this code will compile you'll need to fetch the relevant PostgreSQL +driver. You can use `lib/pq` with the standard library's `database/sql` +package, but in this tutorial we've used `pgx/v5`: + +```shell +go get github.com/jackc/pgx/v5 +go build . +``` + +The program should compile without errors. To make that possible, sqlc generates +readable, **idiomatic** Go code that you otherwise would've had to write +yourself. Take a look in `tutorial/query.sql.go`. + +Of course for this program to run successfully you'll need +to compile after replacing the database connection parameters in the call to +`pgx.Connect()` with the correct parameters for your database. And your +database must have the `authors` table as defined in `schema.sql`. + +You should now have a working program using sqlc's generated Go source code, +and hopefully can see how you'd use sqlc in your own real-world applications. + +## Query verification + +[sqlc Cloud](https://dashboard.sqlc.dev) provides additional verification, catching subtle bugs. To get started, create a +[dashboard account](https://dashboard.sqlc.dev). Once you've signed in, create a +project and generate an auth token. Add your project's ID to the `cloud` block +to your sqlc.yaml. + +```yaml +version: "2" +cloud: + # Replace with your project ID from the sqlc Cloud dashboard + project: "" +sql: + - engine: "postgresql" + queries: "query.sql" + schema: "schema.sql" + gen: + go: + package: "tutorial" + out: "tutorial" + sql_package: "pgx/v5" +``` + +Replace `` with your project ID from the sqlc Cloud dashboard. It +will look something like `01HA8SZH31HKYE9RR3N3N3TSJM`. + +And finally, set the `SQLC_AUTH_TOKEN` environment variable: + +```shell +export SQLC_AUTH_TOKEN="" +``` + +```shell +$ sqlc push --tag tutorial +``` + +In the sidebar, go to the "Queries" section to see your published queries. Run +`verify` to ensure that previously published queries continue to work against +updated database schema. + +```shell +$ sqlc verify --against tutorial +``` diff --git a/docs/tutorials/getting-started-sqlite.md b/docs/tutorials/getting-started-sqlite.md new file mode 100644 index 0000000..e5b45f8 --- /dev/null +++ b/docs/tutorials/getting-started-sqlite.md @@ -0,0 +1,201 @@ +# Getting started with SQLite + +This tutorial assumes that the latest version of sqlc is +[installed](../overview/install.md) and ready to use. + +We'll generate Go code here, but other +[language plugins](../reference/language-support.md) are available. You'll +naturally need the Go toolchain if you want to build and run a program with the +code sqlc generates, but sqlc itself has no dependencies. + +## Setting up + +Create a new directory called `sqlc-tutorial` and open it up. + +Initialize a new Go module named `tutorial.sqlc.dev/app` + +```shell +go mod init tutorial.sqlc.dev/app +``` + +sqlc looks for either a `sqlc.(yaml|yml)` or `sqlc.json` file in the current +directory. In our new directory, create a file named `sqlc.yaml` with the +following contents: + +```yaml +version: "2" +sql: + - engine: "sqlite" + queries: "query.sql" + schema: "schema.sql" + gen: + go: + package: "tutorial" + out: "tutorial" +``` + +## Schema and queries + +sqlc needs to know your database schema and queries in order to generate code. +In the same directory, create a file named `schema.sql` with the following +content: + +```sql +CREATE TABLE authors ( + id INTEGER PRIMARY KEY, + name text NOT NULL, + bio text +); +``` + +Next, create a `query.sql` file with the following five queries: + +```sql +-- name: GetAuthor :one +SELECT * FROM authors +WHERE id = ? LIMIT 1; + +-- name: ListAuthors :many +SELECT * FROM authors +ORDER BY name; + +-- name: CreateAuthor :one +INSERT INTO authors ( + name, bio +) VALUES ( + ?, ? +) +RETURNING *; + +-- name: UpdateAuthor :exec +UPDATE authors +set name = ?, +bio = ? +WHERE id = ?; + +-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = ?; +``` + +If you prefer, you can alter the `UpdateAuthor` query to return the updated +record: + +```sql +-- name: UpdateAuthor :one +UPDATE authors +set name = ?, +bio = ? +WHERE id = ? +RETURNING *; +``` + +## Generating code + +You are now ready to generate code. You shouldn't see any output when you run +the `generate` subcommand, unless something goes wrong: + +```shell +sqlc generate +``` + +You should now have a `tutorial` subdirectory with three files containing Go +source code. These files comprise a Go package named `tutorial`: + +``` +├── go.mod +├── query.sql +├── schema.sql +├── sqlc.yaml +└── tutorial + ├── db.go + ├── models.go + └── query.sql.go +``` + +## Using generated code + +You can use your newly-generated `tutorial` package from any Go program. +Create a file named `tutorial.go` and add the following contents: + +```go +package main + +import ( + "context" + "database/sql" + _ "embed" + "log" + "reflect" + + _ "modernc.org/sqlite" + + "tutorial.sqlc.dev/app/tutorial" +) + +//go:embed schema.sql +var ddl string + +func run() error { + ctx := context.Background() + + db, err := sql.Open("sqlite", ":memory:") + if err != nil { + return err + } + + // create tables + if _, err := db.ExecContext(ctx, ddl); err != nil { + return err + } + + queries := tutorial.New(db) + + // list all authors + authors, err := queries.ListAuthors(ctx) + if err != nil { + return err + } + log.Println(authors) + + // create an author + insertedAuthor, err := queries.CreateAuthor(ctx, tutorial.CreateAuthorParams{ + Name: "Brian Kernighan", + Bio: sql.NullString{String: "Co-author of The C Programming Language and The Go Programming Language", Valid: true}, + }) + if err != nil { + return err + } + log.Println(insertedAuthor) + + // get the author we just inserted + fetchedAuthor, err := queries.GetAuthor(ctx, insertedAuthor.ID) + if err != nil { + return err + } + + // prints true + log.Println(reflect.DeepEqual(insertedAuthor, fetchedAuthor)) + return nil +} + +func main() { + if err := run(); err != nil { + log.Fatal(err) + } +} +``` + +Before this code will compile you'll need to fetch the relevant SQLite driver: + +```shell +go get modernc.org/sqlite +go build . +``` + +The program should compile without errors, and run successfully. To make that +possible, sqlc generates readable, **idiomatic** Go code that you +otherwise would've had to write yourself. Take a look in `tutorial/query.sql.go`. + +You should now have a working program using sqlc's generated Go source code, +and hopefully can see how you'd use sqlc in your own real-world applications. diff --git a/examples/authors/mysql/db.go b/examples/authors/mysql/db.go new file mode 100644 index 0000000..32f660c --- /dev/null +++ b/examples/authors/mysql/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package authors + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/examples/authors/mysql/db_test.go b/examples/authors/mysql/db_test.go new file mode 100644 index 0000000..96ec363 --- /dev/null +++ b/examples/authors/mysql/db_test.go @@ -0,0 +1,53 @@ +//go:build examples + +package authors + +import ( + "context" + "database/sql" + "testing" + + _ "github.com/go-sql-driver/mysql" + + "github.com/sqlc-dev/sqlc/internal/sqltest/local" +) + +func TestAuthors(t *testing.T) { + ctx := context.Background() + uri := local.MySQL(t, []string{"schema.sql"}) + sdb, err := sql.Open("mysql", uri) + if err != nil { + t.Fatal(err) + } + defer sdb.Close() + + db := New(sdb) + + // list all authors + authors, err := db.ListAuthors(ctx) + if err != nil { + t.Fatal(err) + } + t.Log(authors) + + // create an author + result, err := db.CreateAuthor(ctx, CreateAuthorParams{ + Name: "Brian Kernighan", + Bio: sql.NullString{String: "Co-author of The C Programming Language and The Go Programming Language", Valid: true}, + }) + if err != nil { + t.Fatal(err) + } + authorID, err := result.LastInsertId() + if err != nil { + t.Fatal(err) + } + t.Log(authorID) + + // get the author we just inserted + fetchedAuthor, err := db.GetAuthor(ctx, authorID) + if err != nil { + t.Fatal(err) + } + t.Log(fetchedAuthor) +} diff --git a/examples/authors/mysql/models.go b/examples/authors/mysql/models.go new file mode 100644 index 0000000..62bacd8 --- /dev/null +++ b/examples/authors/mysql/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package authors + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/examples/authors/mysql/query.sql b/examples/authors/mysql/query.sql new file mode 100644 index 0000000..c3b5866 --- /dev/null +++ b/examples/authors/mysql/query.sql @@ -0,0 +1,18 @@ +/* name: GetAuthor :one */ +SELECT * FROM authors +WHERE id = ? LIMIT 1; + +/* name: ListAuthors :many */ +SELECT * FROM authors +ORDER BY name; + +/* name: CreateAuthor :execresult */ +INSERT INTO authors ( + name, bio +) VALUES ( + ?, ? +); + +/* name: DeleteAuthor :exec */ +DELETE FROM authors +WHERE id = ?; diff --git a/examples/authors/mysql/query.sql.go b/examples/authors/mysql/query.sql.go new file mode 100644 index 0000000..0d66af7 --- /dev/null +++ b/examples/authors/mysql/query.sql.go @@ -0,0 +1,78 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package authors + +import ( + "context" + "database/sql" +) + +const createAuthor = `-- name: CreateAuthor :execresult +INSERT INTO authors ( + name, bio +) VALUES ( + ?, ? +) +` + +type CreateAuthorParams struct { + Name string + Bio sql.NullString +} + +func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (sql.Result, error) { + return q.db.ExecContext(ctx, createAuthor, arg.Name, arg.Bio) +} + +const deleteAuthor = `-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = ? +` + +func (q *Queries) DeleteAuthor(ctx context.Context, id int64) error { + _, err := q.db.ExecContext(ctx, deleteAuthor, id) + return err +} + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, bio FROM authors +WHERE id = ? LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name, bio FROM authors +ORDER BY name +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); 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/examples/authors/mysql/schema.sql b/examples/authors/mysql/schema.sql new file mode 100644 index 0000000..581ecfe --- /dev/null +++ b/examples/authors/mysql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE authors ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + name text NOT NULL, + bio text +); diff --git a/examples/authors/postgresql/db.go b/examples/authors/postgresql/db.go new file mode 100644 index 0000000..fc39dda --- /dev/null +++ b/examples/authors/postgresql/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package authors + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/examples/authors/postgresql/db_test.go b/examples/authors/postgresql/db_test.go new file mode 100644 index 0000000..0fdd882 --- /dev/null +++ b/examples/authors/postgresql/db_test.go @@ -0,0 +1,49 @@ +//go:build examples + +package authors + +import ( + "context" + "testing" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgtype" + + "github.com/sqlc-dev/sqlc/internal/sqltest/local" +) + +func TestAuthors(t *testing.T) { + ctx := context.Background() + uri := local.PostgreSQL(t, []string{"schema.sql"}) + db, err := pgx.Connect(ctx, uri) + if err != nil { + t.Fatal(err) + } + defer db.Close(ctx) + + q := New(db) + + // list all authors + authors, err := q.ListAuthors(ctx) + if err != nil { + t.Fatal(err) + } + t.Log(authors) + + // create an author + insertedAuthor, err := q.CreateAuthor(ctx, CreateAuthorParams{ + Name: "Brian Kernighan", + Bio: pgtype.Text{String: "Co-author of The C Programming Language and The Go Programming Language", Valid: true}, + }) + if err != nil { + t.Fatal(err) + } + t.Log(insertedAuthor) + + // get the author we just inserted + fetchedAuthor, err := q.GetAuthor(ctx, insertedAuthor.ID) + if err != nil { + t.Fatal(err) + } + t.Log(fetchedAuthor) +} diff --git a/examples/authors/postgresql/models.go b/examples/authors/postgresql/models.go new file mode 100644 index 0000000..d3f6eaa --- /dev/null +++ b/examples/authors/postgresql/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package authors + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Author struct { + ID int64 + Name string + Bio pgtype.Text +} diff --git a/examples/authors/postgresql/query.sql b/examples/authors/postgresql/query.sql new file mode 100644 index 0000000..75e38b2 --- /dev/null +++ b/examples/authors/postgresql/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/examples/authors/postgresql/query.sql.go b/examples/authors/postgresql/query.sql.go new file mode 100644 index 0000000..2910a80 --- /dev/null +++ b/examples/authors/postgresql/query.sql.go @@ -0,0 +1,80 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package authors + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const createAuthor = `-- name: CreateAuthor :one +INSERT INTO authors ( + name, bio +) VALUES ( + $1, $2 +) +RETURNING id, name, bio +` + +type CreateAuthorParams struct { + Name string + Bio pgtype.Text +} + +func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (Author, error) { + row := q.db.QueryRow(ctx, createAuthor, arg.Name, arg.Bio) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const deleteAuthor = `-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = $1 +` + +func (q *Queries) DeleteAuthor(ctx context.Context, id int64) error { + _, err := q.db.Exec(ctx, deleteAuthor, id) + return err +} + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, bio FROM authors +WHERE id = $1 LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRow(ctx, getAuthor, id) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name, bio FROM authors +ORDER BY name +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.Query(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/examples/authors/postgresql/schema.sql b/examples/authors/postgresql/schema.sql new file mode 100644 index 0000000..b4fad78 --- /dev/null +++ b/examples/authors/postgresql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); diff --git a/examples/authors/sqlc.yaml b/examples/authors/sqlc.yaml new file mode 100644 index 0000000..57f2319 --- /dev/null +++ b/examples/authors/sqlc.yaml @@ -0,0 +1,52 @@ +version: '2' +cloud: + project: "01HAQMMECEYQYKFJN8MP16QC41" +sql: +- name: postgresql + schema: postgresql/schema.sql + queries: postgresql/query.sql + engine: postgresql + database: + uri: "${VET_TEST_EXAMPLES_POSTGRES_AUTHORS}" + analyzer: + database: false + rules: + - sqlc/db-prepare + - postgresql-query-too-costly + gen: + go: + package: authors + sql_package: pgx/v5 + out: postgresql +- name: mysql + schema: mysql/schema.sql + queries: mysql/query.sql + engine: mysql + database: + uri: "${VET_TEST_EXAMPLES_MYSQL_AUTHORS}" + rules: + - sqlc/db-prepare + # - mysql-query-too-costly + gen: + go: + package: authors + out: mysql +- name: sqlite + schema: sqlite/schema.sql + queries: sqlite/query.sql + engine: sqlite + database: + uri: file:authors?mode=memory&cache=shared + rules: + - sqlc/db-prepare + gen: + go: + package: authors + out: sqlite +rules: +- name: postgresql-query-too-costly + message: "Too costly" + rule: "postgresql.explain.plan.total_cost > 300.0" +- name: mysql-query-too-costly + message: "Too costly" + rule: "has(mysql.explain.query_block.cost_info) && double(mysql.explain.query_block.cost_info.query_cost) > 2.0" diff --git a/examples/authors/sqlite/db.go b/examples/authors/sqlite/db.go new file mode 100644 index 0000000..32f660c --- /dev/null +++ b/examples/authors/sqlite/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package authors + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/examples/authors/sqlite/db_test.go b/examples/authors/sqlite/db_test.go new file mode 100644 index 0000000..e10ce46 --- /dev/null +++ b/examples/authors/sqlite/db_test.go @@ -0,0 +1,48 @@ +//go:build examples + +package authors + +import ( + "context" + "database/sql" + "testing" + + "github.com/sqlc-dev/sqlc/internal/sqltest" +) + +func TestAuthors(t *testing.T) { + sdb, cleanup := sqltest.SQLite(t, []string{"schema.sql"}) + defer sdb.Close() + defer cleanup() + + ctx := context.Background() + db := New(sdb) + + // list all authors + authors, err := db.ListAuthors(ctx) + if err != nil { + t.Fatal(err) + } + t.Log(authors) + + // create an author + result, err := db.CreateAuthor(ctx, CreateAuthorParams{ + Name: "Brian Kernighan", + Bio: sql.NullString{String: "Co-author of The C Programming Language and The Go Programming Language", Valid: true}, + }) + if err != nil { + t.Fatal(err) + } + authorID, err := result.LastInsertId() + if err != nil { + t.Fatal(err) + } + t.Log(authorID) + + // get the author we just inserted + fetchedAuthor, err := db.GetAuthor(ctx, authorID) + if err != nil { + t.Fatal(err) + } + t.Log(fetchedAuthor) +} diff --git a/examples/authors/sqlite/models.go b/examples/authors/sqlite/models.go new file mode 100644 index 0000000..62bacd8 --- /dev/null +++ b/examples/authors/sqlite/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package authors + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/examples/authors/sqlite/query.sql b/examples/authors/sqlite/query.sql new file mode 100644 index 0000000..c3b5866 --- /dev/null +++ b/examples/authors/sqlite/query.sql @@ -0,0 +1,18 @@ +/* name: GetAuthor :one */ +SELECT * FROM authors +WHERE id = ? LIMIT 1; + +/* name: ListAuthors :many */ +SELECT * FROM authors +ORDER BY name; + +/* name: CreateAuthor :execresult */ +INSERT INTO authors ( + name, bio +) VALUES ( + ?, ? +); + +/* name: DeleteAuthor :exec */ +DELETE FROM authors +WHERE id = ?; diff --git a/examples/authors/sqlite/query.sql.go b/examples/authors/sqlite/query.sql.go new file mode 100644 index 0000000..0d66af7 --- /dev/null +++ b/examples/authors/sqlite/query.sql.go @@ -0,0 +1,78 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package authors + +import ( + "context" + "database/sql" +) + +const createAuthor = `-- name: CreateAuthor :execresult +INSERT INTO authors ( + name, bio +) VALUES ( + ?, ? +) +` + +type CreateAuthorParams struct { + Name string + Bio sql.NullString +} + +func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (sql.Result, error) { + return q.db.ExecContext(ctx, createAuthor, arg.Name, arg.Bio) +} + +const deleteAuthor = `-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = ? +` + +func (q *Queries) DeleteAuthor(ctx context.Context, id int64) error { + _, err := q.db.ExecContext(ctx, deleteAuthor, id) + return err +} + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, bio FROM authors +WHERE id = ? LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name, bio FROM authors +ORDER BY name +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); 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/examples/authors/sqlite/schema.sql b/examples/authors/sqlite/schema.sql new file mode 100644 index 0000000..9b81ece --- /dev/null +++ b/examples/authors/sqlite/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE authors ( + id integer PRIMARY KEY AUTOINCREMENT, + name text NOT NULL, + bio text +); diff --git a/examples/batch/postgresql/batch.go b/examples/batch/postgresql/batch.go new file mode 100644 index 0000000..b6ba467 --- /dev/null +++ b/examples/batch/postgresql/batch.go @@ -0,0 +1,404 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: batch.go + +package batch + +import ( + "context" + "errors" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgtype" +) + +var ( + ErrBatchAlreadyClosed = errors.New("batch already closed") +) + +const booksByYear = `-- name: BooksByYear :batchmany +SELECT book_id, author_id, isbn, book_type, title, year, available, tags FROM books +WHERE year = $1 +` + +type BooksByYearBatchResults struct { + br pgx.BatchResults + tot int + closed bool +} + +func (q *Queries) BooksByYear(ctx context.Context, year []int32) *BooksByYearBatchResults { + batch := &pgx.Batch{} + for _, a := range year { + vals := []any{ + a, + } + batch.Queue(booksByYear, vals...) + } + br := q.db.SendBatch(ctx, batch) + return &BooksByYearBatchResults{br, len(year), false} +} + +func (b *BooksByYearBatchResults) Query(f func(int, []Book, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + var items []Book + if b.closed { + if f != nil { + f(t, items, ErrBatchAlreadyClosed) + } + continue + } + err := func() error { + rows, err := b.br.Query() + if err != nil { + return err + } + defer rows.Close() + for rows.Next() { + var i Book + if err := rows.Scan( + &i.BookID, + &i.AuthorID, + &i.Isbn, + &i.BookType, + &i.Title, + &i.Year, + &i.Available, + &i.Tags, + ); err != nil { + return err + } + items = append(items, i) + } + return rows.Err() + }() + if f != nil { + f(t, items, err) + } + } +} + +func (b *BooksByYearBatchResults) Close() error { + b.closed = true + return b.br.Close() +} + +const createBook = `-- name: CreateBook :batchone +INSERT INTO books ( + author_id, + isbn, + book_type, + title, + year, + available, + tags +) VALUES ( + $1, + $2, + $3, + $4, + $5, + $6, + $7 +) +RETURNING book_id, author_id, isbn, book_type, title, year, available, tags +` + +type CreateBookBatchResults struct { + br pgx.BatchResults + tot int + closed bool +} + +type CreateBookParams struct { + AuthorID int32 `json:"author_id"` + Isbn string `json:"isbn"` + BookType BookType `json:"book_type"` + Title string `json:"title"` + Year int32 `json:"year"` + Available pgtype.Timestamptz `json:"available"` + Tags []string `json:"tags"` +} + +func (q *Queries) CreateBook(ctx context.Context, arg []CreateBookParams) *CreateBookBatchResults { + batch := &pgx.Batch{} + for _, a := range arg { + vals := []any{ + a.AuthorID, + a.Isbn, + a.BookType, + a.Title, + a.Year, + a.Available, + a.Tags, + } + batch.Queue(createBook, vals...) + } + br := q.db.SendBatch(ctx, batch) + return &CreateBookBatchResults{br, len(arg), false} +} + +func (b *CreateBookBatchResults) QueryRow(f func(int, Book, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + var i Book + if b.closed { + if f != nil { + f(t, i, ErrBatchAlreadyClosed) + } + continue + } + row := b.br.QueryRow() + err := row.Scan( + &i.BookID, + &i.AuthorID, + &i.Isbn, + &i.BookType, + &i.Title, + &i.Year, + &i.Available, + &i.Tags, + ) + if f != nil { + f(t, i, err) + } + } +} + +func (b *CreateBookBatchResults) Close() error { + b.closed = true + return b.br.Close() +} + +const deleteBook = `-- name: DeleteBook :batchexec +DELETE FROM books +WHERE book_id = $1 +` + +type DeleteBookBatchResults struct { + br pgx.BatchResults + tot int + closed bool +} + +func (q *Queries) DeleteBook(ctx context.Context, bookID []int32) *DeleteBookBatchResults { + batch := &pgx.Batch{} + for _, a := range bookID { + vals := []any{ + a, + } + batch.Queue(deleteBook, vals...) + } + br := q.db.SendBatch(ctx, batch) + return &DeleteBookBatchResults{br, len(bookID), false} +} + +func (b *DeleteBookBatchResults) Exec(f func(int, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + if b.closed { + if f != nil { + f(t, ErrBatchAlreadyClosed) + } + continue + } + _, err := b.br.Exec() + if f != nil { + f(t, err) + } + } +} + +func (b *DeleteBookBatchResults) Close() error { + b.closed = true + return b.br.Close() +} + +const deleteBookNamedFunc = `-- name: DeleteBookNamedFunc :batchexec +DELETE FROM books +WHERE book_id = $1 +` + +type DeleteBookNamedFuncBatchResults struct { + br pgx.BatchResults + tot int + closed bool +} + +func (q *Queries) DeleteBookNamedFunc(ctx context.Context, bookID []int32) *DeleteBookNamedFuncBatchResults { + batch := &pgx.Batch{} + for _, a := range bookID { + vals := []any{ + a, + } + batch.Queue(deleteBookNamedFunc, vals...) + } + br := q.db.SendBatch(ctx, batch) + return &DeleteBookNamedFuncBatchResults{br, len(bookID), false} +} + +func (b *DeleteBookNamedFuncBatchResults) Exec(f func(int, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + if b.closed { + if f != nil { + f(t, ErrBatchAlreadyClosed) + } + continue + } + _, err := b.br.Exec() + if f != nil { + f(t, err) + } + } +} + +func (b *DeleteBookNamedFuncBatchResults) Close() error { + b.closed = true + return b.br.Close() +} + +const deleteBookNamedSign = `-- name: DeleteBookNamedSign :batchexec +DELETE FROM books +WHERE book_id = $1 +` + +type DeleteBookNamedSignBatchResults struct { + br pgx.BatchResults + tot int + closed bool +} + +func (q *Queries) DeleteBookNamedSign(ctx context.Context, bookID []int32) *DeleteBookNamedSignBatchResults { + batch := &pgx.Batch{} + for _, a := range bookID { + vals := []any{ + a, + } + batch.Queue(deleteBookNamedSign, vals...) + } + br := q.db.SendBatch(ctx, batch) + return &DeleteBookNamedSignBatchResults{br, len(bookID), false} +} + +func (b *DeleteBookNamedSignBatchResults) Exec(f func(int, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + if b.closed { + if f != nil { + f(t, ErrBatchAlreadyClosed) + } + continue + } + _, err := b.br.Exec() + if f != nil { + f(t, err) + } + } +} + +func (b *DeleteBookNamedSignBatchResults) Close() error { + b.closed = true + return b.br.Close() +} + +const getBiography = `-- name: GetBiography :batchone +SELECT biography FROM authors +WHERE author_id = $1 +` + +type GetBiographyBatchResults struct { + br pgx.BatchResults + tot int + closed bool +} + +func (q *Queries) GetBiography(ctx context.Context, authorID []int32) *GetBiographyBatchResults { + batch := &pgx.Batch{} + for _, a := range authorID { + vals := []any{ + a, + } + batch.Queue(getBiography, vals...) + } + br := q.db.SendBatch(ctx, batch) + return &GetBiographyBatchResults{br, len(authorID), false} +} + +func (b *GetBiographyBatchResults) QueryRow(f func(int, []byte, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + var biography []byte + if b.closed { + if f != nil { + f(t, biography, ErrBatchAlreadyClosed) + } + continue + } + row := b.br.QueryRow() + err := row.Scan(&biography) + if f != nil { + f(t, biography, err) + } + } +} + +func (b *GetBiographyBatchResults) Close() error { + b.closed = true + return b.br.Close() +} + +const updateBook = `-- name: UpdateBook :batchexec +UPDATE books +SET title = $1, tags = $2 +WHERE book_id = $3 +` + +type UpdateBookBatchResults struct { + br pgx.BatchResults + tot int + closed bool +} + +type UpdateBookParams struct { + Title string `json:"title"` + Tags []string `json:"tags"` + BookID int32 `json:"book_id"` +} + +func (q *Queries) UpdateBook(ctx context.Context, arg []UpdateBookParams) *UpdateBookBatchResults { + batch := &pgx.Batch{} + for _, a := range arg { + vals := []any{ + a.Title, + a.Tags, + a.BookID, + } + batch.Queue(updateBook, vals...) + } + br := q.db.SendBatch(ctx, batch) + return &UpdateBookBatchResults{br, len(arg), false} +} + +func (b *UpdateBookBatchResults) Exec(f func(int, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + if b.closed { + if f != nil { + f(t, ErrBatchAlreadyClosed) + } + continue + } + _, err := b.br.Exec() + if f != nil { + f(t, err) + } + } +} + +func (b *UpdateBookBatchResults) Close() error { + b.closed = true + return b.br.Close() +} diff --git a/examples/batch/postgresql/db.go b/examples/batch/postgresql/db.go new file mode 100644 index 0000000..64ff18e --- /dev/null +++ b/examples/batch/postgresql/db.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package batch + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row + SendBatch(context.Context, *pgx.Batch) pgx.BatchResults +} + +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/examples/batch/postgresql/db_test.go b/examples/batch/postgresql/db_test.go new file mode 100644 index 0000000..122fa1a --- /dev/null +++ b/examples/batch/postgresql/db_test.go @@ -0,0 +1,153 @@ +//go:build examples + +package batch + +import ( + "context" + "testing" + "time" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgtype" + + "github.com/sqlc-dev/sqlc/internal/sqltest/local" +) + +func TestBatchBooks(t *testing.T) { + uri := local.PostgreSQL(t, []string{"schema.sql"}) + + ctx := context.Background() + + db, err := pgx.Connect(ctx, uri) + if err != nil { + t.Fatal(err) + } + defer db.Close(ctx) + + dq := New(db) + + // create an author + a, err := dq.CreateAuthor(ctx, "Unknown Master") + if err != nil { + t.Fatal(err) + } + + now := pgtype.Timestamptz{Time: time.Now(), Valid: true} + + // batch insert new books + newBooksParams := []CreateBookParams{ + { + AuthorID: a.AuthorID, + Isbn: "1", + Title: "my book title", + BookType: BookTypeFICTION, + Year: 2016, + Available: now, + Tags: []string{}, + }, + { + AuthorID: a.AuthorID, + Isbn: "2", + Title: "the second book", + BookType: BookTypeFICTION, + Year: 2016, + Available: now, + Tags: []string{"cool", "unique"}, + }, + { + AuthorID: a.AuthorID, + Isbn: "3", + Title: "the third book", + BookType: BookTypeFICTION, + Year: 2001, + Available: now, + Tags: []string{"cool"}, + }, + { + AuthorID: a.AuthorID, + Isbn: "4", + Title: "4th place finisher", + BookType: BookTypeNONFICTION, + Year: 2011, + Available: now, + Tags: []string{"other"}, + }, + } + newBooks := make([]Book, len(newBooksParams)) + var cnt int + dq.CreateBook(ctx, newBooksParams).QueryRow(func(i int, b Book, err error) { + if err != nil { + t.Fatalf("failed inserting book (%s): %s", b.Title, err) + } + newBooks[i] = b + cnt = i + }) + // first i was 0, so add 1 + cnt++ + numBooksExpected := len(newBooks) + if cnt != numBooksExpected { + t.Fatalf("expected to insert %d books; got %d", numBooksExpected, cnt) + } + + // batch update the title and tags + updateBooksParams := []UpdateBookParams{ + { + BookID: newBooks[1].BookID, + Title: "changed second title", + Tags: []string{"cool", "disastor"}, + }, + } + dq.UpdateBook(ctx, updateBooksParams).Exec(func(i int, err error) { + if err != nil { + t.Fatalf("error updating book %d: %s", updateBooksParams[i].BookID, err) + } + }) + + // batch many to retrieve books by year + selectBooksByTitleYearParams := []int32{2001, 2016} + var books0 []Book + dq.BooksByYear(ctx, selectBooksByTitleYearParams).Query(func(i int, books []Book, err error) { + if err != nil { + t.Fatal(err) + } + t.Logf("num books for %d: %d", selectBooksByTitleYearParams[i], len(books)) + books0 = append(books0, books...) + }) + + for _, book := range books0 { + t.Logf("Book %d (%s): %s available: %s\n", book.BookID, book.BookType, book.Title, book.Available.Time.Format(time.RFC822Z)) + author, err := dq.GetAuthor(ctx, book.AuthorID) + if err != nil { + t.Fatal(err) + } + t.Logf("Book %d author: %s\n", book.BookID, author.Name) + } + + // batch delete books + deleteBooksParams := make([]int32, len(newBooks)) + for i, book := range newBooks { + deleteBooksParams[i] = book.BookID + } + batchDelete := dq.DeleteBook(ctx, deleteBooksParams) + numDeletesProcessed := 0 + wantNumDeletesProcessed := 2 + batchDelete.Exec(func(i int, err error) { + if err != nil && err.Error() != "batch already closed" { + t.Fatalf("error deleting book %d: %s", deleteBooksParams[i], err) + } + + if err == nil { + numDeletesProcessed++ + } + + if i == wantNumDeletesProcessed-1 { + // close batch operation before processing all errors from delete operation + if err := batchDelete.Close(); err != nil { + t.Fatalf("failed to close batch operation: %s", err) + } + } + }) + if numDeletesProcessed != wantNumDeletesProcessed { + t.Fatalf("expected Close to short-circuit record processing (expected %d; got %d)", wantNumDeletesProcessed, numDeletesProcessed) + } +} diff --git a/examples/batch/postgresql/models.go b/examples/batch/postgresql/models.go new file mode 100644 index 0000000..65d987a --- /dev/null +++ b/examples/batch/postgresql/models.go @@ -0,0 +1,71 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package batch + +import ( + "database/sql/driver" + "fmt" + + "github.com/jackc/pgx/v5/pgtype" +) + +type BookType string + +const ( + BookTypeFICTION BookType = "FICTION" + BookTypeNONFICTION BookType = "NONFICTION" +) + +func (e *BookType) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = BookType(s) + case string: + *e = BookType(s) + default: + return fmt.Errorf("unsupported scan type for BookType: %T", src) + } + return nil +} + +type NullBookType struct { + BookType BookType `json:"book_type"` + Valid bool `json:"valid"` // Valid is true if BookType is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullBookType) Scan(value any) error { + if value == nil { + ns.BookType, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.BookType.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullBookType) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.BookType), nil +} + +type Author struct { + AuthorID int32 `json:"author_id"` + Name string `json:"name"` + Biography []byte `json:"biography"` +} + +type Book struct { + BookID int32 `json:"book_id"` + AuthorID int32 `json:"author_id"` + Isbn string `json:"isbn"` + BookType BookType `json:"book_type"` + Title string `json:"title"` + Year int32 `json:"year"` + Available pgtype.Timestamptz `json:"available"` + Tags []string `json:"tags"` +} diff --git a/examples/batch/postgresql/querier.go b/examples/batch/postgresql/querier.go new file mode 100644 index 0000000..9fe9996 --- /dev/null +++ b/examples/batch/postgresql/querier.go @@ -0,0 +1,26 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package batch + +import ( + "context" + + "github.com/jackc/pgx/v5/pgconn" +) + +type Querier interface { + BooksByYear(ctx context.Context, year []int32) *BooksByYearBatchResults + CreateAuthor(ctx context.Context, name string) (Author, error) + CreateBook(ctx context.Context, arg []CreateBookParams) *CreateBookBatchResults + DeleteBook(ctx context.Context, bookID []int32) *DeleteBookBatchResults + DeleteBookExecResult(ctx context.Context, bookID int32) (pgconn.CommandTag, error) + DeleteBookNamedFunc(ctx context.Context, bookID []int32) *DeleteBookNamedFuncBatchResults + DeleteBookNamedSign(ctx context.Context, bookID []int32) *DeleteBookNamedSignBatchResults + GetAuthor(ctx context.Context, authorID int32) (Author, error) + GetBiography(ctx context.Context, authorID []int32) *GetBiographyBatchResults + UpdateBook(ctx context.Context, arg []UpdateBookParams) *UpdateBookBatchResults +} + +var _ Querier = (*Queries)(nil) diff --git a/examples/batch/postgresql/query.sql b/examples/batch/postgresql/query.sql new file mode 100644 index 0000000..4e21f25 --- /dev/null +++ b/examples/batch/postgresql/query.sql @@ -0,0 +1,56 @@ +-- name: GetAuthor :one +SELECT * FROM authors +WHERE author_id = $1; + +-- name: DeleteBookExecResult :execresult +DELETE FROM books +WHERE book_id = $1; + +-- name: DeleteBook :batchexec +DELETE FROM books +WHERE book_id = $1; + +-- name: DeleteBookNamedFunc :batchexec +DELETE FROM books +WHERE book_id = sqlc.arg (book_id); + +-- name: DeleteBookNamedSign :batchexec +DELETE FROM books +WHERE book_id = @book_id; + +-- name: BooksByYear :batchmany +SELECT * FROM books +WHERE year = $1; + +-- name: CreateAuthor :one +INSERT INTO authors (name) VALUES ($1) +RETURNING *; + +-- name: CreateBook :batchone +INSERT INTO books ( + author_id, + isbn, + book_type, + title, + year, + available, + tags +) VALUES ( + $1, + $2, + $3, + $4, + $5, + $6, + $7 +) +RETURNING *; + +-- name: UpdateBook :batchexec +UPDATE books +SET title = $1, tags = $2 +WHERE book_id = $3; + +-- name: GetBiography :batchone +SELECT biography FROM authors +WHERE author_id = $1; diff --git a/examples/batch/postgresql/query.sql.go b/examples/batch/postgresql/query.sql.go new file mode 100644 index 0000000..ffab325 --- /dev/null +++ b/examples/batch/postgresql/query.sql.go @@ -0,0 +1,45 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package batch + +import ( + "context" + + "github.com/jackc/pgx/v5/pgconn" +) + +const createAuthor = `-- name: CreateAuthor :one +INSERT INTO authors (name) VALUES ($1) +RETURNING author_id, name, biography +` + +func (q *Queries) CreateAuthor(ctx context.Context, name string) (Author, error) { + row := q.db.QueryRow(ctx, createAuthor, name) + var i Author + err := row.Scan(&i.AuthorID, &i.Name, &i.Biography) + return i, err +} + +const deleteBookExecResult = `-- name: DeleteBookExecResult :execresult +DELETE FROM books +WHERE book_id = $1 +` + +func (q *Queries) DeleteBookExecResult(ctx context.Context, bookID int32) (pgconn.CommandTag, error) { + return q.db.Exec(ctx, deleteBookExecResult, bookID) +} + +const getAuthor = `-- name: GetAuthor :one +SELECT author_id, name, biography FROM authors +WHERE author_id = $1 +` + +func (q *Queries) GetAuthor(ctx context.Context, authorID int32) (Author, error) { + row := q.db.QueryRow(ctx, getAuthor, authorID) + var i Author + err := row.Scan(&i.AuthorID, &i.Name, &i.Biography) + return i, err +} diff --git a/examples/batch/postgresql/schema.sql b/examples/batch/postgresql/schema.sql new file mode 100644 index 0000000..b79f773 --- /dev/null +++ b/examples/batch/postgresql/schema.sql @@ -0,0 +1,21 @@ +CREATE TABLE authors ( + author_id SERIAL PRIMARY KEY, + name text NOT NULL DEFAULT '', + biography JSONB +); + +CREATE TYPE book_type AS ENUM ( + 'FICTION', + 'NONFICTION' +); + +CREATE TABLE books ( + book_id SERIAL PRIMARY KEY, + author_id integer NOT NULL REFERENCES authors(author_id), + isbn text NOT NULL DEFAULT '' UNIQUE, + book_type book_type NOT NULL DEFAULT 'FICTION', + title text NOT NULL DEFAULT '', + year integer NOT NULL DEFAULT 2000, + available timestamp with time zone NOT NULL DEFAULT 'NOW()', + tags varchar[] NOT NULL DEFAULT '{}' +); diff --git a/examples/batch/sqlc.json b/examples/batch/sqlc.json new file mode 100644 index 0000000..2f6b9a9 --- /dev/null +++ b/examples/batch/sqlc.json @@ -0,0 +1,28 @@ +{ + "version": "1", + "cloud": { + "project": "01HAQMMECEYQYKFJN8MP16QC41" + }, + "packages": [ + { + "path": "postgresql", + "name": "batch", + "schema": "postgresql/schema.sql", + "queries": "postgresql/query.sql", + "engine": "postgresql", + "database": { + "uri": "${VET_TEST_EXAMPLES_POSTGRES_BATCH}" + }, + "analyzer": { + "database": false + }, + "rules": [ + "sqlc/db-prepare" + ], + "sql_package": "pgx/v5", + "emit_json_tags": true, + "emit_prepared_queries": true, + "emit_interface": true + } + ] +} diff --git a/examples/booktest/mysql/db.go b/examples/booktest/mysql/db.go new file mode 100644 index 0000000..716f4f3 --- /dev/null +++ b/examples/booktest/mysql/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package booktest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/examples/booktest/mysql/db_test.go b/examples/booktest/mysql/db_test.go new file mode 100644 index 0000000..6f97178 --- /dev/null +++ b/examples/booktest/mysql/db_test.go @@ -0,0 +1,174 @@ +//go:build examples + +package booktest + +import ( + "context" + "database/sql" + "testing" + "time" + + _ "github.com/go-sql-driver/mysql" + + "github.com/sqlc-dev/sqlc/internal/sqltest/local" +) + +func TestBooks(t *testing.T) { + ctx := context.Background() + uri := local.MySQL(t, []string{"schema.sql"}) + db, err := sql.Open("mysql", uri) + if err != nil { + t.Fatal(err) + } + defer db.Close() + + dq := New(db) + + // create an author + result, err := dq.CreateAuthor(ctx, "Unknown Master") + if err != nil { + t.Fatal(err) + } + authorID, err := result.LastInsertId() + if err != nil { + t.Fatal(err) + } + + // create transaction + tx, err := db.Begin() + if err != nil { + t.Fatal(err) + } + + tq := dq.WithTx(tx) + + // save first book + now := time.Now() + _, err = tq.CreateBook(ctx, CreateBookParams{ + AuthorID: int32(authorID), + Isbn: "1", + Title: "my book title", + BookType: BooksBookTypeFICTION, + Yr: 2016, + Available: now, + }) + if err != nil { + t.Fatal(err) + } + + // save second book + result, err = tq.CreateBook(ctx, CreateBookParams{ + AuthorID: int32(authorID), + Isbn: "2", + Title: "the second book", + BookType: BooksBookTypeFICTION, + Yr: 2016, + Available: now, + Tags: "cool,unique", + }) + if err != nil { + t.Fatal(err) + } + bookOneID, err := result.LastInsertId() + if err != nil { + t.Fatal(err) + } + + // update the title and tags + err = tq.UpdateBook(ctx, UpdateBookParams{ + BookID: int32(bookOneID), + Title: "changed second title", + Tags: "cool,disastor", + }) + if err != nil { + t.Fatal(err) + } + + // save third book + _, err = tq.CreateBook(ctx, CreateBookParams{ + AuthorID: int32(authorID), + Isbn: "3", + Title: "the third book", + BookType: BooksBookTypeFICTION, + Yr: 2001, + Available: now, + Tags: "cool", + }) + if err != nil { + t.Fatal(err) + } + + // save fourth book + result, err = tq.CreateBook(ctx, CreateBookParams{ + AuthorID: int32(authorID), + Isbn: "4", + Title: "4th place finisher", + BookType: BooksBookTypeNONFICTION, + Yr: 2011, + Available: now, + Tags: "other", + }) + if err != nil { + t.Fatal(err) + } + bookThreeID, err := result.LastInsertId() + if err != nil { + t.Fatal(err) + } + + // tx commit + err = tx.Commit() + if err != nil { + t.Fatal(err) + } + + // upsert, changing ISBN and title + err = dq.UpdateBookISBN(ctx, UpdateBookISBNParams{ + BookID: int32(bookThreeID), + Isbn: "NEW ISBN", + Title: "never ever gonna finish, a quatrain", + Tags: "someother", + }) + if err != nil { + t.Fatal(err) + } + + // retrieve first book + books0, err := dq.BooksByTitleYear(ctx, BooksByTitleYearParams{ + Title: "my book title", + Yr: 2016, + }) + if err != nil { + t.Fatal(err) + } + for _, book := range books0 { + t.Logf("Book %d (%s): %s available: %s\n", book.BookID, book.BookType, book.Title, book.Available.Format(time.RFC822Z)) + author, err := dq.GetAuthor(ctx, book.AuthorID) + if err != nil { + t.Fatal(err) + } + t.Logf("Book %d author: %s\n", book.BookID, author.Name) + } + + // find a book with either "cool" or "other" tag + t.Logf("---------\nTag search results:\n") + res, err := dq.BooksByTags(ctx, "cool") + if err != nil { + t.Fatal(err) + } + for _, ab := range res { + t.Logf("Book %d: '%s', Author: '%s', ISBN: '%s' Tags: '%v'\n", ab.BookID, ab.Title, ab.Name.String, ab.Isbn, ab.Tags) + } + + // TODO: call say_hello(varchar) + + // get book 4 and delete + b5, err := dq.GetBook(ctx, int32(bookThreeID)) + if err != nil { + t.Fatal(err) + } + if err := dq.DeleteBook(ctx, b5.BookID); err != nil { + t.Fatal(err) + } + +} diff --git a/examples/booktest/mysql/models.go b/examples/booktest/mysql/models.go new file mode 100644 index 0000000..f81d3af --- /dev/null +++ b/examples/booktest/mysql/models.go @@ -0,0 +1,69 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package booktest + +import ( + "database/sql/driver" + "fmt" + "time" +) + +type BooksBookType string + +const ( + BooksBookTypeFICTION BooksBookType = "FICTION" + BooksBookTypeNONFICTION BooksBookType = "NONFICTION" +) + +func (e *BooksBookType) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = BooksBookType(s) + case string: + *e = BooksBookType(s) + default: + return fmt.Errorf("unsupported scan type for BooksBookType: %T", src) + } + return nil +} + +type NullBooksBookType struct { + BooksBookType BooksBookType + Valid bool // Valid is true if BooksBookType is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullBooksBookType) Scan(value any) error { + if value == nil { + ns.BooksBookType, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.BooksBookType.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullBooksBookType) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.BooksBookType), nil +} + +type Author struct { + AuthorID int32 + Name string +} + +type Book struct { + BookID int32 + AuthorID int32 + Isbn string + BookType BooksBookType + Title string + Yr int32 + Available time.Time + Tags string +} diff --git a/examples/booktest/mysql/query.sql b/examples/booktest/mysql/query.sql new file mode 100644 index 0000000..a455ad4 --- /dev/null +++ b/examples/booktest/mysql/query.sql @@ -0,0 +1,63 @@ +/* name: GetAuthor :one */ +SELECT * FROM authors +WHERE author_id = ?; + +/* name: GetBook :one */ +SELECT * FROM books +WHERE book_id = ?; + +/* name: DeleteBook :exec */ +DELETE FROM books +WHERE book_id = ?; + +/* name: BooksByTitleYear :many */ +SELECT * FROM books +WHERE title = ? AND yr = ?; + +/* name: BooksByTags :many */ +SELECT + book_id, + title, + name, + isbn, + tags +FROM books +LEFT JOIN authors ON books.author_id = authors.author_id +WHERE tags = ?; + +/* name: CreateAuthor :execresult */ +INSERT INTO authors (name) VALUES (?); + +/* name: CreateBook :execresult */ +INSERT INTO books ( + author_id, + isbn, + book_type, + title, + yr, + available, + tags +) VALUES ( + ?, + ?, + ?, + ?, + ?, + ?, + ? +); + +/* name: UpdateBook :exec */ +UPDATE books +SET title = ?, tags = ? +WHERE book_id = ?; + +/* name: UpdateBookISBN :exec */ +UPDATE books +SET title = ?, tags = ?, isbn = ? +WHERE book_id = ?; + +/* name: DeleteAuthorBeforeYear :exec */ +DELETE FROM books +WHERE yr < ? AND author_id = ?; +-- WHERE yr < sqlc.arg(min_publish_year) AND author_id = ?; diff --git a/examples/booktest/mysql/query.sql.go b/examples/booktest/mysql/query.sql.go new file mode 100644 index 0000000..3957820 --- /dev/null +++ b/examples/booktest/mysql/query.sql.go @@ -0,0 +1,251 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package booktest + +import ( + "context" + "database/sql" + "time" +) + +const booksByTags = `-- name: BooksByTags :many +SELECT + book_id, + title, + name, + isbn, + tags +FROM books +LEFT JOIN authors ON books.author_id = authors.author_id +WHERE tags = ? +` + +type BooksByTagsRow struct { + BookID int32 + Title string + Name sql.NullString + Isbn string + Tags string +} + +func (q *Queries) BooksByTags(ctx context.Context, tags string) ([]BooksByTagsRow, error) { + rows, err := q.db.QueryContext(ctx, booksByTags, tags) + if err != nil { + return nil, err + } + defer rows.Close() + var items []BooksByTagsRow + for rows.Next() { + var i BooksByTagsRow + if err := rows.Scan( + &i.BookID, + &i.Title, + &i.Name, + &i.Isbn, + &i.Tags, + ); 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 booksByTitleYear = `-- name: BooksByTitleYear :many +SELECT book_id, author_id, isbn, book_type, title, yr, available, tags FROM books +WHERE title = ? AND yr = ? +` + +type BooksByTitleYearParams struct { + Title string + Yr int32 +} + +func (q *Queries) BooksByTitleYear(ctx context.Context, arg BooksByTitleYearParams) ([]Book, error) { + rows, err := q.db.QueryContext(ctx, booksByTitleYear, arg.Title, arg.Yr) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Book + for rows.Next() { + var i Book + if err := rows.Scan( + &i.BookID, + &i.AuthorID, + &i.Isbn, + &i.BookType, + &i.Title, + &i.Yr, + &i.Available, + &i.Tags, + ); 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 createAuthor = `-- name: CreateAuthor :execresult +INSERT INTO authors (name) VALUES (?) +` + +func (q *Queries) CreateAuthor(ctx context.Context, name string) (sql.Result, error) { + return q.db.ExecContext(ctx, createAuthor, name) +} + +const createBook = `-- name: CreateBook :execresult +INSERT INTO books ( + author_id, + isbn, + book_type, + title, + yr, + available, + tags +) VALUES ( + ?, + ?, + ?, + ?, + ?, + ?, + ? +) +` + +type CreateBookParams struct { + AuthorID int32 + Isbn string + BookType BooksBookType + Title string + Yr int32 + Available time.Time + Tags string +} + +func (q *Queries) CreateBook(ctx context.Context, arg CreateBookParams) (sql.Result, error) { + return q.db.ExecContext(ctx, createBook, + arg.AuthorID, + arg.Isbn, + arg.BookType, + arg.Title, + arg.Yr, + arg.Available, + arg.Tags, + ) +} + +const deleteAuthorBeforeYear = `-- name: DeleteAuthorBeforeYear :exec +DELETE FROM books +WHERE yr < ? AND author_id = ? +` + +type DeleteAuthorBeforeYearParams struct { + Yr int32 + AuthorID int32 +} + +func (q *Queries) DeleteAuthorBeforeYear(ctx context.Context, arg DeleteAuthorBeforeYearParams) error { + _, err := q.db.ExecContext(ctx, deleteAuthorBeforeYear, arg.Yr, arg.AuthorID) + return err +} + +const deleteBook = `-- name: DeleteBook :exec +DELETE FROM books +WHERE book_id = ? +` + +func (q *Queries) DeleteBook(ctx context.Context, bookID int32) error { + _, err := q.db.ExecContext(ctx, deleteBook, bookID) + return err +} + +const getAuthor = `-- name: GetAuthor :one +SELECT author_id, name FROM authors +WHERE author_id = ? +` + +func (q *Queries) GetAuthor(ctx context.Context, authorID int32) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, authorID) + var i Author + err := row.Scan(&i.AuthorID, &i.Name) + return i, err +} + +const getBook = `-- name: GetBook :one +SELECT book_id, author_id, isbn, book_type, title, yr, available, tags FROM books +WHERE book_id = ? +` + +func (q *Queries) GetBook(ctx context.Context, bookID int32) (Book, error) { + row := q.db.QueryRowContext(ctx, getBook, bookID) + var i Book + err := row.Scan( + &i.BookID, + &i.AuthorID, + &i.Isbn, + &i.BookType, + &i.Title, + &i.Yr, + &i.Available, + &i.Tags, + ) + return i, err +} + +const updateBook = `-- name: UpdateBook :exec +UPDATE books +SET title = ?, tags = ? +WHERE book_id = ? +` + +type UpdateBookParams struct { + Title string + Tags string + BookID int32 +} + +func (q *Queries) UpdateBook(ctx context.Context, arg UpdateBookParams) error { + _, err := q.db.ExecContext(ctx, updateBook, arg.Title, arg.Tags, arg.BookID) + return err +} + +const updateBookISBN = `-- name: UpdateBookISBN :exec +UPDATE books +SET title = ?, tags = ?, isbn = ? +WHERE book_id = ? +` + +type UpdateBookISBNParams struct { + Title string + Tags string + Isbn string + BookID int32 +} + +func (q *Queries) UpdateBookISBN(ctx context.Context, arg UpdateBookISBNParams) error { + _, err := q.db.ExecContext(ctx, updateBookISBN, + arg.Title, + arg.Tags, + arg.Isbn, + arg.BookID, + ) + return err +} diff --git a/examples/booktest/mysql/schema.sql b/examples/booktest/mysql/schema.sql new file mode 100644 index 0000000..e457da9 --- /dev/null +++ b/examples/booktest/mysql/schema.sql @@ -0,0 +1,26 @@ +CREATE TABLE authors ( + author_id integer NOT NULL AUTO_INCREMENT PRIMARY KEY, + name text NOT NULL +) ENGINE=InnoDB; + +CREATE INDEX authors_name_idx ON authors(name(255)); + +CREATE TABLE books ( + book_id integer NOT NULL AUTO_INCREMENT PRIMARY KEY, + author_id integer NOT NULL, + isbn varchar(255) NOT NULL DEFAULT '' UNIQUE, + book_type ENUM('FICTION', 'NONFICTION') NOT NULL DEFAULT 'FICTION', + title text NOT NULL, + yr integer NOT NULL DEFAULT 2000, + available datetime NOT NULL DEFAULT NOW(), + tags text NOT NULL + -- CONSTRAINT FOREIGN KEY (author_id) REFERENCES authors(author_id) +) ENGINE=InnoDB; + +CREATE INDEX books_title_idx ON books(title(255), yr); + +/* +CREATE FUNCTION say_hello(s text) RETURNS text + DETERMINISTIC + RETURN CONCAT('hello ', s); +*/ diff --git a/examples/booktest/postgresql/db.go b/examples/booktest/postgresql/db.go new file mode 100644 index 0000000..ba35086 --- /dev/null +++ b/examples/booktest/postgresql/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package booktest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/examples/booktest/postgresql/db_test.go b/examples/booktest/postgresql/db_test.go new file mode 100644 index 0000000..ae71593 --- /dev/null +++ b/examples/booktest/postgresql/db_test.go @@ -0,0 +1,174 @@ +//go:build examples + +package booktest + +import ( + "context" + "testing" + "time" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgtype" + + "github.com/sqlc-dev/sqlc/internal/sqltest/local" +) + +func TestBooks(t *testing.T) { + ctx := context.Background() + uri := local.PostgreSQL(t, []string{"schema.sql"}) + db, err := pgx.Connect(ctx, uri) + if err != nil { + t.Fatal(err) + } + defer db.Close(ctx) + + dq := New(db) + + // create an author + a, err := dq.CreateAuthor(ctx, "Unknown Master") + if err != nil { + t.Fatal(err) + } + + // create transaction + tx, err := db.Begin(ctx) + if err != nil { + t.Fatal(err) + } + + tq := dq.WithTx(tx) + + // save first book + now := pgtype.Timestamptz{Time: time.Now(), Valid: true} + _, err = tq.CreateBook(ctx, CreateBookParams{ + AuthorID: a.AuthorID, + Isbn: "1", + Title: "my book title", + BookType: BookTypeFICTION, + Year: 2016, + Available: now, + Tags: []string{}, + }) + if err != nil { + t.Fatal(err) + } + + // save second book + b1, err := tq.CreateBook(ctx, CreateBookParams{ + AuthorID: a.AuthorID, + Isbn: "2", + Title: "the second book", + BookType: BookTypeFICTION, + Year: 2016, + Available: now, + Tags: []string{"cool", "unique"}, + }) + if err != nil { + t.Fatal(err) + } + + // update the title and tags + err = tq.UpdateBook(ctx, UpdateBookParams{ + BookID: b1.BookID, + Title: "changed second title", + Tags: []string{"cool", "disastor"}, + }) + if err != nil { + t.Fatal(err) + } + + // save third book + _, err = tq.CreateBook(ctx, CreateBookParams{ + AuthorID: a.AuthorID, + Isbn: "3", + Title: "the third book", + BookType: BookTypeFICTION, + Year: 2001, + Available: now, + Tags: []string{"cool"}, + }) + if err != nil { + t.Fatal(err) + } + + // save fourth book + b3, err := tq.CreateBook(ctx, CreateBookParams{ + AuthorID: a.AuthorID, + Isbn: "4", + Title: "4th place finisher", + BookType: BookTypeNONFICTION, + Year: 2011, + Available: now, + Tags: []string{"other"}, + }) + if err != nil { + t.Fatal(err) + } + + // tx commit + err = tx.Commit(ctx) + if err != nil { + t.Fatal(err) + } + + // upsert, changing ISBN and title + err = dq.UpdateBookISBN(ctx, UpdateBookISBNParams{ + BookID: b3.BookID, + Isbn: "NEW ISBN", + Title: "never ever gonna finish, a quatrain", + Tags: []string{"someother"}, + }) + if err != nil { + t.Fatal(err) + } + + // retrieve first book + books0, err := dq.BooksByTitleYear(ctx, BooksByTitleYearParams{ + Title: "my book title", + Year: 2016, + }) + if err != nil { + t.Fatal(err) + } + for _, book := range books0 { + t.Logf("Book %d (%s): %s available: %s\n", book.BookID, book.BookType, book.Title, book.Available.Time.Format(time.RFC822Z)) + author, err := dq.GetAuthor(ctx, book.AuthorID) + if err != nil { + t.Fatal(err) + } + t.Logf("Book %d author: %s\n", book.BookID, author.Name) + } + + // find a book with either "cool" or "other" tag + t.Logf("---------\nTag search results:\n") + res, err := dq.BooksByTags(ctx, []string{"cool", "other", "someother"}) + if err != nil { + t.Fatal(err) + } + for _, ab := range res { + t.Logf("Book %d: '%s', Author: '%s', ISBN: '%s' Tags: '%v'\n", ab.BookID, ab.Title, ab.Name.String, ab.Isbn, ab.Tags) + } + + // call function + pgText, err := dq.SayHello(ctx, "world") + if err != nil { + t.Fatal(err) + } + str, err := pgText.Value() + if err != nil { + t.Fatal(err) + } + if str != "hello world" { + t.Fatal("expected function result to be \"hello world\". actual:", str) + } + + // get book 4 and delete + b5, err := dq.GetBook(ctx, b3.BookID) + if err != nil { + t.Fatal(err) + } + if err := dq.DeleteBook(ctx, b5.BookID); err != nil { + t.Fatal(err) + } + +} diff --git a/examples/booktest/postgresql/models.go b/examples/booktest/postgresql/models.go new file mode 100644 index 0000000..5c514a3 --- /dev/null +++ b/examples/booktest/postgresql/models.go @@ -0,0 +1,70 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package booktest + +import ( + "database/sql/driver" + "fmt" + + "github.com/jackc/pgx/v5/pgtype" +) + +type BookType string + +const ( + BookTypeFICTION BookType = "FICTION" + BookTypeNONFICTION BookType = "NONFICTION" +) + +func (e *BookType) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = BookType(s) + case string: + *e = BookType(s) + default: + return fmt.Errorf("unsupported scan type for BookType: %T", src) + } + return nil +} + +type NullBookType struct { + BookType BookType + Valid bool // Valid is true if BookType is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullBookType) Scan(value any) error { + if value == nil { + ns.BookType, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.BookType.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullBookType) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.BookType), nil +} + +type Author struct { + AuthorID int32 + Name string +} + +type Book struct { + BookID int32 + AuthorID int32 + Isbn string + BookType BookType + Title string + Year int32 + Available pgtype.Timestamptz + Tags []string +} diff --git a/examples/booktest/postgresql/query.sql b/examples/booktest/postgresql/query.sql new file mode 100644 index 0000000..75b8cd3 --- /dev/null +++ b/examples/booktest/postgresql/query.sql @@ -0,0 +1,63 @@ +-- name: GetAuthor :one +SELECT * FROM authors +WHERE author_id = $1; + +-- name: GetBook :one +SELECT * FROM books +WHERE book_id = $1; + +-- name: DeleteBook :exec +DELETE FROM books +WHERE book_id = $1; + +-- name: BooksByTitleYear :many +SELECT * FROM books +WHERE title = $1 AND year = $2; + +-- name: BooksByTags :many +SELECT + book_id, + title, + name, + isbn, + tags +FROM books +LEFT JOIN authors ON books.author_id = authors.author_id +WHERE tags && $1::varchar[]; + +-- name: CreateAuthor :one +INSERT INTO authors (name) VALUES ($1) +RETURNING *; + +-- name: CreateBook :one +INSERT INTO books ( + author_id, + isbn, + book_type, + title, + year, + available, + tags +) VALUES ( + $1, + $2, + $3, + $4, + $5, + $6, + $7 +) +RETURNING *; + +-- name: UpdateBook :exec +UPDATE books +SET title = $1, tags = $2 +WHERE book_id = $3; + +-- name: UpdateBookISBN :exec +UPDATE books +SET title = $1, tags = $2, isbn = $4 +WHERE book_id = $3; + +-- name: SayHello :one +select * from say_hello($1); diff --git a/examples/booktest/postgresql/query.sql.go b/examples/booktest/postgresql/query.sql.go new file mode 100644 index 0000000..1de3113 --- /dev/null +++ b/examples/booktest/postgresql/query.sql.go @@ -0,0 +1,258 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package booktest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const booksByTags = `-- name: BooksByTags :many +SELECT + book_id, + title, + name, + isbn, + tags +FROM books +LEFT JOIN authors ON books.author_id = authors.author_id +WHERE tags && $1::varchar[] +` + +type BooksByTagsRow struct { + BookID int32 + Title string + Name pgtype.Text + Isbn string + Tags []string +} + +func (q *Queries) BooksByTags(ctx context.Context, dollar_1 []string) ([]BooksByTagsRow, error) { + rows, err := q.db.Query(ctx, booksByTags, dollar_1) + if err != nil { + return nil, err + } + defer rows.Close() + var items []BooksByTagsRow + for rows.Next() { + var i BooksByTagsRow + if err := rows.Scan( + &i.BookID, + &i.Title, + &i.Name, + &i.Isbn, + &i.Tags, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const booksByTitleYear = `-- name: BooksByTitleYear :many +SELECT book_id, author_id, isbn, book_type, title, year, available, tags FROM books +WHERE title = $1 AND year = $2 +` + +type BooksByTitleYearParams struct { + Title string + Year int32 +} + +func (q *Queries) BooksByTitleYear(ctx context.Context, arg BooksByTitleYearParams) ([]Book, error) { + rows, err := q.db.Query(ctx, booksByTitleYear, arg.Title, arg.Year) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Book + for rows.Next() { + var i Book + if err := rows.Scan( + &i.BookID, + &i.AuthorID, + &i.Isbn, + &i.BookType, + &i.Title, + &i.Year, + &i.Available, + &i.Tags, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const createAuthor = `-- name: CreateAuthor :one +INSERT INTO authors (name) VALUES ($1) +RETURNING author_id, name +` + +func (q *Queries) CreateAuthor(ctx context.Context, name string) (Author, error) { + row := q.db.QueryRow(ctx, createAuthor, name) + var i Author + err := row.Scan(&i.AuthorID, &i.Name) + return i, err +} + +const createBook = `-- name: CreateBook :one +INSERT INTO books ( + author_id, + isbn, + book_type, + title, + year, + available, + tags +) VALUES ( + $1, + $2, + $3, + $4, + $5, + $6, + $7 +) +RETURNING book_id, author_id, isbn, book_type, title, year, available, tags +` + +type CreateBookParams struct { + AuthorID int32 + Isbn string + BookType BookType + Title string + Year int32 + Available pgtype.Timestamptz + Tags []string +} + +func (q *Queries) CreateBook(ctx context.Context, arg CreateBookParams) (Book, error) { + row := q.db.QueryRow(ctx, createBook, + arg.AuthorID, + arg.Isbn, + arg.BookType, + arg.Title, + arg.Year, + arg.Available, + arg.Tags, + ) + var i Book + err := row.Scan( + &i.BookID, + &i.AuthorID, + &i.Isbn, + &i.BookType, + &i.Title, + &i.Year, + &i.Available, + &i.Tags, + ) + return i, err +} + +const deleteBook = `-- name: DeleteBook :exec +DELETE FROM books +WHERE book_id = $1 +` + +func (q *Queries) DeleteBook(ctx context.Context, bookID int32) error { + _, err := q.db.Exec(ctx, deleteBook, bookID) + return err +} + +const getAuthor = `-- name: GetAuthor :one +SELECT author_id, name FROM authors +WHERE author_id = $1 +` + +func (q *Queries) GetAuthor(ctx context.Context, authorID int32) (Author, error) { + row := q.db.QueryRow(ctx, getAuthor, authorID) + var i Author + err := row.Scan(&i.AuthorID, &i.Name) + return i, err +} + +const getBook = `-- name: GetBook :one +SELECT book_id, author_id, isbn, book_type, title, year, available, tags FROM books +WHERE book_id = $1 +` + +func (q *Queries) GetBook(ctx context.Context, bookID int32) (Book, error) { + row := q.db.QueryRow(ctx, getBook, bookID) + var i Book + err := row.Scan( + &i.BookID, + &i.AuthorID, + &i.Isbn, + &i.BookType, + &i.Title, + &i.Year, + &i.Available, + &i.Tags, + ) + return i, err +} + +const sayHello = `-- name: SayHello :one +select say_hello from say_hello($1) +` + +func (q *Queries) SayHello(ctx context.Context, s string) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, sayHello, s) + var say_hello pgtype.Text + err := row.Scan(&say_hello) + return say_hello, err +} + +const updateBook = `-- name: UpdateBook :exec +UPDATE books +SET title = $1, tags = $2 +WHERE book_id = $3 +` + +type UpdateBookParams struct { + Title string + Tags []string + BookID int32 +} + +func (q *Queries) UpdateBook(ctx context.Context, arg UpdateBookParams) error { + _, err := q.db.Exec(ctx, updateBook, arg.Title, arg.Tags, arg.BookID) + return err +} + +const updateBookISBN = `-- name: UpdateBookISBN :exec +UPDATE books +SET title = $1, tags = $2, isbn = $4 +WHERE book_id = $3 +` + +type UpdateBookISBNParams struct { + Title string + Tags []string + BookID int32 + Isbn string +} + +func (q *Queries) UpdateBookISBN(ctx context.Context, arg UpdateBookISBNParams) error { + _, err := q.db.Exec(ctx, updateBookISBN, + arg.Title, + arg.Tags, + arg.BookID, + arg.Isbn, + ) + return err +} diff --git a/examples/booktest/postgresql/schema.sql b/examples/booktest/postgresql/schema.sql new file mode 100644 index 0000000..3cdd97c --- /dev/null +++ b/examples/booktest/postgresql/schema.sql @@ -0,0 +1,32 @@ +CREATE TABLE authors ( + author_id SERIAL PRIMARY KEY, + name text NOT NULL DEFAULT '' +); + +CREATE INDEX authors_name_idx ON authors(name); + +CREATE TYPE book_type AS ENUM ( + 'FICTION', + 'NONFICTION' +); + +CREATE TABLE books ( + book_id SERIAL PRIMARY KEY, + author_id integer NOT NULL REFERENCES authors(author_id), + isbn text NOT NULL DEFAULT '' UNIQUE, + book_type book_type NOT NULL DEFAULT 'FICTION', + title text NOT NULL DEFAULT '', + year integer NOT NULL DEFAULT 2000, + available timestamp with time zone NOT NULL DEFAULT 'NOW()', + tags varchar[] NOT NULL DEFAULT '{}' +); + +CREATE INDEX books_title_idx ON books(title, year); + +CREATE FUNCTION say_hello(s text) RETURNS text AS $$ +BEGIN + RETURN CONCAT('hello ', s); +END; +$$ LANGUAGE plpgsql; + +CREATE INDEX books_title_lower_idx ON books(title); diff --git a/examples/booktest/sqlc.json b/examples/booktest/sqlc.json new file mode 100644 index 0000000..b0b0d71 --- /dev/null +++ b/examples/booktest/sqlc.json @@ -0,0 +1,51 @@ +{ + "version": "1", + "cloud": { + "project": "01HAQMMECEYQYKFJN8MP16QC41" + }, + "packages": [ + { + "name": "booktest", + "path": "postgresql", + "schema": "postgresql/schema.sql", + "queries": "postgresql/query.sql", + "engine": "postgresql", + "sql_package": "pgx/v5", + "database": { + "uri": "${VET_TEST_EXAMPLES_POSTGRES_BOOKTEST}" + }, + "analyzer": { + "database": false + }, + "rules": [ + "sqlc/db-prepare" + ] + }, + { + "name": "booktest", + "path": "mysql", + "schema": "mysql/schema.sql", + "queries": "mysql/query.sql", + "engine": "mysql", + "database": { + "uri": "${VET_TEST_EXAMPLES_MYSQL_BOOKTEST}" + }, + "rules": [ + "sqlc/db-prepare" + ] + }, + { + "name": "booktest", + "path": "sqlite", + "schema": "sqlite/schema.sql", + "queries": "sqlite/query.sql", + "engine": "sqlite", + "database": { + "uri": "file:booktest?mode=memory&cache=shared" + }, + "rules": [ + "sqlc/db-prepare" + ] + } + ] +} diff --git a/examples/booktest/sqlite/db.go b/examples/booktest/sqlite/db.go new file mode 100644 index 0000000..716f4f3 --- /dev/null +++ b/examples/booktest/sqlite/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package booktest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/examples/booktest/sqlite/db_test.go b/examples/booktest/sqlite/db_test.go new file mode 100644 index 0000000..42a8b39 --- /dev/null +++ b/examples/booktest/sqlite/db_test.go @@ -0,0 +1,163 @@ +//go:build examples + +package booktest + +import ( + "context" + "testing" + "time" + + "github.com/sqlc-dev/sqlc/internal/sqltest" +) + +// TODO: Enum is not yet supported +const ( + BooksBookTypeFICTION string = "FICTION" + BooksBookTypeNONFICTION string = "NONFICTION" +) + +func TestBooks(t *testing.T) { + db, cleanup := sqltest.SQLite(t, []string{"schema.sql"}) + defer db.Close() + defer cleanup() + + ctx := context.Background() + dq := New(db) + + // create an author + a, err := dq.CreateAuthor(ctx, "Unknown Master") + if err != nil { + t.Fatal(err) + } + + // create transaction + tx, err := db.Begin() + if err != nil { + t.Fatal(err) + } + + tq := dq.WithTx(tx) + + // save first book + now := time.Now() + _, err = tq.CreateBook(ctx, CreateBookParams{ + AuthorID: a.AuthorID, + Isbn: "1", + Title: "my book title", + BookType: BooksBookTypeFICTION, + Yr: 2016, + Available: now, + Tag: "", + }) + if err != nil { + t.Fatal(err) + } + + // save second book + b1, err := tq.CreateBook(ctx, CreateBookParams{ + AuthorID: a.AuthorID, + Isbn: "2", + Title: "the second book", + BookType: BooksBookTypeFICTION, + Yr: 2016, + Available: now, + Tag: "unique", + }) + if err != nil { + t.Fatal(err) + } + + // update the title and tags + err = tq.UpdateBook(ctx, UpdateBookParams{ + BookID: b1.BookID, + Title: "changed second title", + Tag: "disastor", + }) + if err != nil { + t.Fatal(err) + } + + // save third book + _, err = tq.CreateBook(ctx, CreateBookParams{ + AuthorID: a.AuthorID, + Isbn: "3", + Title: "the third book", + BookType: BooksBookTypeFICTION, + Yr: 2001, + Available: now, + Tag: "cool", + }) + if err != nil { + t.Fatal(err) + } + + // save fourth book + b3, err := tq.CreateBook(ctx, CreateBookParams{ + AuthorID: a.AuthorID, + Isbn: "4", + Title: "4th place finisher", + BookType: BooksBookTypeFICTION, + Yr: 2011, + Available: now, + Tag: "other", + }) + if err != nil { + t.Fatal(err) + } + + // tx commit + err = tx.Commit() + if err != nil { + t.Fatal(err) + } + + // upsert, changing ISBN and title + err = dq.UpdateBookISBN(ctx, UpdateBookISBNParams{ + BookID: b3.BookID, + Isbn: "NEW ISBN", + Title: "never ever gonna finish, a quatrain", + Tag: "someother", + }) + if err != nil { + t.Fatal(err) + } + + // retrieve first book + books0, err := dq.BooksByTitleYear(ctx, BooksByTitleYearParams{ + Title: "my book title", + Yr: 2016, + }) + if err != nil { + t.Fatal(err) + } + for _, book := range books0 { + t.Logf("Book %d (%s): %s available: %s\n", book.BookID, book.BookType, book.Title, book.Available.Format(time.RFC822Z)) + author, err := dq.GetAuthor(ctx, book.AuthorID) + if err != nil { + t.Fatal(err) + } + t.Logf("Book %d author: %s\n", book.BookID, author.Name) + } + + // find a book with either "cool" or "other" or "someother" tag + t.Logf("---------\nTag search results:\n") + res, err := dq.BooksByTags(ctx, []string{"cool", "other", "someother"}) + if err != nil { + 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.String, ab.Isbn, ab.Tag) + } + + // TODO: call say_hello(varchar) + + // get book 4 and delete + b5, err := dq.GetBook(ctx, b3.BookID) + if err != nil { + t.Fatal(err) + } + if err := dq.DeleteBook(ctx, b5.BookID); err != nil { + t.Fatal(err) + } + +} diff --git a/examples/booktest/sqlite/models.go b/examples/booktest/sqlite/models.go new file mode 100644 index 0000000..4473733 --- /dev/null +++ b/examples/booktest/sqlite/models.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package booktest + +import ( + "time" +) + +type Author struct { + AuthorID int64 + Name string +} + +type Book struct { + BookID int64 + AuthorID int64 + Isbn string + BookType string + Title string + Yr int64 + Available time.Time + Tag string +} diff --git a/examples/booktest/sqlite/query.sql b/examples/booktest/sqlite/query.sql new file mode 100644 index 0000000..4022c7e --- /dev/null +++ b/examples/booktest/sqlite/query.sql @@ -0,0 +1,64 @@ +/* name: GetAuthor :one */ +SELECT * FROM authors +WHERE author_id = ?; + +/* name: GetBook :one */ +SELECT * FROM books +WHERE book_id = ?; + +/* name: DeleteBook :exec */ +DELETE FROM books +WHERE book_id = ?; + +/* name: BooksByTitleYear :many */ +SELECT * FROM books +WHERE title = ? AND yr = ?; + +/* name: BooksByTags :many */ +SELECT + book_id, + title, + name, + isbn, + tag +FROM books +LEFT JOIN authors ON books.author_id = authors.author_id +WHERE tag IN (sqlc.slice(tags)); + +/* name: CreateAuthor :one */ +INSERT INTO authors (name) VALUES (?) +RETURNING *; + +/* name: CreateBook :one */ +INSERT INTO books ( + author_id, + isbn, + book_type, + title, + yr, + available, + tag +) VALUES ( + ?, + ?, + ?, + ?, + ?, + ?, + ? +) +RETURNING *; + +/* name: UpdateBook :exec */ +UPDATE books +SET title = ?1, tag = ?2 +WHERE book_id = ?3; + +/* name: UpdateBookISBN :exec */ +UPDATE books +SET title = ?1, tag = ?2, isbn = ?4 +WHERE book_id = ?3; + +/* name: DeleteAuthorBeforeYear :exec */ +DELETE FROM books +WHERE yr < ? AND author_id = ?; diff --git a/examples/booktest/sqlite/query.sql.go b/examples/booktest/sqlite/query.sql.go new file mode 100644 index 0000000..c8347b1 --- /dev/null +++ b/examples/booktest/sqlite/query.sql.go @@ -0,0 +1,279 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package booktest + +import ( + "context" + "database/sql" + "strings" + "time" +) + +const booksByTags = `-- name: BooksByTags :many +SELECT + book_id, + title, + name, + isbn, + tag +FROM books +LEFT JOIN authors ON books.author_id = authors.author_id +WHERE tag IN (/*SLICE:tags*/?) +` + +type BooksByTagsRow struct { + BookID int64 + Title string + Name sql.NullString + Isbn string + Tag string +} + +func (q *Queries) BooksByTags(ctx context.Context, tags []string) ([]BooksByTagsRow, error) { + query := booksByTags + var queryParams []any + if len(tags) > 0 { + for _, v := range tags { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:tags*/?", strings.Repeat(",?", len(tags))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:tags*/?", "NULL", 1) + } + rows, err := q.db.QueryContext(ctx, query, queryParams...) + if err != nil { + return nil, err + } + defer rows.Close() + var items []BooksByTagsRow + for rows.Next() { + var i BooksByTagsRow + if err := rows.Scan( + &i.BookID, + &i.Title, + &i.Name, + &i.Isbn, + &i.Tag, + ); 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 booksByTitleYear = `-- name: BooksByTitleYear :many +SELECT book_id, author_id, isbn, book_type, title, yr, available, tag FROM books +WHERE title = ? AND yr = ? +` + +type BooksByTitleYearParams struct { + Title string + Yr int64 +} + +func (q *Queries) BooksByTitleYear(ctx context.Context, arg BooksByTitleYearParams) ([]Book, error) { + rows, err := q.db.QueryContext(ctx, booksByTitleYear, arg.Title, arg.Yr) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Book + for rows.Next() { + var i Book + if err := rows.Scan( + &i.BookID, + &i.AuthorID, + &i.Isbn, + &i.BookType, + &i.Title, + &i.Yr, + &i.Available, + &i.Tag, + ); 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 createAuthor = `-- name: CreateAuthor :one +INSERT INTO authors (name) VALUES (?) +RETURNING author_id, name +` + +func (q *Queries) CreateAuthor(ctx context.Context, name string) (Author, error) { + row := q.db.QueryRowContext(ctx, createAuthor, name) + var i Author + err := row.Scan(&i.AuthorID, &i.Name) + return i, err +} + +const createBook = `-- name: CreateBook :one +INSERT INTO books ( + author_id, + isbn, + book_type, + title, + yr, + available, + tag +) VALUES ( + ?, + ?, + ?, + ?, + ?, + ?, + ? +) +RETURNING book_id, author_id, isbn, book_type, title, yr, available, tag +` + +type CreateBookParams struct { + AuthorID int64 + Isbn string + BookType string + Title string + Yr int64 + Available time.Time + Tag string +} + +func (q *Queries) CreateBook(ctx context.Context, arg CreateBookParams) (Book, error) { + row := q.db.QueryRowContext(ctx, createBook, + arg.AuthorID, + arg.Isbn, + arg.BookType, + arg.Title, + arg.Yr, + arg.Available, + arg.Tag, + ) + var i Book + err := row.Scan( + &i.BookID, + &i.AuthorID, + &i.Isbn, + &i.BookType, + &i.Title, + &i.Yr, + &i.Available, + &i.Tag, + ) + return i, err +} + +const deleteAuthorBeforeYear = `-- name: DeleteAuthorBeforeYear :exec +DELETE FROM books +WHERE yr < ? AND author_id = ? +` + +type DeleteAuthorBeforeYearParams struct { + Yr int64 + AuthorID int64 +} + +func (q *Queries) DeleteAuthorBeforeYear(ctx context.Context, arg DeleteAuthorBeforeYearParams) error { + _, err := q.db.ExecContext(ctx, deleteAuthorBeforeYear, arg.Yr, arg.AuthorID) + return err +} + +const deleteBook = `-- name: DeleteBook :exec +DELETE FROM books +WHERE book_id = ? +` + +func (q *Queries) DeleteBook(ctx context.Context, bookID int64) error { + _, err := q.db.ExecContext(ctx, deleteBook, bookID) + return err +} + +const getAuthor = `-- name: GetAuthor :one +SELECT author_id, name FROM authors +WHERE author_id = ? +` + +func (q *Queries) GetAuthor(ctx context.Context, authorID int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, authorID) + var i Author + err := row.Scan(&i.AuthorID, &i.Name) + return i, err +} + +const getBook = `-- name: GetBook :one +SELECT book_id, author_id, isbn, book_type, title, yr, available, tag FROM books +WHERE book_id = ? +` + +func (q *Queries) GetBook(ctx context.Context, bookID int64) (Book, error) { + row := q.db.QueryRowContext(ctx, getBook, bookID) + var i Book + err := row.Scan( + &i.BookID, + &i.AuthorID, + &i.Isbn, + &i.BookType, + &i.Title, + &i.Yr, + &i.Available, + &i.Tag, + ) + return i, err +} + +const updateBook = `-- name: UpdateBook :exec +UPDATE books +SET title = ?1, tag = ?2 +WHERE book_id = ?3 +` + +type UpdateBookParams struct { + Title string + Tag string + BookID int64 +} + +func (q *Queries) UpdateBook(ctx context.Context, arg UpdateBookParams) error { + _, err := q.db.ExecContext(ctx, updateBook, arg.Title, arg.Tag, arg.BookID) + return err +} + +const updateBookISBN = `-- name: UpdateBookISBN :exec +UPDATE books +SET title = ?1, tag = ?2, isbn = ?4 +WHERE book_id = ?3 +` + +type UpdateBookISBNParams struct { + Title string + Tag string + BookID int64 + Isbn string +} + +func (q *Queries) UpdateBookISBN(ctx context.Context, arg UpdateBookISBNParams) error { + _, err := q.db.ExecContext(ctx, updateBookISBN, + arg.Title, + arg.Tag, + arg.BookID, + arg.Isbn, + ) + return err +} diff --git a/examples/booktest/sqlite/schema.sql b/examples/booktest/sqlite/schema.sql new file mode 100644 index 0000000..fe47c9d --- /dev/null +++ b/examples/booktest/sqlite/schema.sql @@ -0,0 +1,20 @@ +CREATE TABLE authors ( + author_id integer NOT NULL PRIMARY KEY AUTOINCREMENT, + name text NOT NULL +); + +CREATE INDEX authors_name_idx ON authors(name); + +CREATE TABLE books ( + book_id integer NOT NULL PRIMARY KEY AUTOINCREMENT, + author_id integer NOT NULL, + isbn varchar(255) NOT NULL DEFAULT '' UNIQUE, + book_type text NOT NULL DEFAULT 'FICTION', + title text NOT NULL, + yr integer NOT NULL DEFAULT 2000, + available datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + tag text NOT NULL, + CHECK (book_type = 'FICTION' OR book_type = 'NONFICTION') +); + +CREATE INDEX books_title_idx ON books(title, yr); diff --git a/examples/jets/README.md b/examples/jets/README.md new file mode 100644 index 0000000..0f8d995 --- /dev/null +++ b/examples/jets/README.md @@ -0,0 +1,3 @@ +This database schema and query selection is taken from the +[SQLBoiler](https://github.com/volatiletech/sqlboiler#features--examples) +README. diff --git a/examples/jets/postgresql/db.go b/examples/jets/postgresql/db.go new file mode 100644 index 0000000..3fb56f8 --- /dev/null +++ b/examples/jets/postgresql/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package jets + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/examples/jets/postgresql/models.go b/examples/jets/postgresql/models.go new file mode 100644 index 0000000..fc0eb99 --- /dev/null +++ b/examples/jets/postgresql/models.go @@ -0,0 +1,28 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package jets + +type Jet struct { + ID int32 + PilotID int32 + Age int32 + Name string + Color string +} + +type Language struct { + ID int32 + Language string +} + +type Pilot struct { + ID int32 + Name string +} + +type PilotLanguage struct { + PilotID int32 + LanguageID int32 +} diff --git a/examples/jets/postgresql/query-building.sql b/examples/jets/postgresql/query-building.sql new file mode 100644 index 0000000..ede8952 --- /dev/null +++ b/examples/jets/postgresql/query-building.sql @@ -0,0 +1,8 @@ +-- name: CountPilots :one +SELECT COUNT(*) FROM pilots; + +-- name: ListPilots :many +SELECT * FROM pilots LIMIT 5; + +-- name: DeletePilot :exec +DELETE FROM pilots WHERE id = $1; diff --git a/examples/jets/postgresql/query-building.sql.go b/examples/jets/postgresql/query-building.sql.go new file mode 100644 index 0000000..fd8086e --- /dev/null +++ b/examples/jets/postgresql/query-building.sql.go @@ -0,0 +1,54 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query-building.sql + +package jets + +import ( + "context" +) + +const countPilots = `-- name: CountPilots :one +SELECT COUNT(*) FROM pilots +` + +func (q *Queries) CountPilots(ctx context.Context) (int64, error) { + row := q.db.QueryRow(ctx, countPilots) + var count int64 + err := row.Scan(&count) + return count, err +} + +const deletePilot = `-- name: DeletePilot :exec +DELETE FROM pilots WHERE id = $1 +` + +func (q *Queries) DeletePilot(ctx context.Context, id int32) error { + _, err := q.db.Exec(ctx, deletePilot, id) + return err +} + +const listPilots = `-- name: ListPilots :many +SELECT id, name FROM pilots LIMIT 5 +` + +func (q *Queries) ListPilots(ctx context.Context) ([]Pilot, error) { + rows, err := q.db.Query(ctx, listPilots) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Pilot + for rows.Next() { + var i Pilot + if err := rows.Scan(&i.ID, &i.Name); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/examples/jets/postgresql/schema.sql b/examples/jets/postgresql/schema.sql new file mode 100644 index 0000000..2cc4aca --- /dev/null +++ b/examples/jets/postgresql/schema.sql @@ -0,0 +1,35 @@ +CREATE TABLE pilots ( + id integer NOT NULL, + name text NOT NULL +); + +ALTER TABLE pilots ADD CONSTRAINT pilot_pkey PRIMARY KEY (id); + +CREATE TABLE jets ( + id integer NOT NULL, + pilot_id integer NOT NULL, + age integer NOT NULL, + name text NOT NULL, + color text NOT NULL +); + +ALTER TABLE jets ADD CONSTRAINT jet_pkey PRIMARY KEY (id); +ALTER TABLE jets ADD CONSTRAINT jet_pilots_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id); + +CREATE TABLE languages ( + id integer NOT NULL, + language text NOT NULL +); + +ALTER TABLE languages ADD CONSTRAINT language_pkey PRIMARY KEY (id); + +-- Join table +CREATE TABLE pilot_languages ( + pilot_id integer NOT NULL, + language_id integer NOT NULL +); + +-- Composite primary key +ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_pkey PRIMARY KEY (pilot_id, language_id); +ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_pilots_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id); +ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_languages_fkey FOREIGN KEY (language_id) REFERENCES languages(id); diff --git a/examples/jets/sqlc.json b/examples/jets/sqlc.json new file mode 100644 index 0000000..8dfa0df --- /dev/null +++ b/examples/jets/sqlc.json @@ -0,0 +1,25 @@ +{ + "version": "1", + "cloud": { + "project": "01HAQMMECEYQYKFJN8MP16QC41" + }, + "packages": [ + { + "path": "postgresql", + "name": "jets", + "schema": "postgresql/schema.sql", + "queries": "postgresql/query-building.sql", + "engine": "postgresql", + "sql_package": "pgx/v5", + "database": { + "uri": "${VET_TEST_EXAMPLES_POSTGRES_JETS}" + }, + "analyzer": { + "database": false + }, + "rules": [ + "sqlc/db-prepare" + ] + } + ] +} diff --git a/examples/ondeck/mysql/city.sql.go b/examples/ondeck/mysql/city.sql.go new file mode 100644 index 0000000..89b321e --- /dev/null +++ b/examples/ondeck/mysql/city.sql.go @@ -0,0 +1,88 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: city.sql + +package ondeck + +import ( + "context" +) + +const createCity = `-- name: CreateCity :exec +INSERT INTO city ( + name, + slug +) VALUES ( + ?, + ? +) +` + +type CreateCityParams struct { + Name string `json:"name"` + Slug string `json:"slug"` +} + +func (q *Queries) CreateCity(ctx context.Context, arg CreateCityParams) error { + _, err := q.exec(ctx, q.createCityStmt, createCity, arg.Name, arg.Slug) + return err +} + +const getCity = `-- name: GetCity :one +SELECT slug, name +FROM city +WHERE slug = ? +` + +func (q *Queries) GetCity(ctx context.Context, slug string) (City, error) { + row := q.queryRow(ctx, q.getCityStmt, getCity, slug) + var i City + err := row.Scan(&i.Slug, &i.Name) + return i, err +} + +const listCities = `-- name: ListCities :many +SELECT slug, name +FROM city +ORDER BY name +` + +func (q *Queries) ListCities(ctx context.Context) ([]City, error) { + rows, err := q.query(ctx, q.listCitiesStmt, listCities) + if err != nil { + return nil, err + } + defer rows.Close() + var items []City + for rows.Next() { + var i City + if err := rows.Scan(&i.Slug, &i.Name); 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 updateCityName = `-- name: UpdateCityName :exec +UPDATE city +SET name = ? +WHERE slug = ? +` + +type UpdateCityNameParams struct { + Name string `json:"name"` + Slug string `json:"slug"` +} + +func (q *Queries) UpdateCityName(ctx context.Context, arg UpdateCityNameParams) error { + _, err := q.exec(ctx, q.updateCityNameStmt, updateCityName, arg.Name, arg.Slug) + return err +} diff --git a/examples/ondeck/mysql/db.go b/examples/ondeck/mysql/db.go new file mode 100644 index 0000000..67cc093 --- /dev/null +++ b/examples/ondeck/mysql/db.go @@ -0,0 +1,178 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package ondeck + +import ( + "context" + "database/sql" + "fmt" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +func Prepare(ctx context.Context, db DBTX) (*Queries, error) { + q := Queries{db: db} + var err error + if q.createCityStmt, err = db.PrepareContext(ctx, createCity); err != nil { + return nil, fmt.Errorf("error preparing query CreateCity: %w", err) + } + if q.createVenueStmt, err = db.PrepareContext(ctx, createVenue); err != nil { + return nil, fmt.Errorf("error preparing query CreateVenue: %w", err) + } + if q.deleteVenueStmt, err = db.PrepareContext(ctx, deleteVenue); err != nil { + return nil, fmt.Errorf("error preparing query DeleteVenue: %w", err) + } + if q.getCityStmt, err = db.PrepareContext(ctx, getCity); err != nil { + return nil, fmt.Errorf("error preparing query GetCity: %w", err) + } + if q.getVenueStmt, err = db.PrepareContext(ctx, getVenue); err != nil { + return nil, fmt.Errorf("error preparing query GetVenue: %w", err) + } + if q.listCitiesStmt, err = db.PrepareContext(ctx, listCities); err != nil { + return nil, fmt.Errorf("error preparing query ListCities: %w", err) + } + if q.listVenuesStmt, err = db.PrepareContext(ctx, listVenues); err != nil { + return nil, fmt.Errorf("error preparing query ListVenues: %w", err) + } + if q.updateCityNameStmt, err = db.PrepareContext(ctx, updateCityName); err != nil { + return nil, fmt.Errorf("error preparing query UpdateCityName: %w", err) + } + if q.updateVenueNameStmt, err = db.PrepareContext(ctx, updateVenueName); err != nil { + return nil, fmt.Errorf("error preparing query UpdateVenueName: %w", err) + } + if q.venueCountByCityStmt, err = db.PrepareContext(ctx, venueCountByCity); err != nil { + return nil, fmt.Errorf("error preparing query VenueCountByCity: %w", err) + } + return &q, nil +} + +func (q *Queries) Close() error { + var err error + if q.createCityStmt != nil { + if cerr := q.createCityStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing createCityStmt: %w", cerr) + } + } + if q.createVenueStmt != nil { + if cerr := q.createVenueStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing createVenueStmt: %w", cerr) + } + } + if q.deleteVenueStmt != nil { + if cerr := q.deleteVenueStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing deleteVenueStmt: %w", cerr) + } + } + if q.getCityStmt != nil { + if cerr := q.getCityStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getCityStmt: %w", cerr) + } + } + if q.getVenueStmt != nil { + if cerr := q.getVenueStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getVenueStmt: %w", cerr) + } + } + if q.listCitiesStmt != nil { + if cerr := q.listCitiesStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing listCitiesStmt: %w", cerr) + } + } + if q.listVenuesStmt != nil { + if cerr := q.listVenuesStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing listVenuesStmt: %w", cerr) + } + } + if q.updateCityNameStmt != nil { + if cerr := q.updateCityNameStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateCityNameStmt: %w", cerr) + } + } + if q.updateVenueNameStmt != nil { + if cerr := q.updateVenueNameStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateVenueNameStmt: %w", cerr) + } + } + if q.venueCountByCityStmt != nil { + if cerr := q.venueCountByCityStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing venueCountByCityStmt: %w", cerr) + } + } + return err +} + +func (q *Queries) exec(ctx context.Context, stmt *sql.Stmt, query string, args ...any) (sql.Result, error) { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).ExecContext(ctx, args...) + case stmt != nil: + return stmt.ExecContext(ctx, args...) + default: + return q.db.ExecContext(ctx, query, args...) + } +} + +func (q *Queries) query(ctx context.Context, stmt *sql.Stmt, query string, args ...any) (*sql.Rows, error) { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).QueryContext(ctx, args...) + case stmt != nil: + return stmt.QueryContext(ctx, args...) + default: + return q.db.QueryContext(ctx, query, args...) + } +} + +func (q *Queries) queryRow(ctx context.Context, stmt *sql.Stmt, query string, args ...any) *sql.Row { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).QueryRowContext(ctx, args...) + case stmt != nil: + return stmt.QueryRowContext(ctx, args...) + default: + return q.db.QueryRowContext(ctx, query, args...) + } +} + +type Queries struct { + db DBTX + tx *sql.Tx + createCityStmt *sql.Stmt + createVenueStmt *sql.Stmt + deleteVenueStmt *sql.Stmt + getCityStmt *sql.Stmt + getVenueStmt *sql.Stmt + listCitiesStmt *sql.Stmt + listVenuesStmt *sql.Stmt + updateCityNameStmt *sql.Stmt + updateVenueNameStmt *sql.Stmt + venueCountByCityStmt *sql.Stmt +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + tx: tx, + createCityStmt: q.createCityStmt, + createVenueStmt: q.createVenueStmt, + deleteVenueStmt: q.deleteVenueStmt, + getCityStmt: q.getCityStmt, + getVenueStmt: q.getVenueStmt, + listCitiesStmt: q.listCitiesStmt, + listVenuesStmt: q.listVenuesStmt, + updateCityNameStmt: q.updateCityNameStmt, + updateVenueNameStmt: q.updateVenueNameStmt, + venueCountByCityStmt: q.venueCountByCityStmt, + } +} diff --git a/examples/ondeck/mysql/db_test.go b/examples/ondeck/mysql/db_test.go new file mode 100644 index 0000000..6ac70aa --- /dev/null +++ b/examples/ondeck/mysql/db_test.go @@ -0,0 +1,172 @@ +//go:build examples + +package ondeck + +import ( + "context" + "database/sql" + "strings" + "testing" + + _ "github.com/go-sql-driver/mysql" + "github.com/google/go-cmp/cmp" + + "github.com/sqlc-dev/sqlc/internal/sqltest/local" +) + +func join(vals ...string) sql.NullString { + if len(vals) == 0 { + return sql.NullString{} + } + return sql.NullString{ + Valid: true, + String: strings.Join(vals, ","), + } +} + +func runOnDeckQueries(t *testing.T, q *Queries) { + ctx := context.Background() + + err := q.CreateCity(ctx, CreateCityParams{ + Slug: "san-francisco", + Name: "San Francisco", + }) + if err != nil { + t.Fatal(err) + } + + city, err := q.GetCity(ctx, "san-francisco") + if err != nil { + t.Fatal(err) + } + + venueResult, err := q.CreateVenue(ctx, CreateVenueParams{ + Slug: "the-fillmore", + Name: "The Fillmore", + City: city.Slug, + SpotifyPlaylist: "spotify:uri", + Status: VenueStatusOpen, + Statuses: join(string(VenueStatusOpen), string(VenueStatusClosed)), + Tags: join("rock", "punk"), + }) + if err != nil { + t.Fatal(err) + } + venueID, err := venueResult.LastInsertId() + if err != nil { + t.Fatal(err) + } + + venue, err := q.GetVenue(ctx, GetVenueParams{ + Slug: "the-fillmore", + City: city.Slug, + }) + if err != nil { + t.Fatal(err) + } + + if diff := cmp.Diff(venue.ID, uint64(venueID)); diff != "" { + t.Errorf("venue ID mismatch:\n%s", diff) + } + + { + actual, err := q.VenueCountByCity(ctx) + if err != nil { + t.Error(err) + } + if diff := cmp.Diff(actual, []VenueCountByCityRow{ + {city.Slug, int64(1)}, + }); diff != "" { + t.Errorf("venue count mismatch:\n%s", diff) + } + } + + { + actual, err := q.ListCities(ctx) + if err != nil { + t.Error(err) + } + if diff := cmp.Diff(actual, []City{city}); diff != "" { + t.Errorf("list city mismatch:\n%s", diff) + } + } + + { + actual, err := q.ListVenues(ctx, city.Slug) + if err != nil { + t.Error(err) + } + if diff := cmp.Diff(actual, []Venue{venue}); diff != "" { + t.Errorf("list venue mismatch:\n%s", diff) + } + } + + { + err := q.UpdateCityName(ctx, UpdateCityNameParams{ + Slug: city.Slug, + Name: "SF", + }) + if err != nil { + t.Error(err) + } + } + + { + expected := "Fillmore" + err := q.UpdateVenueName(ctx, UpdateVenueNameParams{ + Slug: venue.Slug, + Name: expected, + }) + if err != nil { + t.Error(err) + } + fresh, err := q.GetVenue(ctx, GetVenueParams{ + Slug: venue.Slug, + City: city.Slug, + }) + if diff := cmp.Diff(expected, fresh.Name); diff != "" { + t.Errorf("update venue mismatch:\n%s", diff) + } + } + + { + err := q.DeleteVenue(ctx, DeleteVenueParams{ + Slug: venue.Slug, + Slug_2: venue.Slug, + }) + if err != nil { + t.Error(err) + } + } +} + +func TestPrepared(t *testing.T) { + t.Parallel() + + uri := local.MySQL(t, []string{"schema"}) + db, err := sql.Open("mysql", uri) + if err != nil { + t.Fatalf("%s: %s", uri, err) + } + defer db.Close() + + q, err := Prepare(context.Background(), db) + if err != nil { + t.Fatal(err) + } + + runOnDeckQueries(t, q) +} + +func TestQueries(t *testing.T) { + t.Parallel() + + uri := local.MySQL(t, []string{"schema"}) + db, err := sql.Open("mysql", uri) + if err != nil { + t.Fatalf("%s: %s", uri, err) + } + defer db.Close() + + runOnDeckQueries(t, New(db)) +} diff --git a/examples/ondeck/mysql/models.go b/examples/ondeck/mysql/models.go new file mode 100644 index 0000000..3267be0 --- /dev/null +++ b/examples/ondeck/mysql/models.go @@ -0,0 +1,75 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package ondeck + +import ( + "database/sql" + "database/sql/driver" + "fmt" + "time" +) + +type VenueStatus string + +const ( + VenueStatusOpen VenueStatus = "open" + VenueStatusClosed VenueStatus = "closed" +) + +func (e *VenueStatus) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = VenueStatus(s) + case string: + *e = VenueStatus(s) + default: + return fmt.Errorf("unsupported scan type for VenueStatus: %T", src) + } + return nil +} + +type NullVenueStatus struct { + VenueStatus VenueStatus `json:"venue_status"` + Valid bool `json:"valid"` // Valid is true if VenueStatus is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullVenueStatus) Scan(value any) error { + if value == nil { + ns.VenueStatus, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.VenueStatus.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullVenueStatus) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.VenueStatus), nil +} + +type City struct { + Slug string `json:"slug"` + Name string `json:"name"` +} + +// Venues are places where muisc happens +type Venue struct { + ID uint64 `json:"id"` + // Venues can be either open or closed + Status VenueStatus `json:"status"` + Statuses sql.NullString `json:"statuses"` + // This value appears in public URLs + Slug string `json:"slug"` + Name string `json:"name"` + City string `json:"city"` + SpotifyPlaylist string `json:"spotify_playlist"` + SongkickID sql.NullString `json:"songkick_id"` + Tags sql.NullString `json:"tags"` + CreatedAt time.Time `json:"created_at"` +} diff --git a/examples/ondeck/mysql/querier.go b/examples/ondeck/mysql/querier.go new file mode 100644 index 0000000..e477383 --- /dev/null +++ b/examples/ondeck/mysql/querier.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package ondeck + +import ( + "context" + "database/sql" +) + +type Querier interface { + CreateCity(ctx context.Context, arg CreateCityParams) error + CreateVenue(ctx context.Context, arg CreateVenueParams) (sql.Result, error) + DeleteVenue(ctx context.Context, arg DeleteVenueParams) error + GetCity(ctx context.Context, slug string) (City, error) + GetVenue(ctx context.Context, arg GetVenueParams) (Venue, error) + ListCities(ctx context.Context) ([]City, error) + ListVenues(ctx context.Context, city string) ([]Venue, error) + UpdateCityName(ctx context.Context, arg UpdateCityNameParams) error + UpdateVenueName(ctx context.Context, arg UpdateVenueNameParams) error + VenueCountByCity(ctx context.Context) ([]VenueCountByCityRow, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/examples/ondeck/mysql/query/city.sql b/examples/ondeck/mysql/query/city.sql new file mode 100644 index 0000000..c387e9d --- /dev/null +++ b/examples/ondeck/mysql/query/city.sql @@ -0,0 +1,23 @@ +/* name: ListCities :many */ +SELECT * +FROM city +ORDER BY name; + +/* name: GetCity :one */ +SELECT * +FROM city +WHERE slug = ?; + +/* name: CreateCity :exec */ +INSERT INTO city ( + name, + slug +) VALUES ( + ?, + ? +); + +/* name: UpdateCityName :exec */ +UPDATE city +SET name = ? +WHERE slug = ?; diff --git a/examples/ondeck/mysql/query/venue.sql b/examples/ondeck/mysql/query/venue.sql new file mode 100644 index 0000000..a1dd7a1 --- /dev/null +++ b/examples/ondeck/mysql/query/venue.sql @@ -0,0 +1,48 @@ +/* name: ListVenues :many */ +SELECT * +FROM venue +WHERE city = ? +ORDER BY name; + +/* name: DeleteVenue :exec */ +DELETE FROM venue +WHERE slug = ? AND slug = ?; + +/* name: GetVenue :one */ +SELECT * +FROM venue +WHERE slug = ? AND city = ?; + +/* name: CreateVenue :execresult */ +INSERT INTO venue ( + slug, + name, + city, + created_at, + spotify_playlist, + status, + statuses, + tags +) VALUES ( + ?, + ?, + ?, + NOW(), + ?, + ?, + ?, + ? +); + +/* name: UpdateVenueName :exec */ +UPDATE venue +SET name = ? +WHERE slug = ?; + +/* name: VenueCountByCity :many */ +SELECT + city, + count(*) +FROM venue +GROUP BY 1 +ORDER BY 1; diff --git a/examples/ondeck/mysql/schema/0001_city.sql b/examples/ondeck/mysql/schema/0001_city.sql new file mode 100644 index 0000000..94e9b0f --- /dev/null +++ b/examples/ondeck/mysql/schema/0001_city.sql @@ -0,0 +1,4 @@ +CREATE TABLE city ( + slug varchar(255) PRIMARY KEY, + name text NOT NULL +); diff --git a/examples/ondeck/mysql/schema/0002_venue.sql b/examples/ondeck/mysql/schema/0002_venue.sql new file mode 100644 index 0000000..dcab205 --- /dev/null +++ b/examples/ondeck/mysql/schema/0002_venue.sql @@ -0,0 +1,12 @@ +CREATE TABLE venues ( + id SERIAL primary key, + dropped text, + status ENUM('open', 'closed') not null COMMENT 'Venues can be either open or closed', + statuses text, -- status[], + slug text not null COMMENT 'This value appears in public URLs', + name varchar(255) not null, + city varchar(255) not null references city(slug), + spotify_playlist varchar(255) not null, + songkick_id text, + tags text -- text[] +) COMMENT='Venues are places where muisc happens'; diff --git a/examples/ondeck/mysql/schema/0003_add_column.sql b/examples/ondeck/mysql/schema/0003_add_column.sql new file mode 100644 index 0000000..9b334bc --- /dev/null +++ b/examples/ondeck/mysql/schema/0003_add_column.sql @@ -0,0 +1,3 @@ +ALTER TABLE venues RENAME TO venue; +ALTER TABLE venue ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT NOW(); +ALTER TABLE venue DROP COLUMN dropped; diff --git a/examples/ondeck/mysql/venue.sql.go b/examples/ondeck/mysql/venue.sql.go new file mode 100644 index 0000000..21a7a6e --- /dev/null +++ b/examples/ondeck/mysql/venue.sql.go @@ -0,0 +1,193 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: venue.sql + +package ondeck + +import ( + "context" + "database/sql" +) + +const createVenue = `-- name: CreateVenue :execresult +INSERT INTO venue ( + slug, + name, + city, + created_at, + spotify_playlist, + status, + statuses, + tags +) VALUES ( + ?, + ?, + ?, + NOW(), + ?, + ?, + ?, + ? +) +` + +type CreateVenueParams struct { + Slug string `json:"slug"` + Name string `json:"name"` + City string `json:"city"` + SpotifyPlaylist string `json:"spotify_playlist"` + Status VenueStatus `json:"status"` + Statuses sql.NullString `json:"statuses"` + Tags sql.NullString `json:"tags"` +} + +func (q *Queries) CreateVenue(ctx context.Context, arg CreateVenueParams) (sql.Result, error) { + return q.exec(ctx, q.createVenueStmt, createVenue, + arg.Slug, + arg.Name, + arg.City, + arg.SpotifyPlaylist, + arg.Status, + arg.Statuses, + arg.Tags, + ) +} + +const deleteVenue = `-- name: DeleteVenue :exec +DELETE FROM venue +WHERE slug = ? AND slug = ? +` + +type DeleteVenueParams struct { + Slug string `json:"slug"` + Slug_2 string `json:"slug_2"` +} + +func (q *Queries) DeleteVenue(ctx context.Context, arg DeleteVenueParams) error { + _, err := q.exec(ctx, q.deleteVenueStmt, deleteVenue, arg.Slug, arg.Slug_2) + return err +} + +const getVenue = `-- name: GetVenue :one +SELECT id, status, statuses, slug, name, city, spotify_playlist, songkick_id, tags, created_at +FROM venue +WHERE slug = ? AND city = ? +` + +type GetVenueParams struct { + Slug string `json:"slug"` + City string `json:"city"` +} + +func (q *Queries) GetVenue(ctx context.Context, arg GetVenueParams) (Venue, error) { + row := q.queryRow(ctx, q.getVenueStmt, getVenue, arg.Slug, arg.City) + var i Venue + err := row.Scan( + &i.ID, + &i.Status, + &i.Statuses, + &i.Slug, + &i.Name, + &i.City, + &i.SpotifyPlaylist, + &i.SongkickID, + &i.Tags, + &i.CreatedAt, + ) + return i, err +} + +const listVenues = `-- name: ListVenues :many +SELECT id, status, statuses, slug, name, city, spotify_playlist, songkick_id, tags, created_at +FROM venue +WHERE city = ? +ORDER BY name +` + +func (q *Queries) ListVenues(ctx context.Context, city string) ([]Venue, error) { + rows, err := q.query(ctx, q.listVenuesStmt, listVenues, city) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Venue + for rows.Next() { + var i Venue + if err := rows.Scan( + &i.ID, + &i.Status, + &i.Statuses, + &i.Slug, + &i.Name, + &i.City, + &i.SpotifyPlaylist, + &i.SongkickID, + &i.Tags, + &i.CreatedAt, + ); 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 updateVenueName = `-- name: UpdateVenueName :exec +UPDATE venue +SET name = ? +WHERE slug = ? +` + +type UpdateVenueNameParams struct { + Name string `json:"name"` + Slug string `json:"slug"` +} + +func (q *Queries) UpdateVenueName(ctx context.Context, arg UpdateVenueNameParams) error { + _, err := q.exec(ctx, q.updateVenueNameStmt, updateVenueName, arg.Name, arg.Slug) + return err +} + +const venueCountByCity = `-- name: VenueCountByCity :many +SELECT + city, + count(*) +FROM venue +GROUP BY 1 +ORDER BY 1 +` + +type VenueCountByCityRow struct { + City string `json:"city"` + Count int64 `json:"count"` +} + +func (q *Queries) VenueCountByCity(ctx context.Context) ([]VenueCountByCityRow, error) { + rows, err := q.query(ctx, q.venueCountByCityStmt, venueCountByCity) + if err != nil { + return nil, err + } + defer rows.Close() + var items []VenueCountByCityRow + for rows.Next() { + var i VenueCountByCityRow + if err := rows.Scan(&i.City, &i.Count); 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/examples/ondeck/postgresql/city.sql.go b/examples/ondeck/postgresql/city.sql.go new file mode 100644 index 0000000..5559bf5 --- /dev/null +++ b/examples/ondeck/postgresql/city.sql.go @@ -0,0 +1,95 @@ +//go:build examples + +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: city.sql + +package ondeck + +import ( + "context" +) + +const createCity = `-- name: CreateCity :one +INSERT INTO city ( + name, + slug +) VALUES ( + $1, + $2 +) RETURNING slug, name +` + +type CreateCityParams struct { + Name string `json:"name"` + Slug string `json:"slug"` +} + +// Create a new city. The slug must be unique. +// This is the second line of the comment +// This is the third line +func (q *Queries) CreateCity(ctx context.Context, arg CreateCityParams) (City, error) { + row := q.queryRow(ctx, q.createCityStmt, createCity, arg.Name, arg.Slug) + var i City + err := row.Scan(&i.Slug, &i.Name) + return i, err +} + +const getCity = `-- name: GetCity :one +SELECT slug, name +FROM city +WHERE slug = $1 +` + +func (q *Queries) GetCity(ctx context.Context, slug string) (City, error) { + row := q.queryRow(ctx, q.getCityStmt, getCity, slug) + var i City + err := row.Scan(&i.Slug, &i.Name) + return i, err +} + +const listCities = `-- name: ListCities :many +SELECT slug, name +FROM city +ORDER BY name +` + +func (q *Queries) ListCities(ctx context.Context) ([]City, error) { + rows, err := q.query(ctx, q.listCitiesStmt, listCities) + if err != nil { + return nil, err + } + defer rows.Close() + var items []City + for rows.Next() { + var i City + if err := rows.Scan(&i.Slug, &i.Name); 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 updateCityName = `-- name: UpdateCityName :exec +UPDATE city +SET name = $2 +WHERE slug = $1 +` + +type UpdateCityNameParams struct { + Slug string `json:"slug"` + Name string `json:"name"` +} + +func (q *Queries) UpdateCityName(ctx context.Context, arg UpdateCityNameParams) error { + _, err := q.exec(ctx, q.updateCityNameStmt, updateCityName, arg.Slug, arg.Name) + return err +} diff --git a/examples/ondeck/postgresql/db.go b/examples/ondeck/postgresql/db.go new file mode 100644 index 0000000..8660955 --- /dev/null +++ b/examples/ondeck/postgresql/db.go @@ -0,0 +1,180 @@ +//go:build examples + +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package ondeck + +import ( + "context" + "database/sql" + "fmt" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +func Prepare(ctx context.Context, db DBTX) (*Queries, error) { + q := Queries{db: db} + var err error + if q.createCityStmt, err = db.PrepareContext(ctx, createCity); err != nil { + return nil, fmt.Errorf("error preparing query CreateCity: %w", err) + } + if q.createVenueStmt, err = db.PrepareContext(ctx, createVenue); err != nil { + return nil, fmt.Errorf("error preparing query CreateVenue: %w", err) + } + if q.deleteVenueStmt, err = db.PrepareContext(ctx, deleteVenue); err != nil { + return nil, fmt.Errorf("error preparing query DeleteVenue: %w", err) + } + if q.getCityStmt, err = db.PrepareContext(ctx, getCity); err != nil { + return nil, fmt.Errorf("error preparing query GetCity: %w", err) + } + if q.getVenueStmt, err = db.PrepareContext(ctx, getVenue); err != nil { + return nil, fmt.Errorf("error preparing query GetVenue: %w", err) + } + if q.listCitiesStmt, err = db.PrepareContext(ctx, listCities); err != nil { + return nil, fmt.Errorf("error preparing query ListCities: %w", err) + } + if q.listVenuesStmt, err = db.PrepareContext(ctx, listVenues); err != nil { + return nil, fmt.Errorf("error preparing query ListVenues: %w", err) + } + if q.updateCityNameStmt, err = db.PrepareContext(ctx, updateCityName); err != nil { + return nil, fmt.Errorf("error preparing query UpdateCityName: %w", err) + } + if q.updateVenueNameStmt, err = db.PrepareContext(ctx, updateVenueName); err != nil { + return nil, fmt.Errorf("error preparing query UpdateVenueName: %w", err) + } + if q.venueCountByCityStmt, err = db.PrepareContext(ctx, venueCountByCity); err != nil { + return nil, fmt.Errorf("error preparing query VenueCountByCity: %w", err) + } + return &q, nil +} + +func (q *Queries) Close() error { + var err error + if q.createCityStmt != nil { + if cerr := q.createCityStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing createCityStmt: %w", cerr) + } + } + if q.createVenueStmt != nil { + if cerr := q.createVenueStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing createVenueStmt: %w", cerr) + } + } + if q.deleteVenueStmt != nil { + if cerr := q.deleteVenueStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing deleteVenueStmt: %w", cerr) + } + } + if q.getCityStmt != nil { + if cerr := q.getCityStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getCityStmt: %w", cerr) + } + } + if q.getVenueStmt != nil { + if cerr := q.getVenueStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getVenueStmt: %w", cerr) + } + } + if q.listCitiesStmt != nil { + if cerr := q.listCitiesStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing listCitiesStmt: %w", cerr) + } + } + if q.listVenuesStmt != nil { + if cerr := q.listVenuesStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing listVenuesStmt: %w", cerr) + } + } + if q.updateCityNameStmt != nil { + if cerr := q.updateCityNameStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateCityNameStmt: %w", cerr) + } + } + if q.updateVenueNameStmt != nil { + if cerr := q.updateVenueNameStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateVenueNameStmt: %w", cerr) + } + } + if q.venueCountByCityStmt != nil { + if cerr := q.venueCountByCityStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing venueCountByCityStmt: %w", cerr) + } + } + return err +} + +func (q *Queries) exec(ctx context.Context, stmt *sql.Stmt, query string, args ...any) (sql.Result, error) { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).ExecContext(ctx, args...) + case stmt != nil: + return stmt.ExecContext(ctx, args...) + default: + return q.db.ExecContext(ctx, query, args...) + } +} + +func (q *Queries) query(ctx context.Context, stmt *sql.Stmt, query string, args ...any) (*sql.Rows, error) { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).QueryContext(ctx, args...) + case stmt != nil: + return stmt.QueryContext(ctx, args...) + default: + return q.db.QueryContext(ctx, query, args...) + } +} + +func (q *Queries) queryRow(ctx context.Context, stmt *sql.Stmt, query string, args ...any) *sql.Row { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).QueryRowContext(ctx, args...) + case stmt != nil: + return stmt.QueryRowContext(ctx, args...) + default: + return q.db.QueryRowContext(ctx, query, args...) + } +} + +type Queries struct { + db DBTX + tx *sql.Tx + createCityStmt *sql.Stmt + createVenueStmt *sql.Stmt + deleteVenueStmt *sql.Stmt + getCityStmt *sql.Stmt + getVenueStmt *sql.Stmt + listCitiesStmt *sql.Stmt + listVenuesStmt *sql.Stmt + updateCityNameStmt *sql.Stmt + updateVenueNameStmt *sql.Stmt + venueCountByCityStmt *sql.Stmt +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + tx: tx, + createCityStmt: q.createCityStmt, + createVenueStmt: q.createVenueStmt, + deleteVenueStmt: q.deleteVenueStmt, + getCityStmt: q.getCityStmt, + getVenueStmt: q.getVenueStmt, + listCitiesStmt: q.listCitiesStmt, + listVenuesStmt: q.listVenuesStmt, + updateCityNameStmt: q.updateCityNameStmt, + updateVenueNameStmt: q.updateVenueNameStmt, + venueCountByCityStmt: q.venueCountByCityStmt, + } +} diff --git a/examples/ondeck/postgresql/db_test.go b/examples/ondeck/postgresql/db_test.go new file mode 100644 index 0000000..6d2fba6 --- /dev/null +++ b/examples/ondeck/postgresql/db_test.go @@ -0,0 +1,154 @@ +//go:build examples + +package ondeck + +import ( + "context" + "database/sql" + "testing" + + "github.com/google/go-cmp/cmp" + _ "github.com/lib/pq" + + "github.com/sqlc-dev/sqlc/internal/sqltest/local" +) + +func runOnDeckQueries(t *testing.T, q *Queries) { + ctx := context.Background() + + city, err := q.CreateCity(ctx, CreateCityParams{ + Slug: "san-francisco", + Name: "San Francisco", + }) + if err != nil { + t.Fatal(err) + } + + venueID, err := q.CreateVenue(ctx, CreateVenueParams{ + Slug: "the-fillmore", + Name: "The Fillmore", + City: city.Slug, + SpotifyPlaylist: "spotify:uri", + Status: StatusOpen, + Statuses: []Status{StatusOpen, StatusClosed}, + Tags: []string{"rock", "punk"}, + }) + if err != nil { + t.Fatal(err) + } + + venue, err := q.GetVenue(ctx, GetVenueParams{ + Slug: "the-fillmore", + City: city.Slug, + }) + if err != nil { + t.Fatal(err) + } + + if diff := cmp.Diff(venue.ID, venueID); diff != "" { + t.Errorf("venue ID mismatch:\n%s", diff) + } + + { + actual, err := q.GetCity(ctx, city.Slug) + if err != nil { + t.Error(err) + } + if diff := cmp.Diff(actual, city); diff != "" { + t.Errorf("get city mismatch:\n%s", diff) + } + } + + { + actual, err := q.VenueCountByCity(ctx) + if err != nil { + t.Error(err) + } + if diff := cmp.Diff(actual, []VenueCountByCityRow{ + {city.Slug, 1}, + }); diff != "" { + t.Errorf("venue county mismatch:\n%s", diff) + } + } + + { + actual, err := q.ListCities(ctx) + if err != nil { + t.Error(err) + } + if diff := cmp.Diff(actual, []City{city}); diff != "" { + t.Errorf("list city mismatch:\n%s", diff) + } + } + + { + actual, err := q.ListVenues(ctx, city.Slug) + if err != nil { + t.Error(err) + } + if diff := cmp.Diff(actual, []Venue{venue}); diff != "" { + t.Errorf("list venue mismatch:\n%s", diff) + } + } + + { + err := q.UpdateCityName(ctx, UpdateCityNameParams{ + Slug: city.Slug, + Name: "SF", + }) + if err != nil { + t.Error(err) + } + } + + { + id, err := q.UpdateVenueName(ctx, UpdateVenueNameParams{ + Slug: venue.Slug, + Name: "Fillmore", + }) + if err != nil { + t.Error(err) + } + if diff := cmp.Diff(id, venue.ID); diff != "" { + t.Errorf("update venue mismatch:\n%s", diff) + } + } + + { + err := q.DeleteVenue(ctx, venue.Slug) + if err != nil { + t.Error(err) + } + } +} + +func TestPrepared(t *testing.T) { + t.Parallel() + + uri := local.PostgreSQL(t, []string{"schema"}) + db, err := sql.Open("postgres", uri) + if err != nil { + t.Fatalf("%s: %s", uri, err) + } + defer db.Close() + + q, err := Prepare(context.Background(), db) + if err != nil { + t.Fatal(err) + } + + runOnDeckQueries(t, q) +} + +func TestQueries(t *testing.T) { + t.Parallel() + + uri := local.PostgreSQL(t, []string{"schema"}) + db, err := sql.Open("postgres", uri) + if err != nil { + t.Fatalf("%s: %s", uri, err) + } + defer db.Close() + + runOnDeckQueries(t, New(db)) +} diff --git a/examples/ondeck/postgresql/models.go b/examples/ondeck/postgresql/models.go new file mode 100644 index 0000000..c0f65d7 --- /dev/null +++ b/examples/ondeck/postgresql/models.go @@ -0,0 +1,77 @@ +//go:build examples + +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package ondeck + +import ( + "database/sql" + "database/sql/driver" + "fmt" + "time" +) + +// Venues can be either open or closed +type Status string + +const ( + StatusOpen Status = "op!en" + StatusClosed Status = "clo@sed" +) + +func (e *Status) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = Status(s) + case string: + *e = Status(s) + default: + return fmt.Errorf("unsupported scan type for Status: %T", src) + } + return nil +} + +type NullStatus struct { + Status Status `json:"status"` + Valid bool `json:"valid"` // Valid is true if Status is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullStatus) Scan(value any) error { + if value == nil { + ns.Status, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.Status.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullStatus) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.Status), nil +} + +type City struct { + Slug string `json:"slug"` + Name string `json:"name"` +} + +// Venues are places where muisc happens +type Venue struct { + ID int32 `json:"id"` + Status Status `json:"status"` + Statuses []Status `json:"statuses"` + // This value appears in public URLs + Slug string `json:"slug"` + Name string `json:"name"` + City string `json:"city"` + SpotifyPlaylist string `json:"spotify_playlist"` + SongkickID sql.NullString `json:"songkick_id"` + Tags []string `json:"tags"` + CreatedAt time.Time `json:"created_at"` +} diff --git a/examples/ondeck/postgresql/querier.go b/examples/ondeck/postgresql/querier.go new file mode 100644 index 0000000..6b602d1 --- /dev/null +++ b/examples/ondeck/postgresql/querier.go @@ -0,0 +1,29 @@ +//go:build examples + +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package ondeck + +import ( + "context" +) + +type Querier interface { + // Create a new city. The slug must be unique. + // This is the second line of the comment + // This is the third line + CreateCity(ctx context.Context, arg CreateCityParams) (City, error) + CreateVenue(ctx context.Context, arg CreateVenueParams) (int32, error) + DeleteVenue(ctx context.Context, slug string) error + GetCity(ctx context.Context, slug string) (City, error) + GetVenue(ctx context.Context, arg GetVenueParams) (Venue, error) + ListCities(ctx context.Context) ([]City, error) + ListVenues(ctx context.Context, city string) ([]Venue, error) + UpdateCityName(ctx context.Context, arg UpdateCityNameParams) error + UpdateVenueName(ctx context.Context, arg UpdateVenueNameParams) (int32, error) + VenueCountByCity(ctx context.Context) ([]VenueCountByCityRow, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/examples/ondeck/postgresql/query/city.sql b/examples/ondeck/postgresql/query/city.sql new file mode 100644 index 0000000..f34dc99 --- /dev/null +++ b/examples/ondeck/postgresql/query/city.sql @@ -0,0 +1,26 @@ +-- name: ListCities :many +SELECT * +FROM city +ORDER BY name; + +-- name: GetCity :one +SELECT * +FROM city +WHERE slug = $1; + +-- name: CreateCity :one +-- Create a new city. The slug must be unique. +-- This is the second line of the comment +-- This is the third line +INSERT INTO city ( + name, + slug +) VALUES ( + $1, + $2 +) RETURNING *; + +-- name: UpdateCityName :exec +UPDATE city +SET name = $2 +WHERE slug = $1; diff --git a/examples/ondeck/postgresql/query/venue.sql b/examples/ondeck/postgresql/query/venue.sql new file mode 100644 index 0000000..8c6bd02 --- /dev/null +++ b/examples/ondeck/postgresql/query/venue.sql @@ -0,0 +1,49 @@ +-- name: ListVenues :many +SELECT * +FROM venue +WHERE city = $1 +ORDER BY name; + +-- name: DeleteVenue :exec +DELETE FROM venue +WHERE slug = $1 AND slug = $1; + +-- name: GetVenue :one +SELECT * +FROM venue +WHERE slug = $1 AND city = $2; + +-- name: CreateVenue :one +INSERT INTO venue ( + slug, + name, + city, + created_at, + spotify_playlist, + status, + statuses, + tags +) VALUES ( + $1, + $2, + $3, + NOW(), + $4, + $5, + $6, + $7 +) RETURNING id; + +-- name: UpdateVenueName :one +UPDATE venue +SET name = $2 +WHERE slug = $1 +RETURNING id; + +-- name: VenueCountByCity :many +SELECT + city, + count(*) +FROM venue +GROUP BY 1 +ORDER BY 1; diff --git a/examples/ondeck/postgresql/schema/0001_city.sql b/examples/ondeck/postgresql/schema/0001_city.sql new file mode 100644 index 0000000..af38f16 --- /dev/null +++ b/examples/ondeck/postgresql/schema/0001_city.sql @@ -0,0 +1,4 @@ +CREATE TABLE city ( + slug text PRIMARY KEY, + name text NOT NULL +) diff --git a/examples/ondeck/postgresql/schema/0002_venue.sql b/examples/ondeck/postgresql/schema/0002_venue.sql new file mode 100644 index 0000000..940de7a --- /dev/null +++ b/examples/ondeck/postgresql/schema/0002_venue.sql @@ -0,0 +1,18 @@ +CREATE TYPE status AS ENUM ('op!en', 'clo@sed'); +COMMENT ON TYPE status IS 'Venues can be either open or closed'; + +CREATE TABLE venues ( + id SERIAL primary key, + dropped text, + status status not null, + statuses status[], + slug text not null, + name varchar(255) not null, + city text not null references city(slug), + spotify_playlist varchar not null, + songkick_id text, + tags text[] +); +COMMENT ON TABLE venues IS 'Venues are places where muisc happens'; +COMMENT ON COLUMN venues.slug IS 'This value appears in public URLs'; + diff --git a/examples/ondeck/postgresql/schema/0003_add_column.sql b/examples/ondeck/postgresql/schema/0003_add_column.sql new file mode 100644 index 0000000..9b334bc --- /dev/null +++ b/examples/ondeck/postgresql/schema/0003_add_column.sql @@ -0,0 +1,3 @@ +ALTER TABLE venues RENAME TO venue; +ALTER TABLE venue ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT NOW(); +ALTER TABLE venue DROP COLUMN dropped; diff --git a/examples/ondeck/postgresql/venue.sql.go b/examples/ondeck/postgresql/venue.sql.go new file mode 100644 index 0000000..0bc6713 --- /dev/null +++ b/examples/ondeck/postgresql/venue.sql.go @@ -0,0 +1,197 @@ +//go:build examples + +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: venue.sql + +package ondeck + +import ( + "context" + + "github.com/lib/pq" +) + +const createVenue = `-- name: CreateVenue :one +INSERT INTO venue ( + slug, + name, + city, + created_at, + spotify_playlist, + status, + statuses, + tags +) VALUES ( + $1, + $2, + $3, + NOW(), + $4, + $5, + $6, + $7 +) RETURNING id +` + +type CreateVenueParams struct { + Slug string `json:"slug"` + Name string `json:"name"` + City string `json:"city"` + SpotifyPlaylist string `json:"spotify_playlist"` + Status Status `json:"status"` + Statuses []Status `json:"statuses"` + Tags []string `json:"tags"` +} + +func (q *Queries) CreateVenue(ctx context.Context, arg CreateVenueParams) (int32, error) { + row := q.queryRow(ctx, q.createVenueStmt, createVenue, + arg.Slug, + arg.Name, + arg.City, + arg.SpotifyPlaylist, + arg.Status, + pq.Array(arg.Statuses), + pq.Array(arg.Tags), + ) + var id int32 + err := row.Scan(&id) + return id, err +} + +const deleteVenue = `-- name: DeleteVenue :exec +DELETE FROM venue +WHERE slug = $1 AND slug = $1 +` + +func (q *Queries) DeleteVenue(ctx context.Context, slug string) error { + _, err := q.exec(ctx, q.deleteVenueStmt, deleteVenue, slug) + return err +} + +const getVenue = `-- name: GetVenue :one +SELECT id, status, statuses, slug, name, city, spotify_playlist, songkick_id, tags, created_at +FROM venue +WHERE slug = $1 AND city = $2 +` + +type GetVenueParams struct { + Slug string `json:"slug"` + City string `json:"city"` +} + +func (q *Queries) GetVenue(ctx context.Context, arg GetVenueParams) (Venue, error) { + row := q.queryRow(ctx, q.getVenueStmt, getVenue, arg.Slug, arg.City) + var i Venue + err := row.Scan( + &i.ID, + &i.Status, + pq.Array(&i.Statuses), + &i.Slug, + &i.Name, + &i.City, + &i.SpotifyPlaylist, + &i.SongkickID, + pq.Array(&i.Tags), + &i.CreatedAt, + ) + return i, err +} + +const listVenues = `-- name: ListVenues :many +SELECT id, status, statuses, slug, name, city, spotify_playlist, songkick_id, tags, created_at +FROM venue +WHERE city = $1 +ORDER BY name +` + +func (q *Queries) ListVenues(ctx context.Context, city string) ([]Venue, error) { + rows, err := q.query(ctx, q.listVenuesStmt, listVenues, city) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Venue + for rows.Next() { + var i Venue + if err := rows.Scan( + &i.ID, + &i.Status, + pq.Array(&i.Statuses), + &i.Slug, + &i.Name, + &i.City, + &i.SpotifyPlaylist, + &i.SongkickID, + pq.Array(&i.Tags), + &i.CreatedAt, + ); 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 updateVenueName = `-- name: UpdateVenueName :one +UPDATE venue +SET name = $2 +WHERE slug = $1 +RETURNING id +` + +type UpdateVenueNameParams struct { + Slug string `json:"slug"` + Name string `json:"name"` +} + +func (q *Queries) UpdateVenueName(ctx context.Context, arg UpdateVenueNameParams) (int32, error) { + row := q.queryRow(ctx, q.updateVenueNameStmt, updateVenueName, arg.Slug, arg.Name) + var id int32 + err := row.Scan(&id) + return id, err +} + +const venueCountByCity = `-- name: VenueCountByCity :many +SELECT + city, + count(*) +FROM venue +GROUP BY 1 +ORDER BY 1 +` + +type VenueCountByCityRow struct { + City string `json:"city"` + Count int64 `json:"count"` +} + +func (q *Queries) VenueCountByCity(ctx context.Context) ([]VenueCountByCityRow, error) { + rows, err := q.query(ctx, q.venueCountByCityStmt, venueCountByCity) + if err != nil { + return nil, err + } + defer rows.Close() + var items []VenueCountByCityRow + for rows.Next() { + var i VenueCountByCityRow + if err := rows.Scan(&i.City, &i.Count); 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/examples/ondeck/sqlc.json b/examples/ondeck/sqlc.json new file mode 100644 index 0000000..35f6570 --- /dev/null +++ b/examples/ondeck/sqlc.json @@ -0,0 +1,61 @@ +{ + "version": "1", + "cloud": { + "project": "01HAQMMECEYQYKFJN8MP16QC41" + }, + "packages": [ + { + "path": "postgresql", + "name": "ondeck", + "schema": "postgresql/schema", + "queries": "postgresql/query", + "engine": "postgresql", + "sql_package": "database/sql", + "database": { + "uri": "${VET_TEST_EXAMPLES_POSTGRES_ONDECK}" + }, + "analyzer": { + "database": false + }, + "rules": [ + "sqlc/db-prepare" + ], + "build_tags": "examples", + "emit_json_tags": true, + "emit_prepared_queries": true, + "emit_interface": true + }, + { + "path": "mysql", + "name": "ondeck", + "schema": "mysql/schema", + "queries": "mysql/query", + "engine": "mysql", + "database": { + "uri": "${VET_TEST_EXAMPLES_MYSQL_ONDECK}" + }, + "rules": [ + "sqlc/db-prepare" + ], + "emit_json_tags": true, + "emit_prepared_queries": true, + "emit_interface": true + }, + { + "path": "sqlite", + "name": "ondeck", + "schema": "sqlite/schema", + "queries": "sqlite/query", + "engine": "sqlite", + "database": { + "uri": "file:ondeck?mode=memory&cache=shared" + }, + "rules": [ + "sqlc/db-prepare" + ], + "emit_json_tags": true, + "emit_prepared_queries": true, + "emit_interface": true + } + ] +} diff --git a/examples/ondeck/sqlite/city.sql.go b/examples/ondeck/sqlite/city.sql.go new file mode 100644 index 0000000..89b321e --- /dev/null +++ b/examples/ondeck/sqlite/city.sql.go @@ -0,0 +1,88 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: city.sql + +package ondeck + +import ( + "context" +) + +const createCity = `-- name: CreateCity :exec +INSERT INTO city ( + name, + slug +) VALUES ( + ?, + ? +) +` + +type CreateCityParams struct { + Name string `json:"name"` + Slug string `json:"slug"` +} + +func (q *Queries) CreateCity(ctx context.Context, arg CreateCityParams) error { + _, err := q.exec(ctx, q.createCityStmt, createCity, arg.Name, arg.Slug) + return err +} + +const getCity = `-- name: GetCity :one +SELECT slug, name +FROM city +WHERE slug = ? +` + +func (q *Queries) GetCity(ctx context.Context, slug string) (City, error) { + row := q.queryRow(ctx, q.getCityStmt, getCity, slug) + var i City + err := row.Scan(&i.Slug, &i.Name) + return i, err +} + +const listCities = `-- name: ListCities :many +SELECT slug, name +FROM city +ORDER BY name +` + +func (q *Queries) ListCities(ctx context.Context) ([]City, error) { + rows, err := q.query(ctx, q.listCitiesStmt, listCities) + if err != nil { + return nil, err + } + defer rows.Close() + var items []City + for rows.Next() { + var i City + if err := rows.Scan(&i.Slug, &i.Name); 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 updateCityName = `-- name: UpdateCityName :exec +UPDATE city +SET name = ? +WHERE slug = ? +` + +type UpdateCityNameParams struct { + Name string `json:"name"` + Slug string `json:"slug"` +} + +func (q *Queries) UpdateCityName(ctx context.Context, arg UpdateCityNameParams) error { + _, err := q.exec(ctx, q.updateCityNameStmt, updateCityName, arg.Name, arg.Slug) + return err +} diff --git a/examples/ondeck/sqlite/db.go b/examples/ondeck/sqlite/db.go new file mode 100644 index 0000000..67cc093 --- /dev/null +++ b/examples/ondeck/sqlite/db.go @@ -0,0 +1,178 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package ondeck + +import ( + "context" + "database/sql" + "fmt" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +func Prepare(ctx context.Context, db DBTX) (*Queries, error) { + q := Queries{db: db} + var err error + if q.createCityStmt, err = db.PrepareContext(ctx, createCity); err != nil { + return nil, fmt.Errorf("error preparing query CreateCity: %w", err) + } + if q.createVenueStmt, err = db.PrepareContext(ctx, createVenue); err != nil { + return nil, fmt.Errorf("error preparing query CreateVenue: %w", err) + } + if q.deleteVenueStmt, err = db.PrepareContext(ctx, deleteVenue); err != nil { + return nil, fmt.Errorf("error preparing query DeleteVenue: %w", err) + } + if q.getCityStmt, err = db.PrepareContext(ctx, getCity); err != nil { + return nil, fmt.Errorf("error preparing query GetCity: %w", err) + } + if q.getVenueStmt, err = db.PrepareContext(ctx, getVenue); err != nil { + return nil, fmt.Errorf("error preparing query GetVenue: %w", err) + } + if q.listCitiesStmt, err = db.PrepareContext(ctx, listCities); err != nil { + return nil, fmt.Errorf("error preparing query ListCities: %w", err) + } + if q.listVenuesStmt, err = db.PrepareContext(ctx, listVenues); err != nil { + return nil, fmt.Errorf("error preparing query ListVenues: %w", err) + } + if q.updateCityNameStmt, err = db.PrepareContext(ctx, updateCityName); err != nil { + return nil, fmt.Errorf("error preparing query UpdateCityName: %w", err) + } + if q.updateVenueNameStmt, err = db.PrepareContext(ctx, updateVenueName); err != nil { + return nil, fmt.Errorf("error preparing query UpdateVenueName: %w", err) + } + if q.venueCountByCityStmt, err = db.PrepareContext(ctx, venueCountByCity); err != nil { + return nil, fmt.Errorf("error preparing query VenueCountByCity: %w", err) + } + return &q, nil +} + +func (q *Queries) Close() error { + var err error + if q.createCityStmt != nil { + if cerr := q.createCityStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing createCityStmt: %w", cerr) + } + } + if q.createVenueStmt != nil { + if cerr := q.createVenueStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing createVenueStmt: %w", cerr) + } + } + if q.deleteVenueStmt != nil { + if cerr := q.deleteVenueStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing deleteVenueStmt: %w", cerr) + } + } + if q.getCityStmt != nil { + if cerr := q.getCityStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getCityStmt: %w", cerr) + } + } + if q.getVenueStmt != nil { + if cerr := q.getVenueStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getVenueStmt: %w", cerr) + } + } + if q.listCitiesStmt != nil { + if cerr := q.listCitiesStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing listCitiesStmt: %w", cerr) + } + } + if q.listVenuesStmt != nil { + if cerr := q.listVenuesStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing listVenuesStmt: %w", cerr) + } + } + if q.updateCityNameStmt != nil { + if cerr := q.updateCityNameStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateCityNameStmt: %w", cerr) + } + } + if q.updateVenueNameStmt != nil { + if cerr := q.updateVenueNameStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateVenueNameStmt: %w", cerr) + } + } + if q.venueCountByCityStmt != nil { + if cerr := q.venueCountByCityStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing venueCountByCityStmt: %w", cerr) + } + } + return err +} + +func (q *Queries) exec(ctx context.Context, stmt *sql.Stmt, query string, args ...any) (sql.Result, error) { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).ExecContext(ctx, args...) + case stmt != nil: + return stmt.ExecContext(ctx, args...) + default: + return q.db.ExecContext(ctx, query, args...) + } +} + +func (q *Queries) query(ctx context.Context, stmt *sql.Stmt, query string, args ...any) (*sql.Rows, error) { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).QueryContext(ctx, args...) + case stmt != nil: + return stmt.QueryContext(ctx, args...) + default: + return q.db.QueryContext(ctx, query, args...) + } +} + +func (q *Queries) queryRow(ctx context.Context, stmt *sql.Stmt, query string, args ...any) *sql.Row { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).QueryRowContext(ctx, args...) + case stmt != nil: + return stmt.QueryRowContext(ctx, args...) + default: + return q.db.QueryRowContext(ctx, query, args...) + } +} + +type Queries struct { + db DBTX + tx *sql.Tx + createCityStmt *sql.Stmt + createVenueStmt *sql.Stmt + deleteVenueStmt *sql.Stmt + getCityStmt *sql.Stmt + getVenueStmt *sql.Stmt + listCitiesStmt *sql.Stmt + listVenuesStmt *sql.Stmt + updateCityNameStmt *sql.Stmt + updateVenueNameStmt *sql.Stmt + venueCountByCityStmt *sql.Stmt +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + tx: tx, + createCityStmt: q.createCityStmt, + createVenueStmt: q.createVenueStmt, + deleteVenueStmt: q.deleteVenueStmt, + getCityStmt: q.getCityStmt, + getVenueStmt: q.getVenueStmt, + listCitiesStmt: q.listCitiesStmt, + listVenuesStmt: q.listVenuesStmt, + updateCityNameStmt: q.updateCityNameStmt, + updateVenueNameStmt: q.updateVenueNameStmt, + venueCountByCityStmt: q.venueCountByCityStmt, + } +} diff --git a/examples/ondeck/sqlite/db_test.go b/examples/ondeck/sqlite/db_test.go new file mode 100644 index 0000000..e4bb4e4 --- /dev/null +++ b/examples/ondeck/sqlite/db_test.go @@ -0,0 +1,171 @@ +//go:build examples + +package ondeck + +import ( + "context" + "database/sql" + "strings" + "testing" + + "github.com/sqlc-dev/sqlc/internal/sqltest" + + "github.com/google/go-cmp/cmp" +) + +// TODO: Enum is not yet supported +const ( + VenuesStatusOpen string = "open" + VenuesStatusClosed string = "closed" +) + +func join(vals ...string) sql.NullString { + if len(vals) == 0 { + return sql.NullString{} + } + return sql.NullString{ + Valid: true, + String: strings.Join(vals, ","), + } +} + +func runOnDeckQueries(t *testing.T, q *Queries) { + ctx := context.Background() + + err := q.CreateCity(ctx, CreateCityParams{ + Slug: "san-francisco", + Name: "San Francisco", + }) + if err != nil { + t.Fatal(err) + } + + city, err := q.GetCity(ctx, "san-francisco") + if err != nil { + t.Fatal(err) + } + + venueResult, err := q.CreateVenue(ctx, CreateVenueParams{ + Slug: "the-fillmore", + Name: "The Fillmore", + City: city.Slug, + SpotifyPlaylist: "spotify:uri", + Status: VenuesStatusOpen, + Statuses: join(string(VenuesStatusOpen), string(VenuesStatusClosed)), + Tags: join("rock", "punk"), + }) + if err != nil { + t.Fatal(err) + } + venueID, err := venueResult.LastInsertId() + if err != nil { + t.Fatal(err) + } + + venue, err := q.GetVenue(ctx, GetVenueParams{ + Slug: "the-fillmore", + City: city.Slug, + }) + if err != nil { + t.Fatal(err) + } + + if diff := cmp.Diff(venue.ID, venueID); diff != "" { + t.Errorf("venue ID mismatch:\n%s", diff) + } + + { + actual, err := q.VenueCountByCity(ctx) + if err != nil { + t.Error(err) + } + if diff := cmp.Diff(actual, []VenueCountByCityRow{ + {city.Slug, int64(1)}, + }); diff != "" { + t.Errorf("venue count mismatch:\n%s", diff) + } + } + + { + actual, err := q.ListCities(ctx) + if err != nil { + t.Error(err) + } + if diff := cmp.Diff(actual, []City{city}); diff != "" { + t.Errorf("list city mismatch:\n%s", diff) + } + } + + { + actual, err := q.ListVenues(ctx, city.Slug) + if err != nil { + t.Error(err) + } + if diff := cmp.Diff(actual, []Venue{venue}); diff != "" { + t.Errorf("list venue mismatch:\n%s", diff) + } + } + + { + err := q.UpdateCityName(ctx, UpdateCityNameParams{ + Slug: city.Slug, + Name: "SF", + }) + if err != nil { + t.Error(err) + } + } + + { + expected := "Fillmore" + err := q.UpdateVenueName(ctx, UpdateVenueNameParams{ + Slug: venue.Slug, + Name: expected, + }) + if err != nil { + t.Error(err) + } + fresh, err := q.GetVenue(ctx, GetVenueParams{ + Slug: venue.Slug, + City: city.Slug, + }) + if diff := cmp.Diff(expected, fresh.Name); diff != "" { + t.Errorf("update venue mismatch:\n%s", diff) + } + } + + { + err := q.DeleteVenue(ctx, DeleteVenueParams{ + Slug: venue.Slug, + Slug_2: venue.Slug, + }) + if err != nil { + t.Error(err) + } + } +} + +func TestPrepared(t *testing.T) { + t.Parallel() + + sdb, cleanup := sqltest.SQLite(t, []string{"schema"}) + defer sdb.Close() + defer cleanup() + + q, err := Prepare(context.Background(), sdb) + if err != nil { + t.Fatal(err) + } + + runOnDeckQueries(t, q) +} + +func TestQueries(t *testing.T) { + t.Parallel() + + sdb, cleanup := sqltest.SQLite(t, []string{"schema"}) + defer sdb.Close() + defer cleanup() + + runOnDeckQueries(t, New(sdb)) +} diff --git a/examples/ondeck/sqlite/models.go b/examples/ondeck/sqlite/models.go new file mode 100644 index 0000000..2a66723 --- /dev/null +++ b/examples/ondeck/sqlite/models.go @@ -0,0 +1,28 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package ondeck + +import ( + "database/sql" + "time" +) + +type City struct { + Slug string `json:"slug"` + Name string `json:"name"` +} + +type Venue struct { + ID int64 `json:"id"` + Status string `json:"status"` + Statuses sql.NullString `json:"statuses"` + Slug string `json:"slug"` + Name string `json:"name"` + City string `json:"city"` + SpotifyPlaylist string `json:"spotify_playlist"` + SongkickID sql.NullString `json:"songkick_id"` + Tags sql.NullString `json:"tags"` + CreatedAt time.Time `json:"created_at"` +} diff --git a/examples/ondeck/sqlite/querier.go b/examples/ondeck/sqlite/querier.go new file mode 100644 index 0000000..e477383 --- /dev/null +++ b/examples/ondeck/sqlite/querier.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package ondeck + +import ( + "context" + "database/sql" +) + +type Querier interface { + CreateCity(ctx context.Context, arg CreateCityParams) error + CreateVenue(ctx context.Context, arg CreateVenueParams) (sql.Result, error) + DeleteVenue(ctx context.Context, arg DeleteVenueParams) error + GetCity(ctx context.Context, slug string) (City, error) + GetVenue(ctx context.Context, arg GetVenueParams) (Venue, error) + ListCities(ctx context.Context) ([]City, error) + ListVenues(ctx context.Context, city string) ([]Venue, error) + UpdateCityName(ctx context.Context, arg UpdateCityNameParams) error + UpdateVenueName(ctx context.Context, arg UpdateVenueNameParams) error + VenueCountByCity(ctx context.Context) ([]VenueCountByCityRow, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/examples/ondeck/sqlite/query/city.sql b/examples/ondeck/sqlite/query/city.sql new file mode 100644 index 0000000..c387e9d --- /dev/null +++ b/examples/ondeck/sqlite/query/city.sql @@ -0,0 +1,23 @@ +/* name: ListCities :many */ +SELECT * +FROM city +ORDER BY name; + +/* name: GetCity :one */ +SELECT * +FROM city +WHERE slug = ?; + +/* name: CreateCity :exec */ +INSERT INTO city ( + name, + slug +) VALUES ( + ?, + ? +); + +/* name: UpdateCityName :exec */ +UPDATE city +SET name = ? +WHERE slug = ?; diff --git a/examples/ondeck/sqlite/query/venue.sql b/examples/ondeck/sqlite/query/venue.sql new file mode 100644 index 0000000..b4f5fd4 --- /dev/null +++ b/examples/ondeck/sqlite/query/venue.sql @@ -0,0 +1,48 @@ +/* name: ListVenues :many */ +SELECT * +FROM venue +WHERE city = ? +ORDER BY name; + +/* name: DeleteVenue :exec */ +DELETE FROM venue +WHERE slug = ? AND slug = ?; + +/* name: GetVenue :one */ +SELECT * +FROM venue +WHERE slug = ? AND city = ?; + +/* name: CreateVenue :execresult */ +INSERT INTO venue ( + slug, + name, + city, + created_at, + spotify_playlist, + status, + statuses, + tags +) VALUES ( + ?, + ?, + ?, + CURRENT_TIMESTAMP, + ?, + ?, + ?, + ? +); + +/* name: UpdateVenueName :exec */ +UPDATE venue +SET name = ? +WHERE slug = ?; + +/* name: VenueCountByCity :many */ +SELECT + city, + count(*) +FROM venue +GROUP BY 1 +ORDER BY 1; diff --git a/examples/ondeck/sqlite/schema/0001_city.sql b/examples/ondeck/sqlite/schema/0001_city.sql new file mode 100644 index 0000000..6be35d1 --- /dev/null +++ b/examples/ondeck/sqlite/schema/0001_city.sql @@ -0,0 +1,4 @@ +CREATE TABLE city ( + slug varchar(255) PRIMARY KEY, + name text NOT NULL +) diff --git a/examples/ondeck/sqlite/schema/0002_venue.sql b/examples/ondeck/sqlite/schema/0002_venue.sql new file mode 100644 index 0000000..e57166e --- /dev/null +++ b/examples/ondeck/sqlite/schema/0002_venue.sql @@ -0,0 +1,13 @@ +CREATE TABLE venues ( + id integer primary key AUTOINCREMENT, + dropped text, + status text not null, + statuses text, -- status[] + slug text not null, + name varchar(255) not null, + city text not null references city(slug), + spotify_playlist varchar(255) not null, + songkick_id text, + tags text, -- tags[] + CHECK (status = 'open' OR status = 'closed') +); diff --git a/examples/ondeck/sqlite/schema/0003_add_column.sql b/examples/ondeck/sqlite/schema/0003_add_column.sql new file mode 100644 index 0000000..7d7a644 --- /dev/null +++ b/examples/ondeck/sqlite/schema/0003_add_column.sql @@ -0,0 +1,3 @@ +ALTER TABLE venues RENAME TO venue; +ALTER TABLE venue ADD COLUMN created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP; +ALTER TABLE venue DROP COLUMN dropped; diff --git a/examples/ondeck/sqlite/venue.sql.go b/examples/ondeck/sqlite/venue.sql.go new file mode 100644 index 0000000..6242a9a --- /dev/null +++ b/examples/ondeck/sqlite/venue.sql.go @@ -0,0 +1,193 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: venue.sql + +package ondeck + +import ( + "context" + "database/sql" +) + +const createVenue = `-- name: CreateVenue :execresult +INSERT INTO venue ( + slug, + name, + city, + created_at, + spotify_playlist, + status, + statuses, + tags +) VALUES ( + ?, + ?, + ?, + CURRENT_TIMESTAMP, + ?, + ?, + ?, + ? +) +` + +type CreateVenueParams struct { + Slug string `json:"slug"` + Name string `json:"name"` + City string `json:"city"` + SpotifyPlaylist string `json:"spotify_playlist"` + Status string `json:"status"` + Statuses sql.NullString `json:"statuses"` + Tags sql.NullString `json:"tags"` +} + +func (q *Queries) CreateVenue(ctx context.Context, arg CreateVenueParams) (sql.Result, error) { + return q.exec(ctx, q.createVenueStmt, createVenue, + arg.Slug, + arg.Name, + arg.City, + arg.SpotifyPlaylist, + arg.Status, + arg.Statuses, + arg.Tags, + ) +} + +const deleteVenue = `-- name: DeleteVenue :exec +DELETE FROM venue +WHERE slug = ? AND slug = ? +` + +type DeleteVenueParams struct { + Slug string `json:"slug"` + Slug_2 string `json:"slug_2"` +} + +func (q *Queries) DeleteVenue(ctx context.Context, arg DeleteVenueParams) error { + _, err := q.exec(ctx, q.deleteVenueStmt, deleteVenue, arg.Slug, arg.Slug_2) + return err +} + +const getVenue = `-- name: GetVenue :one +SELECT id, status, statuses, slug, name, city, spotify_playlist, songkick_id, tags, created_at +FROM venue +WHERE slug = ? AND city = ? +` + +type GetVenueParams struct { + Slug string `json:"slug"` + City string `json:"city"` +} + +func (q *Queries) GetVenue(ctx context.Context, arg GetVenueParams) (Venue, error) { + row := q.queryRow(ctx, q.getVenueStmt, getVenue, arg.Slug, arg.City) + var i Venue + err := row.Scan( + &i.ID, + &i.Status, + &i.Statuses, + &i.Slug, + &i.Name, + &i.City, + &i.SpotifyPlaylist, + &i.SongkickID, + &i.Tags, + &i.CreatedAt, + ) + return i, err +} + +const listVenues = `-- name: ListVenues :many +SELECT id, status, statuses, slug, name, city, spotify_playlist, songkick_id, tags, created_at +FROM venue +WHERE city = ? +ORDER BY name +` + +func (q *Queries) ListVenues(ctx context.Context, city string) ([]Venue, error) { + rows, err := q.query(ctx, q.listVenuesStmt, listVenues, city) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Venue + for rows.Next() { + var i Venue + if err := rows.Scan( + &i.ID, + &i.Status, + &i.Statuses, + &i.Slug, + &i.Name, + &i.City, + &i.SpotifyPlaylist, + &i.SongkickID, + &i.Tags, + &i.CreatedAt, + ); 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 updateVenueName = `-- name: UpdateVenueName :exec +UPDATE venue +SET name = ? +WHERE slug = ? +` + +type UpdateVenueNameParams struct { + Name string `json:"name"` + Slug string `json:"slug"` +} + +func (q *Queries) UpdateVenueName(ctx context.Context, arg UpdateVenueNameParams) error { + _, err := q.exec(ctx, q.updateVenueNameStmt, updateVenueName, arg.Name, arg.Slug) + return err +} + +const venueCountByCity = `-- name: VenueCountByCity :many +SELECT + city, + count(*) +FROM venue +GROUP BY 1 +ORDER BY 1 +` + +type VenueCountByCityRow struct { + City string `json:"city"` + Count int64 `json:"count"` +} + +func (q *Queries) VenueCountByCity(ctx context.Context) ([]VenueCountByCityRow, error) { + rows, err := q.query(ctx, q.venueCountByCityStmt, venueCountByCity) + if err != nil { + return nil, err + } + defer rows.Close() + var items []VenueCountByCityRow + for rows.Next() { + var i VenueCountByCityRow + if err := rows.Scan(&i.City, &i.Count); 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/go.mod b/go.mod new file mode 100644 index 0000000..f090ce7 --- /dev/null +++ b/go.mod @@ -0,0 +1,58 @@ +module github.com/sqlc-dev/sqlc + +go 1.26.0 + +toolchain go1.26.5 + +require ( + cel.dev/cel-go v0.32.0 + github.com/cubicdaiya/gonp v1.0.4 + github.com/davecgh/go-spew v1.1.1 + github.com/fatih/structtag v1.2.0 + github.com/go-sql-driver/mysql v1.10.1 + github.com/google/go-cmp v0.7.0 + github.com/jackc/pgx/v5 v5.11.0 + github.com/jinzhu/inflection v1.0.0 + github.com/lib/pq v1.12.3 + github.com/ncruces/go-sqlite3 v0.35.4 + github.com/riza-io/grpc-go v0.2.0 + github.com/spf13/cobra v1.10.2 + github.com/spf13/pflag v1.0.10 + github.com/sqlc-dev/darkwing v0.1.0 + github.com/sqlc-dev/doubleclick v1.0.0 + github.com/sqlc-dev/marino v0.3.1 + github.com/sqlc-dev/meyer v0.1.2 + github.com/sqlc-dev/oliphant v0.2.0 + github.com/sqlc-dev/teesql v1.1.0 + github.com/sqlc-dev/zetajones v0.1.0 + github.com/tetratelabs/wazero v1.12.0 + github.com/xeipuuv/gojsonschema v1.2.0 + github.com/yuin/goldmark v1.8.6 + golang.org/x/sync v0.23.0 + google.golang.org/grpc v1.83.2 + google.golang.org/protobuf v1.36.12 + gopkg.in/yaml.v3 v3.0.1 +) + +require ( + cel.dev/expr v0.25.2 // indirect + filippo.io/edwards25519 v1.2.0 // indirect + github.com/antlr4-go/antlr/v4 v4.13.1 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/ncruces/go-sqlite3-wasm/v5 v5.0.35304 // indirect + github.com/ncruces/julianday v1.0.0 // indirect + github.com/rogpeppe/go-internal v1.10.0 // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect + golang.org/x/net v0.58.0 // indirect + golang.org/x/sys v0.47.0 // indirect + golang.org/x/text v0.41.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..cdad651 --- /dev/null +++ b/go.sum @@ -0,0 +1,136 @@ +cel.dev/cel-go v0.32.0 h1:irvpFKr5EuGPyxeME03ERh0rii1TX+BDAnB9eL3IvNk= +cel.dev/cel-go v0.32.0/go.mod h1:DnVip7tpJSsgZymwfT+m1tnEVy3ivAjSMXPx12YrMkU= +cel.dev/expr v0.25.2 h1:K6j46C81hXtZQfuX60cVWQFBJahKSE2gfRbNuvr5bFs= +cel.dev/expr v0.25.2/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= +filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo= +filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc= +github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= +github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cubicdaiya/gonp v1.0.4 h1:ky2uIAJh81WiLcGKBVD5R7KsM/36W6IqqTy6Bo6rGws= +github.com/cubicdaiya/gonp v1.0.4/go.mod h1:iWGuP/7+JVTn02OWhRemVbMmG1DOUnmrGTYYACpOI0I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= +github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-sql-driver/mysql v1.10.1 h1:arlSnNLq6a5yxGxV7qg9lF4j0C+KwD6NbQyKr9QL6ME= +github.com/go-sql-driver/mysql v1.10.1/go.mod h1:M+cqaI7+xxXGG9swrdeUIoPG3Y3KCkF0pZej+SK+nWk= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.11.0 h1:IzBBtyK9AHqf98cctWFifYSci2hgQR/cd56wB4p+ogg= +github.com/jackc/pgx/v5 v5.11.0/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ= +github.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA= +github.com/ncruces/go-sqlite3 v0.35.4 h1:unjCk+lVaxMpD9hbVaZyDJviS5Unw1P03+HF0ROLlHo= +github.com/ncruces/go-sqlite3 v0.35.4/go.mod h1:dfbnrzPOLEIpCNZ1yDRkIG60pGxjDCwiEKj9A0lGWYE= +github.com/ncruces/go-sqlite3-wasm/v5 v5.0.35304 h1:Ck3GB9h+0n3hJqdhAeehOef3k5V+llGio1c2Dyk/W6w= +github.com/ncruces/go-sqlite3-wasm/v5 v5.0.35304/go.mod h1:gJyN6U50iis7mDt+rzRv8u9vUNr08NTD2p4fVonKn/Q= +github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M= +github.com/ncruces/julianday v1.0.0/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +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.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= +github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/sqlc-dev/darkwing v0.1.0 h1:P5dtJebmCiy10e6DcnBQ2d7Mwuz636obuSAzTlr/1Qo= +github.com/sqlc-dev/darkwing v0.1.0/go.mod h1:kPb+99a6U+oVWtLhsuvkuDb/YRm8deK6x+W/9mX6uug= +github.com/sqlc-dev/doubleclick v1.0.0 h1:2/OApfQ2eLgcfa/Fqs8WSMA6atH0G8j9hHbQIgMfAXI= +github.com/sqlc-dev/doubleclick v1.0.0/go.mod h1:ODHRroSrk/rr5neRHlWMSRijqOak8YmNaO3VAZCNl5Y= +github.com/sqlc-dev/marino v0.3.1 h1:5LkfxftC+drpX1NE6ULTSJlRQ3FzvaFgmXSik+s0Q1Y= +github.com/sqlc-dev/marino v0.3.1/go.mod h1:mQxC2dgDE0DWHMb2B5jZNk7KToJuS6wnxnffBfYnq08= +github.com/sqlc-dev/meyer v0.1.2 h1:40Ng9Glnx7CTf3yOYV7jfvDIN7voIFjrStkIULS+uws= +github.com/sqlc-dev/meyer v0.1.2/go.mod h1:pS4USCRf/SLjWtaMcnTo4YrEEFKBj8CyyqlxcVUJQH8= +github.com/sqlc-dev/oliphant v0.2.0 h1:jJ/s2fh4Plj3U1HsdqiY/clw/IHb4FCNaHfqirwxcsI= +github.com/sqlc-dev/oliphant v0.2.0/go.mod h1:fRM/t4FutRddTIq2YCuS4O9o+2rRwSwELRvLMqtPloo= +github.com/sqlc-dev/teesql v1.1.0 h1:3sVYQ9FGxQVcqrqQOQ27bk0aF4c4yN1H1zLL79uaSxQ= +github.com/sqlc-dev/teesql v1.1.0/go.mod h1:WwOp9UtnxG17+eNFT5KXu/AGBQ8ucdGc8wIOpnj4XCI= +github.com/sqlc-dev/zetajones v0.1.0 h1:VeG0atx6lNABr9V2bSI5vL9DvOKTHX0XjMqWUE/rv40= +github.com/sqlc-dev/zetajones v0.1.0/go.mod h1:dU1DxwqC6Cahbpnw16KpH1J2waWRDMdwyDSvovMZR4I= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tetratelabs/wazero v1.12.0 h1:DuWcpNu/FzgEXgGBDp8J1Spc+CWOvvtvVyjKlaZopYU= +github.com/tetratelabs/wazero v1.12.0/go.mod h1:LvKtzl2RqO4gyF27BiXU+nKAjcV8f38U+kP/q2vgxh0= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/yuin/goldmark v1.8.6 h1:d0VcaP1sx9GkFVkoW+KtggpGi2KZ965i14b0+bDQST4= +github.com/yuin/goldmark v1.8.6/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= +go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= +go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= +go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= +go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= +go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0= +go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= +go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA= +go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= +go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o= +golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= +golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To= +golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU= +golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk= +golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0= +golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= +golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= +golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8= +google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.83.2 h1:EManeRomTObA0BU7I8vXgg/78uE5MJ9M8B39EX2WscU= +google.golang.org/grpc v1.83.2/go.mod h1:YPI1hK3kDked6iHvgX3tR0y+nX/qpMFKhPgFsokw1S8= +google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc= +google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/gomod_test.go b/gomod_test.go new file mode 100644 index 0000000..fd00b12 --- /dev/null +++ b/gomod_test.go @@ -0,0 +1,66 @@ +package sqlc + +import ( + "fmt" + "os" + "strings" + "testing" +) + +// TestGoModHasNoReplaceDirectives guards against regressions of +// https://github.com/sqlc-dev/sqlc/issues/4397. +// +// When go.mod contains a replace directive, the Go toolchain refuses to run +// `go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest` (and the equivalent +// `go run ...@latest`): +// +// go: github.com/sqlc-dev/sqlc/cmd/sqlc@latest (in github.com/sqlc-dev/sqlc@v...): +// The go.mod file for the module providing named packages contains one or +// more replace directives. It must not contain directives that would cause +// it to be interpreted differently than if it were the main module. +// +// https://docs.sqlc.dev/en/latest/overview/install.html tells users to run +// exactly that command, so any replace directive slipping into go.mod breaks +// the advertised installation path for the next release. +func TestGoModHasNoReplaceDirectives(t *testing.T) { + data, err := os.ReadFile("go.mod") + if err != nil { + t.Fatalf("read go.mod: %v", err) + } + + var ( + inBlock bool + offenders []string + ) + for i, raw := range strings.Split(string(data), "\n") { + line := strings.TrimSpace(raw) + if idx := strings.Index(line, "//"); idx >= 0 { + line = strings.TrimSpace(line[:idx]) + } + + if inBlock { + if line == ")" { + inBlock = false + continue + } + if line != "" { + offenders = append(offenders, fmt.Sprintf(" go.mod:%d: %s", i+1, raw)) + } + continue + } + + switch { + case line == "replace (": + inBlock = true + case strings.HasPrefix(line, "replace "): + offenders = append(offenders, fmt.Sprintf(" go.mod:%d: %s", i+1, raw)) + } + } + + if len(offenders) > 0 { + t.Fatalf("go.mod must not contain replace directives; "+ + "they break `go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest`.\n"+ + "See https://github.com/sqlc-dev/sqlc/issues/4397\n%s", + strings.Join(offenders, "\n")) + } +} diff --git a/internal/analysis/analysis.pb.go b/internal/analysis/analysis.pb.go new file mode 100644 index 0000000..e039cd6 --- /dev/null +++ b/internal/analysis/analysis.pb.go @@ -0,0 +1,546 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.30.0 +// protoc (unknown) +// source: analysis/analysis.proto + +package analysis + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Identifier struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Catalog string `protobuf:"bytes,1,opt,name=catalog,proto3" json:"catalog,omitempty"` + Schema string `protobuf:"bytes,2,opt,name=schema,proto3" json:"schema,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *Identifier) Reset() { + *x = Identifier{} + if protoimpl.UnsafeEnabled { + mi := &file_analysis_analysis_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Identifier) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Identifier) ProtoMessage() {} + +func (x *Identifier) ProtoReflect() protoreflect.Message { + mi := &file_analysis_analysis_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Identifier.ProtoReflect.Descriptor instead. +func (*Identifier) Descriptor() ([]byte, []int) { + return file_analysis_analysis_proto_rawDescGZIP(), []int{0} +} + +func (x *Identifier) GetCatalog() string { + if x != nil { + return x.Catalog + } + return "" +} + +func (x *Identifier) GetSchema() string { + if x != nil { + return x.Schema + } + return "" +} + +func (x *Identifier) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type Column struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + OriginalName string `protobuf:"bytes,2,opt,name=original_name,json=originalName,proto3" json:"original_name,omitempty"` + DataType string `protobuf:"bytes,3,opt,name=data_type,json=dataType,proto3" json:"data_type,omitempty"` + NotNull bool `protobuf:"varint,4,opt,name=not_null,json=notNull,proto3" json:"not_null,omitempty"` + Unsigned bool `protobuf:"varint,5,opt,name=unsigned,proto3" json:"unsigned,omitempty"` + IsArray bool `protobuf:"varint,6,opt,name=is_array,json=isArray,proto3" json:"is_array,omitempty"` + ArrayDims int32 `protobuf:"varint,7,opt,name=array_dims,json=arrayDims,proto3" json:"array_dims,omitempty"` + Comment string `protobuf:"bytes,8,opt,name=comment,proto3" json:"comment,omitempty"` + Length int32 `protobuf:"varint,9,opt,name=length,proto3" json:"length,omitempty"` // *int + IsNamedParam bool `protobuf:"varint,10,opt,name=is_named_param,json=isNamedParam,proto3" json:"is_named_param,omitempty"` + IsFuncCall bool `protobuf:"varint,11,opt,name=is_func_call,json=isFuncCall,proto3" json:"is_func_call,omitempty"` + Scope string `protobuf:"bytes,12,opt,name=scope,proto3" json:"scope,omitempty"` + Table *Identifier `protobuf:"bytes,13,opt,name=table,proto3" json:"table,omitempty"` + TableAlias string `protobuf:"bytes,14,opt,name=table_alias,json=tableAlias,proto3" json:"table_alias,omitempty"` + Type *Identifier `protobuf:"bytes,15,opt,name=type,proto3" json:"type,omitempty"` + EmbedTable *Identifier `protobuf:"bytes,16,opt,name=embed_table,json=embedTable,proto3" json:"embed_table,omitempty"` + IsSqlcSlice bool `protobuf:"varint,17,opt,name=is_sqlc_slice,json=isSqlcSlice,proto3" json:"is_sqlc_slice,omitempty"` +} + +func (x *Column) Reset() { + *x = Column{} + if protoimpl.UnsafeEnabled { + mi := &file_analysis_analysis_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Column) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Column) ProtoMessage() {} + +func (x *Column) ProtoReflect() protoreflect.Message { + mi := &file_analysis_analysis_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Column.ProtoReflect.Descriptor instead. +func (*Column) Descriptor() ([]byte, []int) { + return file_analysis_analysis_proto_rawDescGZIP(), []int{1} +} + +func (x *Column) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Column) GetOriginalName() string { + if x != nil { + return x.OriginalName + } + return "" +} + +func (x *Column) GetDataType() string { + if x != nil { + return x.DataType + } + return "" +} + +func (x *Column) GetNotNull() bool { + if x != nil { + return x.NotNull + } + return false +} + +func (x *Column) GetUnsigned() bool { + if x != nil { + return x.Unsigned + } + return false +} + +func (x *Column) GetIsArray() bool { + if x != nil { + return x.IsArray + } + return false +} + +func (x *Column) GetArrayDims() int32 { + if x != nil { + return x.ArrayDims + } + return 0 +} + +func (x *Column) GetComment() string { + if x != nil { + return x.Comment + } + return "" +} + +func (x *Column) GetLength() int32 { + if x != nil { + return x.Length + } + return 0 +} + +func (x *Column) GetIsNamedParam() bool { + if x != nil { + return x.IsNamedParam + } + return false +} + +func (x *Column) GetIsFuncCall() bool { + if x != nil { + return x.IsFuncCall + } + return false +} + +func (x *Column) GetScope() string { + if x != nil { + return x.Scope + } + return "" +} + +func (x *Column) GetTable() *Identifier { + if x != nil { + return x.Table + } + return nil +} + +func (x *Column) GetTableAlias() string { + if x != nil { + return x.TableAlias + } + return "" +} + +func (x *Column) GetType() *Identifier { + if x != nil { + return x.Type + } + return nil +} + +func (x *Column) GetEmbedTable() *Identifier { + if x != nil { + return x.EmbedTable + } + return nil +} + +func (x *Column) GetIsSqlcSlice() bool { + if x != nil { + return x.IsSqlcSlice + } + return false +} + +type Parameter struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Number int32 `protobuf:"varint,1,opt,name=number,proto3" json:"number,omitempty"` + Column *Column `protobuf:"bytes,2,opt,name=column,proto3" json:"column,omitempty"` +} + +func (x *Parameter) Reset() { + *x = Parameter{} + if protoimpl.UnsafeEnabled { + mi := &file_analysis_analysis_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Parameter) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Parameter) ProtoMessage() {} + +func (x *Parameter) ProtoReflect() protoreflect.Message { + mi := &file_analysis_analysis_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Parameter.ProtoReflect.Descriptor instead. +func (*Parameter) Descriptor() ([]byte, []int) { + return file_analysis_analysis_proto_rawDescGZIP(), []int{2} +} + +func (x *Parameter) GetNumber() int32 { + if x != nil { + return x.Number + } + return 0 +} + +func (x *Parameter) GetColumn() *Column { + if x != nil { + return x.Column + } + return nil +} + +type Analysis struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Columns []*Column `protobuf:"bytes,1,rep,name=columns,proto3" json:"columns,omitempty"` + Params []*Parameter `protobuf:"bytes,2,rep,name=params,proto3" json:"params,omitempty"` +} + +func (x *Analysis) Reset() { + *x = Analysis{} + if protoimpl.UnsafeEnabled { + mi := &file_analysis_analysis_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Analysis) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Analysis) ProtoMessage() {} + +func (x *Analysis) ProtoReflect() protoreflect.Message { + mi := &file_analysis_analysis_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Analysis.ProtoReflect.Descriptor instead. +func (*Analysis) Descriptor() ([]byte, []int) { + return file_analysis_analysis_proto_rawDescGZIP(), []int{3} +} + +func (x *Analysis) GetColumns() []*Column { + if x != nil { + return x.Columns + } + return nil +} + +func (x *Analysis) GetParams() []*Parameter { + if x != nil { + return x.Params + } + return nil +} + +var File_analysis_analysis_proto protoreflect.FileDescriptor + +var file_analysis_analysis_proto_rawDesc = []byte{ + 0x0a, 0x17, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x2f, 0x61, 0x6e, 0x61, 0x6c, 0x79, + 0x73, 0x69, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x61, 0x6e, 0x61, 0x6c, 0x79, + 0x73, 0x69, 0x73, 0x22, 0x52, 0x0a, 0x0a, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, + 0x72, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x73, + 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x63, 0x68, + 0x65, 0x6d, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xb1, 0x04, 0x0a, 0x06, 0x43, 0x6f, 0x6c, 0x75, + 0x6d, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, + 0x61, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6f, + 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x64, + 0x61, 0x74, 0x61, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x64, 0x61, 0x74, 0x61, 0x54, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x74, 0x5f, + 0x6e, 0x75, 0x6c, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x6e, 0x6f, 0x74, 0x4e, + 0x75, 0x6c, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x12, + 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x07, 0x69, 0x73, 0x41, 0x72, 0x72, 0x61, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x72, + 0x72, 0x61, 0x79, 0x5f, 0x64, 0x69, 0x6d, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, + 0x61, 0x72, 0x72, 0x61, 0x79, 0x44, 0x69, 0x6d, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, + 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, + 0x65, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0e, 0x69, + 0x73, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x18, 0x0a, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x64, 0x50, 0x61, 0x72, 0x61, + 0x6d, 0x12, 0x20, 0x0a, 0x0c, 0x69, 0x73, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x5f, 0x63, 0x61, 0x6c, + 0x6c, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x46, 0x75, 0x6e, 0x63, 0x43, + 0x61, 0x6c, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x0c, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x6e, 0x61, 0x6c, 0x79, + 0x73, 0x69, 0x73, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x05, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, + 0x6c, 0x69, 0x61, 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x61, 0x62, 0x6c, + 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x28, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0f, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x2e, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x12, 0x35, 0x0a, 0x0b, 0x65, 0x6d, 0x62, 0x65, 0x64, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, + 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, + 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0a, 0x65, 0x6d, 0x62, + 0x65, 0x64, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x69, 0x73, 0x5f, 0x73, 0x71, + 0x6c, 0x63, 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, + 0x69, 0x73, 0x53, 0x71, 0x6c, 0x63, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x22, 0x4d, 0x0a, 0x09, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x12, 0x28, 0x0a, 0x06, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x10, 0x2e, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x2e, 0x43, 0x6f, 0x6c, 0x75, + 0x6d, 0x6e, 0x52, 0x06, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x22, 0x63, 0x0a, 0x08, 0x41, 0x6e, + 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x12, 0x2a, 0x0a, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, + 0x69, 0x73, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, + 0x6e, 0x73, 0x12, 0x2b, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x2e, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, + 0x89, 0x01, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, + 0x42, 0x0d, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, + 0x01, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x71, + 0x6c, 0x63, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x73, 0x71, 0x6c, 0x63, 0x2f, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0xa2, 0x02, 0x03, + 0x41, 0x58, 0x58, 0xaa, 0x02, 0x08, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0xca, 0x02, + 0x08, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0xe2, 0x02, 0x14, 0x41, 0x6e, 0x61, 0x6c, + 0x79, 0x73, 0x69, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0xea, 0x02, 0x08, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, +} + +var ( + file_analysis_analysis_proto_rawDescOnce sync.Once + file_analysis_analysis_proto_rawDescData = file_analysis_analysis_proto_rawDesc +) + +func file_analysis_analysis_proto_rawDescGZIP() []byte { + file_analysis_analysis_proto_rawDescOnce.Do(func() { + file_analysis_analysis_proto_rawDescData = protoimpl.X.CompressGZIP(file_analysis_analysis_proto_rawDescData) + }) + return file_analysis_analysis_proto_rawDescData +} + +var file_analysis_analysis_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_analysis_analysis_proto_goTypes = []interface{}{ + (*Identifier)(nil), // 0: analysis.Identifier + (*Column)(nil), // 1: analysis.Column + (*Parameter)(nil), // 2: analysis.Parameter + (*Analysis)(nil), // 3: analysis.Analysis +} +var file_analysis_analysis_proto_depIdxs = []int32{ + 0, // 0: analysis.Column.table:type_name -> analysis.Identifier + 0, // 1: analysis.Column.type:type_name -> analysis.Identifier + 0, // 2: analysis.Column.embed_table:type_name -> analysis.Identifier + 1, // 3: analysis.Parameter.column:type_name -> analysis.Column + 1, // 4: analysis.Analysis.columns:type_name -> analysis.Column + 2, // 5: analysis.Analysis.params:type_name -> analysis.Parameter + 6, // [6:6] is the sub-list for method output_type + 6, // [6:6] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name +} + +func init() { file_analysis_analysis_proto_init() } +func file_analysis_analysis_proto_init() { + if File_analysis_analysis_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_analysis_analysis_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Identifier); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_analysis_analysis_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Column); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_analysis_analysis_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Parameter); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_analysis_analysis_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Analysis); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_analysis_analysis_proto_rawDesc, + NumEnums: 0, + NumMessages: 4, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_analysis_analysis_proto_goTypes, + DependencyIndexes: file_analysis_analysis_proto_depIdxs, + MessageInfos: file_analysis_analysis_proto_msgTypes, + }.Build() + File_analysis_analysis_proto = out.File + file_analysis_analysis_proto_rawDesc = nil + file_analysis_analysis_proto_goTypes = nil + file_analysis_analysis_proto_depIdxs = nil +} diff --git a/internal/analysis/analysis_vtproto.pb.go b/internal/analysis/analysis_vtproto.pb.go new file mode 100644 index 0000000..7aacb86 --- /dev/null +++ b/internal/analysis/analysis_vtproto.pb.go @@ -0,0 +1,2078 @@ +// Code generated by protoc-gen-go-vtproto. DO NOT EDIT. +// protoc-gen-go-vtproto version: v0.4.0 +// source: analysis/analysis.proto + +package analysis + +import ( + fmt "fmt" + proto "google.golang.org/protobuf/proto" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + bits "math/bits" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +func (m *Identifier) CloneVT() *Identifier { + if m == nil { + return (*Identifier)(nil) + } + r := &Identifier{ + Catalog: m.Catalog, + Schema: m.Schema, + Name: m.Name, + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *Identifier) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *Column) CloneVT() *Column { + if m == nil { + return (*Column)(nil) + } + r := &Column{ + Name: m.Name, + OriginalName: m.OriginalName, + DataType: m.DataType, + NotNull: m.NotNull, + Unsigned: m.Unsigned, + IsArray: m.IsArray, + ArrayDims: m.ArrayDims, + Comment: m.Comment, + Length: m.Length, + IsNamedParam: m.IsNamedParam, + IsFuncCall: m.IsFuncCall, + Scope: m.Scope, + Table: m.Table.CloneVT(), + TableAlias: m.TableAlias, + Type: m.Type.CloneVT(), + EmbedTable: m.EmbedTable.CloneVT(), + IsSqlcSlice: m.IsSqlcSlice, + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *Column) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *Parameter) CloneVT() *Parameter { + if m == nil { + return (*Parameter)(nil) + } + r := &Parameter{ + Number: m.Number, + Column: m.Column.CloneVT(), + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *Parameter) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *Analysis) CloneVT() *Analysis { + if m == nil { + return (*Analysis)(nil) + } + r := &Analysis{} + if rhs := m.Columns; rhs != nil { + tmpContainer := make([]*Column, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Columns = tmpContainer + } + if rhs := m.Params; rhs != nil { + tmpContainer := make([]*Parameter, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Params = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *Analysis) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (this *Identifier) EqualVT(that *Identifier) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Catalog != that.Catalog { + return false + } + if this.Schema != that.Schema { + return false + } + if this.Name != that.Name { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *Identifier) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*Identifier) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *Column) EqualVT(that *Column) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Name != that.Name { + return false + } + if this.OriginalName != that.OriginalName { + return false + } + if this.DataType != that.DataType { + return false + } + if this.NotNull != that.NotNull { + return false + } + if this.Unsigned != that.Unsigned { + return false + } + if this.IsArray != that.IsArray { + return false + } + if this.ArrayDims != that.ArrayDims { + return false + } + if this.Comment != that.Comment { + return false + } + if this.Length != that.Length { + return false + } + if this.IsNamedParam != that.IsNamedParam { + return false + } + if this.IsFuncCall != that.IsFuncCall { + return false + } + if this.Scope != that.Scope { + return false + } + if !this.Table.EqualVT(that.Table) { + return false + } + if this.TableAlias != that.TableAlias { + return false + } + if !this.Type.EqualVT(that.Type) { + return false + } + if !this.EmbedTable.EqualVT(that.EmbedTable) { + return false + } + if this.IsSqlcSlice != that.IsSqlcSlice { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *Column) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*Column) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *Parameter) EqualVT(that *Parameter) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Number != that.Number { + return false + } + if !this.Column.EqualVT(that.Column) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *Parameter) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*Parameter) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *Analysis) EqualVT(that *Analysis) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.Columns) != len(that.Columns) { + return false + } + for i, vx := range this.Columns { + vy := that.Columns[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &Column{} + } + if q == nil { + q = &Column{} + } + if !p.EqualVT(q) { + return false + } + } + } + if len(this.Params) != len(that.Params) { + return false + } + for i, vx := range this.Params { + vy := that.Params[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &Parameter{} + } + if q == nil { + q = &Parameter{} + } + if !p.EqualVT(q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *Analysis) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*Analysis) + if !ok { + return false + } + return this.EqualVT(that) +} +func (m *Identifier) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Identifier) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *Identifier) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarint(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x1a + } + if len(m.Schema) > 0 { + i -= len(m.Schema) + copy(dAtA[i:], m.Schema) + i = encodeVarint(dAtA, i, uint64(len(m.Schema))) + i-- + dAtA[i] = 0x12 + } + if len(m.Catalog) > 0 { + i -= len(m.Catalog) + copy(dAtA[i:], m.Catalog) + i = encodeVarint(dAtA, i, uint64(len(m.Catalog))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Column) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Column) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *Column) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.IsSqlcSlice { + i-- + if m.IsSqlcSlice { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x88 + } + if m.EmbedTable != nil { + size, err := m.EmbedTable.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x82 + } + if m.Type != nil { + size, err := m.Type.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x7a + } + if len(m.TableAlias) > 0 { + i -= len(m.TableAlias) + copy(dAtA[i:], m.TableAlias) + i = encodeVarint(dAtA, i, uint64(len(m.TableAlias))) + i-- + dAtA[i] = 0x72 + } + if m.Table != nil { + size, err := m.Table.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x6a + } + if len(m.Scope) > 0 { + i -= len(m.Scope) + copy(dAtA[i:], m.Scope) + i = encodeVarint(dAtA, i, uint64(len(m.Scope))) + i-- + dAtA[i] = 0x62 + } + if m.IsFuncCall { + i-- + if m.IsFuncCall { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x58 + } + if m.IsNamedParam { + i-- + if m.IsNamedParam { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x50 + } + if m.Length != 0 { + i = encodeVarint(dAtA, i, uint64(m.Length)) + i-- + dAtA[i] = 0x48 + } + if len(m.Comment) > 0 { + i -= len(m.Comment) + copy(dAtA[i:], m.Comment) + i = encodeVarint(dAtA, i, uint64(len(m.Comment))) + i-- + dAtA[i] = 0x42 + } + if m.ArrayDims != 0 { + i = encodeVarint(dAtA, i, uint64(m.ArrayDims)) + i-- + dAtA[i] = 0x38 + } + if m.IsArray { + i-- + if m.IsArray { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x30 + } + if m.Unsigned { + i-- + if m.Unsigned { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x28 + } + if m.NotNull { + i-- + if m.NotNull { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x20 + } + if len(m.DataType) > 0 { + i -= len(m.DataType) + copy(dAtA[i:], m.DataType) + i = encodeVarint(dAtA, i, uint64(len(m.DataType))) + i-- + dAtA[i] = 0x1a + } + if len(m.OriginalName) > 0 { + i -= len(m.OriginalName) + copy(dAtA[i:], m.OriginalName) + i = encodeVarint(dAtA, i, uint64(len(m.OriginalName))) + i-- + dAtA[i] = 0x12 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarint(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Parameter) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Parameter) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *Parameter) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Column != nil { + size, err := m.Column.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + if m.Number != 0 { + i = encodeVarint(dAtA, i, uint64(m.Number)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Analysis) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Analysis) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *Analysis) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Params) > 0 { + for iNdEx := len(m.Params) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Params[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + } + if len(m.Columns) > 0 { + for iNdEx := len(m.Columns) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Columns[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarint(dAtA []byte, offset int, v uint64) int { + offset -= sov(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Identifier) MarshalVTStrict() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVTStrict(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Identifier) MarshalToVTStrict(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVTStrict(dAtA[:size]) +} + +func (m *Identifier) MarshalToSizedBufferVTStrict(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarint(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x1a + } + if len(m.Schema) > 0 { + i -= len(m.Schema) + copy(dAtA[i:], m.Schema) + i = encodeVarint(dAtA, i, uint64(len(m.Schema))) + i-- + dAtA[i] = 0x12 + } + if len(m.Catalog) > 0 { + i -= len(m.Catalog) + copy(dAtA[i:], m.Catalog) + i = encodeVarint(dAtA, i, uint64(len(m.Catalog))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Column) MarshalVTStrict() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVTStrict(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Column) MarshalToVTStrict(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVTStrict(dAtA[:size]) +} + +func (m *Column) MarshalToSizedBufferVTStrict(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.IsSqlcSlice { + i-- + if m.IsSqlcSlice { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x88 + } + if m.EmbedTable != nil { + size, err := m.EmbedTable.MarshalToSizedBufferVTStrict(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x82 + } + if m.Type != nil { + size, err := m.Type.MarshalToSizedBufferVTStrict(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x7a + } + if len(m.TableAlias) > 0 { + i -= len(m.TableAlias) + copy(dAtA[i:], m.TableAlias) + i = encodeVarint(dAtA, i, uint64(len(m.TableAlias))) + i-- + dAtA[i] = 0x72 + } + if m.Table != nil { + size, err := m.Table.MarshalToSizedBufferVTStrict(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x6a + } + if len(m.Scope) > 0 { + i -= len(m.Scope) + copy(dAtA[i:], m.Scope) + i = encodeVarint(dAtA, i, uint64(len(m.Scope))) + i-- + dAtA[i] = 0x62 + } + if m.IsFuncCall { + i-- + if m.IsFuncCall { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x58 + } + if m.IsNamedParam { + i-- + if m.IsNamedParam { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x50 + } + if m.Length != 0 { + i = encodeVarint(dAtA, i, uint64(m.Length)) + i-- + dAtA[i] = 0x48 + } + if len(m.Comment) > 0 { + i -= len(m.Comment) + copy(dAtA[i:], m.Comment) + i = encodeVarint(dAtA, i, uint64(len(m.Comment))) + i-- + dAtA[i] = 0x42 + } + if m.ArrayDims != 0 { + i = encodeVarint(dAtA, i, uint64(m.ArrayDims)) + i-- + dAtA[i] = 0x38 + } + if m.IsArray { + i-- + if m.IsArray { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x30 + } + if m.Unsigned { + i-- + if m.Unsigned { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x28 + } + if m.NotNull { + i-- + if m.NotNull { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x20 + } + if len(m.DataType) > 0 { + i -= len(m.DataType) + copy(dAtA[i:], m.DataType) + i = encodeVarint(dAtA, i, uint64(len(m.DataType))) + i-- + dAtA[i] = 0x1a + } + if len(m.OriginalName) > 0 { + i -= len(m.OriginalName) + copy(dAtA[i:], m.OriginalName) + i = encodeVarint(dAtA, i, uint64(len(m.OriginalName))) + i-- + dAtA[i] = 0x12 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarint(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Parameter) MarshalVTStrict() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVTStrict(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Parameter) MarshalToVTStrict(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVTStrict(dAtA[:size]) +} + +func (m *Parameter) MarshalToSizedBufferVTStrict(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Column != nil { + size, err := m.Column.MarshalToSizedBufferVTStrict(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + if m.Number != 0 { + i = encodeVarint(dAtA, i, uint64(m.Number)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Analysis) MarshalVTStrict() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVTStrict(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Analysis) MarshalToVTStrict(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVTStrict(dAtA[:size]) +} + +func (m *Analysis) MarshalToSizedBufferVTStrict(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Params) > 0 { + for iNdEx := len(m.Params) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Params[iNdEx].MarshalToSizedBufferVTStrict(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + } + if len(m.Columns) > 0 { + for iNdEx := len(m.Columns) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Columns[iNdEx].MarshalToSizedBufferVTStrict(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *Identifier) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Catalog) + if l > 0 { + n += 1 + l + sov(uint64(l)) + } + l = len(m.Schema) + if l > 0 { + n += 1 + l + sov(uint64(l)) + } + l = len(m.Name) + if l > 0 { + n += 1 + l + sov(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *Column) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + sov(uint64(l)) + } + l = len(m.OriginalName) + if l > 0 { + n += 1 + l + sov(uint64(l)) + } + l = len(m.DataType) + if l > 0 { + n += 1 + l + sov(uint64(l)) + } + if m.NotNull { + n += 2 + } + if m.Unsigned { + n += 2 + } + if m.IsArray { + n += 2 + } + if m.ArrayDims != 0 { + n += 1 + sov(uint64(m.ArrayDims)) + } + l = len(m.Comment) + if l > 0 { + n += 1 + l + sov(uint64(l)) + } + if m.Length != 0 { + n += 1 + sov(uint64(m.Length)) + } + if m.IsNamedParam { + n += 2 + } + if m.IsFuncCall { + n += 2 + } + l = len(m.Scope) + if l > 0 { + n += 1 + l + sov(uint64(l)) + } + if m.Table != nil { + l = m.Table.SizeVT() + n += 1 + l + sov(uint64(l)) + } + l = len(m.TableAlias) + if l > 0 { + n += 1 + l + sov(uint64(l)) + } + if m.Type != nil { + l = m.Type.SizeVT() + n += 1 + l + sov(uint64(l)) + } + if m.EmbedTable != nil { + l = m.EmbedTable.SizeVT() + n += 2 + l + sov(uint64(l)) + } + if m.IsSqlcSlice { + n += 3 + } + n += len(m.unknownFields) + return n +} + +func (m *Parameter) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Number != 0 { + n += 1 + sov(uint64(m.Number)) + } + if m.Column != nil { + l = m.Column.SizeVT() + n += 1 + l + sov(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *Analysis) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Columns) > 0 { + for _, e := range m.Columns { + l = e.SizeVT() + n += 1 + l + sov(uint64(l)) + } + } + if len(m.Params) > 0 { + for _, e := range m.Params { + l = e.SizeVT() + n += 1 + l + sov(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func sov(x uint64) (n int) { + return (bits.Len64(x|1) + 6) / 7 +} +func soz(x uint64) (n int) { + return sov(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Identifier) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Identifier: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Identifier: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Catalog", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Catalog = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Schema", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Schema = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Column) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Column: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Column: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OriginalName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OriginalName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DataType", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DataType = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NotNull", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.NotNull = bool(v != 0) + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Unsigned", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Unsigned = bool(v != 0) + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IsArray", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IsArray = bool(v != 0) + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ArrayDims", wireType) + } + m.ArrayDims = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ArrayDims |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Comment", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Comment = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Length", wireType) + } + m.Length = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Length |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IsNamedParam", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IsNamedParam = bool(v != 0) + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IsFuncCall", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IsFuncCall = bool(v != 0) + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Scope", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Scope = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 13: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Table", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Table == nil { + m.Table = &Identifier{} + } + if err := m.Table.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 14: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TableAlias", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TableAlias = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 15: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Type == nil { + m.Type = &Identifier{} + } + if err := m.Type.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 16: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EmbedTable", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.EmbedTable == nil { + m.EmbedTable = &Identifier{} + } + if err := m.EmbedTable.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 17: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IsSqlcSlice", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IsSqlcSlice = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Parameter) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Parameter: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Parameter: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Number", wireType) + } + m.Number = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Number |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Column", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Column == nil { + m.Column = &Column{} + } + if err := m.Column.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Analysis) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Analysis: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Analysis: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Columns", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Columns = append(m.Columns, &Column{}) + if err := m.Columns[len(m.Columns)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Params = append(m.Params, &Parameter{}) + if err := m.Params[len(m.Params)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} + +func skip(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflow + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflow + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflow + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLength + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroup + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLength + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLength = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflow = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroup = fmt.Errorf("proto: unexpected end of group") +) diff --git a/internal/analyzer/analyzer.go b/internal/analyzer/analyzer.go new file mode 100644 index 0000000..81094ef --- /dev/null +++ b/internal/analyzer/analyzer.go @@ -0,0 +1,131 @@ +package analyzer + +import ( + "context" + "encoding/json" + "errors" + "log/slog" + + "google.golang.org/protobuf/proto" + + "github.com/sqlc-dev/sqlc/internal/analysis" + "github.com/sqlc-dev/sqlc/internal/cache" + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/named" +) + +type CachedAnalyzer struct { + a Analyzer + config config.Config + configBytes []byte + db config.Database + store *cache.Cache +} + +func Cached(a Analyzer, c config.Config, db config.Database) *CachedAnalyzer { + return &CachedAnalyzer{ + a: a, + config: c, + db: db, + } +} + +// Create a new error here + +func (c *CachedAnalyzer) Analyze(ctx context.Context, n ast.Node, q string, schema []string, np *named.ParamSet) (*analysis.Analysis, error) { + result, rerun, err := c.analyze(ctx, n, q, schema, np) + if rerun { + if err != nil { + slog.Warn("first analysis failed with error", "err", err) + } + return c.a.Analyze(ctx, n, q, schema, np) + } + return result, err +} + +// The name of the sole output blob a QueryAnalysis action produces. +const analysisOutput = "analysis.pb" + +func (c *CachedAnalyzer) analyze(ctx context.Context, n ast.Node, q string, schema []string, np *named.ParamSet) (*analysis.Analysis, bool, error) { + // Only cache queries for managed databases. We can't be certain the + // database is in an unchanged state otherwise + if !c.db.Managed { + return nil, true, nil + } + + if c.store == nil { + var err error + c.store, err = cache.Open() + if err != nil { + return nil, true, err + } + } + store := c.store + + if c.configBytes == nil { + var err error + c.configBytes, err = json.Marshal(c.config) + if err != nil { + return nil, true, err + } + } + + // Analyzing a query is an action whose inputs are the configuration, the + // schema migrations, and the query itself. (The sqlc binary is an + // implicit input of every action.) + action := store.NewAction("QueryAnalysis"). + AddInput("config", c.configBytes) + for _, m := range schema { + action.AddInput("schema", []byte(m)) + } + actionDigest := action.AddInput("query", []byte(q)).Digest() + + if cached, err := store.Actions.Get(actionDigest); err == nil { + contents, err := store.CAS.Get(cached.Outputs[analysisOutput]) + if err == nil { + var a analysis.Analysis + if err := proto.Unmarshal(contents, &a); err == nil { + return &a, false, nil + } + } + if !errors.Is(err, cache.ErrNotFound) { + slog.Warn("reading analysis from cache failed", "err", err) + } + } + + result, err := c.a.Analyze(ctx, n, q, schema, np) + + if err == nil { + contents, err := proto.Marshal(result) + if err != nil { + slog.Warn("unable to marshal analysis", "err", err) + return result, false, nil + } + outDigest, err := store.CAS.Put(contents) + if err != nil { + slog.Warn("saving analysis to cache failed", "err", err) + return result, false, nil + } + err = store.Actions.Put(actionDigest, &cache.ActionResult{ + Outputs: map[string]cache.Digest{analysisOutput: outDigest}, + }) + if err != nil { + slog.Warn("saving analysis action result failed", "err", err) + } + } + + return result, false, err +} + +func (c *CachedAnalyzer) Close(ctx context.Context) error { + if c.store != nil { + c.store.Close() + } + return c.a.Close(ctx) +} + +type Analyzer interface { + Analyze(context.Context, ast.Node, string, []string, *named.ParamSet) (*analysis.Analysis, error) + Close(context.Context) error +} diff --git a/internal/bundler/multipart.go b/internal/bundler/multipart.go new file mode 100644 index 0000000..b1d1925 --- /dev/null +++ b/internal/bundler/multipart.go @@ -0,0 +1,40 @@ +package bundler + +import ( + "os" + "path/filepath" + + pb "github.com/sqlc-dev/sqlc/internal/quickdb/v1" + "github.com/sqlc-dev/sqlc/internal/sql/sqlpath" +) + +func readFiles(dir string, paths []string) ([]*pb.File, error) { + files, err := sqlpath.Glob(paths) + if err != nil { + return nil, err + } + var out []*pb.File + for _, file := range files { + f, err := readFile(dir, file) + if err != nil { + return nil, err + } + out = append(out, f) + } + return out, nil +} + +func readFile(dir string, path string) (*pb.File, error) { + rel, err := filepath.Rel(dir, path) + if err != nil { + return nil, err + } + blob, err := os.ReadFile(path) + if err != nil { + return nil, err + } + return &pb.File{ + Name: rel, + Contents: blob, + }, nil +} diff --git a/internal/bundler/upload.go b/internal/bundler/upload.go new file mode 100644 index 0000000..49e3b44 --- /dev/null +++ b/internal/bundler/upload.go @@ -0,0 +1,164 @@ +package bundler + +import ( + "context" + "errors" + "fmt" + "log/slog" + "os" + "strings" + + "google.golang.org/protobuf/proto" + + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/info" + "github.com/sqlc-dev/sqlc/internal/plugin" + "github.com/sqlc-dev/sqlc/internal/quickdb" + pb "github.com/sqlc-dev/sqlc/internal/quickdb/v1" +) + +var ErrNoProject = errors.New(`project uploads require a cloud project + +If you don't have a project, you can create one from the sqlc Cloud +dashboard at https://dashboard.sqlc.dev/. If you have a project, ensure +you've set its id as the value of the "project" field within the "cloud" +section of your sqlc configuration. The id will look similar to +"01HA8TWGMYPHK0V2GGMB3R2TP9".`) +var ErrNoAuthToken = errors.New(`project uploads require an auth token + +If you don't have an auth token, you can create one from the sqlc Cloud +dashboard at https://dashboard.sqlc.dev/. If you have an auth token, ensure +you've set it as the value of the SQLC_AUTH_TOKEN environment variable.`) + +type Uploader struct { + configPath string + config *config.Config + dir string + client pb.QuickClient +} + +type QuerySetArchive struct { + Name string + Queries []string + Schema []string + Request *plugin.GenerateRequest +} + +func NewUploader(configPath, dir string, conf *config.Config) *Uploader { + return &Uploader{ + configPath: configPath, + config: conf, + dir: dir, + } +} + +func (up *Uploader) Validate() error { + if up.config.Cloud.Project == "" { + return ErrNoProject + } + if up.config.Cloud.AuthToken == "" { + return ErrNoAuthToken + } + if up.client == nil { + client, err := quickdb.NewClientFromConfig(up.config.Cloud) + if err != nil { + return fmt.Errorf("client init failed: %w", err) + } + up.client = client + } + return nil +} + +var envvars = []string{ + "GITHUB_REPOSITORY", + "GITHUB_REF", + "GITHUB_REF_NAME", + "GITHUB_REF_TYPE", + "GITHUB_SHA", +} + +func annotate() map[string]string { + labels := map[string]string{} + for _, ev := range envvars { + key := strings.ReplaceAll(strings.ToLower(ev), "_", ".") + labels[key] = os.Getenv(ev) + } + return labels +} + +func BuildRequest(ctx context.Context, dir, configPath string, results []*QuerySetArchive, tags []string) (*pb.UploadArchiveRequest, error) { + conf, err := readFile(dir, configPath) + if err != nil { + return nil, err + } + res := &pb.UploadArchiveRequest{ + SqlcVersion: info.Version, + Config: conf, + Tags: tags, + Annotations: annotate(), + } + for i, result := range results { + schema, err := readFiles(dir, result.Schema) + if err != nil { + return nil, err + } + queries, err := readFiles(dir, result.Queries) + if err != nil { + return nil, err + } + name := result.Name + if name == "" { + name = fmt.Sprintf("queryset_%d", i) + } + genreq, err := proto.Marshal(result.Request) + if err != nil { + return nil, err + } + res.QuerySets = append(res.QuerySets, &pb.QuerySet{ + Name: name, + Schema: schema, + Queries: queries, + CodegenRequest: &pb.File{ + Name: "codegen_request.pb", + Contents: genreq, + }, + }) + } + return res, nil +} + +func (up *Uploader) buildRequest(ctx context.Context, results []*QuerySetArchive, tags []string) (*pb.UploadArchiveRequest, error) { + return BuildRequest(ctx, up.dir, up.configPath, results, tags) +} + +func (up *Uploader) DumpRequestOut(ctx context.Context, result []*QuerySetArchive) error { + req, err := up.buildRequest(ctx, result, []string{}) + if err != nil { + return err + } + slog.Info("config", "file", req.Config.Name, "bytes", len(req.Config.Contents)) + for _, qs := range req.QuerySets { + slog.Info("codegen_request", "queryset", qs.Name, "file", "codegen_request.pb") + for _, file := range qs.Schema { + slog.Info("schema", "queryset", qs.Name, "file", file.Name, "bytes", len(file.Contents)) + } + for _, file := range qs.Queries { + slog.Info("query", "queryset", qs.Name, "file", file.Name, "bytes", len(file.Contents)) + } + } + return nil +} + +func (up *Uploader) Upload(ctx context.Context, result []*QuerySetArchive, tags []string) error { + if err := up.Validate(); err != nil { + return err + } + req, err := up.buildRequest(ctx, result, tags) + if err != nil { + return err + } + if _, err := up.client.UploadArchive(ctx, req); err != nil { + return fmt.Errorf("upload error: %w", err) + } + return nil +} diff --git a/internal/cache/action.go b/internal/cache/action.go new file mode 100644 index 0000000..16f4df9 --- /dev/null +++ b/internal/cache/action.go @@ -0,0 +1,209 @@ +package cache + +import ( + "encoding/json" + "errors" + "fmt" + "io/fs" + "os" + "path/filepath" +) + +// ActionResult records the outputs of a completed action, mirroring Bazel's +// ActionResult message. Outputs are not stored inline: each named output is a +// digest pointing into the CAS. +type ActionResult struct { + // Outputs maps an output name (e.g. "analysis.pb", "plugin.wasm") to the + // CAS digest of its contents. + Outputs map[string]Digest `json:"outputs"` +} + +// ActionCache maps action digests to ActionResults, stored as JSON files at +// ac// under the cache root. Unlike CAS entries, action cache +// entries are not self-validating — the value is not derivable from the key — +// so Get additionally checks that every referenced output still exists in the +// CAS before reporting a hit, exactly like Bazel's disk cache does. +// +// Entry I/O goes through the same os.Root as the CAS, confining every read +// and write to the cache directory. +type ActionCache struct { + root *os.Root + cas *CAS +} + +func newActionCache(root *os.Root, cas *CAS) *ActionCache { + return &ActionCache{root: root, cas: cas} +} + +// path returns an entry's path relative to the cache root. +func (a *ActionCache) path(d Digest) string { + return filepath.Join("ac", d.Hash[:2], d.Hash) +} + +// Get returns the cached result for an action, or ErrNotFound on a miss. An +// entry whose outputs are missing or corrupt in the CAS is treated as a miss +// and evicted. +func (a *ActionCache) Get(action Digest) (*ActionResult, error) { + if !action.valid() { + return nil, ErrNotFound + } + path := a.path(action) + data, err := a.root.ReadFile(path) + if err != nil { + if errors.Is(err, fs.ErrNotExist) { + return nil, ErrNotFound + } + return nil, fmt.Errorf("cache: %w", err) + } + var result ActionResult + if err := json.Unmarshal(data, &result); err != nil { + a.root.Remove(path) + return nil, ErrNotFound + } + for _, d := range result.Outputs { + if !a.cas.Contains(d) { + a.root.Remove(path) + return nil, ErrNotFound + } + } + return &result, nil +} + +// PutTree stores every file under dir in the CAS and records them as the +// action's outputs, named by their paths relative to dir. Use this for +// actions whose tool writes an output directory, like WASM compilation. +func (a *ActionCache) PutTree(action Digest, dir string) error { + outputs := map[string]Digest{} + err := filepath.WalkDir(dir, func(path string, entry fs.DirEntry, err error) error { + if err != nil || entry.IsDir() { + return err + } + rel, err := filepath.Rel(dir, path) + if err != nil { + return err + } + data, err := os.ReadFile(path) + if err != nil { + return err + } + d, err := a.cas.Put(data) + if err != nil { + return err + } + outputs[filepath.ToSlash(rel)] = d + return nil + }) + if err != nil { + return fmt.Errorf("cache: %w", err) + } + if len(outputs) == 0 { + return fmt.Errorf("cache: no outputs found under %s", dir) + } + return a.Put(action, &ActionResult{Outputs: outputs}) +} + +// GetTree materializes a cached action's outputs as files under dir, or +// returns ErrNotFound on a miss. A file already present is reused only if its +// contents still hash to the expected digest; otherwise it is rewritten from +// the CAS. Writes are staged, fsynced, and renamed, so a crash cannot leave a +// right-sized but torn file that later reads would trust. +func (a *ActionCache) GetTree(action Digest, dir string) error { + result, err := a.Get(action) + if err != nil { + return err + } + for rel, d := range result.Outputs { + // Output names come from the action cache entry, which — unlike a CAS + // blob — is not self-validating, so a tampered entry could carry a + // name like "../../etc/x". Reject anything that isn't a relative path + // confined to dir; this is the confinement the os.Root gives the rest + // of the cache, which GetTree can't use because dir is a caller-owned + // path a tool must read by absolute name. + if !filepath.IsLocal(rel) { + return fmt.Errorf("cache: unsafe output path %q in action %s", rel, action) + } + path := filepath.Join(dir, filepath.FromSlash(rel)) + // Trust an existing file only if it still hashes to the digest; + // size alone can mask in-place corruption that would make the + // consuming tool hard-fail with no way to repair (see wazero). + if existing, err := os.ReadFile(path); err == nil && DigestOf(existing) == d { + continue + } + data, err := a.cas.Get(d) + if err != nil { + return err + } + if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { + return fmt.Errorf("cache: %w", err) + } + if err := writeFileAtomic(path, data); err != nil { + return fmt.Errorf("cache: %w", err) + } + } + return nil +} + +// writeFileAtomic writes data to path via a staged temp file in the same +// directory, fsynced before an atomic rename, so a reader never observes a +// partial or torn file even across a crash. +func writeFileAtomic(path string, data []byte) error { + f, err := os.CreateTemp(filepath.Dir(path), "."+filepath.Base(path)+"-*") + if err != nil { + return err + } + tmp := f.Name() + if _, err := f.Write(data); err != nil { + f.Close() + os.Remove(tmp) + return err + } + if err := f.Sync(); err != nil { + f.Close() + os.Remove(tmp) + return err + } + if err := f.Close(); err != nil { + os.Remove(tmp) + return err + } + if err := os.Rename(tmp, path); err != nil { + os.Remove(tmp) + return err + } + return nil +} + +// Put records the result of an action. All outputs must already be in the +// CAS; writes are staged and renamed so concurrent processes never observe a +// partial entry. +func (a *ActionCache) Put(action Digest, result *ActionResult) error { + for name, d := range result.Outputs { + if !a.cas.Contains(d) { + return fmt.Errorf("cache: output %q (%s) missing from CAS", name, d) + } + } + data, err := json.Marshal(result) + if err != nil { + return fmt.Errorf("cache: %w", err) + } + path := a.path(action) + if err := a.root.MkdirAll(filepath.Dir(path), 0755); err != nil { + return fmt.Errorf("cache: %w", err) + } + f, name, err := a.cas.createTemp(action.Hash[:8] + "-") + if err != nil { + return fmt.Errorf("cache: %w", err) + } + defer a.root.Remove(name) + if _, err := f.Write(data); err != nil { + f.Close() + return fmt.Errorf("cache: %w", err) + } + if err := f.Close(); err != nil { + return fmt.Errorf("cache: %w", err) + } + if err := a.root.Rename(name, path); err != nil { + return fmt.Errorf("cache: %w", err) + } + return nil +} diff --git a/internal/cache/cache.go b/internal/cache/cache.go new file mode 100644 index 0000000..f0528ad --- /dev/null +++ b/internal/cache/cache.go @@ -0,0 +1,103 @@ +// Package cache implements sqlc's on-disk cache, designed after Bazel's +// local disk cache. +// +// It has two halves: +// +// - A content-addressable store (CAS) holding blobs keyed by the SHA-256 +// hash of their contents, laid out as cas//. +// - An action cache (AC) mapping the digest of an action — a description of +// cacheable work and all of its inputs — to the digests of the outputs +// that work produced, laid out as ac//. +// +// Work whose output is not derivable from its inputs, like query analysis, +// uses both halves, just like Bazel: hash the action, look its digest up in +// the action cache, then fetch the referenced output blobs from the CAS. +// +// Remote fetches with a declared checksum, like WASM plugins, need no action +// cache entry at all: the declared sha256 is itself a content address, so the +// blob is stored and loaded directly from the CAS keyed by that checksum. +package cache + +import ( + "fmt" + "os" + "path/filepath" +) + +// Cache bundles the CAS and the action cache that shares it. All storage +// I/O is confined to the cache directory through an os.Root; callers should +// Close the cache when finished with it to release the root. +type Cache struct { + root *os.Root + CAS *CAS + Actions *ActionCache +} + +// Dir returns the cache root, defaulting to os.UserCacheDir(). The location +// can be overridden with the SQLCCACHE environment variable. +func Dir() (string, error) { + cache := os.Getenv("SQLCCACHE") + if cache != "" { + return cache, nil + } + cacheHome, err := os.UserCacheDir() + if err != nil { + return "", err + } + return filepath.Join(cacheHome, "sqlc"), nil +} + +// Open returns the cache rooted at Dir(). +func Open() (*Cache, error) { + root, err := Dir() + if err != nil { + return nil, err + } + return OpenAt(root) +} + +// OpenAt returns the cache rooted at the given directory, creating it if +// necessary. +func OpenAt(dir string) (*Cache, error) { + if err := os.MkdirAll(dir, 0755); err != nil { + return nil, fmt.Errorf("failed to create %s directory: %w", dir, err) + } + root, err := os.OpenRoot(dir) + if err != nil { + return nil, fmt.Errorf("cache: %w", err) + } + cas, err := newCAS(root) + if err != nil { + root.Close() + return nil, err + } + return &Cache{ + root: root, + CAS: cas, + Actions: newActionCache(root, cas), + }, nil +} + +// Close releases the cache's handle on its root directory. +func (c *Cache) Close() error { + return c.root.Close() +} + +// ExecDir creates a fresh, private scratch directory for materializing the +// output tree of the given action, for tools that need their outputs on disk +// (like wazero's compilation cache). Each call returns a new directory under +// exec/, so two concurrent processes never share one — otherwise a tool +// staging files there (wazero writes .tmp files in place) could be swept +// into the other's PutTree. The caller must remove it when done; its contents +// are always reproducible from the CAS, so losing it is harmless. +func (c *Cache) ExecDir(action Digest) (string, error) { + base := filepath.Join(c.root.Name(), "exec") + if err := os.MkdirAll(base, 0755); err != nil { + return "", fmt.Errorf("failed to create %s directory: %w", base, err) + } + dir, err := os.MkdirTemp(base, action.Hash+"-") + if err != nil { + return "", fmt.Errorf("cache: %w", err) + } + return dir, nil +} diff --git a/internal/cache/cas.go b/internal/cache/cas.go new file mode 100644 index 0000000..baf959d --- /dev/null +++ b/internal/cache/cas.go @@ -0,0 +1,138 @@ +package cache + +import ( + "errors" + "fmt" + "io/fs" + "math/rand/v2" + "os" + "path/filepath" + "strconv" +) + +// ErrNotFound is returned when a blob or action result is not in the cache. +var ErrNotFound = errors.New("cache: not found") + +// CAS is an on-disk content-addressable store keyed by SHA-256, modeled on +// Bazel's disk cache. Blobs live at cas// under the cache root, +// where is the first two hex characters of the hash. Because a blob's +// name is derived from its contents, entries never change once written: +// writers race benignly and readers can detect corruption by re-hashing. +// +// Content with an externally declared checksum (remotely fetched plugins) +// needs no action cache entry: the declared sha256 is the address, so it is +// stored and loaded directly — see SHA256Digest. +// +// All I/O goes through an os.Root, so no entry name — hash-derived or read +// from an action cache entry — can escape the cache directory. +type CAS struct { + root *os.Root +} + +func newCAS(root *os.Root) (*CAS, error) { + if err := root.MkdirAll("tmp", 0755); err != nil { + return nil, fmt.Errorf("cache: create tmp: %w", err) + } + return &CAS{root: root}, nil +} + +// path returns a blob's path relative to the cache root. +func (c *CAS) path(d Digest) string { + return filepath.Join("cas", d.Hash[:2], d.Hash) +} + +// Filename returns the path of a stored blob, for a consumer that needs the +// file rather than its bytes — SQLite, for one, opens a database by name. A +// blob is named after the hash of its contents, so the file at this path never +// changes and any number of processes may read it at once. +// +// It reports false when the blob is not stored. +func (c *CAS) Filename(d Digest) (string, bool) { + if !c.Contains(d) { + return "", false + } + return filepath.Join(c.root.Name(), c.path(d)), true +} + +// createTemp creates a staging file under tmp/ in the cache root, returning +// the open file and its root-relative name. +func (c *CAS) createTemp(prefix string) (*os.File, string, error) { + for range 10000 { + name := filepath.Join("tmp", prefix+strconv.FormatUint(rand.Uint64(), 36)) + f, err := c.root.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0644) + if errors.Is(err, fs.ErrExist) { + continue + } + return f, name, err + } + return nil, "", errors.New("cache: could not create temp file") +} + +// Put stores a blob and returns its digest. Writing is atomic: the blob is +// staged in a temp file and renamed into place, so concurrent sqlc processes +// never observe partial entries. +func (c *CAS) Put(data []byte) (Digest, error) { + d := DigestOf(data) + path := c.path(d) + // Skip the write only when an entry of the right size already exists; a + // wrong-sized entry is corrupt and is atomically replaced by the rename + // below. + if fi, err := c.root.Stat(path); err == nil && fi.Size() == d.SizeBytes { + return d, nil + } + if err := c.root.MkdirAll(filepath.Dir(path), 0755); err != nil { + return Digest{}, fmt.Errorf("cache: %w", err) + } + f, name, err := c.createTemp(d.Hash[:8] + "-") + if err != nil { + return Digest{}, fmt.Errorf("cache: %w", err) + } + defer c.root.Remove(name) + if _, err := f.Write(data); err != nil { + f.Close() + return Digest{}, fmt.Errorf("cache: %w", err) + } + if err := f.Close(); err != nil { + return Digest{}, fmt.Errorf("cache: %w", err) + } + if err := c.root.Rename(name, path); err != nil { + return Digest{}, fmt.Errorf("cache: %w", err) + } + return d, nil +} + +// Get returns the blob for a digest. Contents are re-hashed before being +// returned; a corrupt entry is evicted and reported as ErrNotFound so +// callers simply redo the work that produced it. +func (c *CAS) Get(d Digest) ([]byte, error) { + if !d.valid() { + return nil, ErrNotFound + } + path := c.path(d) + data, err := c.root.ReadFile(path) + if err != nil { + if errors.Is(err, fs.ErrNotExist) { + return nil, ErrNotFound + } + return nil, fmt.Errorf("cache: %w", err) + } + if DigestOf(data).Hash != d.Hash { + c.root.Remove(path) + return nil, ErrNotFound + } + return data, nil +} + +// Contains reports whether a blob with the given digest is present, checking +// size when the digest carries one. It does not verify contents; Get performs +// full verification. +func (c *CAS) Contains(d Digest) bool { + if !d.valid() { + return false + } + fi, err := c.root.Stat(c.path(d)) + if err != nil { + return false + } + return d.SizeBytes < 0 || fi.Size() == d.SizeBytes +} diff --git a/internal/cache/digest.go b/internal/cache/digest.go new file mode 100644 index 0000000..4909d46 --- /dev/null +++ b/internal/cache/digest.go @@ -0,0 +1,100 @@ +package cache + +import ( + "crypto/sha256" + "encoding/binary" + "encoding/hex" + "fmt" + "hash" +) + +// Digest identifies a blob by its SHA-256 hash and size, mirroring the +// Digest message from Bazel's remote execution API. The size is stored +// alongside the hash so that entries can be validated without reading blob +// contents; a negative size means the size is unknown, as with a checksum +// declared in a configuration file. +type Digest struct { + // Hash is the lowercase hex-encoded SHA-256 hash of the blob. + Hash string `json:"hash"` + // SizeBytes is the length of the blob in bytes, or negative if unknown. + SizeBytes int64 `json:"size_bytes"` +} + +func (d Digest) String() string { + return fmt.Sprintf("sha256:%s/%d", d.Hash, d.SizeBytes) +} + +func (d Digest) valid() bool { + if len(d.Hash) != 64 { + return false + } + _, err := hex.DecodeString(d.Hash) + return err == nil +} + +// DigestOf returns the Digest of a blob. +func DigestOf(data []byte) Digest { + sum := sha256.Sum256(data) + return Digest{ + Hash: hex.EncodeToString(sum[:]), + SizeBytes: int64(len(data)), + } +} + +// SHA256Digest returns a Digest referencing a blob by a declared SHA-256 +// checksum whose size is not known, suitable for looking up remotely fetched +// content in the CAS. +func SHA256Digest(hexhash string) Digest { + return Digest{ + Hash: hexhash, + SizeBytes: -1, + } +} + +// An Action describes a unit of cacheable work, playing the role of Bazel's +// Action message: a mnemonic naming the kind of work plus the complete set of +// inputs that determine its outputs. Two actions with the same digest are +// assumed to produce the same outputs. +// +// Inputs are hashed incrementally with length-prefixed framing so that the +// boundary between inputs is unambiguous ("ab"+"c" hashes differently from +// "a"+"bc"). +type Action struct { + hasher hash.Hash +} + +// NewAction starts building an action key for the given mnemonic, e.g. +// "QueryAnalysis". The sha256 of the sqlc binary itself is always the first +// input: the tool that executes an action determines its outputs just as +// much as the declared inputs do, so a rebuilt sqlc never reuses stale +// entries. The binary's digest is memoized in the cache — see toolDigest — +// which is why actions are created through a Cache. +func (c *Cache) NewAction(mnemonic string) *Action { + a := &Action{hasher: sha256.New()} + a.write([]byte(mnemonic)) + a.AddInput("tool", c.toolDigest()) + return a +} + +// AddInput mixes a named input into the action key. Order matters: callers +// must add inputs in a deterministic order. +func (a *Action) AddInput(name string, data []byte) *Action { + a.write([]byte(name)) + a.write(data) + return a +} + +// Digest returns the action's digest, used as the action cache key. +func (a *Action) Digest() Digest { + return Digest{ + Hash: hex.EncodeToString(a.hasher.Sum(nil)), + SizeBytes: 0, + } +} + +func (a *Action) write(data []byte) { + var frame [8]byte + binary.LittleEndian.PutUint64(frame[:], uint64(len(data))) + a.hasher.Write(frame[:]) + a.hasher.Write(data) +} diff --git a/internal/cache/tool.go b/internal/cache/tool.go new file mode 100644 index 0000000..51c8c42 --- /dev/null +++ b/internal/cache/tool.go @@ -0,0 +1,95 @@ +package cache + +import ( + "crypto/sha256" + "encoding/hex" + "encoding/json" + "io" + "os" + "sync" + + "github.com/sqlc-dev/sqlc/internal/info" +) + +// The sha256 of the sqlc binary is an input to every action — a rebuilt sqlc +// may analyze queries or embed a different wazero than the one that produced +// a cache entry, even when the version string is unchanged (dev builds). +// +// Hashing a ~100MB executable costs tens of milliseconds, too much to pay on +// every short-lived sqlc process, so the digest is memoized on disk keyed by +// the executable's path, size, and mtime — the same trick Bazel's file +// digest cache uses. A warm run costs one stat and a tiny read; only a +// rebuilt (or moved) binary is re-hashed. +var tool struct { + sync.Mutex + digest []byte +} + +type toolMemo struct { + Path string `json:"path"` + SizeBytes int64 `json:"size_bytes"` + MtimeNS int64 `json:"mtime_ns"` + SHA256 string `json:"sha256"` +} + +const toolMemoPath = "tool" + +func (c *Cache) toolDigest() []byte { + tool.Lock() + defer tool.Unlock() + if tool.digest == nil { + tool.digest = c.computeToolDigest() + } + return tool.digest +} + +func (c *Cache) computeToolDigest() []byte { + path, err := os.Executable() + if err != nil { + return []byte(info.Version) + } + fi, err := os.Stat(path) + if err != nil { + return []byte(info.Version) + } + + var memo toolMemo + if data, err := c.root.ReadFile(toolMemoPath); err == nil { + if err := json.Unmarshal(data, &memo); err == nil && + memo.Path == path && + memo.SizeBytes == fi.Size() && + memo.MtimeNS == fi.ModTime().UnixNano() && + memo.SHA256 != "" { + return []byte(memo.SHA256) + } + } + + f, err := os.Open(path) + if err != nil { + return []byte(info.Version) + } + defer f.Close() + h := sha256.New() + if _, err := io.Copy(h, f); err != nil { + return []byte(info.Version) + } + sum := hex.EncodeToString(h.Sum(nil)) + + memo = toolMemo{ + Path: path, + SizeBytes: fi.Size(), + MtimeNS: fi.ModTime().UnixNano(), + SHA256: sum, + } + if data, err := json.Marshal(memo); err == nil { + if f, name, err := c.CAS.createTemp("tool-"); err == nil { + if _, werr := f.Write(data); werr == nil && f.Close() == nil { + c.root.Rename(name, toolMemoPath) + } else { + f.Close() + } + c.root.Remove(name) + } + } + return []byte(sum) +} diff --git a/internal/cmd/analyze.go b/internal/cmd/analyze.go new file mode 100644 index 0000000..ba27849 --- /dev/null +++ b/internal/cmd/analyze.go @@ -0,0 +1,275 @@ +package cmd + +import ( + "encoding/json" + "fmt" + "io" + "os" + "strings" + + "github.com/spf13/cobra" + + "github.com/sqlc-dev/sqlc/internal/compiler" + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/core" + "github.com/sqlc-dev/sqlc/internal/multierr" + "github.com/sqlc-dev/sqlc/internal/opts" + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +func newAnalyzeCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "analyze [query-file]", + Short: "Analyze a query against a schema and output the result columns and parameters", + Long: `Analyze a query file against a schema file and output the inferred result +columns and parameters as JSON. + +Unlike "sqlc generate", this command does not require a configuration file and +does not connect to a database. It uses sqlc's native static analysis to infer +types from the provided schema. + +Examples: + # Analyze a PostgreSQL query + sqlc analyze --dialect postgresql --schema schema.sql query.sql + + # Analyze a MySQL query + sqlc analyze --dialect mysql --schema schema.sql query.sql + + # Analyze a SQLite query + sqlc analyze --dialect sqlite --schema schema.sql query.sql + + # Analyze a ClickHouse query + sqlc analyze --dialect clickhouse --schema schema.sql query.sql + + # Analyze a GoogleSQL (BigQuery, Spanner) query + sqlc analyze --dialect googlesql --schema schema.sql query.sql + + # Analyze a SQL Server (T-SQL) query + sqlc analyze --dialect mssql --schema schema.sql query.sql + + # Analyze a DuckDB query + sqlc analyze --dialect duckdb --schema schema.sql query.sql + + # Analyze a query piped via stdin + echo "-- name: GetAuthor :one + SELECT * FROM authors WHERE id = $1;" | sqlc analyze --dialect postgresql --schema schema.sql + + # Include the statement AST in the output + sqlc analyze --dialect postgresql --schema schema.sql --ast query.sql`, + Args: cobra.MaximumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + dialect, err := cmd.Flags().GetString("dialect") + if err != nil { + return err + } + if dialect == "" { + return fmt.Errorf("--dialect flag is required (postgresql, mysql, sqlite, clickhouse, googlesql, mssql, or duckdb)") + } + + schemaPath, err := cmd.Flags().GetString("schema") + if err != nil { + return err + } + if schemaPath == "" { + return fmt.Errorf("--schema flag is required") + } + + includeAST, err := cmd.Flags().GetBool("ast") + if err != nil { + return err + } + + // The query comes from a file argument or, when none is given, from + // stdin. The compiler reads queries from files, so stdin is written to + // a temporary file. + var queryPath string + if len(args) == 1 { + queryPath = args[0] + } else { + stat, err := os.Stdin.Stat() + if err != nil { + return fmt.Errorf("failed to stat stdin: %w", err) + } + if (stat.Mode() & os.ModeCharDevice) != 0 { + return fmt.Errorf("no query provided. Specify a query file or pipe SQL via stdin") + } + data, err := io.ReadAll(cmd.InOrStdin()) + if err != nil { + return fmt.Errorf("failed to read stdin: %w", err) + } + tmp, err := os.CreateTemp("", "sqlc-analyze-*.sql") + if err != nil { + return fmt.Errorf("failed to create temp file: %w", err) + } + defer os.Remove(tmp.Name()) + if _, err := tmp.Write(data); err != nil { + tmp.Close() + return fmt.Errorf("failed to write temp file: %w", err) + } + if err := tmp.Close(); err != nil { + return fmt.Errorf("failed to close temp file: %w", err) + } + queryPath = tmp.Name() + } + + var engine config.Engine + switch dialect { + case "postgresql", "postgres", "pg": + engine = config.EnginePostgreSQL + case "mysql": + engine = config.EngineMySQL + case "sqlite": + engine = config.EngineSQLite + case "clickhouse": + engine = config.EngineClickHouse + case "googlesql": + engine = config.EngineGoogleSQL + case "mssql", "sqlserver": + engine = config.EngineMSSQL + case "duckdb": + engine = config.EngineDuckDB + default: + return fmt.Errorf("unsupported dialect: %s (use postgresql, mysql, sqlite, clickhouse, googlesql, mssql, or duckdb)", dialect) + } + + sql := config.SQL{ + Engine: engine, + Schema: config.Paths{schemaPath}, + Queries: config.Paths{queryPath}, + } + combo := config.Combine(config.Config{}, sql) + parserOpts := opts.Parser{} + + ctx := cmd.Context() + c, err := compiler.NewCompiler(sql, combo, parserOpts, compiler.WithCoreAnalysis()) + if err != nil { + return fmt.Errorf("error creating compiler: %w", err) + } + defer c.Close(ctx) + + if err := c.ParseCatalog(sql.Schema); err != nil { + return fmt.Errorf("error parsing schema: %w", formatParseError(err)) + } + if err := c.ParseQueries(sql.Queries, parserOpts); err != nil { + return fmt.Errorf("error parsing queries: %w", formatParseError(err)) + } + + result := c.Result() + + out := make([]analyzedQuery, 0, len(result.Queries)) + for _, q := range result.Queries { + out = append(out, newAnalyzedQuery(q, includeAST)) + } + + stdout := cmd.OutOrStdout() + encoder := json.NewEncoder(stdout) + encoder.SetIndent("", " ") + if err := encoder.Encode(out); err != nil { + return fmt.Errorf("failed to encode analysis: %w", err) + } + + return nil + }, + } + cmd.Flags().StringP("dialect", "d", "", "SQL dialect to use (postgresql, mysql, sqlite, clickhouse, googlesql, mssql, or duckdb)") + cmd.Flags().StringP("schema", "s", "", "path to the schema file") + cmd.Flags().BoolP("ast", "", false, "include the statement AST in the output") + return cmd +} + +// formatParseError unwraps a multierr.Error into a single error containing all +// of the underlying file errors, so the analyze command can report each one with +// its file location. +func formatParseError(err error) error { + parserErr, ok := err.(*multierr.Error) + if !ok { + return err + } + var msgs []string + for _, fileErr := range parserErr.Errs() { + msgs = append(msgs, fmt.Sprintf("%s:%d:%d: %s", + fileErr.Filename, fileErr.Line, fileErr.Column, fileErr.Err)) + } + if len(msgs) == 0 { + return err + } + return fmt.Errorf("%s", strings.Join(msgs, "; ")) +} + +type analyzedQuery struct { + Name string `json:"name"` + Cmd string `json:"cmd"` + Columns []analyzedColumn `json:"columns"` + Params []analyzedParam `json:"params"` + AST *ast.RawStmt `json:"ast,omitempty"` +} + +type analyzedColumn struct { + Name string `json:"name"` + Type *core.TypeExpr `json:"type,omitempty"` + Table string `json:"table,omitempty"` +} + +type analyzedParam struct { + Number int `json:"number"` + Column analyzedColumn `json:"column"` +} + +func newAnalyzedQuery(q *compiler.Query, includeAST bool) analyzedQuery { + aq := analyzedQuery{ + Name: q.Metadata.Name, + Cmd: q.Metadata.Cmd, + Columns: make([]analyzedColumn, 0, len(q.Columns)), + Params: make([]analyzedParam, 0, len(q.Params)), + } + for _, col := range q.Columns { + aq.Columns = append(aq.Columns, newAnalyzedColumn(col)) + } + for _, p := range q.Params { + aq.Params = append(aq.Params, analyzedParam{ + Number: p.Number, + Column: newAnalyzedColumn(p.Column), + }) + } + if includeAST { + aq.AST = q.RawStmt + } + return aq +} + +func newAnalyzedColumn(col *compiler.Column) analyzedColumn { + if col == nil { + return analyzedColumn{} + } + ac := analyzedColumn{ + Name: col.Name, + Type: newAnalyzedType(col), + } + if col.Table != nil { + ac.Table = col.Table.Name + } + return ac +} + +// newAnalyzedType is the column's type as an expression: the one the +// analysis core wrote when it did, otherwise the flat description the +// compiler holds, which is the data type wrapped in one array node per +// dimension with the column's nullability on the outermost node. +func newAnalyzedType(col *compiler.Column) *core.TypeExpr { + if col.TypeExpr != nil { + return col.TypeExpr + } + if col.DataType == "" { + return nil + } + t := core.ParseTypeExpr(col.DataType) + dims := col.ArrayDims + if col.IsArray && dims == 0 { + dims = 1 + } + for i := 0; i < dims; i++ { + t = &core.TypeExpr{Name: "array", Args: []core.TypeArg{{Type: t}}} + } + t.Nullable = !col.NotNull + return t +} diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go new file mode 100644 index 0000000..4b14751 --- /dev/null +++ b/internal/cmd/cmd.go @@ -0,0 +1,277 @@ +package cmd + +import ( + "bufio" + "bytes" + "context" + "errors" + "fmt" + "io" + "os" + "os/exec" + "path/filepath" + "runtime/trace" + + "github.com/cubicdaiya/gonp" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "gopkg.in/yaml.v3" + + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/info" + "github.com/sqlc-dev/sqlc/internal/opts" + "github.com/sqlc-dev/sqlc/internal/sqlcdebug" + "github.com/sqlc-dev/sqlc/internal/tracer" +) + +var debugProcessPlugins = sqlcdebug.New("processplugins") + +func init() { + createDBCmd.Flags().StringP("queryset", "", "", "name of the queryset to use") + pushCmd.Flags().BoolP("dry-run", "", false, "dump push request (default: false)") + initCmd.Flags().BoolP("v1", "", false, "generate v1 config yaml file") + initCmd.Flags().BoolP("v2", "", true, "generate v2 config yaml file") + initCmd.MarkFlagsMutuallyExclusive("v1", "v2") +} + +// Do runs the command logic. +func Do(args []string, stdin io.Reader, stdout io.Writer, stderr io.Writer) int { + rootCmd := &cobra.Command{Use: "sqlc", SilenceUsage: true} + rootCmd.PersistentFlags().StringP("file", "f", "", "specify an alternate config file (default: sqlc.yaml)") + + rootCmd.AddCommand(checkCmd) + rootCmd.AddCommand(createDBCmd) + rootCmd.AddCommand(diffCmd) + rootCmd.AddCommand(genCmd) + rootCmd.AddCommand(newFmtCmd()) + rootCmd.AddCommand(initCmd) + rootCmd.AddCommand(newParseCmd()) + rootCmd.AddCommand(newAnalyzeCmd()) + rootCmd.AddCommand(versionCmd) + rootCmd.AddCommand(verifyCmd) + rootCmd.AddCommand(pushCmd) + rootCmd.AddCommand(NewCmdVet()) + + rootCmd.SetArgs(args) + rootCmd.SetIn(stdin) + rootCmd.SetOut(stdout) + rootCmd.SetErr(stderr) + + ctx := context.Background() + if tracer.Path() != "" { + tracectx, cleanup, err := tracer.Start(ctx) + if err != nil { + fmt.Printf("failed to start trace: %v\n", err) + return 1 + } + ctx = tracectx + defer cleanup() + } + if err := rootCmd.ExecuteContext(ctx); err != nil { + if exitError, ok := err.(*exec.ExitError); ok { + return exitError.ExitCode() + } else { + return 1 + } + } + return 0 +} + +var version string + +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Print the sqlc version number", + RunE: func(cmd *cobra.Command, args []string) error { + defer trace.StartRegion(cmd.Context(), "version").End() + if version == "" { + fmt.Fprintf(cmd.OutOrStdout(), "%s\n", info.Version) + } else { + fmt.Fprintf(cmd.OutOrStdout(), "%s\n", version) + } + return nil + }, +} + +var initCmd = &cobra.Command{ + Use: "init", + Short: "Create an empty sqlc.yaml settings file", + RunE: func(cmd *cobra.Command, args []string) error { + useV1, err := cmd.Flags().GetBool("v1") + if err != nil { + return err + } + var yamlConfig any + if useV1 { + yamlConfig = config.V1GenerateSettings{Version: "1"} + } else { + yamlConfig = config.Config{Version: "2"} + } + + defer trace.StartRegion(cmd.Context(), "init").End() + file := "sqlc.yaml" + if f := cmd.Flag("file"); f != nil && f.Changed { + file = f.Value.String() + if file == "" { + return fmt.Errorf("file argument is empty") + } + } + if _, err := os.Stat(file); !os.IsNotExist(err) { + fmt.Printf("%s is already created\n", file) + return nil + } + blob, err := yaml.Marshal(yamlConfig) + if err != nil { + return err + } + err = os.WriteFile(file, blob, 0644) + if err != nil { + return err + } + configDoc := "https://docs.sqlc.dev/en/stable/reference/config.html" + fmt.Printf( + "%s is added. Please visit %s to learn more about configuration\n", + file, + configDoc, + ) + return nil + }, +} + +type Env struct { + DryRun bool + Experiment opts.Experiment +} + +func ParseEnv(c *cobra.Command) Env { + dr := c.Flag("dry-run") + return Env{ + DryRun: dr != nil && dr.Changed, + Experiment: opts.ExperimentFromEnv(), + } +} + +var ErrPluginProcessDisabled = errors.New("plugin: process-based plugins disabled via SQLCDEBUG=processplugins=0") + +func (e *Env) Validate(cfg *config.Config) error { + for _, plugin := range cfg.Plugins { + if plugin.Process != nil && debugProcessPlugins.Value() == "0" { + return ErrPluginProcessDisabled + } + } + return nil +} + +func getConfigPath(stderr io.Writer, f *pflag.Flag) (string, string) { + if f != nil && f.Changed { + file := f.Value.String() + if file == "" { + fmt.Fprintln(stderr, "error parsing config: file argument is empty") + os.Exit(1) + } + abspath, err := filepath.Abs(file) + if err != nil { + fmt.Fprintf(stderr, "error parsing config: absolute file path lookup failed: %s\n", err) + os.Exit(1) + } + return filepath.Dir(abspath), filepath.Base(abspath) + } else { + wd, err := os.Getwd() + if err != nil { + fmt.Fprintln(stderr, "error parsing sqlc.json: file does not exist") + os.Exit(1) + } + return wd, "" + } +} + +var genCmd = &cobra.Command{ + Use: "generate", + Short: "Generate source code from SQL", + RunE: func(cmd *cobra.Command, args []string) error { + defer trace.StartRegion(cmd.Context(), "generate").End() + stderr := cmd.ErrOrStderr() + dir, name := getConfigPath(stderr, cmd.Flag("file")) + output, err := Generate(cmd.Context(), dir, name, &Options{ + Env: ParseEnv(cmd), + Stderr: stderr, + }) + if err != nil { + os.Exit(1) + } + defer trace.StartRegion(cmd.Context(), "writefiles").End() + for filename, source := range output { + os.MkdirAll(filepath.Dir(filename), 0755) + if err := os.WriteFile(filename, []byte(source), 0644); err != nil { + fmt.Fprintf(stderr, "%s: %s\n", filename, err) + return err + } + } + return nil + }, +} + +var checkCmd = &cobra.Command{ + Use: "compile", + Short: "Statically check SQL for syntax and type errors", + RunE: func(cmd *cobra.Command, args []string) error { + defer trace.StartRegion(cmd.Context(), "compile").End() + stderr := cmd.ErrOrStderr() + dir, name := getConfigPath(stderr, cmd.Flag("file")) + _, err := Generate(cmd.Context(), dir, name, &Options{ + Env: ParseEnv(cmd), + Stderr: stderr, + }) + if err != nil { + os.Exit(1) + } + return nil + }, +} + +func getLines(f []byte) []string { + fp := bytes.NewReader(f) + scanner := bufio.NewScanner(fp) + lines := make([]string, 0) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + return lines +} + +func filterHunks[T gonp.Elem](uniHunks []gonp.UniHunk[T]) []gonp.UniHunk[T] { + var out []gonp.UniHunk[T] + for i, uniHunk := range uniHunks { + var changed bool + for _, e := range uniHunk.GetChanges() { + switch e.GetType() { + case gonp.SesDelete: + changed = true + case gonp.SesAdd: + changed = true + } + } + if changed { + out = append(out, uniHunks[i]) + } + } + return out +} + +var diffCmd = &cobra.Command{ + Use: "diff", + Short: "Compare the generated files to the existing files", + RunE: func(cmd *cobra.Command, args []string) error { + defer trace.StartRegion(cmd.Context(), "diff").End() + stderr := cmd.ErrOrStderr() + dir, name := getConfigPath(stderr, cmd.Flag("file")) + opts := &Options{ + Env: ParseEnv(cmd), + Stderr: stderr, + } + if err := Diff(cmd.Context(), dir, name, opts); err != nil { + os.Exit(1) + } + return nil + }, +} diff --git a/internal/cmd/createdb.go b/internal/cmd/createdb.go new file mode 100644 index 0000000..0953681 --- /dev/null +++ b/internal/cmd/createdb.go @@ -0,0 +1,102 @@ +package cmd + +import ( + "context" + "fmt" + "os" + "runtime/trace" + "time" + + "github.com/spf13/cobra" + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/dbmanager" + "github.com/sqlc-dev/sqlc/internal/migrations" + "github.com/sqlc-dev/sqlc/internal/sql/sqlpath" +) + +var createDBCmd = &cobra.Command{ + Use: "createdb", + Short: "Create an ephemeral database", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + defer trace.StartRegion(cmd.Context(), "createdb").End() + stderr := cmd.ErrOrStderr() + dir, filename := getConfigPath(stderr, cmd.Flag("file")) + querySetName, err := cmd.Flags().GetString("queryset") + if err != nil { + return err + } + err = CreateDB(cmd.Context(), dir, filename, querySetName, &Options{ + Env: ParseEnv(cmd), + Stderr: stderr, + }) + if err != nil { + fmt.Fprintln(stderr, err.Error()) + os.Exit(1) + } + return nil + }, +} + +func CreateDB(ctx context.Context, dir, filename, querySetName string, o *Options) error { + _, conf, err := o.ReadConfig(dir, filename) + if err != nil { + return err + } + // Find the first queryset with a managed database + var queryset *config.SQL + var count int + for _, sql := range conf.SQL { + if querySetName != "" && sql.Name != querySetName { + continue + } + if sql.Database != nil && sql.Database.Managed { + queryset = &sql + count += 1 + } + } + if queryset == nil && querySetName != "" { + return fmt.Errorf("no queryset found with name %q", querySetName) + } + if queryset == nil { + return fmt.Errorf("no querysets configured to use a managed database") + } + if count > 1 { + return fmt.Errorf("multiple querysets configured to use managed databases") + } + + switch queryset.Engine { + case config.EngineMySQL: + // pass + case config.EnginePostgreSQL: + // pass + default: + return fmt.Errorf("createdb does not support the %s engine", queryset.Engine) + } + + var ddl []string + files, err := sqlpath.Glob(queryset.Schema) + if err != nil { + return err + } + for _, schema := range files { + contents, err := os.ReadFile(schema) + if err != nil { + return fmt.Errorf("read file: %w", err) + } + ddl = append(ddl, migrations.RemoveRollbackStatements(string(contents))) + } + + now := time.Now().UTC().UnixNano() + client := dbmanager.NewClient(conf.Servers) + resp, err := client.CreateDatabase(ctx, &dbmanager.CreateDatabaseRequest{ + Engine: string(queryset.Engine), + Migrations: ddl, + Prefix: fmt.Sprintf("sqlc_createdb_%d", now), + }) + if err != nil { + return fmt.Errorf("managed: create database: %w", err) + } + fmt.Println(resp.Uri) + return nil +} diff --git a/internal/cmd/diff.go b/internal/cmd/diff.go new file mode 100644 index 0000000..8998971 --- /dev/null +++ b/internal/cmd/diff.go @@ -0,0 +1,59 @@ +package cmd + +import ( + "context" + "errors" + "fmt" + "os" + "runtime/trace" + "sort" + "strings" + + "github.com/cubicdaiya/gonp" +) + +func Diff(ctx context.Context, dir, name string, opts *Options) error { + stderr := opts.Stderr + output, err := Generate(ctx, dir, name, opts) + if err != nil { + return err + } + defer trace.StartRegion(ctx, "checkfiles").End() + var errored bool + + keys := make([]string, 0, len(output)) + for k, _ := range output { + kk := k + keys = append(keys, kk) + } + sort.Strings(keys) + + for _, filename := range keys { + source := output[filename] + if _, err := os.Stat(filename); errors.Is(err, os.ErrNotExist) { + errored = true + // stdout message + continue + } + existing, err := os.ReadFile(filename) + if err != nil { + errored = true + fmt.Fprintf(stderr, "%s: %s\n", filename, err) + continue + } + diff := gonp.New(getLines(existing), getLines([]byte(source))) + diff.Compose() + uniHunks := filterHunks(diff.UnifiedHunks()) + + if len(uniHunks) > 0 { + errored = true + fmt.Fprintf(stderr, "--- a%s\n", strings.TrimPrefix(filename, dir)) + fmt.Fprintf(stderr, "+++ b%s\n", strings.TrimPrefix(filename, dir)) + diff.FprintUniHunks(stderr, uniHunks) + } + } + if errored { + return errors.New("diff found") + } + return nil +} diff --git a/internal/cmd/fmt.go b/internal/cmd/fmt.go new file mode 100644 index 0000000..54763d9 --- /dev/null +++ b/internal/cmd/fmt.go @@ -0,0 +1,481 @@ +package cmd + +import ( + "context" + "fmt" + "io" + "os" + "path/filepath" + "runtime/trace" + "sort" + "strings" + + "github.com/cubicdaiya/gonp" + "github.com/spf13/cobra" + + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/engine/dolphin" + "github.com/sqlc-dev/sqlc/internal/engine/postgresql" + "github.com/sqlc-dev/sqlc/internal/engine/sqlite" + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/format" + "github.com/sqlc-dev/sqlc/internal/sql/sqlpath" +) + +// noLineLimit renders without a maximum line width: like gofmt, fmt never +// rewraps a line on its own. Breaks come from the author's own line breaks +// at the boundaries the printer models, and from comments, which cannot +// share a line with the code after them. +const noLineLimit = 1 << 30 + +// queryFormatter is what the fmt command needs from an engine: a parser +// that surfaces the comments its lexer already scans (so statements and +// comments come from one pass, and interior comments format along with +// their statements) plus dialect-aware formatting. Comments cannot be +// reprinted without parser support, so ParseFile is the price of admission. +type queryFormatter interface { + ParseFile(io.Reader) (*ast.File, error) + format.Dialect +} + +// newQueryFormatter returns the formatter for engines fmt supports — +// SQLite, PostgreSQL and MySQL today. An engine joins by teaching its +// parser to surface comments (meyer's, oliphant's and marino's ParseFile +// are the templates) and adding its case here. +func newQueryFormatter(engine config.Engine) queryFormatter { + switch engine { + case config.EnginePostgreSQL: + return postgresql.NewParser() + case config.EngineSQLite: + return sqlite.NewParser() + case config.EngineMySQL: + // The format parser preserves identifier case and proves every + // statement via Fingerprint, the way oliphant does for PostgreSQL. + return dolphin.NewFormatParser() + default: + return nil + } +} + +func newFmtCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "fmt", + Short: "Format SQL queries", + Long: `Format the SQL query files referenced by the configuration file. + +Each query is parsed with the engine's parser and printed back in a canonical +form, with its comments kept where they were written. A statement that cannot +be proven to survive formatting unchanged is left exactly as written. Files +are rewritten in place; pass --diff to print the changes to stdout instead.`, + RunE: func(cmd *cobra.Command, args []string) error { + defer trace.StartRegion(cmd.Context(), "fmt").End() + stderr := cmd.ErrOrStderr() + stdout := cmd.OutOrStdout() + showDiff, err := cmd.Flags().GetBool("diff") + if err != nil { + return err + } + dir, name := getConfigPath(stderr, cmd.Flag("file")) + output, err := Format(cmd.Context(), dir, name, &Options{ + Env: ParseEnv(cmd), + Stderr: stderr, + }) + if err != nil { + os.Exit(1) + } + + filenames := make([]string, 0, len(output)) + for filename := range output { + filenames = append(filenames, filename) + } + sort.Strings(filenames) + + for _, filename := range filenames { + existing, err := os.ReadFile(filename) + if err != nil { + fmt.Fprintf(stderr, "%s: %s\n", filename, err) + return err + } + source := output[filename] + if string(existing) == source { + continue + } + if showDiff { + diff := gonp.New(getLines(existing), getLines([]byte(source))) + diff.Compose() + uniHunks := filterHunks(diff.UnifiedHunks()) + if len(uniHunks) == 0 { + continue + } + rel := filepath.ToSlash(strings.TrimPrefix(filename, dir)) + fmt.Fprintf(stdout, "--- a%s\n", rel) + fmt.Fprintf(stdout, "+++ b%s\n", rel) + diff.FprintUniHunks(stdout, uniHunks) + continue + } + if err := os.WriteFile(filename, []byte(source), 0644); err != nil { + fmt.Fprintf(stderr, "%s: %s\n", filename, err) + return err + } + } + return nil + }, + } + cmd.Flags().Bool("diff", false, "display diffs instead of rewriting files") + return cmd +} + +// Format formats every query file referenced by the configuration with its +// engine's SQL formatter. It returns the formatted contents of each file, +// keyed by absolute path. Query files for engines without a formatter are +// skipped. +func Format(ctx context.Context, dir, filename string, o *Options) (map[string]string, error) { + defer trace.StartRegion(ctx, "format").End() + stderr := o.Stderr + + configPath, conf, err := o.ReadConfig(dir, filename) + if err != nil { + return nil, err + } + base := filepath.Base(configPath) + if err := config.Validate(conf); err != nil { + fmt.Fprintf(stderr, "error validating %s: %s\n", base, err) + return nil, err + } + + engines := map[string]config.Engine{} + var files []string + for _, sql := range conf.SQL { + joined := make([]string, 0, len(sql.Queries)) + for _, q := range sql.Queries { + joined = append(joined, filepath.Join(dir, q)) + } + list, err := sqlpath.Glob(joined) + if err != nil { + fmt.Fprintf(stderr, "error listing queries: %s\n", err) + return nil, err + } + for _, file := range list { + if _, ok := engines[file]; ok { + continue + } + engines[file] = sql.Engine + files = append(files, file) + } + } + + output := map[string]string{} + unsupported := map[config.Engine]bool{} + for _, file := range files { + f := newQueryFormatter(engines[file]) + if f == nil { + if !unsupported[engines[file]] { + unsupported[engines[file]] = true + fmt.Fprintf(stderr, "sqlc fmt does not yet support the %s engine; query files left unchanged\n", engines[file]) + } + continue + } + rel, err := filepath.Rel(dir, file) + if err != nil { + rel = file + } + contents, err := os.ReadFile(file) + if err != nil { + fmt.Fprintf(stderr, "%s: skipped: %s\n", rel, err) + continue + } + formatted, err := formatQueries(f, string(contents)) + if err != nil { + // Not every query file parses without the compiler's help — for + // example, some engines only accept sqlc.slice() after + // preprocessing. Leave those files as they are. + fmt.Fprintf(stderr, "%s: skipped: %s\n", rel, err) + continue + } + // File-level belt for the reprinter path: no formatting result may + // change the file's comments or its statement count. A violation is + // a formatter bug; keep the file as written and say so. + before, err1 := f.ParseFile(strings.NewReader(string(contents))) + after, err2 := f.ParseFile(strings.NewReader(formatted)) + if err1 == nil && (err2 != nil || len(before.Stmts) != len(after.Stmts) || !sameComments(before.Comments, after.Comments)) { + fmt.Fprintf(stderr, "%s: skipped: formatting would alter the file (this is a bug in sqlc fmt)\n", rel) + continue + } + output[file] = formatted + } + return output, nil +} + +// formatQueries formats each statement in a query file. The comments above +// every statement (that's where the "-- name:" annotation lives) are kept +// as written; comments inside a statement are threaded through the printer +// by position. +func formatQueries(f queryFormatter, src string) (string, error) { + // The parser hands over statements and comments from one lexer pass; + // statement bodies slice the comment list by span. + file, err := f.ParseFile(strings.NewReader(src)) + if err != nil { + return "", err + } + stmts, fileComments := file.Stmts, file.Comments + var blocks []string + prevEnd := 0 + for _, stmt := range stmts { + if stmt.Raw == nil { + continue + } + start := stmt.Raw.StmtLocation + length := stmt.Raw.StmtLen + if length == 0 { + // An unterminated final statement is reported with a zero length. + length = len(src) - start + } + if start < 0 || start+length > len(src) { + return "", fmt.Errorf("statement location out of bounds") + } + // Engines differ on whether a statement's span covers the comments + // above it, so start each segment where the previous one ended: the + // gap holds nothing but the previous terminator, whitespace and + // comments. + segStart := prevEnd + if start < segStart { + segStart = start + } + if start+length <= prevEnd { + continue + } + prevEnd = start + length + seg := src[segStart : start+length] + segOff := segStart + // A comment on the same line as the previous statement's terminator + // belongs to that statement, not to this one's header. + if len(blocks) > 0 { + if trailing, remainder := splitTrailingComment(seg); trailing != "" { + blocks[len(blocks)-1] += " " + trailing + segOff += len(seg) - len(remainder) + seg = remainder + } + } + orig := strings.TrimSpace(strings.TrimLeft(seg, "; \t\r\n")) + if orig == "" { + continue + } + header, rest := splitLeadingComments(orig) + // The statement body's own file offset, so its interior comments + // can be sliced out of the file's comment list in the same + // coordinates the parser stamped on the nodes. + restOff := segOff + strings.Index(seg, orig) + len(orig) - len(rest) + var interior []ast.Comment + for _, c := range fileComments { + if c.Start >= restOff && c.End <= start+length { + interior = append(interior, c) + } + } + block := append([]string{}, header...) + block = append(block, formatStmt(f, stmt.Raw, rest, interior, src)) + blocks = append(blocks, strings.Join(block, "\n")) + } + // Everything after the last statement is its terminator, whitespace and + // trailing comments; keep the comments. + tailSeg := src[prevEnd:] + if len(blocks) > 0 { + if trailing, remainder := splitTrailingComment(tailSeg); trailing != "" { + blocks[len(blocks)-1] += " " + trailing + tailSeg = remainder + } + } + if tail := strings.TrimSpace(strings.TrimLeft(tailSeg, "; \t\r\n")); tail != "" { + blocks = append(blocks, tail) + } + if len(blocks) == 0 { + return src, nil + } + return strings.Join(blocks, "\n\n") + "\n", nil +} + +// splitTrailingComment splits a comment sitting on the same line as the +// previous statement's terminator off the front of the text between two +// statements, returning the comment (or "") and the remaining text. +func splitTrailingComment(seg string) (string, string) { + k := 0 + for k < len(seg) && (seg[k] == ';' || seg[k] == ' ' || seg[k] == '\t' || seg[k] == '\r') { + k++ + } + rest := seg[k:] + line, _, _ := strings.Cut(rest, "\n") + trimmed := strings.TrimSpace(line) + switch { + case strings.HasPrefix(trimmed, "--"), strings.HasPrefix(trimmed, "#"): + return trimmed, seg[k+len(line):] + case strings.HasPrefix(trimmed, "/*") && + strings.HasSuffix(trimmed, "*/") && strings.Count(trimmed, "*/") == 1: + // A block comment contained on the terminator's line. + return trimmed, seg[k+len(line):] + } + return "", seg +} + +// splitLeadingComments splits a statement's text into the comment lines above +// it and the statement itself. Comment lines are returned with surrounding +// whitespace trimmed (block comment continuation lines keep their leading +// whitespace); blank lines between comments are kept. +func splitLeadingComments(text string) ([]string, string) { + var header []string + rest := text + for rest != "" { + line, remainder, found := strings.Cut(rest, "\n") + trimmed := strings.TrimSpace(line) + if strings.HasPrefix(trimmed, "/*") && !strings.Contains(trimmed, "*/") { + // A block comment spanning several lines: commit it to the + // header only when its closing line arrives with nothing after + // it. Otherwise leave the whole block with the statement. + block := []string{trimmed} + blockRest := remainder + for closed := false; !closed; { + if !found || blockRest == "" { + return header, rest + } + var blockLine string + blockLine, blockRest, found = strings.Cut(blockRest, "\n") + if end := strings.TrimSpace(blockLine); strings.Contains(end, "*/") { + if !strings.HasSuffix(end, "*/") || strings.Count(end, "*/") != 1 { + return header, rest + } + closed = true + } + block = append(block, strings.TrimRight(blockLine, " \t\r")) + } + header = append(header, block...) + rest = blockRest + continue + } + if !isCommentLine(trimmed) { + break + } + header = append(header, trimmed) + if !found { + rest = "" + break + } + rest = remainder + } + // A statement never ends with a comment-only line here (the parser found a + // statement in this segment), but drop any blank lines left at the end of + // the header so comments sit directly above their query. + for len(header) > 0 && header[len(header)-1] == "" { + header = header[:len(header)-1] + } + return header, rest +} + +func isCommentLine(line string) bool { + switch { + case line == "": + // A blank line between comments. + return true + case strings.HasPrefix(line, "--"): + return true + case strings.HasPrefix(line, "#"): + // MySQL's line-comment syntax; text that reaches these helpers sits + // outside statements, where a # line in a file the engine parsed + // can only be a comment. + return true + case strings.HasPrefix(line, "/*") && strings.HasSuffix(line, "*/") && strings.Count(line, "*/") == 1: + // A block comment contained on a single line. + return true + default: + return false + } +} + +// fingerprinter is implemented by engines that can reduce a query to a +// fingerprint that survives changes in whitespace, case and layout — +// PostgreSQL via oliphant's pg_query-compatible Fingerprint. Where it is +// available, fmt gets a proof the other checks cannot give: the formatted +// statement still parses to the same query as the original. +type fingerprinter interface { + Fingerprint(string) (string, error) +} + +// formatStmt returns the canonical form of a single statement, or the +// original text when formatting cannot be proven to preserve the query. +func formatStmt(f queryFormatter, raw *ast.RawStmt, orig string, interior []ast.Comment, src string) string { + fallback := strings.TrimSuffix(strings.TrimSpace(orig), ";") + ";" + if out, ok := formatWithComments(f, raw, interior, src); ok { + if fp, ok := f.(fingerprinter); ok && !sameFingerprint(fp, orig, out) { + return fallback + } + return out + } + return fallback +} + +// sameFingerprint reports that both texts fingerprint successfully to the +// same value. Anything less is not a proof, so the caller keeps the +// statement as written. +func sameFingerprint(fp fingerprinter, orig, out string) bool { + a, err1 := fp.Fingerprint(orig) + b, err2 := fp.Fingerprint(out) + return err1 == nil && err2 == nil && a == b +} + +// formatWithComments pretty-prints a statement with its interior comments +// and proves the result faithful three ways before accepting it: every +// comment survives (multiset equality after reparsing the output), the SQL +// still parses as one statement, and the output is a fixed point (printing +// the reparsed statement with its reparsed comments reproduces it). +func formatWithComments(f queryFormatter, raw *ast.RawStmt, interior []ast.Comment, src string) (string, bool) { + out := prettyCommented(raw, f, interior, src) + if strings.TrimSpace(strings.TrimSuffix(out, ";")) == "" { + return "", false + } + file, err := f.ParseFile(strings.NewReader(out)) + if err != nil || len(file.Stmts) != 1 || file.Stmts[0].Raw == nil { + return "", false + } + if !sameComments(interior, file.Comments) { + return "", false + } + again := prettyCommented(file.Stmts[0].Raw, f, file.Comments, out) + if !strings.EqualFold(again, out) { + return "", false + } + return out, true +} + +// prettyCommented attaches a statement's comments to its nodes and renders +// it, returning "" when the printer panics or fails to place every comment. +func prettyCommented(raw *ast.RawStmt, f queryFormatter, comments []ast.Comment, src string) (out string) { + defer func() { + if r := recover(); r != nil { + out = "" + } + }() + ct := ast.AttachComments(raw, f, comments, src) + out = ast.PrettyWithComments(raw, f, noLineLimit, ct) + if !ct.Exhausted() { + return "" + } + return out +} + +// sameComments reports whether two comment lists carry the same comment +// texts, as multisets, ignoring surrounding whitespace. +func sameComments(a, b []ast.Comment) bool { + if len(a) != len(b) { + return false + } + counts := make(map[string]int, len(a)) + for _, c := range a { + counts[strings.TrimSpace(c.Text)]++ + } + for _, c := range b { + counts[strings.TrimSpace(c.Text)]-- + } + for _, n := range counts { + if n != 0 { + return false + } + } + return true +} diff --git a/internal/cmd/generate.go b/internal/cmd/generate.go new file mode 100644 index 0000000..fbdb084 --- /dev/null +++ b/internal/cmd/generate.go @@ -0,0 +1,376 @@ +package cmd + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "os" + "path/filepath" + "runtime/trace" + "strings" + "sync" + + "google.golang.org/grpc" + + "github.com/sqlc-dev/sqlc/internal/codegen/golang" + genjson "github.com/sqlc-dev/sqlc/internal/codegen/json" + "github.com/sqlc-dev/sqlc/internal/compiler" + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/config/convert" + "github.com/sqlc-dev/sqlc/internal/debug" + "github.com/sqlc-dev/sqlc/internal/ext" + "github.com/sqlc-dev/sqlc/internal/ext/process" + "github.com/sqlc-dev/sqlc/internal/ext/wasm" + "github.com/sqlc-dev/sqlc/internal/multierr" + "github.com/sqlc-dev/sqlc/internal/opts" + "github.com/sqlc-dev/sqlc/internal/plugin" + "github.com/sqlc-dev/sqlc/internal/sqlcdebug" +) + +var debugDumpCatalog = sqlcdebug.New("dumpcatalog") + +const errMessageNoVersion = `The configuration file must have a version number. +Set the version to 1 or 2 at the top of sqlc.json: + +{ + "version": "1" + ... +} +` + +const errMessageUnknownVersion = `The configuration file has an invalid version number. +The supported version can only be "1" or "2". +` + +const errMessageNoPackages = `No packages are configured` + +func printFileErr(stderr io.Writer, dir string, fileErr *multierr.FileError) { + filename, err := filepath.Rel(dir, fileErr.Filename) + if err != nil { + filename = fileErr.Filename + } + fmt.Fprintf(stderr, "%s:%d:%d: %s\n", filename, fileErr.Line, fileErr.Column, fileErr.Err) +} + +func findPlugin(conf config.Config, name string) (*config.Plugin, error) { + for _, plug := range conf.Plugins { + if plug.Name == name { + return &plug, nil + } + } + return nil, fmt.Errorf("plugin not found") +} + +func readConfig(stderr io.Writer, dir, filename string) (string, *config.Config, error) { + configPath := "" + if filename != "" { + configPath = filepath.Join(dir, filename) + } else { + var yamlMissing, jsonMissing, ymlMissing bool + yamlPath := filepath.Join(dir, "sqlc.yaml") + ymlPath := filepath.Join(dir, "sqlc.yml") + jsonPath := filepath.Join(dir, "sqlc.json") + + if _, err := os.Stat(yamlPath); os.IsNotExist(err) { + yamlMissing = true + } + if _, err := os.Stat(jsonPath); os.IsNotExist(err) { + jsonMissing = true + } + + if _, err := os.Stat(ymlPath); os.IsNotExist(err) { + ymlMissing = true + } + + if yamlMissing && ymlMissing && jsonMissing { + fmt.Fprintln(stderr, "error parsing configuration files. sqlc.(yaml|yml) or sqlc.json: file does not exist") + return "", nil, errors.New("config file missing") + } + + if (!yamlMissing || !ymlMissing) && !jsonMissing { + fmt.Fprintln(stderr, "error: both sqlc.json and sqlc.(yaml|yml) files present") + return "", nil, errors.New("sqlc.json and sqlc.(yaml|yml) present") + } + + if jsonMissing { + if yamlMissing { + configPath = ymlPath + } else { + configPath = yamlPath + } + } else { + configPath = jsonPath + } + } + + base := filepath.Base(configPath) + file, err := os.Open(configPath) + if err != nil { + fmt.Fprintf(stderr, "error parsing %s: file does not exist\n", base) + return "", nil, err + } + defer file.Close() + + conf, err := config.ParseConfig(file) + if err != nil { + switch err { + case config.ErrMissingVersion: + fmt.Fprint(stderr, errMessageNoVersion) + case config.ErrUnknownVersion: + fmt.Fprint(stderr, errMessageUnknownVersion) + case config.ErrNoPackages: + fmt.Fprint(stderr, errMessageNoPackages) + } + fmt.Fprintf(stderr, "error parsing %s: %s\n", base, err) + return "", nil, err + } + + return configPath, &conf, nil +} + +func Generate(ctx context.Context, dir, filename string, o *Options) (map[string]string, error) { + e := o.Env + stderr := o.Stderr + + configPath, conf, err := o.ReadConfig(dir, filename) + if err != nil { + return nil, err + } + + base := filepath.Base(configPath) + if err := config.Validate(conf); err != nil { + fmt.Fprintf(stderr, "error validating %s: %s\n", base, err) + return nil, err + } + + if err := e.Validate(conf); err != nil { + fmt.Fprintf(stderr, "error validating %s: %s\n", base, err) + return nil, err + } + + g := &generator{ + dir: dir, + output: map[string]string{}, + } + + if err := processQuerySets(ctx, g, conf, dir, o); err != nil { + return nil, err + } + + return g.output, nil +} + +type generator struct { + m sync.Mutex + dir string + output map[string]string +} + +func (g *generator) Pairs(ctx context.Context, conf *config.Config) []OutputPair { + var pairs []OutputPair + for _, sql := range conf.SQL { + if sql.Gen.Go != nil { + pairs = append(pairs, OutputPair{ + SQL: sql, + Gen: config.SQLGen{Go: sql.Gen.Go}, + }) + } + if sql.Gen.JSON != nil { + pairs = append(pairs, OutputPair{ + SQL: sql, + Gen: config.SQLGen{JSON: sql.Gen.JSON}, + }) + } + for i := range sql.Codegen { + pairs = append(pairs, OutputPair{ + SQL: sql, + Plugin: &sql.Codegen[i], + }) + } + } + return pairs +} + +func (g *generator) ProcessResult(ctx context.Context, combo config.CombinedSettings, sql OutputPair, result *compiler.Result) error { + out, resp, err := codegen(ctx, combo, sql, result) + if err != nil { + return err + } + files := map[string]string{} + for _, file := range resp.Files { + files[file.Name] = string(file.Contents) + } + g.m.Lock() + + // out is specified by the user, not a plugin + absout := filepath.Join(g.dir, out) + + // When the Go codegen is configured to emit the models file into a + // separate package directory, route that file to its own absolute path. + // This is the only file allowed to live outside of `out`. + var ( + modelsFileName string + modelsAbsout string + modelsAbsfile string + ) + if sql.Gen.Go != nil && sql.Gen.Go.OutputModelsPath != "" && sql.Gen.Go.ModelsEmitEnabled() { + modelsFileName = sql.Gen.Go.OutputModelsFileName + if modelsFileName == "" { + modelsFileName = "models.go" + } + modelsAbsout = filepath.Join(g.dir, sql.Gen.Go.OutputModelsPath) + modelsAbsfile = filepath.Join(modelsAbsout, modelsFileName) + } + + for n, source := range files { + if modelsFileName != "" && n == modelsFileName { + // Models file routed to a separate package directory. + if strings.Contains(modelsAbsfile, "..") { + return fmt.Errorf("invalid file output path: %s", modelsAbsfile) + } + if !strings.HasPrefix(modelsAbsfile, modelsAbsout) { + return fmt.Errorf("invalid file output path: %s", modelsAbsfile) + } + g.output[modelsAbsfile] = source + continue + } + filename := filepath.Join(g.dir, out, n) + // filepath.Join calls filepath.Clean which should remove all "..", but + // double check to make sure + if strings.Contains(filename, "..") { + return fmt.Errorf("invalid file output path: %s", filename) + } + // The output file must be contained inside the output directory + if !strings.HasPrefix(filename, absout) { + return fmt.Errorf("invalid file output path: %s", filename) + } + g.output[filename] = source + } + g.m.Unlock() + return nil +} + +func parse(ctx context.Context, name, dir string, sql config.SQL, combo config.CombinedSettings, parserOpts opts.Parser, stderr io.Writer) (*compiler.Result, bool) { + defer trace.StartRegion(ctx, "parse").End() + var copts []compiler.Option + if parserOpts.Experiment.CoreAnalyzer { + copts = append(copts, compiler.WithCoreAnalysis()) + } + c, err := compiler.NewCompiler(sql, combo, parserOpts, copts...) + defer func() { + if c != nil { + c.Close(ctx) + } + }() + if err != nil { + fmt.Fprintf(stderr, "error creating compiler: %s\n", err) + return nil, true + } + if err := c.ParseCatalog(sql.Schema); err != nil { + fmt.Fprintf(stderr, "# package %s\n", name) + if parserErr, ok := err.(*multierr.Error); ok { + for _, fileErr := range parserErr.Errs() { + printFileErr(stderr, dir, fileErr) + } + } else { + fmt.Fprintf(stderr, "error parsing schema: %s\n", err) + } + return nil, true + } + if debugDumpCatalog.Value() == "1" { + debug.Dump(c.Catalog()) + } + if err := c.ParseQueries(sql.Queries, parserOpts); err != nil { + fmt.Fprintf(stderr, "# package %s\n", name) + if parserErr, ok := err.(*multierr.Error); ok { + for _, fileErr := range parserErr.Errs() { + printFileErr(stderr, dir, fileErr) + } + } else { + fmt.Fprintf(stderr, "error parsing queries: %s\n", err) + } + return nil, true + } + return c.Result(), false +} + +func codegen(ctx context.Context, combo config.CombinedSettings, sql OutputPair, result *compiler.Result) (string, *plugin.GenerateResponse, error) { + defer trace.StartRegion(ctx, "codegen").End() + req := codeGenRequest(result, combo) + var handler grpc.ClientConnInterface + var out string + switch { + case sql.Plugin != nil: + out = sql.Plugin.Out + plug, err := findPlugin(combo.Global, sql.Plugin.Plugin) + if err != nil { + return "", nil, fmt.Errorf("plugin not found: %s", err) + } + + switch { + case plug.Process != nil: + handler = &process.Runner{ + Cmd: plug.Process.Cmd, + Env: plug.Env, + Format: plug.Process.Format, + } + 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") + } + + opts, err := convert.YAMLtoJSON(sql.Plugin.Options) + if err != nil { + return "", nil, fmt.Errorf("invalid plugin options: %w", err) + } + req.PluginOptions = opts + + global, found := combo.Global.Options[plug.Name] + if found { + opts, err := convert.YAMLtoJSON(global) + if err != nil { + return "", nil, fmt.Errorf("invalid global options: %w", err) + } + req.GlobalOptions = opts + } + + case sql.Gen.Go != nil: + out = combo.Go.Out + handler = ext.HandleFunc(golang.Generate) + opts, err := json.Marshal(sql.Gen.Go) + if err != nil { + return "", nil, fmt.Errorf("opts marshal failed: %w", err) + } + req.PluginOptions = opts + + if combo.Global.Overrides.Go != nil { + opts, err := json.Marshal(combo.Global.Overrides.Go) + if err != nil { + return "", nil, fmt.Errorf("opts marshal failed: %w", err) + } + req.GlobalOptions = opts + } + + case sql.Gen.JSON != nil: + out = combo.JSON.Out + handler = ext.HandleFunc(genjson.Generate) + opts, err := json.Marshal(sql.Gen.JSON) + if err != nil { + return "", nil, fmt.Errorf("opts marshal failed: %w", err) + } + req.PluginOptions = opts + + default: + return "", nil, fmt.Errorf("missing language backend") + } + client := plugin.NewCodegenServiceClient(handler) + resp, err := client.Generate(ctx, req) + return out, resp, err +} diff --git a/internal/cmd/options.go b/internal/cmd/options.go new file mode 100644 index 0000000..02d3614 --- /dev/null +++ b/internal/cmd/options.go @@ -0,0 +1,29 @@ +package cmd + +import ( + "io" + + "github.com/sqlc-dev/sqlc/internal/config" +) + +type Options struct { + Env Env + Stderr io.Writer + // TODO: Move these to a command-specific struct + Tags []string + Against string + + // Testing only + MutateConfig func(*config.Config) +} + +func (o *Options) ReadConfig(dir, filename string) (string, *config.Config, error) { + path, conf, err := readConfig(o.Stderr, dir, filename) + if err != nil { + return path, conf, err + } + if o.MutateConfig != nil { + o.MutateConfig(conf) + } + return path, conf, nil +} diff --git a/internal/cmd/parse.go b/internal/cmd/parse.go new file mode 100644 index 0000000..72f5961 --- /dev/null +++ b/internal/cmd/parse.go @@ -0,0 +1,166 @@ +package cmd + +import ( + "encoding/json" + "fmt" + "io" + "os" + "strings" + + "github.com/spf13/cobra" + + "github.com/sqlc-dev/sqlc/internal/engine/clickhouse" + "github.com/sqlc-dev/sqlc/internal/engine/dolphin" + "github.com/sqlc-dev/sqlc/internal/engine/duckdb" + "github.com/sqlc-dev/sqlc/internal/engine/googlesql" + "github.com/sqlc-dev/sqlc/internal/engine/mssql" + "github.com/sqlc-dev/sqlc/internal/engine/postgresql" + "github.com/sqlc-dev/sqlc/internal/engine/sqlite" + "github.com/sqlc-dev/sqlc/internal/metadata" + "github.com/sqlc-dev/sqlc/internal/source" + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +// dialectParser is the subset of the engine parsers that the parse command +// needs: parsing SQL into statements and reporting the dialect's comment syntax +// (used to extract the sqlc query name and command). +type dialectParser interface { + Parse(io.Reader) ([]ast.Statement, error) + CommentSyntax() source.CommentSyntax +} + +// parsedStatement is the JSON representation of a single parsed statement. The +// name and cmd are extracted from the sqlc query annotation (e.g. +// "-- name: GetAuthor :one") and are omitted when the statement has none. +type parsedStatement struct { + Name string `json:"name,omitempty"` + Cmd string `json:"cmd,omitempty"` + AST *ast.RawStmt `json:"ast"` +} + +func newParseCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "parse [file]", + Short: "Parse SQL and output the AST as JSON", + Long: `Parse SQL from a file or stdin and output the abstract syntax tree as JSON. + +Each statement is reported with its sqlc query name and command (when the +statement carries a "-- name:" annotation) alongside the AST. + +Examples: + # Parse a SQL file with PostgreSQL dialect + sqlc parse --dialect postgresql schema.sql + + # Parse from stdin with MySQL dialect + echo "SELECT * FROM users" | sqlc parse --dialect mysql + + # Parse SQLite SQL + sqlc parse --dialect sqlite queries.sql + + # Parse ClickHouse SQL + sqlc parse --dialect clickhouse queries.sql + + # Parse GoogleSQL (BigQuery, Spanner) + sqlc parse --dialect googlesql queries.sql + + # Parse SQL Server (T-SQL) SQL + sqlc parse --dialect mssql queries.sql + + # Parse DuckDB SQL + sqlc parse --dialect duckdb queries.sql`, + Args: cobra.MaximumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + dialect, err := cmd.Flags().GetString("dialect") + if err != nil { + return err + } + if dialect == "" { + return fmt.Errorf("--dialect flag is required (postgresql, mysql, sqlite, clickhouse, googlesql, mssql, or duckdb)") + } + + // Determine input source + var input io.Reader + if len(args) == 1 { + file, err := os.Open(args[0]) + if err != nil { + return fmt.Errorf("failed to open file: %w", err) + } + defer file.Close() + input = file + } else { + // Check if stdin has data + stat, err := os.Stdin.Stat() + if err != nil { + return fmt.Errorf("failed to stat stdin: %w", err) + } + if (stat.Mode() & os.ModeCharDevice) != 0 { + return fmt.Errorf("no input provided. Specify a file path or pipe SQL via stdin") + } + input = cmd.InOrStdin() + } + + // Select the parser for the requested dialect + var parser dialectParser + switch dialect { + case "postgresql", "postgres", "pg": + parser = postgresql.NewParser() + case "mysql": + parser = dolphin.NewParser() + case "sqlite": + parser = sqlite.NewParser() + case "clickhouse": + parser = clickhouse.NewParser() + case "googlesql": + parser = googlesql.NewParser() + case "mssql", "sqlserver": + parser = mssql.NewParser() + case "duckdb": + parser = duckdb.NewParser() + default: + return fmt.Errorf("unsupported dialect: %s (use postgresql, mysql, sqlite, clickhouse, googlesql, mssql, or duckdb)", dialect) + } + + // Read the full source so each statement's name and command can be + // extracted from its annotation comment. + src, err := io.ReadAll(input) + if err != nil { + return fmt.Errorf("failed to read input: %w", err) + } + + stmts, err := parser.Parse(strings.NewReader(string(src))) + if err != nil { + return fmt.Errorf("parse error: %w", err) + } + + commentSyntax := metadata.CommentSyntax(parser.CommentSyntax()) + + // Output the AST as a single JSON document + out := make([]parsedStatement, 0, len(stmts)) + for _, stmt := range stmts { + ps := parsedStatement{AST: stmt.Raw} + rawSQL, err := source.Pluck(string(src), stmt.Raw.StmtLocation, stmt.Raw.StmtLen) + if err != nil { + return fmt.Errorf("failed to read statement source: %w", err) + } + name, cmd, err := metadata.ParseQueryNameAndType(rawSQL, commentSyntax) + if err != nil { + return fmt.Errorf("failed to parse query annotation: %w", err) + } + ps.Name = name + ps.Cmd = cmd + out = append(out, ps) + } + + stdout := cmd.OutOrStdout() + encoder := json.NewEncoder(stdout) + encoder.SetIndent("", " ") + if err := encoder.Encode(out); err != nil { + return fmt.Errorf("failed to encode AST: %w", err) + } + + return nil + }, + } + cmd.Flags().StringP("dialect", "d", "", "SQL dialect to use (postgresql, mysql, sqlite, clickhouse, googlesql, mssql, or duckdb)") + return cmd +} diff --git a/internal/cmd/process.go b/internal/cmd/process.go new file mode 100644 index 0000000..e54eb43 --- /dev/null +++ b/internal/cmd/process.go @@ -0,0 +1,133 @@ +package cmd + +import ( + "bytes" + "context" + "fmt" + "io" + "path/filepath" + "runtime" + "runtime/trace" + + "golang.org/x/sync/errgroup" + + "github.com/sqlc-dev/sqlc/internal/compiler" + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/opts" +) + +type OutputPair struct { + Gen config.SQLGen + Plugin *config.Codegen + + config.SQL +} + +type ResultProcessor interface { + Pairs(context.Context, *config.Config) []OutputPair + ProcessResult(context.Context, config.CombinedSettings, OutputPair, *compiler.Result) error +} + +func Process(ctx context.Context, rp ResultProcessor, dir, filename string, o *Options) error { + e := o.Env + stderr := o.Stderr + + configPath, conf, err := o.ReadConfig(dir, filename) + if err != nil { + return err + } + + base := filepath.Base(configPath) + if err := config.Validate(conf); err != nil { + fmt.Fprintf(stderr, "error validating %s: %s\n", base, err) + return err + } + + if err := e.Validate(conf); err != nil { + fmt.Fprintf(stderr, "error validating %s: %s\n", base, err) + return err + } + + return processQuerySets(ctx, rp, conf, dir, o) +} + +func processQuerySets(ctx context.Context, rp ResultProcessor, conf *config.Config, dir string, o *Options) error { + stderr := o.Stderr + + errored := false + + pairs := rp.Pairs(ctx, conf) + grp, gctx := errgroup.WithContext(ctx) + grp.SetLimit(runtime.GOMAXPROCS(0)) + + stderrs := make([]bytes.Buffer, len(pairs)) + + for i, pair := range pairs { + sql := pair + errout := &stderrs[i] + + grp.Go(func() error { + combo := config.Combine(*conf, sql.SQL) + if sql.Plugin != nil { + combo.Codegen = *sql.Plugin + } + + // TODO: This feels like a hack that will bite us later + joined := make([]string, 0, len(sql.Schema)) + for _, s := range sql.Schema { + joined = append(joined, filepath.Join(dir, s)) + } + sql.Schema = joined + + joined = make([]string, 0, len(sql.Queries)) + for _, q := range sql.Queries { + joined = append(joined, filepath.Join(dir, q)) + } + sql.Queries = joined + + var name, lang string + parseOpts := opts.Parser{ + Experiment: o.Env.Experiment, + } + + switch { + case sql.Gen.Go != nil: + name = combo.Go.Package + lang = "golang" + + case sql.Plugin != nil: + lang = fmt.Sprintf("process:%s", sql.Plugin.Plugin) + name = sql.Plugin.Plugin + } + + packageRegion := trace.StartRegion(gctx, "package") + trace.Logf(gctx, "", "name=%s dir=%s plugin=%s", name, dir, lang) + + result, failed := parse(gctx, name, dir, sql.SQL, combo, parseOpts, errout) + if failed { + packageRegion.End() + errored = true + return nil + } + if err := rp.ProcessResult(gctx, combo, sql, result); err != nil { + fmt.Fprintf(errout, "# package %s\n", name) + fmt.Fprintf(errout, "error generating code: %s\n", err) + errored = true + } + packageRegion.End() + return nil + }) + } + if err := grp.Wait(); err != nil { + return err + } + if errored { + for i, _ := range stderrs { + if _, err := io.Copy(stderr, &stderrs[i]); err != nil { + return err + } + } + return fmt.Errorf("errored") + } + return nil +} diff --git a/internal/cmd/push.go b/internal/cmd/push.go new file mode 100644 index 0000000..19aca67 --- /dev/null +++ b/internal/cmd/push.go @@ -0,0 +1,92 @@ +package cmd + +import ( + "context" + "fmt" + "os" + "sync" + + "github.com/spf13/cobra" + + "github.com/sqlc-dev/sqlc/internal/bundler" + "github.com/sqlc-dev/sqlc/internal/compiler" + "github.com/sqlc-dev/sqlc/internal/config" +) + +func init() { + pushCmd.Flags().StringSliceP("tag", "t", nil, "tag this push with a value") +} + +var pushCmd = &cobra.Command{ + Use: "push", + Aliases: []string{"upload"}, + Short: "Push the schema, queries, and configuration for this project", + RunE: func(cmd *cobra.Command, args []string) error { + stderr := cmd.ErrOrStderr() + dir, name := getConfigPath(stderr, cmd.Flag("file")) + tags, err := cmd.Flags().GetStringSlice("tag") + if err != nil { + return err + } + opts := &Options{ + Env: ParseEnv(cmd), + Stderr: stderr, + Tags: tags, + } + if err := Push(cmd.Context(), dir, name, opts); err != nil { + fmt.Fprintf(stderr, "error pushing: %s\n", err) + os.Exit(1) + } + return nil + }, +} + +type pusher struct { + m sync.Mutex + results []*bundler.QuerySetArchive +} + +func (g *pusher) Pairs(ctx context.Context, conf *config.Config) []OutputPair { + var pairs []OutputPair + for _, sql := range conf.SQL { + pairs = append(pairs, OutputPair{ + SQL: sql, + }) + } + return pairs +} + +func (g *pusher) ProcessResult(ctx context.Context, combo config.CombinedSettings, sql OutputPair, result *compiler.Result) error { + req := codeGenRequest(result, combo) + g.m.Lock() + g.results = append(g.results, &bundler.QuerySetArchive{ + Name: sql.Name, + Schema: sql.Schema, + Queries: sql.Queries, + Request: req, + }) + g.m.Unlock() + return nil +} + +func Push(ctx context.Context, dir, filename string, opts *Options) error { + e := opts.Env + stderr := opts.Stderr + configPath, conf, err := readConfig(stderr, dir, filename) + if err != nil { + return err + } + up := bundler.NewUploader(configPath, dir, conf) + if err := up.Validate(); err != nil { + return err + } + p := &pusher{} + if err := Process(ctx, p, dir, filename, opts); err != nil { + return err + } + if e.DryRun { + return up.DumpRequestOut(ctx, p.results) + } else { + return up.Upload(ctx, p.results, opts.Tags) + } +} diff --git a/internal/cmd/shim.go b/internal/cmd/shim.go new file mode 100644 index 0000000..6545004 --- /dev/null +++ b/internal/cmd/shim.go @@ -0,0 +1,233 @@ +package cmd + +import ( + "github.com/sqlc-dev/sqlc/internal/compiler" + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/config/convert" + "github.com/sqlc-dev/sqlc/internal/info" + "github.com/sqlc-dev/sqlc/internal/plugin" + "github.com/sqlc-dev/sqlc/internal/sql/catalog" +) + +func pluginSettings(r *compiler.Result, cs config.CombinedSettings) *plugin.Settings { + return &plugin.Settings{ + Version: cs.Global.Version, + Engine: string(cs.Package.Engine), + Schema: []string(cs.Package.Schema), + Queries: []string(cs.Package.Queries), + Codegen: pluginCodegen(cs, cs.Codegen), + } +} + +func pluginCodegen(cs config.CombinedSettings, s config.Codegen) *plugin.Codegen { + opts, err := convert.YAMLtoJSON(s.Options) + if err != nil { + panic(err) + } + cg := &plugin.Codegen{ + Out: s.Out, + Plugin: s.Plugin, + Options: opts, + } + for _, p := range cs.Global.Plugins { + if p.Name == s.Plugin { + cg.Env = p.Env + cg.Process = pluginProcess(p) + cg.Wasm = pluginWASM(p) + return cg + } + } + return cg +} + +func pluginProcess(p config.Plugin) *plugin.Codegen_Process { + if p.Process != nil { + return &plugin.Codegen_Process{ + Cmd: p.Process.Cmd, + } + } + return nil +} + +func pluginWASM(p config.Plugin) *plugin.Codegen_WASM { + if p.WASM != nil { + return &plugin.Codegen_WASM{ + Url: p.WASM.URL, + Sha256: p.WASM.SHA256, + } + } + return nil +} + +func pluginCatalog(c *catalog.Catalog) *plugin.Catalog { + var schemas []*plugin.Schema + for _, s := range c.Schemas { + var enums []*plugin.Enum + var cts []*plugin.CompositeType + for _, typ := range s.Types { + switch typ := typ.(type) { + case *catalog.Enum: + enums = append(enums, &plugin.Enum{ + Name: typ.Name, + Comment: typ.Comment, + Vals: typ.Vals, + }) + case *catalog.CompositeType: + cts = append(cts, &plugin.CompositeType{ + Name: typ.Name, + Comment: typ.Comment, + }) + } + } + var tables []*plugin.Table + for _, t := range s.Tables { + var columns []*plugin.Column + for _, c := range t.Columns { + l := -1 + if c.Length != nil { + l = *c.Length + } + columns = append(columns, &plugin.Column{ + Name: c.Name, + Type: &plugin.Identifier{ + Catalog: c.Type.Catalog, + Schema: c.Type.Schema, + Name: c.Type.Name, + }, + Comment: c.Comment, + NotNull: c.IsNotNull, + Unsigned: c.IsUnsigned, + IsArray: c.IsArray, + ArrayDims: int32(c.ArrayDims), + Length: int32(l), + Table: &plugin.Identifier{ + Catalog: t.Rel.Catalog, + Schema: t.Rel.Schema, + Name: t.Rel.Name, + }, + }) + } + tables = append(tables, &plugin.Table{ + Rel: &plugin.Identifier{ + Catalog: t.Rel.Catalog, + Schema: t.Rel.Schema, + Name: t.Rel.Name, + }, + Columns: columns, + Comment: t.Comment, + }) + } + schemas = append(schemas, &plugin.Schema{ + Comment: s.Comment, + Name: s.Name, + Tables: tables, + Enums: enums, + CompositeTypes: cts, + }) + } + return &plugin.Catalog{ + Name: c.Name, + DefaultSchema: c.DefaultSchema, + Comment: c.Comment, + Schemas: schemas, + } +} + +func pluginQueries(r *compiler.Result) []*plugin.Query { + var out []*plugin.Query + for _, q := range r.Queries { + var params []*plugin.Parameter + var columns []*plugin.Column + for _, c := range q.Columns { + columns = append(columns, pluginQueryColumn(c)) + } + for _, p := range q.Params { + params = append(params, pluginQueryParam(p)) + } + var iit *plugin.Identifier + if q.InsertIntoTable != nil { + iit = &plugin.Identifier{ + Catalog: q.InsertIntoTable.Catalog, + Schema: q.InsertIntoTable.Schema, + Name: q.InsertIntoTable.Name, + } + } + out = append(out, &plugin.Query{ + Name: q.Metadata.Name, + Cmd: q.Metadata.Cmd, + Text: q.SQL, + Comments: q.Metadata.Comments, + Columns: columns, + Params: params, + Filename: q.Metadata.Filename, + InsertIntoTable: iit, + }) + } + return out +} + +func pluginQueryColumn(c *compiler.Column) *plugin.Column { + l := -1 + if c.Length != nil { + l = *c.Length + } + out := &plugin.Column{ + Name: c.Name, + OriginalName: c.OriginalName, + Comment: c.Comment, + NotNull: c.NotNull, + Unsigned: c.Unsigned, + IsArray: c.IsArray, + ArrayDims: int32(c.ArrayDims), + Length: int32(l), + IsNamedParam: c.IsNamedParam, + IsFuncCall: c.IsFuncCall, + IsSqlcSlice: c.IsSqlcSlice, + } + + if c.Type != nil { + out.Type = &plugin.Identifier{ + Catalog: c.Type.Catalog, + Schema: c.Type.Schema, + Name: c.Type.Name, + } + } else { + out.Type = &plugin.Identifier{ + Name: c.DataType, + } + } + + if c.Table != nil { + out.Table = &plugin.Identifier{ + Catalog: c.Table.Catalog, + Schema: c.Table.Schema, + Name: c.Table.Name, + } + } + + if c.EmbedTable != nil { + out.EmbedTable = &plugin.Identifier{ + Catalog: c.EmbedTable.Catalog, + Schema: c.EmbedTable.Schema, + Name: c.EmbedTable.Name, + } + } + + return out +} + +func pluginQueryParam(p compiler.Parameter) *plugin.Parameter { + return &plugin.Parameter{ + Number: int32(p.Number), + Column: pluginQueryColumn(p.Column), + } +} + +func codeGenRequest(r *compiler.Result, settings config.CombinedSettings) *plugin.GenerateRequest { + return &plugin.GenerateRequest{ + Settings: pluginSettings(r, settings), + Catalog: pluginCatalog(r.Catalog), + Queries: pluginQueries(r), + SqlcVersion: info.Version, + } +} diff --git a/internal/cmd/verify.go b/internal/cmd/verify.go new file mode 100644 index 0000000..a52c218 --- /dev/null +++ b/internal/cmd/verify.go @@ -0,0 +1,156 @@ +package cmd + +import ( + "context" + "database/sql" + "errors" + "fmt" + "log/slog" + "os" + + _ "github.com/jackc/pgx/v5/stdlib" + "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" + + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/dbmanager" + "github.com/sqlc-dev/sqlc/internal/migrations" + "github.com/sqlc-dev/sqlc/internal/plugin" + "github.com/sqlc-dev/sqlc/internal/quickdb" + pb "github.com/sqlc-dev/sqlc/internal/quickdb/v1" + "github.com/sqlc-dev/sqlc/internal/sql/sqlpath" +) + +func init() { + verifyCmd.Flags().String("against", "", "compare against this tag") +} + +var verifyCmd = &cobra.Command{ + Use: "verify", + Short: "Verify schema, queries, and configuration for this project", + RunE: func(cmd *cobra.Command, args []string) error { + stderr := cmd.ErrOrStderr() + dir, name := getConfigPath(stderr, cmd.Flag("file")) + against, err := cmd.Flags().GetString("against") + if err != nil { + return err + } + opts := &Options{ + Env: ParseEnv(cmd), + Stderr: stderr, + Against: against, + } + if err := Verify(cmd.Context(), dir, name, opts); err != nil { + fmt.Fprintf(stderr, "Error verifying queries: %s\n", err) + os.Exit(1) + } + return nil + }, +} + +func Verify(ctx context.Context, dir, filename string, opts *Options) error { + stderr := opts.Stderr + _, conf, err := readConfig(stderr, dir, filename) + if err != nil { + return err + } + + client, err := quickdb.NewClientFromConfig(conf.Cloud) + if err != nil { + return fmt.Errorf("client init failed: %w", err) + } + + manager := dbmanager.NewClient(conf.Servers) + + // Get query sets from a previous archive by tag. If no tag is provided, get + // the latest query sets. + previous, err := client.GetQuerySets(ctx, &pb.GetQuerySetsRequest{ + Tag: opts.Against, + }) + if err != nil { + return err + } + + // Create a mapping of name to query set + existing := map[string]config.SQL{} + for _, qs := range conf.SQL { + existing[qs.Name] = qs + } + + var verr error + for _, qs := range previous.QuerySets { + // TODO: Create a function for this so that we can return early on errors + + check := func() error { + if qs.Name == "" { + return fmt.Errorf("unnamed query set") + } + + current, found := existing[qs.Name] + if !found { + return fmt.Errorf("unknown query set: %s", qs.Name) + } + + // Read the schema files into memory, removing rollback statements + var ddl []string + files, err := sqlpath.Glob(current.Schema) + if err != nil { + return err + } + for _, schema := range files { + contents, err := os.ReadFile(schema) + if err != nil { + return fmt.Errorf("read file: %w", err) + } + ddl = append(ddl, migrations.RemoveRollbackStatements(string(contents))) + } + + var codegen plugin.GenerateRequest + if err := proto.Unmarshal(qs.CodegenRequest.Contents, &codegen); err != nil { + return err + } + + // Create (or re-use) a database to verify against + resp, err := manager.CreateDatabase(ctx, &dbmanager.CreateDatabaseRequest{ + Engine: string(current.Engine), + Migrations: ddl, + }) + if err != nil { + return err + } + + db, err := sql.Open("pgx", resp.Uri) + if err != nil { + return err + } + defer db.Close() + + var qerr error + for _, query := range codegen.Queries { + stmt, err := db.PrepareContext(ctx, query.Text) + if err != nil { + fmt.Fprintf(stderr, "Failed to prepare the following query:\n") + fmt.Fprintf(stderr, "%s\n", query.Text) + fmt.Fprintf(stderr, "Error was: %s\n", err) + qerr = err + continue + } + if err := stmt.Close(); err != nil { + slog.Error("stmt.Close failed", "err", err) + } + } + + return qerr + } + + if err := check(); err != nil { + verr = errors.New("errored") + fmt.Fprintf(stderr, "FAIL\t%s\n", qs.Name) + fmt.Fprintf(stderr, " ERROR\t%s\n", err) + } else { + fmt.Fprintf(stderr, "ok\t%s\n", qs.Name) + } + } + + return verr +} diff --git a/internal/cmd/vet.go b/internal/cmd/vet.go new file mode 100644 index 0000000..1bdf87d --- /dev/null +++ b/internal/cmd/vet.go @@ -0,0 +1,709 @@ +package cmd + +import ( + "context" + "database/sql" + "encoding/json" + "errors" + "fmt" + "github.com/sqlc-dev/sqlc/internal/constants" + "io" + "log" + "os" + "path/filepath" + "runtime/trace" + "slices" + "strings" + "sync" + "time" + + _ "github.com/go-sql-driver/mysql" + "cel.dev/cel-go/cel" + "cel.dev/cel-go/ext" + "github.com/jackc/pgx/v5" + "github.com/spf13/cobra" + "google.golang.org/protobuf/encoding/protojson" + + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/dbmanager" + "github.com/sqlc-dev/sqlc/internal/debug" + "github.com/sqlc-dev/sqlc/internal/migrations" + "github.com/sqlc-dev/sqlc/internal/opts" + "github.com/sqlc-dev/sqlc/internal/plugin" + "github.com/sqlc-dev/sqlc/internal/quickdb" + "github.com/sqlc-dev/sqlc/internal/shfmt" + "github.com/sqlc-dev/sqlc/internal/sql/sqlpath" + "github.com/sqlc-dev/sqlc/internal/sqlcdebug" + "github.com/sqlc-dev/sqlc/internal/vet" +) + +var ( + debugDumpExplain = sqlcdebug.New("dumpexplain") + debugDumpVetEnv = sqlcdebug.New("dumpvetenv") + debugDatabases = sqlcdebug.New("databases") +) + +var ErrFailedChecks = errors.New("failed checks") + +var pjson = protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + +func NewCmdVet() *cobra.Command { + return &cobra.Command{ + Use: "vet", + Short: "Vet examines queries", + RunE: func(cmd *cobra.Command, args []string) error { + defer trace.StartRegion(cmd.Context(), "vet").End() + stderr := cmd.ErrOrStderr() + opts := &Options{ + Env: ParseEnv(cmd), + Stderr: stderr, + } + dir, name := getConfigPath(stderr, cmd.Flag("file")) + if err := Vet(cmd.Context(), dir, name, opts); err != nil { + if !errors.Is(err, ErrFailedChecks) { + fmt.Fprintf(stderr, "%s\n", err) + } + os.Exit(1) + } + return nil + }, + } +} + +func Vet(ctx context.Context, dir, filename string, opts *Options) error { + e := opts.Env + stderr := opts.Stderr + configPath, conf, err := readConfig(stderr, dir, filename) + if err != nil { + return err + } + + base := filepath.Base(configPath) + if err := config.Validate(conf); err != nil { + fmt.Fprintf(stderr, "error validating %s: %s\n", base, err) + return err + } + + if err := e.Validate(conf); err != nil { + fmt.Fprintf(stderr, "error validating %s: %s\n", base, err) + return err + } + + env, err := cel.NewEnv( + cel.StdLib(), + ext.Strings(ext.StringsVersion(1)), + cel.Types( + &vet.Config{}, + &vet.Query{}, + &vet.PostgreSQL{}, + &vet.MySQL{}, + ), + cel.Variable("query", + cel.ObjectType("vet.Query"), + ), + cel.Variable("config", + cel.ObjectType("vet.Config"), + ), + cel.Variable("postgresql", + cel.ObjectType("vet.PostgreSQL"), + ), + cel.Variable("mysql", + cel.ObjectType("vet.MySQL"), + ), + ) + if err != nil { + return fmt.Errorf("new CEL env error: %s", err) + } + + rules := map[string]rule{ + constants.QueryRuleDbPrepare: {NeedsPrepare: true}, + } + + for _, c := range conf.Rules { + if c.Name == "" { + return fmt.Errorf("rules require a name") + } + if _, found := rules[c.Name]; found { + return fmt.Errorf("type-check error: a rule with the name '%s' already exists", c.Name) + } + if c.Rule == "" { + return fmt.Errorf("type-check error: %s is empty", c.Name) + } + ast, issues := env.Compile(c.Rule) + if issues != nil && issues.Err() != nil { + return fmt.Errorf("type-check error: %s %s", c.Name, issues.Err()) + } + prg, err := env.Program(ast) + if err != nil { + return fmt.Errorf("program construction error: %s %s", c.Name, err) + } + rule := rule{Program: &prg, Message: c.Msg} + + // TODO There's probably a nicer way to do this from the ast + // https://pkg.go.dev/cel.dev/cel-go/common/ast#AllMatcher + if strings.Contains(c.Rule, "postgresql.explain") || + strings.Contains(c.Rule, "mysql.explain") { + rule.NeedsExplain = true + } + + rules[c.Name] = rule + } + + c := checker{ + Rules: rules, + Conf: conf, + Dir: dir, + Env: env, + Stderr: stderr, + OnlyManagedDB: debugDatabases.Value() == "managed", + Replacer: shfmt.NewReplacer(nil), + } + errored := false + for _, sql := range conf.SQL { + if err := c.checkSQL(ctx, sql); err != nil { + if !errors.Is(err, ErrFailedChecks) { + fmt.Fprintf(stderr, "%s\n", err) + } + errored = true + } + } + if errored { + return ErrFailedChecks + } + return nil +} + +type preparer interface { + Prepare(context.Context, string, string) error +} + +type pgxConn struct { + c *pgx.Conn +} + +func (p *pgxConn) Prepare(ctx context.Context, name, query string) error { + _, err := p.c.Prepare(ctx, name, query) + return err +} + +// Return a default value for a PostgreSQL column based on its type. Returns nil +// if the type is unknown. +func pgDefaultValue(col *plugin.Column) any { + if col == nil { + return nil + } + if col.Type == nil { + return nil + } + typname := strings.TrimPrefix(col.Type.Name, "pg_catalog.") + switch typname { + case "any", "void": + if col.IsArray { + return []any{} + } else { + return nil + } + case "anyarray": + return []any{} + case "bool", "boolean": + if col.IsArray { + return []bool{} + } else { + return false + } + case "double", "double precision", "real": + if col.IsArray { + return []float32{} + } else { + return 0.1 + } + case "json", "jsonb": + if col.IsArray { + return []string{} + } else { + return "{}" + } + case "citext", "string", "text", "varchar": + if col.IsArray { + return []string{} + } else { + return "" + } + case "bigint", "bigserial", "integer", "int", "int2", "int4", "int8", "serial": + if col.IsArray { + return []int{} + } else { + return 1 + } + case "date", "time", "timestamp", "timestamptz": + if col.IsArray { + return []time.Time{} + } else { + return time.Time{} + } + case "uuid": + if col.IsArray { + return []string{} + } else { + return "00000000-0000-0000-0000-000000000000" + } + case "numeric", "decimal": + if col.IsArray { + return []string{} + } else { + return "0.1" + } + case "inet": + if col.IsArray { + return []string{} + } else { + return "192.168.0.1/24" + } + case "cidr": + if col.IsArray { + return []string{} + } else { + return "192.168.1/24" + } + default: + return nil + } +} + +// Return a default value for a MySQL column based on its type. Returns nil +// if the type is unknown. +func mysqlDefaultValue(col *plugin.Column) any { + if col == nil { + return nil + } + if col.Type == nil { + return nil + } + switch col.Type.Name { + case "any": + return nil + case "bool": + return false + case "int", "bigint", "mediumint", "smallint", "tinyint", "bit": + return 1 + case "decimal": // "numeric", "dec", "fixed" + // No perfect choice here to avoid "Impossible WHERE" but I think + // 0.1 is decent. It works for all cases where `scale` > 0 which + // should be the majority. For more information refer to + // https://dev.mysql.com/doc/refman/8.1/en/fixed-point-types.html. + return 0.1 + case "float", "double": + return 0.1 + case "date": + return "0000-00-00" + case "datetime", "timestamp": + return "0000-00-00 00:00:00" + case "time": + return "00:00:00" + case "year": + return "0000" + case "char", "varchar", "binary", "varbinary", "tinyblob", "blob", + "mediumblob", "longblob", "tinytext", "text", "mediumtext", "longtext": + return "" + case "json": + return "{}" + default: + return nil + } +} + +func (p *pgxConn) Explain(ctx context.Context, query string, args ...*plugin.Parameter) (*vetEngineOutput, error) { + eQuery := "EXPLAIN (ANALYZE false, VERBOSE, COSTS, SETTINGS, BUFFERS, FORMAT JSON) " + query + eArgs := make([]any, len(args)) + for i, a := range args { + eArgs[i] = pgDefaultValue(a.Column) + } + row := p.c.QueryRow(ctx, eQuery, eArgs...) + var result []json.RawMessage + if err := row.Scan(&result); err != nil { + return nil, err + } + if debugDumpExplain.Value() == "1" { + fmt.Println(eQuery, "with args", eArgs) + fmt.Println(string(result[0])) + } + var explain vet.PostgreSQLExplain + if err := pjson.Unmarshal(result[0], &explain); err != nil { + return nil, err + } + return &vetEngineOutput{PostgreSQL: &vet.PostgreSQL{Explain: &explain}}, nil +} + +type dbPreparer struct { + db *sql.DB +} + +func (p *dbPreparer) Prepare(ctx context.Context, name, query string) error { + s, err := p.db.PrepareContext(ctx, query) + if s != nil { + s.Close() + } + return err +} + +type explainer interface { + Explain(context.Context, string, ...*plugin.Parameter) (*vetEngineOutput, error) +} + +type mysqlExplainer struct { + *sql.DB +} + +func (me *mysqlExplainer) Explain(ctx context.Context, query string, args ...*plugin.Parameter) (*vetEngineOutput, error) { + eQuery := "EXPLAIN FORMAT=JSON " + query + eArgs := make([]any, len(args)) + for i, a := range args { + eArgs[i] = mysqlDefaultValue(a.Column) + } + row := me.QueryRowContext(ctx, eQuery, eArgs...) + var result json.RawMessage + if err := row.Scan(&result); err != nil { + return nil, err + } + if debugDumpExplain.Value() == "1" { + fmt.Println(eQuery, "with args", eArgs) + fmt.Println(string(result)) + } + var explain vet.MySQLExplain + if err := pjson.Unmarshal(result, &explain); err != nil { + return nil, err + } + if explain.QueryBlock.Message != "" { + return nil, fmt.Errorf("mysql explain: %s", explain.QueryBlock.Message) + } + return &vetEngineOutput{MySQL: &vet.MySQL{Explain: &explain}}, nil +} + +type rule struct { + Program *cel.Program + Message string + NeedsPrepare bool + NeedsExplain bool +} + +type checker struct { + Rules map[string]rule + Conf *config.Config + Dir string + Env *cel.Env + Stderr io.Writer + OnlyManagedDB bool + Client dbmanager.Client + clientOnce sync.Once + Replacer *shfmt.Replacer +} + +// isInMemorySQLite checks if a SQLite URI refers to an in-memory database +func isInMemorySQLite(uri string) bool { + if uri == ":memory:" || uri == "" { + return true + } + // Check for file URI with mode=memory parameter + // e.g., "file:test?mode=memory&cache=shared" + if strings.Contains(uri, "mode=memory") { + return true + } + return false +} + +func (c *checker) fetchDatabaseUri(ctx context.Context, s config.SQL) (string, func() error, error) { + cleanup := func() error { + return nil + } + + if s.Database == nil { + panic("fetch database URI called with nil database") + } + if !s.Database.Managed { + uri, err := c.DSN(s.Database.URI) + return uri, cleanup, err + } + + // Initialize the client exactly once, even if called concurrently + c.clientOnce.Do(func() { + c.Client = dbmanager.NewClient(c.Conf.Servers) + }) + + var ddl []string + files, err := sqlpath.Glob(s.Schema) + if err != nil { + return "", cleanup, err + } + for _, schema := range files { + contents, err := os.ReadFile(schema) + if err != nil { + return "", cleanup, fmt.Errorf("read file: %w", err) + } + ddl = append(ddl, migrations.RemoveRollbackStatements(string(contents))) + } + + resp, err := c.Client.CreateDatabase(ctx, &dbmanager.CreateDatabaseRequest{ + Engine: string(s.Engine), + Migrations: ddl, + }) + if err != nil { + return "", cleanup, fmt.Errorf("managed: create database: %w", err) + } + + var uri string + switch s.Engine { + case config.EngineMySQL: + dburi, err := quickdb.MySQLReformatURI(resp.Uri) + if err != nil { + return "", cleanup, fmt.Errorf("reformat uri: %w", err) + } + uri = dburi + default: + uri = resp.Uri + } + + return uri, cleanup, nil +} + +func (c *checker) DSN(dsn string) (string, error) { + return c.Replacer.Replace(dsn), nil +} + +func (c *checker) checkSQL(ctx context.Context, s config.SQL) error { + // TODO: Create a separate function for this logic so we can + combo := config.Combine(*c.Conf, s) + + // TODO: This feels like a hack that will bite us later + joined := make([]string, 0, len(s.Schema)) + for _, s := range s.Schema { + joined = append(joined, filepath.Join(c.Dir, s)) + } + s.Schema = joined + + joined = make([]string, 0, len(s.Queries)) + for _, q := range s.Queries { + joined = append(joined, filepath.Join(c.Dir, q)) + } + s.Queries = joined + + var name string + parseOpts := opts.Parser{} + + result, failed := parse(ctx, name, c.Dir, s, combo, parseOpts, c.Stderr) + if failed { + return ErrFailedChecks + } + + var prep preparer + var expl explainer + if s.Database != nil { // TODO only set up a database connection if a rule evaluation requires it + if s.Database.URI != "" && c.OnlyManagedDB { + return fmt.Errorf("database: connections disabled via SQLCDEBUG=databases=managed") + } + dburl, cleanup, err := c.fetchDatabaseUri(ctx, s) + if err != nil { + return err + } + defer func() { + if err := cleanup(); err != nil { + fmt.Fprintf(c.Stderr, "error cleaning up: %s\n", err) + } + }() + + switch s.Engine { + case config.EnginePostgreSQL: + conn, err := pgx.Connect(ctx, dburl) + if err != nil { + return fmt.Errorf("database: connection error: %s", err) + } + if err := conn.Ping(ctx); err != nil { + return fmt.Errorf("database: connection error: %s", err) + } + defer conn.Close(ctx) + pConn := &pgxConn{conn} + prep = pConn + expl = pConn + case config.EngineMySQL: + db, err := sql.Open("mysql", dburl) + if err != nil { + return fmt.Errorf("database: connection error: %s", err) + } + if err := db.PingContext(ctx); err != nil { + return fmt.Errorf("database: connection error: %s", err) + } + defer db.Close() + prep = &dbPreparer{db} + expl = &mysqlExplainer{db} + case config.EngineSQLite: + db, err := sql.Open("sqlite3", dburl) + if err != nil { + return fmt.Errorf("database: connection error: %s", err) + } + if err := db.PingContext(ctx); err != nil { + return fmt.Errorf("database: connection error: %s", err) + } + defer db.Close() + // For in-memory SQLite databases, apply migrations + if isInMemorySQLite(dburl) { + files, err := sqlpath.Glob(s.Schema) + if err != nil { + return fmt.Errorf("schema: %w", err) + } + for _, schema := range files { + contents, err := os.ReadFile(schema) + if err != nil { + return fmt.Errorf("read schema file: %w", err) + } + ddl := migrations.RemoveRollbackStatements(string(contents)) + if _, err := db.ExecContext(ctx, ddl); err != nil { + return fmt.Errorf("apply schema %s: %w", schema, err) + } + } + } + prep = &dbPreparer{db} + // SQLite really doesn't want us to depend on the output of EXPLAIN + // QUERY PLAN: https://www.sqlite.org/eqp.html + expl = nil + default: + return fmt.Errorf("unsupported database uri: %s", s.Engine) + } + } + + errored := false + req := codeGenRequest(result, combo) + cfg := vetConfig(req) + for i, query := range req.Queries { + md := result.Queries[i].Metadata + if md.Flags[constants.QueryFlagSqlcVetDisable] { + // If the vet disable flag is specified without any rules listed, all rules are ignored. + if len(md.RuleSkiplist) == 0 { + if debug.Active { + log.Printf("Skipping all vet rules for query: %s\n", query.Name) + } + continue + } + + // Rules which are listed to be disabled but not declared in the config file are rejected. + for r := range md.RuleSkiplist { + if !slices.Contains(s.Rules, r) { + fmt.Fprintf(c.Stderr, "%s: %s: rule-check error: rule %q does not exist in the config file\n", query.Filename, query.Name, r) + errored = true + } + } + } + + evalMap := map[string]any{ + "query": vetQuery(query), + "config": cfg, + } + + for _, name := range s.Rules { + if _, skip := md.RuleSkiplist[name]; skip { + if debug.Active { + log.Printf("Skipping vet rule %q for query: %s\n", name, query.Name) + } + } else { + rule, ok := c.Rules[name] + if !ok { + return fmt.Errorf("type-check error: a rule with the name '%s' does not exist", name) + } + + if rule.NeedsPrepare { + if prep == nil { + fmt.Fprintf(c.Stderr, "%s: %s: %s: error preparing query: database connection required\n", query.Filename, query.Name, name) + errored = true + continue + } + prepName := fmt.Sprintf("sqlc_vet_%d_%d", time.Now().Unix(), i) + if err := prep.Prepare(ctx, prepName, query.Text); err != nil { + fmt.Fprintf(c.Stderr, "%s: %s: %s: error preparing query: %s\n", query.Filename, query.Name, name, err) + errored = true + continue + } + } + + // short-circuit for "sqlc/db-prepare" rule which doesn't have a CEL program + if rule.Program == nil { + continue + } + + // Get explain output for this query if we need it + _, pgsqlOK := evalMap["postgresql"] + _, mysqlOK := evalMap["mysql"] + if rule.NeedsExplain && !(pgsqlOK || mysqlOK) { + if expl == nil { + fmt.Fprintf(c.Stderr, "%s: %s: %s: error explaining query: database connection required\n", query.Filename, query.Name, name) + errored = true + continue + } + engineOutput, err := expl.Explain(ctx, query.Text, query.Params...) + if err != nil { + fmt.Fprintf(c.Stderr, "%s: %s: %s: error explaining query: %s\n", query.Filename, query.Name, name, err) + errored = true + continue + } + + evalMap["postgresql"] = engineOutput.PostgreSQL + evalMap["mysql"] = engineOutput.MySQL + } + + if debugDumpVetEnv.Value() == "1" { + fmt.Printf("vars for rule '%s' evaluating against query '%s':\n", name, query.Name) + debug.DumpAsJSON(evalMap) + } + + out, _, err := (*rule.Program).Eval(evalMap) + if err != nil { + return err + } + tripped, ok := out.Value().(bool) + if !ok { + return fmt.Errorf("expression returned non-bool value: %v", out.Value()) + } + if tripped { + // TODO: Get line numbers in the output + if rule.Message == "" { + fmt.Fprintf(c.Stderr, "%s: %s: %s\n", query.Filename, query.Name, name) + } else { + fmt.Fprintf(c.Stderr, "%s: %s: %s: %s\n", query.Filename, query.Name, name, rule.Message) + } + errored = true + } + } + } + } + + if errored { + return ErrFailedChecks + } + return nil +} + +func vetConfig(req *plugin.GenerateRequest) *vet.Config { + return &vet.Config{ + Version: req.Settings.Version, + Engine: req.Settings.Engine, + Schema: req.Settings.Schema, + Queries: req.Settings.Queries, + } +} + +func vetQuery(q *plugin.Query) *vet.Query { + var params []*vet.Parameter + for _, p := range q.Params { + params = append(params, &vet.Parameter{ + Number: p.Number, + }) + } + return &vet.Query{ + Sql: q.Text, + Name: q.Name, + Cmd: strings.TrimPrefix(q.Cmd, ":"), + Params: params, + } +} + +type vetEngineOutput struct { + PostgreSQL *vet.PostgreSQL + MySQL *vet.MySQL +} diff --git a/internal/cmd/vet_sqlite.go b/internal/cmd/vet_sqlite.go new file mode 100644 index 0000000..ed79fe7 --- /dev/null +++ b/internal/cmd/vet_sqlite.go @@ -0,0 +1,7 @@ +package cmd + +import ( + _ "github.com/ncruces/go-sqlite3/driver" + + _ "github.com/sqlc-dev/sqlc/internal/sqlite3ext" +) diff --git a/internal/codegen/golang/driver.go b/internal/codegen/golang/driver.go new file mode 100644 index 0000000..5e3a533 --- /dev/null +++ b/internal/codegen/golang/driver.go @@ -0,0 +1,14 @@ +package golang + +import "github.com/sqlc-dev/sqlc/internal/codegen/golang/opts" + +func parseDriver(sqlPackage string) opts.SQLDriver { + switch sqlPackage { + case opts.SQLPackagePGXV4: + return opts.SQLDriverPGXV4 + case opts.SQLPackagePGXV5: + return opts.SQLDriverPGXV5 + default: + return opts.SQLDriverLibPQ + } +} diff --git a/internal/codegen/golang/enum.go b/internal/codegen/golang/enum.go new file mode 100644 index 0000000..f429551 --- /dev/null +++ b/internal/codegen/golang/enum.go @@ -0,0 +1,64 @@ +package golang + +import ( + "strings" + "unicode" +) + +type Constant struct { + Name string + Type string + Value string +} + +type Enum struct { + Name string + Comment string + Constants []Constant + NameTags map[string]string + ValidTags map[string]string +} + +func (e Enum) NameTag() string { + return TagsToString(e.NameTags) +} + +func (e Enum) ValidTag() string { + return TagsToString(e.ValidTags) +} + +func enumReplacer(r rune) rune { + if strings.ContainsRune("-/:_", r) { + return '_' + } else if (r >= 'a' && r <= 'z') || + (r >= 'A' && r <= 'Z') || + (r >= '0' && r <= '9') { + return r + } else { + return -1 + } +} + +// EnumReplace removes all non ident symbols (all but letters, numbers and +// underscore) and returns valid ident name for provided name. +func EnumReplace(value string) string { + return strings.Map(enumReplacer, value) +} + +// EnumValueName removes all non ident symbols (all but letters, numbers and +// underscore) and converts snake case ident to camel case. +func EnumValueName(value string) string { + parts := strings.Split(EnumReplace(value), "_") + for i, part := range parts { + parts[i] = titleFirst(part) + } + + return strings.Join(parts, "") +} + +func titleFirst(s string) string { + r := []rune(s) + r[0] = unicode.ToUpper(r[0]) + + return string(r) +} diff --git a/internal/codegen/golang/field.go b/internal/codegen/golang/field.go new file mode 100644 index 0000000..90ea1a7 --- /dev/null +++ b/internal/codegen/golang/field.go @@ -0,0 +1,143 @@ +package golang + +import ( + "fmt" + "regexp" + "sort" + "strings" + + "github.com/sqlc-dev/sqlc/internal/codegen/golang/opts" + "github.com/sqlc-dev/sqlc/internal/plugin" +) + +type Field struct { + Name string // CamelCased name for Go + DBName string // Name as used in the DB + Type string + Tags map[string]string + Comment string + Column *plugin.Column + // EmbedFields contains the embedded fields that require scanning. + EmbedFields []Field +} + +func (gf Field) Tag() string { + return TagsToString(gf.Tags) +} + +func (gf Field) HasSqlcSlice() bool { + return gf.Column.IsSqlcSlice +} + +func TagsToString(tags map[string]string) string { + if len(tags) == 0 { + return "" + } + tagParts := make([]string, 0, len(tags)) + for key, val := range tags { + tagParts = append(tagParts, fmt.Sprintf("%s:%q", key, val)) + } + sort.Strings(tagParts) + return strings.Join(tagParts, " ") +} + +func JSONTagName(name string, options *opts.Options) string { + style := options.JsonTagsCaseStyle + idUppercase := options.JsonTagsIdUppercase + if style == "" || style == "none" { + return name + } else { + return SetJSONCaseStyle(name, style, idUppercase) + } +} + +func SetCaseStyle(name string, style string) string { + switch style { + case "camel": + return toCamelCase(name) + case "pascal": + return toPascalCase(name) + case "snake": + return toSnakeCase(name) + default: + panic(fmt.Sprintf("unsupported JSON tags case style: '%s'", style)) + } +} + +func SetJSONCaseStyle(name string, style string, idUppercase bool) string { + switch style { + case "camel": + return toJsonCamelCase(name, idUppercase) + case "pascal": + return toPascalCase(name) + case "snake": + return toSnakeCase(name) + default: + panic(fmt.Sprintf("unsupported JSON tags case style: '%s'", style)) + } +} + +var camelPattern = regexp.MustCompile("[^A-Z][A-Z]+") + +func toSnakeCase(s string) string { + if !strings.ContainsRune(s, '_') { + s = camelPattern.ReplaceAllStringFunc(s, func(x string) string { + return x[:1] + "_" + x[1:] + }) + } + return strings.ToLower(s) +} + +func toCamelCase(s string) string { + return toCamelInitCase(s, false) +} + +func toPascalCase(s string) string { + return toCamelInitCase(s, true) +} + +func toCamelInitCase(name string, initUpper bool) string { + var out strings.Builder + for i, p := range strings.Split(name, "_") { + if !initUpper && i == 0 { + out.WriteString(p) + continue + } + if p == "id" { + out.WriteString("ID") + } else { + out.WriteString(strings.Title(p)) + } + } + return out.String() +} + +func toJsonCamelCase(name string, idUppercase bool) string { + var out strings.Builder + idStr := "Id" + + if idUppercase { + idStr = "ID" + } + + for i, p := range strings.Split(name, "_") { + if i == 0 { + out.WriteString(p) + continue + } + if p == "id" { + out.WriteString(idStr) + } else { + out.WriteString(strings.Title(p)) + } + } + return out.String() +} + +func toLowerCase(str string) string { + if str == "" { + return "" + } + + return strings.ToLower(str[:1]) + str[1:] +} diff --git a/internal/codegen/golang/gen.go b/internal/codegen/golang/gen.go new file mode 100644 index 0000000..332fe24 --- /dev/null +++ b/internal/codegen/golang/gen.go @@ -0,0 +1,426 @@ +package golang + +import ( + "bufio" + "bytes" + "context" + "errors" + "fmt" + "go/format" + "slices" + "strings" + "text/template" + + "github.com/sqlc-dev/sqlc/internal/codegen/golang/opts" + "github.com/sqlc-dev/sqlc/internal/codegen/sdk" + "github.com/sqlc-dev/sqlc/internal/metadata" + "github.com/sqlc-dev/sqlc/internal/plugin" +) + +type tmplCtx struct { + Q string + Package string + ModelsPackage string + SQLDriver opts.SQLDriver + Enums []Enum + Structs []Struct + GoQueries []Query + SqlcVersion string + + // TODO: Race conditions + SourceName string + + EmitJSONTags bool + JsonTagsIDUppercase bool + EmitDBTags bool + EmitPreparedQueries bool + EmitInterface bool + EmitEmptySlices bool + EmitMethodsWithDBArgument bool + EmitEnumValidMethod bool + EmitAllEnumValues bool + UsesCopyFrom bool + UsesBatch bool + OmitSqlcVersion bool + BuildTags string + WrapErrors bool +} + +func (t *tmplCtx) OutputQuery(sourceName string) bool { + return t.SourceName == sourceName +} + +func (t *tmplCtx) codegenDbarg() string { + if t.EmitMethodsWithDBArgument { + return "db DBTX, " + } + return "" +} + +// Called as a global method since subtemplate queryCodeStdExec does not have +// access to the toplevel tmplCtx +func (t *tmplCtx) codegenEmitPreparedQueries() bool { + return t.EmitPreparedQueries +} + +func (t *tmplCtx) codegenQueryMethod(q Query) string { + db := "q.db" + if t.EmitMethodsWithDBArgument { + db = "db" + } + + switch q.Cmd { + case ":one": + if t.EmitPreparedQueries { + return "q.queryRow" + } + return db + ".QueryRowContext" + + case ":many": + if t.EmitPreparedQueries { + return "q.query" + } + return db + ".QueryContext" + + default: + if t.EmitPreparedQueries { + return "q.exec" + } + return db + ".ExecContext" + } +} + +func (t *tmplCtx) codegenQueryRetval(q Query) (string, error) { + switch q.Cmd { + case ":one": + return "row :=", nil + case ":many": + return "rows, err :=", nil + case ":exec": + return "_, err :=", nil + case ":execrows", ":execlastid": + return "result, err :=", nil + case ":execresult": + if t.WrapErrors { + return "result, err :=", nil + } + return "return", nil + default: + return "", fmt.Errorf("unhandled q.Cmd case %q", q.Cmd) + } +} + +func Generate(ctx context.Context, req *plugin.GenerateRequest) (*plugin.GenerateResponse, error) { + options, err := opts.Parse(req) + if err != nil { + return nil, err + } + + if err := opts.ValidateOpts(options); err != nil { + return nil, err + } + + enums := buildEnums(req, options) + structs := buildStructs(req, options) + queries, err := buildQueries(req, options, enums, structs) + if err != nil { + return nil, err + } + + if options.OmitUnusedStructs { + enums, structs = filterUnusedStructs(enums, structs, queries, options.ModelsTypeQualifier()) + } + + if err := validate(options, enums, structs, queries); err != nil { + return nil, err + } + + return generate(req, options, enums, structs, queries) +} + +func validate(options *opts.Options, enums []Enum, structs []Struct, queries []Query) error { + enumNames := make(map[string]struct{}) + for _, enum := range enums { + enumNames[enum.Name] = struct{}{} + enumNames["Null"+enum.Name] = struct{}{} + } + structNames := make(map[string]struct{}) + for _, struckt := range structs { + if _, ok := enumNames[struckt.Name]; ok { + return fmt.Errorf("struct name conflicts with enum name: %s", struckt.Name) + } + structNames[struckt.Name] = struct{}{} + } + if !options.EmitExportedQueries { + return nil + } + for _, query := range queries { + if _, ok := enumNames[query.ConstantName]; ok { + return fmt.Errorf("query constant name conflicts with enum name: %s", query.ConstantName) + } + if _, ok := structNames[query.ConstantName]; ok { + return fmt.Errorf("query constant name conflicts with struct name: %s", query.ConstantName) + } + } + return nil +} + +func generate(req *plugin.GenerateRequest, options *opts.Options, enums []Enum, structs []Struct, queries []Query) (*plugin.GenerateResponse, error) { + i := &importer{ + Options: options, + Queries: queries, + Enums: enums, + Structs: structs, + } + + tctx := tmplCtx{ + EmitInterface: options.EmitInterface, + EmitJSONTags: options.EmitJsonTags, + JsonTagsIDUppercase: options.JsonTagsIdUppercase, + EmitDBTags: options.EmitDbTags, + EmitPreparedQueries: options.EmitPreparedQueries, + EmitEmptySlices: options.EmitEmptySlices, + EmitMethodsWithDBArgument: options.EmitMethodsWithDbArgument, + EmitEnumValidMethod: options.EmitEnumValidMethod, + EmitAllEnumValues: options.EmitAllEnumValues, + UsesCopyFrom: usesCopyFrom(queries), + UsesBatch: usesBatch(queries), + SQLDriver: parseDriver(options.SqlPackage), + Q: "`", + Package: options.Package, + ModelsPackage: options.ModelsPackage(), + Enums: enums, + Structs: structs, + SqlcVersion: req.SqlcVersion, + BuildTags: options.BuildTags, + OmitSqlcVersion: options.OmitSqlcVersion, + WrapErrors: options.WrapErrors, + } + + if tctx.UsesCopyFrom && !tctx.SQLDriver.IsPGX() && options.SqlDriver != opts.SQLDriverGoSQLDriverMySQL { + return nil, errors.New(":copyfrom is only supported by pgx and github.com/go-sql-driver/mysql") + } + + if tctx.UsesCopyFrom && options.SqlDriver == opts.SQLDriverGoSQLDriverMySQL { + if err := checkNoTimesForMySQLCopyFrom(queries); err != nil { + return nil, err + } + tctx.SQLDriver = opts.SQLDriverGoSQLDriverMySQL + } + + if tctx.UsesBatch && !tctx.SQLDriver.IsPGX() { + return nil, errors.New(":batch* commands are only supported by pgx") + } + + funcMap := template.FuncMap{ + "lowerTitle": sdk.LowerTitle, + "comment": sdk.DoubleSlashComment, + "escape": sdk.EscapeBacktick, + "imports": i.Imports, + "hasImports": i.HasImports, + "hasPrefix": strings.HasPrefix, + + // These methods are Go specific, they do not belong in the codegen package + // (as that is language independent) + "dbarg": tctx.codegenDbarg, + "emitPreparedQueries": tctx.codegenEmitPreparedQueries, + "queryMethod": tctx.codegenQueryMethod, + "queryRetval": tctx.codegenQueryRetval, + } + + tmpl := template.Must( + template.New("table"). + Funcs(funcMap). + ParseFS( + templates, + "templates/*.tmpl", + "templates/*/*.tmpl", + ), + ) + + output := map[string]string{} + + execute := func(name, templateName string) error { + imports := i.Imports(name) + replacedQueries := replaceConflictedArg(imports, queries) + + var b bytes.Buffer + w := bufio.NewWriter(&b) + tctx.SourceName = name + tctx.GoQueries = replacedQueries + err := tmpl.ExecuteTemplate(w, templateName, &tctx) + w.Flush() + if err != nil { + return err + } + code, err := format.Source(b.Bytes()) + if err != nil { + fmt.Println(b.String()) + return fmt.Errorf("source error: %w", err) + } + + if templateName == "queryFile" && options.OutputFilesSuffix != "" { + name += options.OutputFilesSuffix + } + + if !strings.HasSuffix(name, ".go") { + name += ".go" + } + output[name] = string(code) + return nil + } + + dbFileName := "db.go" + if options.OutputDbFileName != "" { + dbFileName = options.OutputDbFileName + } + modelsFileName := "models.go" + if options.OutputModelsFileName != "" { + modelsFileName = options.OutputModelsFileName + } + querierFileName := "querier.go" + if options.OutputQuerierFileName != "" { + querierFileName = options.OutputQuerierFileName + } + copyfromFileName := "copyfrom.go" + if options.OutputCopyfromFileName != "" { + copyfromFileName = options.OutputCopyfromFileName + } + + batchFileName := "batch.go" + if options.OutputBatchFileName != "" { + batchFileName = options.OutputBatchFileName + } + + if err := execute(dbFileName, "dbFile"); err != nil { + return nil, err + } + if options.ModelsEmitEnabled() { + if err := execute(modelsFileName, "modelsFile"); err != nil { + return nil, err + } + } + if options.EmitInterface { + if err := execute(querierFileName, "interfaceFile"); err != nil { + return nil, err + } + } + if tctx.UsesCopyFrom { + if err := execute(copyfromFileName, "copyfromFile"); err != nil { + return nil, err + } + } + if tctx.UsesBatch { + if err := execute(batchFileName, "batchFile"); err != nil { + return nil, err + } + } + + files := map[string]struct{}{} + for _, gq := range queries { + files[gq.SourceName] = struct{}{} + } + + for source := range files { + if err := execute(source, "queryFile"); err != nil { + return nil, err + } + } + resp := plugin.GenerateResponse{} + + for filename, code := range output { + resp.Files = append(resp.Files, &plugin.File{ + Name: filename, + Contents: []byte(code), + }) + } + + return &resp, nil +} + +func usesCopyFrom(queries []Query) bool { + for _, q := range queries { + if q.Cmd == metadata.CmdCopyFrom { + return true + } + } + return false +} + +func usesBatch(queries []Query) bool { + for _, q := range queries { + if slices.Contains([]string{metadata.CmdBatchExec, metadata.CmdBatchMany, metadata.CmdBatchOne}, q.Cmd) { + return true + } + } + return false +} + +func checkNoTimesForMySQLCopyFrom(queries []Query) error { + for _, q := range queries { + if q.Cmd != metadata.CmdCopyFrom { + continue + } + for _, f := range q.Arg.CopyFromMySQLFields() { + if f.Type == "time.Time" { + return fmt.Errorf("values with a timezone are not yet supported") + } + } + } + return nil +} + +func filterUnusedStructs(enums []Enum, structs []Struct, queries []Query, qualifier string) ([]Enum, []Struct) { + keepTypes := make(map[string]struct{}) + + keep := func(t string) { + keepTypes[t] = struct{}{} + // Also store the bare type name so that lookups against + // bare struct/enum names match even when types have been + // qualified with the models package prefix (e.g. "model.User"). + if bare := stripQualifier(t, qualifier); bare != t { + keepTypes[bare] = struct{}{} + } + } + + for _, query := range queries { + if !query.Arg.isEmpty() { + keep(query.Arg.Type()) + if query.Arg.IsStruct() { + for _, field := range query.Arg.Struct.Fields { + keep(field.Type) + } + } + } + if query.hasRetType() { + keep(query.Ret.Type()) + if query.Ret.IsStruct() { + for _, field := range query.Ret.Struct.Fields { + keep(strings.TrimPrefix(field.Type, "[]")) + for _, embedField := range field.EmbedFields { + keep(embedField.Type) + } + } + } + } + } + + keepEnums := make([]Enum, 0, len(enums)) + for _, enum := range enums { + _, keep := keepTypes[enum.Name] + _, keepNull := keepTypes["Null"+enum.Name] + _, keepPointer := keepTypes["*"+enum.Name] + if keep || keepNull || keepPointer { + keepEnums = append(keepEnums, enum) + } + } + + keepStructs := make([]Struct, 0, len(structs)) + for _, st := range structs { + if _, ok := keepTypes[st.Name]; ok { + keepStructs = append(keepStructs, st) + } + } + + return keepEnums, keepStructs +} diff --git a/internal/codegen/golang/go_type.go b/internal/codegen/golang/go_type.go new file mode 100644 index 0000000..7da5424 --- /dev/null +++ b/internal/codegen/golang/go_type.go @@ -0,0 +1,92 @@ +package golang + +import ( + "maps" + "strings" + + "github.com/sqlc-dev/sqlc/internal/codegen/golang/opts" + "github.com/sqlc-dev/sqlc/internal/codegen/sdk" + "github.com/sqlc-dev/sqlc/internal/plugin" +) + +func addExtraGoStructTags(tags map[string]string, req *plugin.GenerateRequest, options *opts.Options, col *plugin.Column) { + for _, override := range options.Overrides { + oride := override.ShimOverride + if oride.GoType.StructTags == nil { + continue + } + if override.MatchesColumn(col) { + maps.Copy(tags, oride.GoType.StructTags) + continue + } + if !override.Matches(col.Table, req.Catalog.DefaultSchema) { + // Different table. + continue + } + cname := col.Name + if col.OriginalName != "" { + cname = col.OriginalName + } + if !sdk.MatchString(oride.ColumnName, cname) { + // Different column. + continue + } + // Add the extra tags. + maps.Copy(tags, oride.GoType.StructTags) + } +} + +func goType(req *plugin.GenerateRequest, options *opts.Options, col *plugin.Column) string { + // Check if the column's type has been overridden + for _, override := range options.Overrides { + oride := override.ShimOverride + + if oride.GoType.TypeName == "" { + continue + } + cname := col.Name + if col.OriginalName != "" { + cname = col.OriginalName + } + sameTable := override.Matches(col.Table, req.Catalog.DefaultSchema) + if oride.Column != "" && sdk.MatchString(oride.ColumnName, cname) && sameTable { + if col.IsSqlcSlice { + return "[]" + oride.GoType.TypeName + } + return oride.GoType.TypeName + } + } + typ := goInnerType(req, options, col) + if col.IsSqlcSlice { + return "[]" + typ + } + if col.IsArray { + return strings.Repeat("[]", int(col.ArrayDims)) + typ + } + return typ +} + +func goInnerType(req *plugin.GenerateRequest, options *opts.Options, col *plugin.Column) string { + // package overrides have a higher precedence + for _, override := range options.Overrides { + oride := override.ShimOverride + if oride.GoType.TypeName == "" { + continue + } + if override.MatchesColumn(col) { + return oride.GoType.TypeName + } + } + + // TODO: Extend the engine interface to handle types + switch req.Settings.Engine { + case "mysql": + return mysqlType(req, options, col) + case "postgresql": + return postgresType(req, options, col) + case "sqlite": + return sqliteType(req, options, col) + default: + return "any" + } +} diff --git a/internal/codegen/golang/imports.go b/internal/codegen/golang/imports.go new file mode 100644 index 0000000..7696424 --- /dev/null +++ b/internal/codegen/golang/imports.go @@ -0,0 +1,537 @@ +package golang + +import ( + "fmt" + "sort" + "strings" + + "github.com/sqlc-dev/sqlc/internal/codegen/golang/opts" + "github.com/sqlc-dev/sqlc/internal/metadata" +) + +type fileImports struct { + Std []ImportSpec + Dep []ImportSpec +} + +type ImportSpec struct { + ID string + Path string +} + +func (s ImportSpec) String() string { + if s.ID != "" { + return fmt.Sprintf("%s %q", s.ID, s.Path) + } else { + return fmt.Sprintf("%q", s.Path) + } +} + +func mergeImports(imps ...fileImports) [][]ImportSpec { + if len(imps) == 1 { + return [][]ImportSpec{ + imps[0].Std, + imps[0].Dep, + } + } + + var stds, pkgs []ImportSpec + seenStd := map[string]struct{}{} + seenPkg := map[string]struct{}{} + for i := range imps { + for _, spec := range imps[i].Std { + if _, ok := seenStd[spec.Path]; ok { + continue + } + stds = append(stds, spec) + seenStd[spec.Path] = struct{}{} + } + for _, spec := range imps[i].Dep { + if _, ok := seenPkg[spec.Path]; ok { + continue + } + pkgs = append(pkgs, spec) + seenPkg[spec.Path] = struct{}{} + } + } + return [][]ImportSpec{stds, pkgs} +} + +type importer struct { + Options *opts.Options + Queries []Query + Enums []Enum + Structs []Struct +} + +func (i *importer) usesType(typ string) bool { + for _, strct := range i.Structs { + for _, f := range strct.Fields { + if hasPrefixIgnoringSliceAndPointerPrefix(f.Type, typ) { + return true + } + } + } + return false +} + +func (i *importer) HasImports(filename string) bool { + imports := i.Imports(filename) + return len(imports[0]) != 0 || len(imports[1]) != 0 +} + +func (i *importer) Imports(filename string) [][]ImportSpec { + dbFileName := "db.go" + if i.Options.OutputDbFileName != "" { + dbFileName = i.Options.OutputDbFileName + } + modelsFileName := "models.go" + if i.Options.OutputModelsFileName != "" { + modelsFileName = i.Options.OutputModelsFileName + } + querierFileName := "querier.go" + if i.Options.OutputQuerierFileName != "" { + querierFileName = i.Options.OutputQuerierFileName + } + copyfromFileName := "copyfrom.go" + if i.Options.OutputCopyfromFileName != "" { + copyfromFileName = i.Options.OutputCopyfromFileName + } + batchFileName := "batch.go" + if i.Options.OutputBatchFileName != "" { + batchFileName = i.Options.OutputBatchFileName + } + + switch filename { + case dbFileName: + return mergeImports(i.dbImports()) + case modelsFileName: + return mergeImports(i.modelImports()) + case querierFileName: + return mergeImports(i.interfaceImports()) + case copyfromFileName: + return mergeImports(i.copyfromImports()) + case batchFileName: + return mergeImports(i.batchImports()) + default: + return mergeImports(i.queryImports(filename)) + } +} + +func (i *importer) dbImports() fileImports { + var pkg []ImportSpec + std := []ImportSpec{ + {Path: "context"}, + } + + sqlpkg := parseDriver(i.Options.SqlPackage) + switch sqlpkg { + case opts.SQLDriverPGXV4: + pkg = append(pkg, ImportSpec{Path: "github.com/jackc/pgconn"}) + pkg = append(pkg, ImportSpec{Path: "github.com/jackc/pgx/v4"}) + case opts.SQLDriverPGXV5: + pkg = append(pkg, ImportSpec{Path: "github.com/jackc/pgx/v5/pgconn"}) + pkg = append(pkg, ImportSpec{Path: "github.com/jackc/pgx/v5"}) + default: + std = append(std, ImportSpec{Path: "database/sql"}) + if i.Options.EmitPreparedQueries { + std = append(std, ImportSpec{Path: "fmt"}) + } + } + + sort.Slice(std, func(i, j int) bool { return std[i].Path < std[j].Path }) + sort.Slice(pkg, func(i, j int) bool { return pkg[i].Path < pkg[j].Path }) + return fileImports{Std: std, Dep: pkg} +} + +var stdlibTypes = map[string]string{ + "json.RawMessage": "encoding/json", + "time.Time": "time", + "net.IP": "net", + "net.HardwareAddr": "net", + "netip.Addr": "net/netip", + "netip.Prefix": "net/netip", +} + +var pqtypeTypes = map[string]struct{}{ + "pqtype.CIDR": {}, + "pqtype.Inet": {}, + "pqtype.Macaddr": {}, + "pqtype.NullRawMessage": {}, +} + +func buildImports(options *opts.Options, queries []Query, uses func(string) bool) (map[string]struct{}, map[ImportSpec]struct{}) { + pkg := make(map[ImportSpec]struct{}) + std := make(map[string]struct{}) + + if uses("sql.Null") { + std["database/sql"] = struct{}{} + } + + sqlpkg := parseDriver(options.SqlPackage) + for _, q := range queries { + if q.Cmd == metadata.CmdExecResult { + switch sqlpkg { + case opts.SQLDriverPGXV4: + pkg[ImportSpec{Path: "github.com/jackc/pgconn"}] = struct{}{} + case opts.SQLDriverPGXV5: + pkg[ImportSpec{Path: "github.com/jackc/pgx/v5/pgconn"}] = struct{}{} + default: + std["database/sql"] = struct{}{} + } + } + } + + for typeName, pkg := range stdlibTypes { + if uses(typeName) { + std[pkg] = struct{}{} + } + } + + if uses("pgtype.") { + if sqlpkg == opts.SQLDriverPGXV5 { + pkg[ImportSpec{Path: "github.com/jackc/pgx/v5/pgtype"}] = struct{}{} + } else { + pkg[ImportSpec{Path: "github.com/jackc/pgtype"}] = struct{}{} + } + } + + for typeName := range pqtypeTypes { + if uses(typeName) { + pkg[ImportSpec{Path: "github.com/sqlc-dev/pqtype"}] = struct{}{} + break + } + } + + overrideTypes := map[string]string{} + for _, override := range options.Overrides { + o := override.ShimOverride + if o.GoType.BasicType || o.GoType.TypeName == "" { + continue + } + overrideTypes[o.GoType.TypeName] = o.GoType.ImportPath + } + + _, overrideNullTime := overrideTypes["pq.NullTime"] + if uses("pq.NullTime") && !overrideNullTime { + pkg[ImportSpec{Path: "github.com/lib/pq"}] = struct{}{} + } + _, overrideUUID := overrideTypes["uuid.UUID"] + if uses("uuid.UUID") && !overrideUUID { + pkg[ImportSpec{Path: "github.com/google/uuid"}] = struct{}{} + } + _, overrideNullUUID := overrideTypes["uuid.NullUUID"] + if uses("uuid.NullUUID") && !overrideNullUUID { + pkg[ImportSpec{Path: "github.com/google/uuid"}] = struct{}{} + } + _, overrideVector := overrideTypes["pgvector.Vector"] + if uses("pgvector.Vector") && !overrideVector { + pkg[ImportSpec{Path: "github.com/pgvector/pgvector-go"}] = struct{}{} + } + + // Custom imports + for _, override := range options.Overrides { + o := override.ShimOverride + + if o.GoType.BasicType || o.GoType.TypeName == "" { + continue + } + _, alreadyImported := std[o.GoType.ImportPath] + hasPackageAlias := o.GoType.Package != "" + if (!alreadyImported || hasPackageAlias) && uses(o.GoType.TypeName) { + pkg[ImportSpec{Path: o.GoType.ImportPath, ID: o.GoType.Package}] = struct{}{} + } + } + + // Models package import. When models live in a separate Go package and + // any type in this file references a qualified model type, import the + // models package under a fixed `models` alias so query files always + // reference types as `models.User` regardless of how the actual + // package is named. + if options.ModelsAreExternal() { + if uses(options.ModelsTypeQualifier()) { + pkg[ImportSpec{Path: options.OutputModelsImport, ID: opts.ModelsImportAlias}] = struct{}{} + } + } + + return std, pkg +} + +func (i *importer) interfaceImports() fileImports { + std, pkg := buildImports(i.Options, i.Queries, func(name string) bool { + for _, q := range i.Queries { + if q.hasRetType() { + if usesBatch([]Query{q}) { + continue + } + if hasPrefixIgnoringSliceAndPointerPrefix(q.Ret.Type(), name) { + return true + } + } + for _, f := range q.Arg.Pairs() { + if hasPrefixIgnoringSliceAndPointerPrefix(f.Type, name) { + return true + } + } + } + return false + }) + + std["context"] = struct{}{} + + return sortedImports(std, pkg) +} + +func (i *importer) modelImports() fileImports { + std, pkg := buildImports(i.Options, nil, i.usesType) + + if len(i.Enums) > 0 { + std["fmt"] = struct{}{} + std["database/sql/driver"] = struct{}{} + } + + return sortedImports(std, pkg) +} + +func sortedImports(std map[string]struct{}, pkg map[ImportSpec]struct{}) fileImports { + pkgs := make([]ImportSpec, 0, len(pkg)) + for spec := range pkg { + pkgs = append(pkgs, spec) + } + stds := make([]ImportSpec, 0, len(std)) + for path := range std { + stds = append(stds, ImportSpec{Path: path}) + } + sort.Slice(stds, func(i, j int) bool { return stds[i].Path < stds[j].Path }) + sort.Slice(pkgs, func(i, j int) bool { return pkgs[i].Path < pkgs[j].Path }) + return fileImports{stds, pkgs} +} + +func (i *importer) queryImports(filename string) fileImports { + var gq []Query + anyNonCopyFrom := false + for _, query := range i.Queries { + if usesBatch([]Query{query}) { + continue + } + if query.SourceName == filename { + gq = append(gq, query) + if query.Cmd != metadata.CmdCopyFrom { + anyNonCopyFrom = true + } + } + } + + std, pkg := buildImports(i.Options, gq, func(name string) bool { + for _, q := range gq { + if q.hasRetType() { + if q.Ret.EmitStruct() { + for _, f := range q.Ret.Struct.Fields { + if hasPrefixIgnoringSliceAndPointerPrefix(f.Type, name) { + return true + } + } + } + if hasPrefixIgnoringSliceAndPointerPrefix(q.Ret.Type(), name) { + return true + } + } + // Check the fields of the argument struct if it's emitted + if q.Arg.EmitStruct() { + for _, f := range q.Arg.Struct.Fields { + if hasPrefixIgnoringSliceAndPointerPrefix(f.Type, name) { + return true + } + } + } + // Check the argument pairs inside the method definition + for _, f := range q.Arg.Pairs() { + if hasPrefixIgnoringSliceAndPointerPrefix(f.Type, name) { + return true + } + } + } + return false + }) + + sliceScan := func() bool { + for _, q := range gq { + if q.hasRetType() { + if q.Ret.IsStruct() { + for _, f := range q.Ret.Struct.Fields { + if strings.HasPrefix(f.Type, "[]") && f.Type != "[]byte" { + return true + } + for _, embed := range f.EmbedFields { + if strings.HasPrefix(embed.Type, "[]") && embed.Type != "[]byte" { + return true + } + } + } + } else { + if strings.HasPrefix(q.Ret.Type(), "[]") && q.Ret.Type() != "[]byte" { + return true + } + } + } + if !q.Arg.isEmpty() { + if q.Arg.IsStruct() { + for _, f := range q.Arg.Struct.Fields { + if strings.HasPrefix(f.Type, "[]") && f.Type != "[]byte" && !f.HasSqlcSlice() { + return true + } + } + } else { + if strings.HasPrefix(q.Arg.Type(), "[]") && q.Arg.Type() != "[]byte" && !q.Arg.HasSqlcSlices() { + return true + } + } + } + } + return false + } + + // Search for sqlc.slice() calls + sqlcSliceScan := func() bool { + for _, q := range gq { + if q.Arg.HasSqlcSlices() { + return true + } + } + return false + } + + if anyNonCopyFrom { + std["context"] = struct{}{} + } + + sqlpkg := parseDriver(i.Options.SqlPackage) + if sqlcSliceScan() && !sqlpkg.IsPGX() { + std["strings"] = struct{}{} + } + if sliceScan() && !sqlpkg.IsPGX() { + pkg[ImportSpec{Path: "github.com/lib/pq"}] = struct{}{} + } + + if i.Options.WrapErrors { + std["fmt"] = struct{}{} + } + + return sortedImports(std, pkg) +} + +func (i *importer) copyfromImports() fileImports { + copyFromQueries := make([]Query, 0, len(i.Queries)) + for _, q := range i.Queries { + if q.Cmd == metadata.CmdCopyFrom { + copyFromQueries = append(copyFromQueries, q) + } + } + std, pkg := buildImports(i.Options, copyFromQueries, func(name string) bool { + for _, q := range copyFromQueries { + if q.hasRetType() { + if strings.HasPrefix(q.Ret.Type(), name) { + return true + } + } + if !q.Arg.isEmpty() { + if strings.HasPrefix(q.Arg.Type(), name) { + return true + } + } + } + return false + }) + + std["context"] = struct{}{} + if i.Options.SqlDriver == opts.SQLDriverGoSQLDriverMySQL { + std["io"] = struct{}{} + std["fmt"] = struct{}{} + std["sync/atomic"] = struct{}{} + pkg[ImportSpec{Path: "github.com/go-sql-driver/mysql"}] = struct{}{} + pkg[ImportSpec{Path: "github.com/hexon/mysqltsv"}] = struct{}{} + } + + return sortedImports(std, pkg) +} + +func (i *importer) batchImports() fileImports { + batchQueries := make([]Query, 0, len(i.Queries)) + for _, q := range i.Queries { + if usesBatch([]Query{q}) { + batchQueries = append(batchQueries, q) + } + } + std, pkg := buildImports(i.Options, batchQueries, func(name string) bool { + for _, q := range batchQueries { + if q.hasRetType() { + if q.Ret.EmitStruct() { + for _, f := range q.Ret.Struct.Fields { + if hasPrefixIgnoringSliceAndPointerPrefix(f.Type, name) { + return true + } + } + } + if hasPrefixIgnoringSliceAndPointerPrefix(q.Ret.Type(), name) { + return true + } + } + if q.Arg.EmitStruct() { + for _, f := range q.Arg.Struct.Fields { + if hasPrefixIgnoringSliceAndPointerPrefix(f.Type, name) { + return true + } + } + } + for _, f := range q.Arg.Pairs() { + if hasPrefixIgnoringSliceAndPointerPrefix(f.Type, name) { + return true + } + } + } + return false + }) + + std["context"] = struct{}{} + std["errors"] = struct{}{} + sqlpkg := parseDriver(i.Options.SqlPackage) + switch sqlpkg { + case opts.SQLDriverPGXV4: + pkg[ImportSpec{Path: "github.com/jackc/pgx/v4"}] = struct{}{} + case opts.SQLDriverPGXV5: + pkg[ImportSpec{Path: "github.com/jackc/pgx/v5"}] = struct{}{} + } + + return sortedImports(std, pkg) +} + +func trimSliceAndPointerPrefix(v string) string { + v = strings.TrimPrefix(v, "[]") + v = strings.TrimPrefix(v, "*") + return v +} + +func hasPrefixIgnoringSliceAndPointerPrefix(s, prefix string) bool { + trimmedS := trimSliceAndPointerPrefix(s) + trimmedPrefix := trimSliceAndPointerPrefix(prefix) + return strings.HasPrefix(trimmedS, trimmedPrefix) +} + +func replaceConflictedArg(imports [][]ImportSpec, queries []Query) []Query { + m := make(map[string]struct{}) + for _, is := range imports { + for _, i := range is { + paths := strings.Split(i.Path, "/") + m[paths[len(paths)-1]] = struct{}{} + } + } + + replacedQueries := make([]Query, 0, len(queries)) + for _, query := range queries { + if _, exist := m[query.Arg.Name]; exist { + query.Arg.Name = toCamelCase(fmt.Sprintf("arg_%s", query.Arg.Name)) + } + replacedQueries = append(replacedQueries, query) + } + return replacedQueries +} diff --git a/internal/codegen/golang/mysql_type.go b/internal/codegen/golang/mysql_type.go new file mode 100644 index 0000000..7586e02 --- /dev/null +++ b/internal/codegen/golang/mysql_type.go @@ -0,0 +1,144 @@ +package golang + +import ( + "log" + + "github.com/sqlc-dev/sqlc/internal/codegen/golang/opts" + "github.com/sqlc-dev/sqlc/internal/codegen/sdk" + "github.com/sqlc-dev/sqlc/internal/debug" + "github.com/sqlc-dev/sqlc/internal/plugin" +) + +func mysqlType(req *plugin.GenerateRequest, options *opts.Options, col *plugin.Column) string { + columnType := sdk.DataType(col.Type) + notNull := col.NotNull || col.IsArray + unsigned := col.Unsigned + + switch columnType { + + case "varchar", "text", "char", "tinytext", "mediumtext", "longtext": + if notNull { + return "string" + } + return "sql.NullString" + + case "tinyint": + if col.Length == 1 { + if notNull { + return "bool" + } + return "sql.NullBool" + } else { + if notNull { + if unsigned { + return "uint8" + } + return "int8" + } + // The database/sql package does not have a sql.NullInt8 type, so we + // use the smallest type they have which is NullInt16 + return "sql.NullInt16" + } + + case "year": + if notNull { + return "int16" + } + return "sql.NullInt16" + + case "smallint": + if notNull { + if unsigned { + return "uint16" + } + return "int16" + } + return "sql.NullInt16" + + case "int", "integer", "mediumint": + if notNull { + if unsigned { + return "uint32" + } + return "int32" + } + return "sql.NullInt32" + + case "bigint", "bigint unsigned", "bigint signed": + // "bigint unsigned" and "bigint signed" are MySQL CAST types + // Note: We use int64 for CAST AS UNSIGNED to match original behavior, + // even though uint64 would be more semantically correct. + // The Unsigned flag on columns (from table schema) still uses uint64. + if notNull { + if unsigned { + return "uint64" + } + return "int64" + } + return "sql.NullInt64" + + case "blob", "binary", "varbinary", "tinyblob", "mediumblob", "longblob": + if notNull { + return "[]byte" + } + return "sql.NullString" + + case "double", "double precision", "real", "float": + if notNull { + return "float64" + } + return "sql.NullFloat64" + + case "decimal", "dec", "fixed": + if notNull { + return "string" + } + return "sql.NullString" + + case "enum": + // TODO: Proper Enum support + return "string" + + case "date", "timestamp", "datetime", "time": + if notNull { + return "time.Time" + } + return "sql.NullTime" + + case "boolean", "bool": + if notNull { + return "bool" + } + return "sql.NullBool" + + case "json": + return "json.RawMessage" + + case "any": + return "any" + + default: + for _, schema := range req.Catalog.Schemas { + for _, enum := range schema.Enums { + if enum.Name == columnType { + if notNull { + if schema.Name == req.Catalog.DefaultSchema { + return StructName(enum.Name, options) + } + return StructName(schema.Name+"_"+enum.Name, options) + } else { + if schema.Name == req.Catalog.DefaultSchema { + return "Null" + StructName(enum.Name, options) + } + return "Null" + StructName(schema.Name+"_"+enum.Name, options) + } + } + } + } + if debug.Active { + log.Printf("Unknown MySQL type: %s\n", columnType) + } + return "any" + + } +} diff --git a/internal/codegen/golang/opts/enum.go b/internal/codegen/golang/opts/enum.go new file mode 100644 index 0000000..40457d0 --- /dev/null +++ b/internal/codegen/golang/opts/enum.go @@ -0,0 +1,64 @@ +package opts + +import "fmt" + +type SQLDriver string + +const ( + SQLPackagePGXV4 string = "pgx/v4" + SQLPackagePGXV5 string = "pgx/v5" + SQLPackageStandard string = "database/sql" +) + +var validPackages = map[string]struct{}{ + string(SQLPackagePGXV4): {}, + string(SQLPackagePGXV5): {}, + string(SQLPackageStandard): {}, +} + +func validatePackage(sqlPackage string) error { + if _, found := validPackages[sqlPackage]; !found { + return fmt.Errorf("unknown SQL package: %s", sqlPackage) + } + return nil +} + +const ( + SQLDriverPGXV4 SQLDriver = "github.com/jackc/pgx/v4" + SQLDriverPGXV5 = "github.com/jackc/pgx/v5" + SQLDriverLibPQ = "github.com/lib/pq" + SQLDriverGoSQLDriverMySQL = "github.com/go-sql-driver/mysql" +) + +var validDrivers = map[string]struct{}{ + string(SQLDriverPGXV4): {}, + string(SQLDriverPGXV5): {}, + string(SQLDriverLibPQ): {}, + string(SQLDriverGoSQLDriverMySQL): {}, +} + +func validateDriver(sqlDriver string) error { + if _, found := validDrivers[sqlDriver]; !found { + return fmt.Errorf("unknown SQL driver: %s", sqlDriver) + } + return nil +} + +func (d SQLDriver) IsPGX() bool { + return d == SQLDriverPGXV4 || d == SQLDriverPGXV5 +} + +func (d SQLDriver) IsGoSQLDriverMySQL() bool { + return d == SQLDriverGoSQLDriverMySQL +} + +func (d SQLDriver) Package() string { + switch d { + case SQLDriverPGXV4: + return SQLPackagePGXV4 + case SQLDriverPGXV5: + return SQLPackagePGXV5 + default: + return SQLPackageStandard + } +} diff --git a/internal/codegen/golang/opts/go_type.go b/internal/codegen/golang/opts/go_type.go new file mode 100644 index 0000000..723594c --- /dev/null +++ b/internal/codegen/golang/opts/go_type.go @@ -0,0 +1,192 @@ +package opts + +import ( + "encoding/json" + "fmt" + "go/types" + "regexp" + "strings" + + "github.com/fatih/structtag" +) + +type GoType struct { + Path string `json:"import" yaml:"import"` + Package string `json:"package" yaml:"package"` + Name string `json:"type" yaml:"type"` + Pointer bool `json:"pointer" yaml:"pointer"` + Slice bool `json:"slice" yaml:"slice"` + Spec string `json:"-"` + BuiltIn bool `json:"-"` +} + +type ParsedGoType struct { + ImportPath string + Package string + TypeName string + BasicType bool + StructTag string +} + +func (o *GoType) MarshalJSON() ([]byte, error) { + if o.Spec != "" { + return json.Marshal(o.Spec) + } + type alias GoType + return json.Marshal(alias(*o)) +} + +func (o *GoType) UnmarshalJSON(data []byte) error { + var spec string + if err := json.Unmarshal(data, &spec); err == nil { + *o = GoType{Spec: spec} + return nil + } + type alias GoType + var a alias + if err := json.Unmarshal(data, &a); err != nil { + return err + } + *o = GoType(a) + return nil +} + +func (o *GoType) UnmarshalYAML(unmarshal func(any) error) error { + var spec string + if err := unmarshal(&spec); err == nil { + *o = GoType{Spec: spec} + return nil + } + type alias GoType + var a alias + if err := unmarshal(&a); err != nil { + return err + } + *o = GoType(a) + return nil +} + +var validIdentifier = regexp.MustCompile(`^[a-zA-Z0-9_]+$`) +var versionNumber = regexp.MustCompile(`^v[0-9]+$`) +var invalidIdentifier = regexp.MustCompile(`[^a-zA-Z0-9_]`) + +func generatePackageID(importPath string) (string, bool) { + parts := strings.Split(importPath, "/") + name := parts[len(parts)-1] + // If the last part of the import path is a valid identifier, assume that's the package name + if versionNumber.MatchString(name) && len(parts) >= 2 { + name = parts[len(parts)-2] + return invalidIdentifier.ReplaceAllString(strings.ToLower(name), "_"), true + } + if validIdentifier.MatchString(name) { + return name, false + } + return invalidIdentifier.ReplaceAllString(strings.ToLower(name), "_"), true +} + +// validate GoType +func (gt GoType) parse() (*ParsedGoType, error) { + var o ParsedGoType + + if gt.Spec == "" { + // TODO: Validation + if gt.Path == "" && gt.Package != "" { + return nil, fmt.Errorf("Package override `go_type`: package name requires an import path") + } + var pkg string + var pkgNeedsAlias bool + + if gt.Package == "" && gt.Path != "" { + pkg, pkgNeedsAlias = generatePackageID(gt.Path) + if pkgNeedsAlias { + o.Package = pkg + } + } else { + pkg = gt.Package + o.Package = gt.Package + } + + o.ImportPath = gt.Path + o.TypeName = gt.Name + o.BasicType = gt.Path == "" && gt.Package == "" + if pkg != "" { + o.TypeName = pkg + "." + o.TypeName + } + if gt.Pointer { + o.TypeName = "*" + o.TypeName + } + if gt.Slice { + o.TypeName = "[]" + o.TypeName + } + return &o, nil + } + + input := gt.Spec + lastDot := strings.LastIndex(input, ".") + lastSlash := strings.LastIndex(input, "/") + typename := input + if lastDot == -1 && lastSlash == -1 { + // if the type name has no slash and no dot, validate that the type is a basic Go type + var found bool + for _, typ := range types.Typ { + info := typ.Info() + if info == 0 { + continue + } + if info&types.IsUntyped != 0 { + continue + } + if typename == typ.Name() { + found = true + } + } + if !found { + return nil, fmt.Errorf("Package override `go_type` specifier %q is not a Go basic type e.g. 'string'", input) + } + o.BasicType = true + } else { + // assume the type lives in a Go package + if lastDot == -1 { + return nil, fmt.Errorf("Package override `go_type` specifier %q is not the proper format, expected 'package.type', e.g. 'github.com/segmentio/ksuid.KSUID'", input) + } + typename = input[lastSlash+1:] + // a package name beginning with "go-" will give syntax errors in + // generated code. We should do the right thing and get the actual + // import name, but in lieu of that, stripping the leading "go-" may get + // us what we want. + typename = strings.TrimPrefix(typename, "go-") + typename = strings.TrimSuffix(typename, "-go") + o.ImportPath = input[:lastDot] + } + o.TypeName = typename + isPointer := input[0] == '*' + if isPointer { + o.ImportPath = o.ImportPath[1:] + o.TypeName = "*" + o.TypeName + } + return &o, nil +} + +// GoStructTag is a raw Go struct tag. +type GoStructTag string + +// Parse parses and validates a GoStructTag. +// The output is in a form convenient for codegen. +// +// Sample valid inputs/outputs: +// +// In Out +// empty string {} +// `a:"b"` {"a": "b"} +// `a:"b" x:"y,z"` {"a": "b", "x": "y,z"} +func (s GoStructTag) parse() (map[string]string, error) { + m := make(map[string]string) + tags, err := structtag.Parse(string(s)) + if err != nil { + return nil, err + } + for _, tag := range tags.Tags() { + m[tag.Key] = tag.Value() + } + return m, nil +} diff --git a/internal/codegen/golang/opts/options.go b/internal/codegen/golang/opts/options.go new file mode 100644 index 0000000..646bf1e --- /dev/null +++ b/internal/codegen/golang/opts/options.go @@ -0,0 +1,243 @@ +package opts + +import ( + "encoding/json" + "fmt" + "maps" + "path/filepath" + + "github.com/sqlc-dev/sqlc/internal/plugin" +) + +type Options struct { + EmitInterface bool `json:"emit_interface" yaml:"emit_interface"` + EmitJsonTags bool `json:"emit_json_tags" yaml:"emit_json_tags"` + JsonTagsIdUppercase bool `json:"json_tags_id_uppercase" yaml:"json_tags_id_uppercase"` + EmitDbTags bool `json:"emit_db_tags" yaml:"emit_db_tags"` + EmitPreparedQueries bool `json:"emit_prepared_queries" yaml:"emit_prepared_queries"` + EmitExactTableNames bool `json:"emit_exact_table_names,omitempty" yaml:"emit_exact_table_names"` + EmitEmptySlices bool `json:"emit_empty_slices,omitempty" yaml:"emit_empty_slices"` + EmitExportedQueries bool `json:"emit_exported_queries" yaml:"emit_exported_queries"` + EmitResultStructPointers bool `json:"emit_result_struct_pointers" yaml:"emit_result_struct_pointers"` + EmitParamsStructPointers bool `json:"emit_params_struct_pointers" yaml:"emit_params_struct_pointers"` + EmitMethodsWithDbArgument bool `json:"emit_methods_with_db_argument,omitempty" yaml:"emit_methods_with_db_argument"` + EmitPointersForNullTypes bool `json:"emit_pointers_for_null_types" yaml:"emit_pointers_for_null_types"` + // nil inherits EmitPointersForNullTypes; non-nil overrides for enums only. + EmitPointersForNullEnumTypes *bool `json:"emit_pointers_for_null_enum_types,omitempty" yaml:"emit_pointers_for_null_enum_types"` + EmitEnumValidMethod bool `json:"emit_enum_valid_method,omitempty" yaml:"emit_enum_valid_method"` + EmitAllEnumValues bool `json:"emit_all_enum_values,omitempty" yaml:"emit_all_enum_values"` + EmitSqlAsComment bool `json:"emit_sql_as_comment,omitempty" yaml:"emit_sql_as_comment"` + JsonTagsCaseStyle string `json:"json_tags_case_style,omitempty" yaml:"json_tags_case_style"` + Package string `json:"package" yaml:"package"` + Out string `json:"out" yaml:"out"` + Overrides []Override `json:"overrides,omitempty" yaml:"overrides"` + Rename map[string]string `json:"rename,omitempty" yaml:"rename"` + SqlPackage string `json:"sql_package" yaml:"sql_package"` + SqlDriver string `json:"sql_driver" yaml:"sql_driver"` + OutputBatchFileName string `json:"output_batch_file_name,omitempty" yaml:"output_batch_file_name"` + OutputDbFileName string `json:"output_db_file_name,omitempty" yaml:"output_db_file_name"` + OutputModelsFileName string `json:"output_models_file_name,omitempty" yaml:"output_models_file_name"` + OutputModelsPath string `json:"output_models_path,omitempty" yaml:"output_models_path"` + OutputModelsPackage string `json:"output_models_package,omitempty" yaml:"output_models_package"` + OutputModelsImport string `json:"output_models_import,omitempty" yaml:"output_models_import"` + OutputModelsEmit *bool `json:"output_models_emit,omitempty" yaml:"output_models_emit"` + OutputQuerierFileName string `json:"output_querier_file_name,omitempty" yaml:"output_querier_file_name"` + OutputCopyfromFileName string `json:"output_copyfrom_file_name,omitempty" yaml:"output_copyfrom_file_name"` + OutputFilesSuffix string `json:"output_files_suffix,omitempty" yaml:"output_files_suffix"` + InflectionExcludeTableNames []string `json:"inflection_exclude_table_names,omitempty" yaml:"inflection_exclude_table_names"` + WrapErrors bool `json:"wrap_errors,omitempty" yaml:"wrap_errors"` + QueryParameterLimit *int32 `json:"query_parameter_limit,omitempty" yaml:"query_parameter_limit"` + OmitSqlcVersion bool `json:"omit_sqlc_version,omitempty" yaml:"omit_sqlc_version"` + OmitUnusedStructs bool `json:"omit_unused_structs,omitempty" yaml:"omit_unused_structs"` + BuildTags string `json:"build_tags,omitempty" yaml:"build_tags"` + Initialisms *[]string `json:"initialisms,omitempty" yaml:"initialisms"` + + InitialismsMap map[string]struct{} `json:"-" yaml:"-"` +} + +type GlobalOptions struct { + Overrides []Override `json:"overrides,omitempty" yaml:"overrides"` + Rename map[string]string `json:"rename,omitempty" yaml:"rename"` +} + +func Parse(req *plugin.GenerateRequest) (*Options, error) { + options, err := parseOpts(req) + if err != nil { + return nil, err + } + global, err := parseGlobalOpts(req) + if err != nil { + return nil, err + } + if len(global.Overrides) > 0 { + options.Overrides = append(global.Overrides, options.Overrides...) + } + if len(global.Rename) > 0 { + if options.Rename == nil { + options.Rename = map[string]string{} + } + maps.Copy(options.Rename, global.Rename) + } + return options, nil +} + +func parseOpts(req *plugin.GenerateRequest) (*Options, error) { + var options Options + if len(req.PluginOptions) == 0 { + return &options, nil + } + if err := json.Unmarshal(req.PluginOptions, &options); err != nil { + return nil, fmt.Errorf("unmarshalling plugin options: %w", err) + } + + if options.Package == "" { + if options.Out != "" { + options.Package = filepath.Base(options.Out) + } else { + return nil, fmt.Errorf("invalid options: missing package name") + } + } + + // Default the models package name to the base of the models path. When + // the user only configures output_models_emit: false (no path), fall + // back to the base of the import path. + if options.OutputModelsPackage == "" { + if options.OutputModelsPath != "" { + options.OutputModelsPackage = filepath.Base(options.OutputModelsPath) + } else if options.OutputModelsImport != "" { + options.OutputModelsPackage = filepath.Base(options.OutputModelsImport) + } + } + + for i := range options.Overrides { + if err := options.Overrides[i].parse(req); err != nil { + return nil, err + } + } + + if options.SqlPackage != "" { + if err := validatePackage(options.SqlPackage); err != nil { + return nil, fmt.Errorf("invalid options: %s", err) + } + } + + if options.SqlDriver != "" { + if err := validateDriver(options.SqlDriver); err != nil { + return nil, fmt.Errorf("invalid options: %s", err) + } + } + + if options.QueryParameterLimit == nil { + options.QueryParameterLimit = new(int32) + *options.QueryParameterLimit = 1 + } + + if options.Initialisms == nil { + options.Initialisms = new([]string) + *options.Initialisms = []string{"id"} + } + + options.InitialismsMap = map[string]struct{}{} + for _, initial := range *options.Initialisms { + options.InitialismsMap[initial] = struct{}{} + } + + return &options, nil +} + +func parseGlobalOpts(req *plugin.GenerateRequest) (*GlobalOptions, error) { + var options GlobalOptions + if len(req.GlobalOptions) == 0 { + return &options, nil + } + if err := json.Unmarshal(req.GlobalOptions, &options); err != nil { + return nil, fmt.Errorf("unmarshalling global options: %w", err) + } + for i := range options.Overrides { + if err := options.Overrides[i].parse(req); err != nil { + return nil, err + } + } + return &options, nil +} + +func ValidateOpts(opts *Options) error { + if opts.EmitMethodsWithDbArgument && opts.EmitPreparedQueries { + return fmt.Errorf("invalid options: emit_methods_with_db_argument and emit_prepared_queries options are mutually exclusive") + } + if *opts.QueryParameterLimit < 0 { + return fmt.Errorf("invalid options: query parameter limit must not be negative") + } + + if err := validateModelsOptions(opts); err != nil { + return err + } + + return nil +} + +// ModelsEmitEnabled reports whether this codegen block should write the +// models file. Defaults to true when the option is unset. +func (o *Options) ModelsEmitEnabled() bool { + if o.OutputModelsEmit == nil { + return true + } + return *o.OutputModelsEmit +} + +// ModelsImportAlias is the fixed Go import alias used for the models +// package in query files. Using a constant alias keeps the type qualifier +// consistent regardless of how the user names the actual package. +const ModelsImportAlias = "models" + +// ModelsPackage returns the Go package name to use in the models file +// itself (i.e. the `package X` declaration). When the caller has not +// configured a separate models package, this is the same as Package. +func (o *Options) ModelsPackage() string { + if o.OutputModelsPackage != "" { + return o.OutputModelsPackage + } + return o.Package +} + +// ModelsAreExternal reports whether model types live in a different Go +// package than the queries package. When true, query files must import the +// models package and reference types as `models.Type`. +func (o *Options) ModelsAreExternal() bool { + return o.OutputModelsImport != "" +} + +// ModelsTypeQualifier returns the prefix to use when referencing a model +// type from a query file ("models."). Empty string when no qualifier is +// needed. +func (o *Options) ModelsTypeQualifier() string { + if o.ModelsAreExternal() { + return ModelsImportAlias + "." + } + return "" +} + +func validateModelsOptions(opts *Options) error { + hasAnyModelsOpt := opts.OutputModelsPath != "" || + opts.OutputModelsPackage != "" || + opts.OutputModelsImport != "" || + opts.OutputModelsEmit != nil + + if !hasAnyModelsOpt { + return nil + } + + if opts.OutputModelsImport == "" { + return fmt.Errorf("invalid options: output_models_import is required when any output_models_* option is set") + } + + if opts.ModelsEmitEnabled() && opts.OutputModelsPath == "" { + return fmt.Errorf("invalid options: output_models_path is required when emitting models to a separate package") + } + + if opts.ModelsEmitEnabled() && opts.OutputModelsPath == opts.Out { + return fmt.Errorf("invalid options: output_models_path matches out; models would overwrite the queries package") + } + + return nil +} diff --git a/internal/codegen/golang/opts/override.go b/internal/codegen/golang/opts/override.go new file mode 100644 index 0000000..6916c0c --- /dev/null +++ b/internal/codegen/golang/opts/override.go @@ -0,0 +1,176 @@ +package opts + +import ( + "fmt" + "os" + "strings" + + "github.com/sqlc-dev/sqlc/internal/codegen/sdk" + "github.com/sqlc-dev/sqlc/internal/pattern" + "github.com/sqlc-dev/sqlc/internal/plugin" +) + +type Override struct { + // name of the golang type to use, e.g. `github.com/segmentio/ksuid.KSUID` + GoType GoType `json:"go_type" yaml:"go_type"` + + // additional Go struct tags to add to this field, in raw Go struct tag form, e.g. `validate:"required" x:"y,z"` + // see https://github.com/sqlc-dev/sqlc/issues/534 + GoStructTag GoStructTag `json:"go_struct_tag" yaml:"go_struct_tag"` + + // fully qualified name of the Go type, e.g. `github.com/segmentio/ksuid.KSUID` + DBType string `json:"db_type" yaml:"db_type"` + Deprecated_PostgresType string `json:"postgres_type" yaml:"postgres_type"` + + // for global overrides only when two different engines are in use + Engine string `json:"engine,omitempty" yaml:"engine"` + + // True if the GoType should override if the matching type is nullable + Nullable bool `json:"nullable" yaml:"nullable"` + + // True if the GoType should override if the matching type is unsiged. + Unsigned bool `json:"unsigned" yaml:"unsigned"` + + // Deprecated. Use the `nullable` property instead + Deprecated_Null bool `json:"null" yaml:"null"` + + // fully qualified name of the column, e.g. `accounts.id` + Column string `json:"column" yaml:"column"` + + ColumnName *pattern.Match `json:"-"` + TableCatalog *pattern.Match `json:"-"` + TableSchema *pattern.Match `json:"-"` + TableRel *pattern.Match `json:"-"` + GoImportPath string `json:"-"` + GoPackage string `json:"-"` + GoTypeName string `json:"-"` + GoBasicType bool `json:"-"` + + // Parsed form of GoStructTag, e.g. {"validate:", "required"} + GoStructTags map[string]string `json:"-"` + ShimOverride *ShimOverride `json:"-"` +} + +func (o *Override) Matches(n *plugin.Identifier, defaultSchema string) bool { + if n == nil { + return false + } + schema := n.Schema + if n.Schema == "" { + schema = defaultSchema + } + if o.TableCatalog != nil && !o.TableCatalog.MatchString(n.Catalog) { + return false + } + if o.TableSchema == nil && schema != "" { + return false + } + if o.TableSchema != nil && !o.TableSchema.MatchString(schema) { + return false + } + if o.TableRel == nil && n.Name != "" { + return false + } + if o.TableRel != nil && !o.TableRel.MatchString(n.Name) { + return false + } + return true +} + +func (o *Override) MatchesColumn(col *plugin.Column) bool { + columnType := sdk.DataType(col.Type) + notNull := col.NotNull || col.IsArray + return o.DBType != "" && o.DBType == columnType && o.Nullable != notNull && o.Unsigned == col.Unsigned +} + +func (o *Override) parse(req *plugin.GenerateRequest) (err error) { + // validate deprecated postgres_type field + if o.Deprecated_PostgresType != "" { + fmt.Fprintf(os.Stderr, "WARNING: \"postgres_type\" is deprecated. Instead, use \"db_type\" to specify a type override.\n") + if o.DBType != "" { + return fmt.Errorf(`Type override configurations cannot have "db_type" and "postres_type" together. Use "db_type" alone`) + } + o.DBType = o.Deprecated_PostgresType + } + + // validate deprecated null field + if o.Deprecated_Null { + fmt.Fprintf(os.Stderr, "WARNING: \"null\" is deprecated. Instead, use the \"nullable\" field.\n") + o.Nullable = true + } + + schema := "public" + if req != nil && req.Catalog != nil { + schema = req.Catalog.DefaultSchema + } + + // validate option combinations + switch { + case o.Column != "" && o.DBType != "": + return fmt.Errorf("Override specifying both `column` (%q) and `db_type` (%q) is not valid.", o.Column, o.DBType) + case o.Column == "" && o.DBType == "": + return fmt.Errorf("Override must specify one of either `column` or `db_type`") + } + + // validate Column + if o.Column != "" { + colParts := strings.Split(o.Column, ".") + switch len(colParts) { + case 2: + if o.ColumnName, err = pattern.MatchCompile(colParts[1]); err != nil { + return err + } + if o.TableRel, err = pattern.MatchCompile(colParts[0]); err != nil { + return err + } + if o.TableSchema, err = pattern.MatchCompile(schema); err != nil { + return err + } + case 3: + if o.ColumnName, err = pattern.MatchCompile(colParts[2]); err != nil { + return err + } + if o.TableRel, err = pattern.MatchCompile(colParts[1]); err != nil { + return err + } + if o.TableSchema, err = pattern.MatchCompile(colParts[0]); err != nil { + return err + } + case 4: + if o.ColumnName, err = pattern.MatchCompile(colParts[3]); err != nil { + return err + } + if o.TableRel, err = pattern.MatchCompile(colParts[2]); err != nil { + return err + } + if o.TableSchema, err = pattern.MatchCompile(colParts[1]); err != nil { + return err + } + if o.TableCatalog, err = pattern.MatchCompile(colParts[0]); err != nil { + return err + } + default: + return fmt.Errorf("Override `column` specifier %q is not the proper format, expected '[catalog.][schema.]tablename.colname'", o.Column) + } + } + + // validate GoType + parsed, err := o.GoType.parse() + if err != nil { + return err + } + o.GoImportPath = parsed.ImportPath + o.GoPackage = parsed.Package + o.GoTypeName = parsed.TypeName + o.GoBasicType = parsed.BasicType + + // validate GoStructTag + tags, err := o.GoStructTag.parse() + if err != nil { + return err + } + o.GoStructTags = tags + + o.ShimOverride = shimOverride(req, o) + return nil +} diff --git a/internal/codegen/golang/opts/override_test.go b/internal/codegen/golang/opts/override_test.go new file mode 100644 index 0000000..8405666 --- /dev/null +++ b/internal/codegen/golang/opts/override_test.go @@ -0,0 +1,117 @@ +package opts + +import ( + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestTypeOverrides(t *testing.T) { + for _, test := range []struct { + override Override + pkg string + typeName string + basic bool + }{ + { + Override{ + DBType: "uuid", + GoType: GoType{Spec: "github.com/segmentio/ksuid.KSUID"}, + }, + "github.com/segmentio/ksuid", + "ksuid.KSUID", + false, + }, + // TODO: Add test for struct pointers + // + // { + // Override{ + // DBType: "uuid", + // GoType: "github.com/segmentio/*ksuid.KSUID", + // }, + // "github.com/segmentio/ksuid", + // "*ksuid.KSUID", + // false, + // }, + { + Override{ + DBType: "citext", + GoType: GoType{Spec: "string"}, + }, + "", + "string", + true, + }, + { + Override{ + DBType: "timestamp", + GoType: GoType{Spec: "time.Time"}, + }, + "time", + "time.Time", + false, + }, + } { + tt := test + t.Run(tt.override.GoType.Spec, func(t *testing.T) { + if err := tt.override.parse(nil); err != nil { + t.Fatalf("override parsing failed; %s", err) + } + if diff := cmp.Diff(tt.pkg, tt.override.GoImportPath); diff != "" { + t.Errorf("package mismatch;\n%s", diff) + } + if diff := cmp.Diff(tt.typeName, tt.override.GoTypeName); diff != "" { + t.Errorf("type name mismatch;\n%s", diff) + } + if diff := cmp.Diff(tt.basic, tt.override.GoBasicType); diff != "" { + t.Errorf("basic mismatch;\n%s", diff) + } + }) + } + for _, test := range []struct { + override Override + err string + }{ + { + Override{ + DBType: "uuid", + GoType: GoType{Spec: "Pointer"}, + }, + "Package override `go_type` specifier \"Pointer\" is not a Go basic type e.g. 'string'", + }, + { + Override{ + DBType: "uuid", + GoType: GoType{Spec: "untyped rune"}, + }, + "Package override `go_type` specifier \"untyped rune\" is not a Go basic type e.g. 'string'", + }, + } { + tt := test + t.Run(tt.override.GoType.Spec, func(t *testing.T) { + err := tt.override.parse(nil) + if err == nil { + t.Fatalf("expected parse to fail; got nil") + } + if diff := cmp.Diff(tt.err, err.Error()); diff != "" { + t.Errorf("error mismatch;\n%s", diff) + } + }) + } +} + +func FuzzOverride(f *testing.F) { + for _, spec := range []string{ + "string", + "github.com/gofrs/uuid.UUID", + "github.com/segmentio/ksuid.KSUID", + } { + f.Add(spec) + } + f.Fuzz(func(t *testing.T, s string) { + o := Override{ + GoType: GoType{Spec: s}, + } + o.parse(nil) + }) +} diff --git a/internal/codegen/golang/opts/shim.go b/internal/codegen/golang/opts/shim.go new file mode 100644 index 0000000..7912e17 --- /dev/null +++ b/internal/codegen/golang/opts/shim.go @@ -0,0 +1,77 @@ +package opts + +import ( + "strings" + + "github.com/sqlc-dev/sqlc/internal/plugin" +) + +// The ShimOverride struct exists to bridge the gap between the Override struct +// and the previous Override struct defined in codegen.proto. Eventually these +// shim structs should be removed in favor of using the existing Override and +// GoType structs, but it's easier to provide these shim structs to not change +// the existing, working code. +type ShimOverride struct { + DbType string + Nullable bool + Column string + Table *plugin.Identifier + ColumnName string + Unsigned bool + GoType *ShimGoType +} + +func shimOverride(req *plugin.GenerateRequest, o *Override) *ShimOverride { + var column string + var table plugin.Identifier + + if o.Column != "" { + colParts := strings.Split(o.Column, ".") + switch len(colParts) { + case 2: + table.Schema = req.Catalog.DefaultSchema + table.Name = colParts[0] + column = colParts[1] + case 3: + table.Schema = colParts[0] + table.Name = colParts[1] + column = colParts[2] + case 4: + table.Catalog = colParts[0] + table.Schema = colParts[1] + table.Name = colParts[2] + column = colParts[3] + } + } + return &ShimOverride{ + DbType: o.DBType, + Nullable: o.Nullable, + Unsigned: o.Unsigned, + Column: o.Column, + ColumnName: column, + Table: &table, + GoType: shimGoType(o), + } +} + +type ShimGoType struct { + ImportPath string + Package string + TypeName string + BasicType bool + StructTags map[string]string +} + +func shimGoType(o *Override) *ShimGoType { + // Note that there is a slight mismatch between this and the + // proto api. The GoType on the override is the unparsed type, + // which could be a qualified path or an object, as per + // https://docs.sqlc.dev/en/v1.18.0/reference/config.html#type-overriding + return &ShimGoType{ + ImportPath: o.GoImportPath, + Package: o.GoPackage, + TypeName: o.GoTypeName, + BasicType: o.GoBasicType, + StructTags: o.GoStructTags, + } +} diff --git a/internal/codegen/golang/postgresql_type.go b/internal/codegen/golang/postgresql_type.go new file mode 100644 index 0000000..3bdfed6 --- /dev/null +++ b/internal/codegen/golang/postgresql_type.go @@ -0,0 +1,619 @@ +package golang + +import ( + "fmt" + "log" + "strings" + + "github.com/sqlc-dev/sqlc/internal/codegen/golang/opts" + "github.com/sqlc-dev/sqlc/internal/codegen/sdk" + "github.com/sqlc-dev/sqlc/internal/debug" + "github.com/sqlc-dev/sqlc/internal/plugin" +) + +func parseIdentifierString(name string) (*plugin.Identifier, error) { + parts := strings.Split(name, ".") + switch len(parts) { + case 1: + return &plugin.Identifier{ + Name: parts[0], + }, nil + case 2: + return &plugin.Identifier{ + Schema: parts[0], + Name: parts[1], + }, nil + case 3: + return &plugin.Identifier{ + Catalog: parts[0], + Schema: parts[1], + Name: parts[2], + }, nil + default: + return nil, fmt.Errorf("invalid name: %s", name) + } +} + +func postgresType(req *plugin.GenerateRequest, options *opts.Options, col *plugin.Column) string { + columnType := sdk.DataType(col.Type) + notNull := col.NotNull || col.IsArray + driver := parseDriver(options.SqlPackage) + emitPointersForNull := driver.IsPGX() && options.EmitPointersForNullTypes + emitPointersForNullEnums := emitPointersForNull + if options.EmitPointersForNullEnumTypes != nil { + emitPointersForNullEnums = driver.IsPGX() && *options.EmitPointersForNullEnumTypes + } + + switch columnType { + case "serial", "serial4", "pg_catalog.serial4": + if notNull { + return "int32" + } + if emitPointersForNull { + return "*int32" + } + if driver == opts.SQLDriverPGXV5 { + return "pgtype.Int4" + } + return "sql.NullInt32" + + case "bigserial", "serial8", "pg_catalog.serial8": + if notNull { + return "int64" + } + if emitPointersForNull { + return "*int64" + } + if driver == opts.SQLDriverPGXV5 { + return "pgtype.Int8" + } + return "sql.NullInt64" + + case "smallserial", "serial2", "pg_catalog.serial2": + if notNull { + return "int16" + } + if emitPointersForNull { + return "*int16" + } + if driver == opts.SQLDriverPGXV5 { + return "pgtype.Int2" + } + return "sql.NullInt16" + + case "integer", "int", "int4", "pg_catalog.int4": + if notNull { + return "int32" + } + if emitPointersForNull { + return "*int32" + } + if driver == opts.SQLDriverPGXV5 { + return "pgtype.Int4" + } + return "sql.NullInt32" + + case "bigint", "int8", "pg_catalog.int8": + if notNull { + return "int64" + } + if emitPointersForNull { + return "*int64" + } + if driver == opts.SQLDriverPGXV5 { + return "pgtype.Int8" + } + return "sql.NullInt64" + + case "smallint", "int2", "pg_catalog.int2": + if notNull { + return "int16" + } + if emitPointersForNull { + return "*int16" + } + if driver == opts.SQLDriverPGXV5 { + return "pgtype.Int2" + } + return "sql.NullInt16" + + case "float", "double precision", "float8", "pg_catalog.float8": + if notNull { + return "float64" + } + if emitPointersForNull { + return "*float64" + } + if driver == opts.SQLDriverPGXV5 { + return "pgtype.Float8" + } + return "sql.NullFloat64" + + case "real", "float4", "pg_catalog.float4": + if notNull { + return "float32" + } + if emitPointersForNull { + return "*float32" + } + if driver == opts.SQLDriverPGXV5 { + return "pgtype.Float4" + } + return "sql.NullFloat64" // TODO: Change to sql.NullFloat32 after updating the go.mod file + + case "numeric", "pg_catalog.numeric", "money": + if driver.IsPGX() { + return "pgtype.Numeric" + } + // Since the Go standard library does not have a decimal type, lib/pq + // returns numerics as strings. + // + // https://github.com/lib/pq/issues/648 + if notNull { + return "string" + } + if emitPointersForNull { + return "*string" + } + return "sql.NullString" + + case "boolean", "bool", "pg_catalog.bool": + if notNull { + return "bool" + } + if emitPointersForNull { + return "*bool" + } + if driver == opts.SQLDriverPGXV5 { + return "pgtype.Bool" + } + return "sql.NullBool" + + case "json", "pg_catalog.json": + switch driver { + case opts.SQLDriverPGXV5: + return "[]byte" + case opts.SQLDriverPGXV4: + return "pgtype.JSON" + case opts.SQLDriverLibPQ: + if notNull { + return "json.RawMessage" + } else { + return "pqtype.NullRawMessage" + } + default: + return "any" + } + + case "jsonb", "pg_catalog.jsonb": + switch driver { + case opts.SQLDriverPGXV5: + return "[]byte" + case opts.SQLDriverPGXV4: + return "pgtype.JSONB" + case opts.SQLDriverLibPQ: + if notNull { + return "json.RawMessage" + } else { + return "pqtype.NullRawMessage" + } + default: + return "any" + } + + case "bytea", "blob", "pg_catalog.bytea": + return "[]byte" + + case "date": + if driver == opts.SQLDriverPGXV5 { + return "pgtype.Date" + } + if notNull { + return "time.Time" + } + if emitPointersForNull { + return "*time.Time" + } + return "sql.NullTime" + + case "pg_catalog.time", "time", "time without time zone": + if driver == opts.SQLDriverPGXV5 { + return "pgtype.Time" + } + if notNull { + return "time.Time" + } + if emitPointersForNull { + return "*time.Time" + } + return "sql.NullTime" + + case "pg_catalog.timetz", "timetz", "time with time zone": + if notNull { + return "time.Time" + } + if emitPointersForNull { + return "*time.Time" + } + return "sql.NullTime" + + case "pg_catalog.timestamp", "timestamp", "timestamp without time zone": + if driver == opts.SQLDriverPGXV5 { + return "pgtype.Timestamp" + } + if notNull { + return "time.Time" + } + if emitPointersForNull { + return "*time.Time" + } + return "sql.NullTime" + + case "pg_catalog.timestamptz", "timestamptz", "timestamp with time zone": + if driver == opts.SQLDriverPGXV5 { + return "pgtype.Timestamptz" + } + if notNull { + return "time.Time" + } + if emitPointersForNull { + return "*time.Time" + } + return "sql.NullTime" + + case "text", "pg_catalog.varchar", "varchar", "character varying", "pg_catalog.bpchar", "bpchar", "character", "string", "citext", "name": + if notNull { + return "string" + } + if emitPointersForNull { + return "*string" + } + if driver == opts.SQLDriverPGXV5 { + return "pgtype.Text" + } + return "sql.NullString" + + case "uuid": + if driver == opts.SQLDriverPGXV5 { + return "pgtype.UUID" + } + if notNull { + return "uuid.UUID" + } + if emitPointersForNull { + return "*uuid.UUID" + } + return "uuid.NullUUID" + + case "inet": + switch driver { + case opts.SQLDriverPGXV5: + if notNull { + return "netip.Addr" + } + return "*netip.Addr" + case opts.SQLDriverPGXV4: + return "pgtype.Inet" + case opts.SQLDriverLibPQ: + return "pqtype.Inet" + default: + return "any" + } + + case "cidr": + switch driver { + case opts.SQLDriverPGXV5: + if notNull { + return "netip.Prefix" + } + return "*netip.Prefix" + case opts.SQLDriverPGXV4: + return "pgtype.CIDR" + case opts.SQLDriverLibPQ: + return "pqtype.CIDR" + default: + return "any" + } + + case "macaddr", "macaddr8": + switch driver { + case opts.SQLDriverPGXV5: + return "net.HardwareAddr" + case opts.SQLDriverPGXV4: + return "pgtype.Macaddr" + case opts.SQLDriverLibPQ: + return "pqtype.Macaddr" + default: + return "any" + } + + case "ltree", "lquery", "ltxtquery": + // This module implements a data type ltree for representing labels + // of data stored in a hierarchical tree-like structure. Extensive + // facilities for searching through label trees are provided. + // + // https://www.postgresql.org/docs/current/ltree.html + if notNull { + return "string" + } + if emitPointersForNull { + return "*string" + } + if driver == opts.SQLDriverPGXV5 { + return "pgtype.Text" + } + return "sql.NullString" + + case "interval", "pg_catalog.interval": + if driver == opts.SQLDriverPGXV5 { + return "pgtype.Interval" + } + if notNull { + return "int64" + } + if emitPointersForNull { + return "*int64" + } + return "sql.NullInt64" + + case "daterange": + switch driver { + case opts.SQLDriverPGXV4: + return "pgtype.Daterange" + case opts.SQLDriverPGXV5: + return "pgtype.Range[pgtype.Date]" + default: + return "any" + } + + case "datemultirange": + switch driver { + case opts.SQLDriverPGXV5: + return "pgtype.Multirange[pgtype.Range[pgtype.Date]]" + default: + return "any" + } + + case "tsrange": + switch driver { + case opts.SQLDriverPGXV4: + return "pgtype.Tsrange" + case opts.SQLDriverPGXV5: + return "pgtype.Range[pgtype.Timestamp]" + default: + return "any" + } + + case "tsmultirange": + switch driver { + case opts.SQLDriverPGXV5: + return "pgtype.Multirange[pgtype.Range[pgtype.Timestamp]]" + default: + return "any" + } + + case "tstzrange": + switch driver { + case opts.SQLDriverPGXV4: + return "pgtype.Tstzrange" + case opts.SQLDriverPGXV5: + return "pgtype.Range[pgtype.Timestamptz]" + default: + return "any" + } + + case "tstzmultirange": + switch driver { + case opts.SQLDriverPGXV5: + return "pgtype.Multirange[pgtype.Range[pgtype.Timestamptz]]" + default: + return "any" + } + + case "numrange": + switch driver { + case opts.SQLDriverPGXV4: + return "pgtype.Numrange" + case opts.SQLDriverPGXV5: + return "pgtype.Range[pgtype.Numeric]" + default: + return "any" + } + + case "nummultirange": + switch driver { + case opts.SQLDriverPGXV5: + return "pgtype.Multirange[pgtype.Range[pgtype.Numeric]]" + default: + return "any" + } + + case "int4range": + switch driver { + case opts.SQLDriverPGXV4: + return "pgtype.Int4range" + case opts.SQLDriverPGXV5: + return "pgtype.Range[pgtype.Int4]" + default: + return "any" + } + + case "int4multirange": + switch driver { + case opts.SQLDriverPGXV5: + return "pgtype.Multirange[pgtype.Range[pgtype.Int4]]" + default: + return "any" + } + + case "int8range": + switch driver { + case opts.SQLDriverPGXV4: + return "pgtype.Int8range" + case opts.SQLDriverPGXV5: + return "pgtype.Range[pgtype.Int8]" + default: + return "any" + } + + case "int8multirange": + switch driver { + case opts.SQLDriverPGXV5: + return "pgtype.Multirange[pgtype.Range[pgtype.Int8]]" + default: + return "any" + } + + case "hstore": + if driver.IsPGX() { + return "pgtype.Hstore" + } + return "any" + + case "bit", "varbit", "bit varying", "pg_catalog.bit", "pg_catalog.varbit": + if driver == opts.SQLDriverPGXV5 { + return "pgtype.Bits" + } + if driver == opts.SQLDriverPGXV4 { + return "pgtype.Varbit" + } + + case "cid": + if driver == opts.SQLDriverPGXV5 { + return "pgtype.Uint32" + } + if driver == opts.SQLDriverPGXV4 { + return "pgtype.CID" + } + + case "oid": + if driver == opts.SQLDriverPGXV5 { + return "pgtype.Uint32" + } + if driver == opts.SQLDriverPGXV4 { + return "pgtype.OID" + } + + case "tid": + if driver.IsPGX() { + return "pgtype.TID" + } + + case "xid": + if driver == opts.SQLDriverPGXV5 { + return "pgtype.Uint32" + } + if driver == opts.SQLDriverPGXV4 { + return "pgtype.XID" + } + + case "xid8": + if driver == opts.SQLDriverPGXV5 { + return "pgtype.Uint64" + } + + case "box": + if driver.IsPGX() { + return "pgtype.Box" + } + + case "circle": + if driver.IsPGX() { + return "pgtype.Circle" + } + + case "line": + if driver.IsPGX() { + return "pgtype.Line" + } + + case "lseg": + if driver.IsPGX() { + return "pgtype.Lseg" + } + + case "path": + if driver.IsPGX() { + return "pgtype.Path" + } + + case "point": + if driver.IsPGX() { + return "pgtype.Point" + } + + case "polygon": + if driver.IsPGX() { + return "pgtype.Polygon" + } + + case "vector": + if driver == opts.SQLDriverPGXV5 { + if emitPointersForNull { + return "*pgvector.Vector" + } else { + return "pgvector.Vector" + } + } + + case "void": + // A void value can only be scanned into an empty interface. + return "any" + + case "any": + return "any" + + default: + rel, err := parseIdentifierString(columnType) + if err != nil { + // TODO: Should this actually return an error here? + return "any" + } + if rel.Schema == "" { + rel.Schema = req.Catalog.DefaultSchema + } + + for _, schema := range req.Catalog.Schemas { + if schema.Name == "pg_catalog" || schema.Name == "information_schema" { + continue + } + + for _, enum := range schema.Enums { + if rel.Name == enum.Name && rel.Schema == schema.Name { + if notNull { + if schema.Name == req.Catalog.DefaultSchema { + return StructName(enum.Name, options) + } + return StructName(schema.Name+"_"+enum.Name, options) + } else { + nullPrefix := "Null" + if emitPointersForNullEnums { + nullPrefix = "*" + } + if schema.Name == req.Catalog.DefaultSchema { + return nullPrefix + StructName(enum.Name, options) + } + return nullPrefix + StructName(schema.Name+"_"+enum.Name, options) + } + } + } + + for _, ct := range schema.CompositeTypes { + if rel.Name == ct.Name && rel.Schema == schema.Name { + if notNull { + return "string" + } + if emitPointersForNull { + return "*string" + } + return "sql.NullString" + } + } + } + } + + if debug.Active { + log.Printf("unknown PostgreSQL type: %s\n", columnType) + } + return "any" +} diff --git a/internal/codegen/golang/qualify.go b/internal/codegen/golang/qualify.go new file mode 100644 index 0000000..47577bf --- /dev/null +++ b/internal/codegen/golang/qualify.go @@ -0,0 +1,79 @@ +package golang + +import "strings" + +// stripQualifier removes a leading slice/pointer prefix and the given +// `pkg.` qualifier from a Go type expression. When the qualifier is empty +// or absent from the type, the input is returned unchanged. +func stripQualifier(t, qualifier string) string { + if qualifier == "" { + return t + } + var prefix strings.Builder + rest := t + for { + if strings.HasPrefix(rest, "[]") { + prefix.WriteString("[]") + rest = rest[2:] + continue + } + if strings.HasPrefix(rest, "*") { + prefix.WriteString("*") + rest = rest[1:] + continue + } + break + } + if strings.HasPrefix(rest, qualifier) { + return prefix.String() + rest[len(qualifier):] + } + return t +} + +// modelTypeSet is the set of Go type names that live in the models file. +type modelTypeSet map[string]struct{} + +// buildModelTypeSet returns the set of type names that are declared in +// models.go for the current codegen invocation. +func buildModelTypeSet(enums []Enum, structs []Struct) modelTypeSet { + set := make(modelTypeSet, len(enums)*4+len(structs)) + for _, e := range enums { + set[e.Name] = struct{}{} + set["Null"+e.Name] = struct{}{} + } + for _, s := range structs { + if s.IsModel { + set[s.Name] = struct{}{} + } + } + return set +} + +// qualifyType prefixes a Go type expression with `qualifier` when the bare +// type name belongs to `models`. Slice and pointer prefixes are preserved. +// When qualifier is empty (i.e. models live in the queries package), the +// input is returned unchanged. +func qualifyType(t string, models modelTypeSet, qualifier string) string { + if qualifier == "" || t == "" || len(models) == 0 { + return t + } + var prefix strings.Builder + rest := t + for { + if strings.HasPrefix(rest, "[]") { + prefix.WriteString("[]") + rest = rest[2:] + continue + } + if strings.HasPrefix(rest, "*") { + prefix.WriteString("*") + rest = rest[1:] + continue + } + break + } + if _, ok := models[rest]; ok { + return prefix.String() + qualifier + rest + } + return t +} diff --git a/internal/codegen/golang/query.go b/internal/codegen/golang/query.go new file mode 100644 index 0000000..27c596c --- /dev/null +++ b/internal/codegen/golang/query.go @@ -0,0 +1,308 @@ +package golang + +import ( + "fmt" + "strings" + + "github.com/sqlc-dev/sqlc/internal/codegen/golang/opts" + "github.com/sqlc-dev/sqlc/internal/metadata" + "github.com/sqlc-dev/sqlc/internal/plugin" +) + +type QueryValue struct { + Emit bool + EmitPointer bool + Name string + DBName string // The name of the field in the database. Only set if Struct==nil. + Struct *Struct + Typ string + SQLDriver opts.SQLDriver + + // ModelQualifier prefixes references to model types when the models file + // lives in a different Go package (e.g. "model."). Empty otherwise. + ModelQualifier string + + // Column is kept so late in the generation process around to differentiate + // between mysql slices and pg arrays + Column *plugin.Column +} + +func (v QueryValue) EmitStruct() bool { + return v.Emit +} + +func (v QueryValue) IsStruct() bool { + return v.Struct != nil +} + +func (v QueryValue) IsPointer() bool { + return v.EmitPointer && v.Struct != nil +} + +func (v QueryValue) isEmpty() bool { + return v.Typ == "" && v.Name == "" && v.Struct == nil +} + +type Argument struct { + Name string + Type string +} + +func (v QueryValue) Pair() string { + var out []string + for _, arg := range v.Pairs() { + out = append(out, arg.Name+" "+arg.Type) + } + return strings.Join(out, ",") +} + +// Return the argument name and type for query methods. Should only be used in +// the context of method arguments. +func (v QueryValue) Pairs() []Argument { + if v.isEmpty() { + return nil + } + if !v.EmitStruct() && v.IsStruct() { + var out []Argument + for _, f := range v.Struct.Fields { + out = append(out, Argument{ + Name: escape(toLowerCase(f.Name)), + Type: f.Type, + }) + } + return out + } + return []Argument{ + { + Name: escape(v.Name), + Type: v.DefineType(), + }, + } +} + +func (v QueryValue) SlicePair() string { + if v.isEmpty() { + return "" + } + return v.Name + " []" + v.DefineType() +} + +func (v QueryValue) Type() string { + if v.Typ != "" { + return v.Typ + } + if v.Struct != nil { + // Model structs (table-derived) live in the models file. When that + // file is generated into a different Go package, references from + // query files must be qualified. Synthetic structs (Params/Row) + // are defined in the same query file as their use, so they stay + // bare. + if v.Struct.IsModel && v.ModelQualifier != "" { + return v.ModelQualifier + v.Struct.Name + } + return v.Struct.Name + } + panic("no type for QueryValue: " + v.Name) +} + +func (v *QueryValue) DefineType() string { + t := v.Type() + if v.IsPointer() { + return "*" + t + } + return t +} + +func (v *QueryValue) ReturnName() string { + if v.IsPointer() { + return "&" + escape(v.Name) + } + return escape(v.Name) +} + +func (v QueryValue) UniqueFields() []Field { + seen := map[string]struct{}{} + fields := make([]Field, 0, len(v.Struct.Fields)) + + for _, field := range v.Struct.Fields { + if _, found := seen[field.Name]; found { + continue + } + seen[field.Name] = struct{}{} + fields = append(fields, field) + } + + return fields +} + +func (v QueryValue) Params() string { + if v.isEmpty() { + return "" + } + var out []string + if v.Struct == nil { + if !v.Column.IsSqlcSlice && strings.HasPrefix(v.Typ, "[]") && v.Typ != "[]byte" && !v.SQLDriver.IsPGX() { + out = append(out, "pq.Array("+escape(v.Name)+")") + } else { + out = append(out, escape(v.Name)) + } + } else { + for _, f := range v.Struct.Fields { + if !f.HasSqlcSlice() && strings.HasPrefix(f.Type, "[]") && f.Type != "[]byte" && !v.SQLDriver.IsPGX() { + out = append(out, "pq.Array("+escape(v.VariableForField(f))+")") + } else { + out = append(out, escape(v.VariableForField(f))) + } + } + } + if len(out) <= 3 { + return strings.Join(out, ",") + } + out = append(out, "") + return "\n" + strings.Join(out, ",\n") +} + +func (v QueryValue) ColumnNames() []string { + if v.Struct == nil { + return []string{v.DBName} + } + names := make([]string, len(v.Struct.Fields)) + for i, f := range v.Struct.Fields { + names[i] = f.DBName + } + return names +} + +func (v QueryValue) ColumnNamesAsGoSlice() string { + if v.Struct == nil { + return fmt.Sprintf("[]string{%q}", v.DBName) + } + escapedNames := make([]string, len(v.Struct.Fields)) + for i, f := range v.Struct.Fields { + if f.Column != nil && f.Column.OriginalName != "" { + escapedNames[i] = fmt.Sprintf("%q", f.Column.OriginalName) + } else { + escapedNames[i] = fmt.Sprintf("%q", f.DBName) + } + } + return "[]string{" + strings.Join(escapedNames, ", ") + "}" +} + +// When true, we have to build the arguments to q.db.QueryContext in addition to +// munging the SQL +func (v QueryValue) HasSqlcSlices() bool { + if v.Struct == nil { + return v.Column != nil && v.Column.IsSqlcSlice + } + for _, v := range v.Struct.Fields { + if v.Column.IsSqlcSlice { + return true + } + } + return false +} + +func (v QueryValue) Scan() string { + var out []string + if v.Struct == nil { + if strings.HasPrefix(v.Typ, "[]") && v.Typ != "[]byte" && !v.SQLDriver.IsPGX() { + out = append(out, "pq.Array(&"+v.Name+")") + } else { + out = append(out, "&"+v.Name) + } + } else { + for _, f := range v.Struct.Fields { + + // append any embedded fields + if len(f.EmbedFields) > 0 { + for _, embed := range f.EmbedFields { + if strings.HasPrefix(embed.Type, "[]") && embed.Type != "[]byte" && !v.SQLDriver.IsPGX() { + out = append(out, "pq.Array(&"+v.Name+"."+f.Name+"."+embed.Name+")") + } else { + out = append(out, "&"+v.Name+"."+f.Name+"."+embed.Name) + } + } + continue + } + + if strings.HasPrefix(f.Type, "[]") && f.Type != "[]byte" && !v.SQLDriver.IsPGX() { + out = append(out, "pq.Array(&"+v.Name+"."+f.Name+")") + } else { + out = append(out, "&"+v.Name+"."+f.Name) + } + } + } + if len(out) <= 3 { + return strings.Join(out, ",") + } + out = append(out, "") + return "\n" + strings.Join(out, ",\n") +} + +// Deprecated: This method does not respect the Emit field set on the +// QueryValue. It's used by the go-sql-driver-mysql/copyfromCopy.tmpl and should +// not be used other places. +func (v QueryValue) CopyFromMySQLFields() []Field { + // fmt.Printf("%#v\n", v) + if v.Struct != nil { + return v.Struct.Fields + } + return []Field{ + { + Name: v.Name, + DBName: v.DBName, + Type: v.Typ, + }, + } +} + +func (v QueryValue) VariableForField(f Field) string { + if !v.IsStruct() { + return v.Name + } + if !v.EmitStruct() { + return toLowerCase(f.Name) + } + return v.Name + "." + f.Name +} + +// A struct used to generate methods and fields on the Queries struct +type Query struct { + Cmd string + Comments []string + MethodName string + FieldName string + ConstantName string + SQL string + SourceName string + Ret QueryValue + Arg QueryValue + // Used for :copyfrom + Table *plugin.Identifier +} + +func (q Query) hasRetType() bool { + scanned := q.Cmd == metadata.CmdOne || q.Cmd == metadata.CmdMany || + q.Cmd == metadata.CmdBatchMany || q.Cmd == metadata.CmdBatchOne + return scanned && !q.Ret.isEmpty() +} + +func (q Query) TableIdentifierAsGoSlice() string { + escapedNames := make([]string, 0, 3) + for _, p := range []string{q.Table.Catalog, q.Table.Schema, q.Table.Name} { + if p != "" { + escapedNames = append(escapedNames, fmt.Sprintf("%q", p)) + } + } + return "[]string{" + strings.Join(escapedNames, ", ") + "}" +} + +func (q Query) TableIdentifierForMySQL() string { + escapedNames := make([]string, 0, 3) + for _, p := range []string{q.Table.Catalog, q.Table.Schema, q.Table.Name} { + if p != "" { + escapedNames = append(escapedNames, fmt.Sprintf("`%s`", p)) + } + } + return strings.Join(escapedNames, ".") +} diff --git a/internal/codegen/golang/reserved.go b/internal/codegen/golang/reserved.go new file mode 100644 index 0000000..e4a30c7 --- /dev/null +++ b/internal/codegen/golang/reserved.go @@ -0,0 +1,71 @@ +package golang + +func escape(s string) string { + if IsReserved(s) { + return s + "_" + } + return s +} + +func IsReserved(s string) bool { + switch s { + // Not a keyword, but generated code refers to the predeclared type + // `any`, so a package-scope identifier with that name would shadow it. + case "any": + return true + case "break": + return true + case "default": + return true + case "func": + return true + case "interface": + return true + case "select": + return true + case "case": + return true + case "defer": + return true + case "go": + return true + case "map": + return true + case "struct": + return true + case "chan": + return true + case "else": + return true + case "goto": + return true + case "package": + return true + case "switch": + return true + case "const": + return true + case "fallthrough": + return true + case "if": + return true + case "range": + return true + case "type": + return true + case "continue": + return true + case "for": + return true + case "import": + return true + case "return": + return true + case "var": + return true + case "q": + return true + default: + return false + } +} diff --git a/internal/codegen/golang/result.go b/internal/codegen/golang/result.go new file mode 100644 index 0000000..50d654a --- /dev/null +++ b/internal/codegen/golang/result.go @@ -0,0 +1,473 @@ +package golang + +import ( + "bufio" + "fmt" + "sort" + "strings" + + "github.com/sqlc-dev/sqlc/internal/codegen/golang/opts" + "github.com/sqlc-dev/sqlc/internal/codegen/sdk" + "github.com/sqlc-dev/sqlc/internal/inflection" + "github.com/sqlc-dev/sqlc/internal/metadata" + "github.com/sqlc-dev/sqlc/internal/plugin" +) + +func buildEnums(req *plugin.GenerateRequest, options *opts.Options) []Enum { + var enums []Enum + for _, schema := range req.Catalog.Schemas { + if schema.Name == "pg_catalog" || schema.Name == "information_schema" { + continue + } + for _, enum := range schema.Enums { + var enumName string + if schema.Name == req.Catalog.DefaultSchema { + enumName = enum.Name + } else { + enumName = schema.Name + "_" + enum.Name + } + + e := Enum{ + Name: StructName(enumName, options), + Comment: enum.Comment, + NameTags: map[string]string{}, + ValidTags: map[string]string{}, + } + if options.EmitJsonTags { + e.NameTags["json"] = JSONTagName(enumName, options) + e.ValidTags["json"] = JSONTagName("valid", options) + } + + seen := make(map[string]struct{}, len(enum.Vals)) + for i, v := range enum.Vals { + value := EnumReplace(v) + if _, found := seen[value]; found || value == "" { + value = fmt.Sprintf("value_%d", i) + } + e.Constants = append(e.Constants, Constant{ + Name: StructName(enumName+"_"+value, options), + Value: v, + Type: e.Name, + }) + seen[value] = struct{}{} + } + enums = append(enums, e) + } + } + if len(enums) > 0 { + sort.Slice(enums, func(i, j int) bool { return enums[i].Name < enums[j].Name }) + } + return enums +} + +func buildStructs(req *plugin.GenerateRequest, options *opts.Options) []Struct { + var structs []Struct + for _, schema := range req.Catalog.Schemas { + if schema.Name == "pg_catalog" || schema.Name == "information_schema" { + continue + } + for _, table := range schema.Tables { + var tableName string + if schema.Name == req.Catalog.DefaultSchema { + tableName = table.Rel.Name + } else { + tableName = schema.Name + "_" + table.Rel.Name + } + structName := tableName + if !options.EmitExactTableNames { + structName = inflection.Singular(inflection.SingularParams{ + Name: structName, + Exclusions: options.InflectionExcludeTableNames, + }) + } + s := Struct{ + Table: &plugin.Identifier{Schema: schema.Name, Name: table.Rel.Name}, + Name: StructName(structName, options), + Comment: table.Comment, + IsModel: true, + } + for _, column := range table.Columns { + tags := map[string]string{} + if options.EmitDbTags { + tags["db"] = column.Name + } + if options.EmitJsonTags { + tags["json"] = JSONTagName(column.Name, options) + } + addExtraGoStructTags(tags, req, options, column) + s.Fields = append(s.Fields, Field{ + Name: StructName(column.Name, options), + Type: goType(req, options, column), + Tags: tags, + Comment: column.Comment, + }) + } + structs = append(structs, s) + } + } + if len(structs) > 0 { + sort.Slice(structs, func(i, j int) bool { return structs[i].Name < structs[j].Name }) + } + return structs +} + +type goColumn struct { + id int + *plugin.Column + embed *goEmbed +} + +type goEmbed struct { + modelType string + modelName string + fields []Field +} + +// look through all the structs and attempt to find a matching one to embed +// We need the name of the struct and its field names. +func newGoEmbed(embed *plugin.Identifier, structs []Struct, defaultSchema string) *goEmbed { + if embed == nil { + return nil + } + + for _, s := range structs { + embedSchema := defaultSchema + if embed.Schema != "" { + embedSchema = embed.Schema + } + + // compare the other attributes + if embed.Catalog != s.Table.Catalog || embed.Name != s.Table.Name || embedSchema != s.Table.Schema { + continue + } + + fields := make([]Field, len(s.Fields)) + copy(fields, s.Fields) + + return &goEmbed{ + modelType: s.Name, + modelName: s.Name, + fields: fields, + } + } + + return nil +} + +func columnName(c *plugin.Column, pos int) string { + if c.Name != "" { + return c.Name + } + return fmt.Sprintf("column_%d", pos+1) +} + +func paramName(p *plugin.Parameter) string { + if p.Column.Name != "" { + return argName(p.Column.Name) + } + return fmt.Sprintf("dollar_%d", p.Number) +} + +func argName(name string) string { + var out strings.Builder + for i, p := range strings.Split(name, "_") { + if i == 0 { + out.WriteString(strings.ToLower(p)) + } else if p == "id" { + out.WriteString("ID") + } else { + out.WriteString(strings.Title(p)) + } + } + return out.String() +} + +func buildQueries(req *plugin.GenerateRequest, options *opts.Options, enums []Enum, structs []Struct) ([]Query, error) { + models := buildModelTypeSet(enums, structs) + qualifier := options.ModelsTypeQualifier() + qs := make([]Query, 0, len(req.Queries)) + for _, query := range req.Queries { + if query.Name == "" { + continue + } + if query.Cmd == "" { + continue + } + + var constantName string + if options.EmitExportedQueries { + constantName = sdk.Title(query.Name) + } else { + constantName = escape(sdk.LowerTitle(query.Name)) + } + + comments := query.Comments + if options.EmitSqlAsComment { + if len(comments) == 0 { + comments = append(comments, query.Name) + } + comments = append(comments, " ") + scanner := bufio.NewScanner(strings.NewReader(query.Text)) + for scanner.Scan() { + line := scanner.Text() + comments = append(comments, " "+line) + } + if err := scanner.Err(); err != nil { + return nil, err + } + } + + gq := Query{ + Cmd: query.Cmd, + ConstantName: constantName, + FieldName: sdk.LowerTitle(query.Name) + "Stmt", + MethodName: query.Name, + SourceName: query.Filename, + SQL: query.Text, + Comments: comments, + Table: query.InsertIntoTable, + } + sqlpkg := parseDriver(options.SqlPackage) + + qpl := int(*options.QueryParameterLimit) + + if len(query.Params) == 1 && qpl != 0 { + p := query.Params[0] + gq.Arg = QueryValue{ + Name: escape(paramName(p)), + DBName: p.Column.GetName(), + Typ: qualifyType(goType(req, options, p.Column), models, qualifier), + SQLDriver: sqlpkg, + ModelQualifier: qualifier, + Column: p.Column, + } + } else if len(query.Params) >= 1 { + var cols []goColumn + for _, p := range query.Params { + cols = append(cols, goColumn{ + id: int(p.Number), + Column: p.Column, + }) + } + s, err := columnsToStruct(req, options, gq.MethodName+"Params", cols, false, models, qualifier) + if err != nil { + return nil, err + } + gq.Arg = QueryValue{ + Emit: true, + Name: "arg", + Struct: s, + SQLDriver: sqlpkg, + EmitPointer: options.EmitParamsStructPointers, + ModelQualifier: qualifier, + } + + // if query params is 2, and query params limit is 4 AND this is a copyfrom, we still want to emit the query's model + // otherwise we end up with a copyfrom using a struct without the struct definition + if len(query.Params) <= qpl && query.Cmd != ":copyfrom" { + gq.Arg.Emit = false + } + } + + if len(query.Columns) == 1 && query.Columns[0].EmbedTable == nil { + c := query.Columns[0] + name := columnName(c, 0) + name = strings.Replace(name, "$", "_", -1) + retName := escape(name) + // For :one queries the scan destination lives in the same scope as + // the query parameters, so reusing a parameter's name would cause + // Scan to overwrite the input and leak it back to the caller on + // sql.ErrNoRows (see sqlc-dev/sqlc#4354). Rename the return + // variable when it would collide. + if query.Cmd == metadata.CmdOne { + argNames := map[string]struct{}{} + for _, p := range gq.Arg.Pairs() { + argNames[p.Name] = struct{}{} + } + for { + if _, conflict := argNames[retName]; !conflict { + break + } + retName += "_2" + } + } + gq.Ret = QueryValue{ + Name: retName, + DBName: name, + Typ: qualifyType(goType(req, options, c), models, qualifier), + SQLDriver: sqlpkg, + ModelQualifier: qualifier, + } + } else if putOutColumns(query) { + var gs *Struct + var emit bool + + for _, s := range structs { + if len(s.Fields) != len(query.Columns) { + continue + } + same := true + for i, f := range s.Fields { + c := query.Columns[i] + sameName := f.Name == StructName(columnName(c, i), options) + sameType := f.Type == goType(req, options, c) + sameTable := sdk.SameTableName(c.Table, s.Table, req.Catalog.DefaultSchema) + if !sameName || !sameType || !sameTable { + same = false + } + } + if same { + gs = &s + break + } + } + + if gs == nil { + var columns []goColumn + for i, c := range query.Columns { + columns = append(columns, goColumn{ + id: i, + Column: c, + embed: newGoEmbed(c.EmbedTable, structs, req.Catalog.DefaultSchema), + }) + } + var err error + gs, err = columnsToStruct(req, options, gq.MethodName+"Row", columns, true, models, qualifier) + if err != nil { + return nil, err + } + emit = true + } + gq.Ret = QueryValue{ + Emit: emit, + Name: "i", + Struct: gs, + SQLDriver: sqlpkg, + EmitPointer: options.EmitResultStructPointers, + ModelQualifier: qualifier, + } + } + + qs = append(qs, gq) + } + sort.Slice(qs, func(i, j int) bool { return qs[i].MethodName < qs[j].MethodName }) + return qs, nil +} + +var cmdReturnsData = map[string]struct{}{ + metadata.CmdBatchMany: {}, + metadata.CmdBatchOne: {}, + metadata.CmdMany: {}, + metadata.CmdOne: {}, +} + +func putOutColumns(query *plugin.Query) bool { + _, found := cmdReturnsData[query.Cmd] + return found +} + +// It's possible that this method will generate duplicate JSON tag values +// +// Columns: count, count, count_2 +// Fields: Count, Count_2, Count2 +// +// JSON tags: count, count_2, count_2 +// +// This is unlikely to happen, so don't fix it yet +func columnsToStruct(req *plugin.GenerateRequest, options *opts.Options, name string, columns []goColumn, useID bool, models modelTypeSet, qualifier string) (*Struct, error) { + gs := Struct{ + Name: name, + } + seen := map[string][]int{} + suffixes := map[int]int{} + for i, c := range columns { + colName := columnName(c.Column, i) + tagName := colName + + // override col/tag with expected model name + if c.embed != nil { + colName = c.embed.modelName + tagName = SetCaseStyle(colName, "snake") + } + + fieldName := StructName(colName, options) + baseFieldName := fieldName + // Track suffixes by the ID of the column, so that columns referring to the same numbered parameter can be + // reused. + suffix := 0 + if o, ok := suffixes[c.id]; ok && useID { + suffix = o + } else if v := len(seen[fieldName]); v > 0 && !c.IsNamedParam { + suffix = v + 1 + } + suffixes[c.id] = suffix + if suffix > 0 { + tagName = fmt.Sprintf("%s_%d", tagName, suffix) + fieldName = fmt.Sprintf("%s_%d", fieldName, suffix) + } + tags := map[string]string{} + if options.EmitDbTags { + tags["db"] = tagName + } + if options.EmitJsonTags { + tags["json"] = JSONTagName(tagName, options) + } + addExtraGoStructTags(tags, req, options, c.Column) + f := Field{ + Name: fieldName, + DBName: colName, + Tags: tags, + Column: c.Column, + } + if c.embed == nil { + f.Type = qualifyType(goType(req, options, c.Column), models, qualifier) + } else { + f.Type = qualifyType(c.embed.modelType, models, qualifier) + f.EmbedFields = c.embed.fields + } + + gs.Fields = append(gs.Fields, f) + if _, found := seen[baseFieldName]; !found { + seen[baseFieldName] = []int{i} + } else { + seen[baseFieldName] = append(seen[baseFieldName], i) + } + } + + // If a field does not have a known type, but another + // field with the same name has a known type, assign + // the known type to the field without a known type + for i, field := range gs.Fields { + if len(seen[field.Name]) > 1 && field.Type == "any" { + for _, j := range seen[field.Name] { + if i == j { + continue + } + otherField := gs.Fields[j] + if otherField.Type != field.Type { + field.Type = otherField.Type + } + gs.Fields[i] = field + } + } + } + + err := checkIncompatibleFieldTypes(gs.Fields) + if err != nil { + return nil, err + } + + return &gs, nil +} + +func checkIncompatibleFieldTypes(fields []Field) error { + fieldTypes := map[string]string{} + for _, field := range fields { + if fieldType, found := fieldTypes[field.Name]; !found { + fieldTypes[field.Name] = field.Type + } else if field.Type != fieldType { + return fmt.Errorf("named param %s has incompatible types: %s, %s", field.Name, field.Type, fieldType) + } + } + return nil +} diff --git a/internal/codegen/golang/result_test.go b/internal/codegen/golang/result_test.go new file mode 100644 index 0000000..0c58525 --- /dev/null +++ b/internal/codegen/golang/result_test.go @@ -0,0 +1,78 @@ +package golang + +import ( + "testing" + + "github.com/sqlc-dev/sqlc/internal/metadata" + "github.com/sqlc-dev/sqlc/internal/plugin" +) + +func TestPutOutColumns_ForZeroColumns(t *testing.T) { + tests := []struct { + cmd string + want bool + }{ + { + cmd: metadata.CmdExec, + want: false, + }, + { + cmd: metadata.CmdExecResult, + want: false, + }, + { + cmd: metadata.CmdExecRows, + want: false, + }, + { + cmd: metadata.CmdExecLastId, + want: false, + }, + { + cmd: metadata.CmdMany, + want: true, + }, + { + cmd: metadata.CmdOne, + want: true, + }, + { + cmd: metadata.CmdCopyFrom, + want: false, + }, + { + cmd: metadata.CmdBatchExec, + want: false, + }, + { + cmd: metadata.CmdBatchMany, + want: true, + }, + { + cmd: metadata.CmdBatchOne, + want: true, + }, + } + for _, tc := range tests { + t.Run(tc.cmd, func(t *testing.T) { + query := &plugin.Query{ + Cmd: tc.cmd, + Columns: []*plugin.Column{}, + } + got := putOutColumns(query) + if got != tc.want { + t.Errorf("putOutColumns failed. want %v, got %v", tc.want, got) + } + }) + } +} + +func TestPutOutColumns_AlwaysTrueWhenQueryHasColumns(t *testing.T) { + query := &plugin.Query{ + Cmd: metadata.CmdMany, + Columns: []*plugin.Column{{}}, + } + if putOutColumns(query) != true { + t.Error("should be true when we have columns") + } +} diff --git a/internal/codegen/golang/sqlite_type.go b/internal/codegen/golang/sqlite_type.go new file mode 100644 index 0000000..364f8c8 --- /dev/null +++ b/internal/codegen/golang/sqlite_type.go @@ -0,0 +1,102 @@ +package golang + +import ( + "log" + "strings" + + "github.com/sqlc-dev/sqlc/internal/codegen/golang/opts" + "github.com/sqlc-dev/sqlc/internal/codegen/sdk" + "github.com/sqlc-dev/sqlc/internal/debug" + "github.com/sqlc-dev/sqlc/internal/plugin" +) + +func sqliteType(req *plugin.GenerateRequest, options *opts.Options, col *plugin.Column) string { + dt := strings.ToLower(sdk.DataType(col.Type)) + notNull := col.NotNull || col.IsArray + emitPointersForNull := options.EmitPointersForNullTypes + + switch dt { + + case "int", "integer", "tinyint", "smallint", "mediumint", "bigint", "unsignedbigint", "int2", "int8": + if notNull { + return "int64" + } + if emitPointersForNull { + return "*int64" + } + return "sql.NullInt64" + + case "blob": + return "[]byte" + + case "real", "double", "doubleprecision", "float": + if notNull { + return "float64" + } + if emitPointersForNull { + return "*float64" + } + return "sql.NullFloat64" + + case "boolean", "bool": + if notNull { + return "bool" + } + if emitPointersForNull { + return "*bool" + } + return "sql.NullBool" + + case "date", "datetime", "timestamp": + if notNull { + return "time.Time" + } + if emitPointersForNull { + return "*time.Time" + } + return "sql.NullTime" + + case "json", "jsonb": + return "json.RawMessage" + + case "any": + return "any" + + } + + switch { + + case strings.HasPrefix(dt, "character"), + strings.HasPrefix(dt, "varchar"), + strings.HasPrefix(dt, "varyingcharacter"), + strings.HasPrefix(dt, "nchar"), + strings.HasPrefix(dt, "nativecharacter"), + strings.HasPrefix(dt, "nvarchar"), + dt == "text", + dt == "clob": + if notNull { + return "string" + } + if emitPointersForNull { + return "*string" + } + return "sql.NullString" + + case strings.HasPrefix(dt, "decimal"), dt == "numeric": + if notNull { + return "float64" + } + if emitPointersForNull { + return "*float64" + } + return "sql.NullFloat64" + + default: + if debug.Active { + log.Printf("unknown SQLite type: %s\n", dt) + } + + return "any" + + } +} diff --git a/internal/codegen/golang/struct.go b/internal/codegen/golang/struct.go new file mode 100644 index 0000000..9845c0c --- /dev/null +++ b/internal/codegen/golang/struct.go @@ -0,0 +1,53 @@ +package golang + +import ( + "strings" + "unicode" + "unicode/utf8" + + "github.com/sqlc-dev/sqlc/internal/codegen/golang/opts" + "github.com/sqlc-dev/sqlc/internal/plugin" +) + +type Struct struct { + Table *plugin.Identifier + Name string + Fields []Field + Comment string + // IsModel is true for table structs that live in the models file. When + // the models file is generated into a different Go package, references + // to these types from query files must be qualified. + IsModel bool +} + +func StructName(name string, options *opts.Options) string { + if rename := options.Rename[name]; rename != "" { + return rename + } + var out strings.Builder + name = strings.Map(func(r rune) rune { + if unicode.IsLetter(r) { + return r + } + if unicode.IsDigit(r) { + return r + } + return rune('_') + }, name) + + for p := range strings.SplitSeq(name, "_") { + if _, found := options.InitialismsMap[p]; found { + out.WriteString(strings.ToUpper(p)) + } else { + out.WriteString(strings.Title(p)) + } + } + + // If a name has a digit as its first char, prepand an underscore to make it a valid Go name. + r, _ := utf8.DecodeRuneInString(out.String()) + if unicode.IsDigit(r) { + return "_" + out.String() + } else { + return out.String() + } +} diff --git a/internal/codegen/golang/template.go b/internal/codegen/golang/template.go new file mode 100644 index 0000000..0aa7c9f --- /dev/null +++ b/internal/codegen/golang/template.go @@ -0,0 +1,7 @@ +package golang + +import "embed" + +//go:embed templates/* +//go:embed templates/*/* +var templates embed.FS diff --git a/internal/codegen/golang/templates/go-sql-driver-mysql/copyfromCopy.tmpl b/internal/codegen/golang/templates/go-sql-driver-mysql/copyfromCopy.tmpl new file mode 100644 index 0000000..e21475b --- /dev/null +++ b/internal/codegen/golang/templates/go-sql-driver-mysql/copyfromCopy.tmpl @@ -0,0 +1,52 @@ +{{define "copyfromCodeGoSqlDriver"}} +{{range .GoQueries}} +{{if eq .Cmd ":copyfrom" }} +var readerHandlerSequenceFor{{.MethodName}} uint32 = 1 + +func convertRowsFor{{.MethodName}}(w *io.PipeWriter, {{.Arg.SlicePair}}) { + e := mysqltsv.NewEncoder(w, {{ len .Arg.CopyFromMySQLFields }}, nil) + for _, row := range {{.Arg.Name}} { +{{- with $arg := .Arg }} +{{- range $arg.CopyFromMySQLFields}} +{{- if eq .Type "string"}} + e.AppendString({{if $arg.Struct}}row.{{.Name}}{{else}}row{{end}}) +{{- else if or (eq .Type "[]byte") (eq .Type "json.RawMessage")}} + e.AppendBytes({{if $arg.Struct}}row.{{.Name}}{{else}}row{{end}}) +{{- else}} + e.AppendValue({{if $arg.Struct}}row.{{.Name}}{{else}}row{{end}}) +{{- end}} +{{- end}} +{{- end}} + } + w.CloseWithError(e.Close()) +} + +{{range .Comments}}//{{.}} +{{end -}} +// {{.MethodName}} uses MySQL's LOAD DATA LOCAL INFILE and is not atomic. +// +// Errors and duplicate keys are treated as warnings and insertion will +// continue, even without an error for some cases. Use this in a transaction +// and use SHOW WARNINGS to check for any problems and roll back if you want to. +// +// Check the documentation for more information: +// https://dev.mysql.com/doc/refman/8.0/en/load-data.html#load-data-error-handling +func (q *Queries) {{.MethodName}}(ctx context.Context{{if $.EmitMethodsWithDBArgument}}, db DBTX{{end}}, {{.Arg.SlicePair}}) (int64, error) { + pr, pw := io.Pipe() + defer pr.Close() + rh := fmt.Sprintf("{{.MethodName}}_%d", atomic.AddUint32(&readerHandlerSequenceFor{{.MethodName}}, 1)) + mysql.RegisterReaderHandler(rh, func() io.Reader { return pr }) + defer mysql.DeregisterReaderHandler(rh) + go convertRowsFor{{.MethodName}}(pw, {{.Arg.Name}}) + // The string interpolation is necessary because LOAD DATA INFILE requires + // the file name to be given as a literal string. + result, err := {{if (not $.EmitMethodsWithDBArgument)}}q.{{end}}db.ExecContext(ctx, fmt.Sprintf("LOAD DATA LOCAL INFILE '%s' INTO TABLE {{.TableIdentifierForMySQL}} %s ({{range $index, $name := .Arg.ColumnNames}}{{if gt $index 0}}, {{end}}{{$name}}{{end}})", "Reader::" + rh, mysqltsv.Escaping)) + if err != nil { + return 0, err + } + return result.RowsAffected() +} + +{{end}} +{{end}} +{{end}} diff --git a/internal/codegen/golang/templates/pgx/batchCode.tmpl b/internal/codegen/golang/templates/pgx/batchCode.tmpl new file mode 100644 index 0000000..cec2ddb --- /dev/null +++ b/internal/codegen/golang/templates/pgx/batchCode.tmpl @@ -0,0 +1,134 @@ +{{define "batchCodePgx"}} + +var ( + ErrBatchAlreadyClosed = errors.New("batch already closed") +) + +{{range .GoQueries}} +{{if eq (hasPrefix .Cmd ":batch") true }} +const {{.ConstantName}} = {{$.Q}}-- name: {{.MethodName}} {{.Cmd}} +{{escape .SQL}} +{{$.Q}} + +type {{.MethodName}}BatchResults struct { + br pgx.BatchResults + tot int + closed bool +} + +{{if .Arg.Struct}} +type {{.Arg.Type}} struct { {{- range .Arg.Struct.Fields}} + {{.Name}} {{.Type}} {{if .Tag}}{{$.Q}}{{.Tag}}{{$.Q}}{{end}} + {{- end}} +} +{{end}} + +{{if .Ret.EmitStruct}} +type {{.Ret.Type}} struct { {{- range .Ret.Struct.Fields}} + {{.Name}} {{.Type}} {{if .Tag}}{{$.Q}}{{.Tag}}{{$.Q}}{{end}} + {{- end}} +} +{{end}} + +{{range .Comments}}//{{.}} +{{end -}} +func (q *Queries) {{.MethodName}}(ctx context.Context, {{ if $.EmitMethodsWithDBArgument}}db DBTX,{{end}} {{.Arg.SlicePair}}) *{{.MethodName}}BatchResults { + batch := &pgx.Batch{} + for _, a := range {{index .Arg.Name}} { + vals := []any{ + {{- if .Arg.Struct }} + {{- range .Arg.Struct.Fields }} + a.{{.Name}}, + {{- end }} + {{- else }} + a, + {{- end }} + } + batch.Queue({{.ConstantName}}, vals...) + } + br := {{if not $.EmitMethodsWithDBArgument}}q.{{end}}db.SendBatch(ctx, batch) + return &{{.MethodName}}BatchResults{br,len({{.Arg.Name}}),false} +} + +{{if eq .Cmd ":batchexec"}} +func (b *{{.MethodName}}BatchResults) Exec(f func(int, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + if b.closed { + if f != nil { + f(t, ErrBatchAlreadyClosed) + } + continue + } + _, err := b.br.Exec() + if f != nil { + f(t, err) + } + } +} +{{end}} + +{{if eq .Cmd ":batchmany"}} +func (b *{{.MethodName}}BatchResults) Query(f func(int, []{{.Ret.DefineType}}, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + {{- if $.EmitEmptySlices}} + items := []{{.Ret.DefineType}}{} + {{else}} + var items []{{.Ret.DefineType}} + {{end -}} + if b.closed { + if f != nil { + f(t, items, ErrBatchAlreadyClosed) + } + continue + } + err := func() error { + rows, err := b.br.Query() + if err != nil { + return err + } + defer rows.Close() + for rows.Next() { + var {{.Ret.Name}} {{.Ret.Type}} + if err := rows.Scan({{.Ret.Scan}}); err != nil { + return err + } + items = append(items, {{.Ret.ReturnName}}) + } + return rows.Err() + }() + if f != nil { + f(t, items, err) + } + } +} +{{end}} + +{{if eq .Cmd ":batchone"}} +func (b *{{.MethodName}}BatchResults) QueryRow(f func(int, {{.Ret.DefineType}}, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + var {{.Ret.Name}} {{.Ret.Type}} + if b.closed { + if f != nil { + f(t, {{if .Ret.IsPointer}}nil{{else}}{{.Ret.Name}}{{end}}, ErrBatchAlreadyClosed) + } + continue + } + row := b.br.QueryRow() + err := row.Scan({{.Ret.Scan}}) + if f != nil { + f(t, {{.Ret.ReturnName}}, err) + } + } +} +{{end}} + +func (b *{{.MethodName}}BatchResults) Close() error { + b.closed = true + return b.br.Close() +} +{{end}} +{{end}} +{{end}} diff --git a/internal/codegen/golang/templates/pgx/copyfromCopy.tmpl b/internal/codegen/golang/templates/pgx/copyfromCopy.tmpl new file mode 100644 index 0000000..5c14ba3 --- /dev/null +++ b/internal/codegen/golang/templates/pgx/copyfromCopy.tmpl @@ -0,0 +1,51 @@ +{{define "copyfromCodePgx"}} +{{range .GoQueries}} +{{if eq .Cmd ":copyfrom" }} +// iteratorFor{{.MethodName}} implements pgx.CopyFromSource. +type iteratorFor{{.MethodName}} struct { + rows []{{.Arg.DefineType}} + skippedFirstNextCall bool +} + +func (r *iteratorFor{{.MethodName}}) Next() bool { + if len(r.rows) == 0 { + return false + } + if !r.skippedFirstNextCall { + r.skippedFirstNextCall = true + return true + } + r.rows = r.rows[1:] + return len(r.rows) > 0 +} + +func (r iteratorFor{{.MethodName}}) Values() ([]any, error) { + return []any{ +{{- if .Arg.Struct }} +{{- range .Arg.Struct.Fields }} + r.rows[0].{{.Name}}, +{{- end }} +{{- else }} + r.rows[0], +{{- end }} + }, nil +} + +func (r iteratorFor{{.MethodName}}) Err() error { + return nil +} + +{{range .Comments}}//{{.}} +{{end -}} +{{- if $.EmitMethodsWithDBArgument -}} +func (q *Queries) {{.MethodName}}(ctx context.Context, db DBTX, {{.Arg.SlicePair}}) (int64, error) { + return db.CopyFrom(ctx, {{.TableIdentifierAsGoSlice}}, {{.Arg.ColumnNamesAsGoSlice}}, &iteratorFor{{.MethodName}}{rows: {{.Arg.Name}}}) +{{- else -}} +func (q *Queries) {{.MethodName}}(ctx context.Context, {{.Arg.SlicePair}}) (int64, error) { + return q.db.CopyFrom(ctx, {{.TableIdentifierAsGoSlice}}, {{.Arg.ColumnNamesAsGoSlice}}, &iteratorFor{{.MethodName}}{rows: {{.Arg.Name}}}) +{{- end}} +} + +{{end}} +{{end}} +{{end}} diff --git a/internal/codegen/golang/templates/pgx/dbCode.tmpl b/internal/codegen/golang/templates/pgx/dbCode.tmpl new file mode 100644 index 0000000..592ea5c --- /dev/null +++ b/internal/codegen/golang/templates/pgx/dbCode.tmpl @@ -0,0 +1,37 @@ +{{define "dbCodeTemplatePgx"}} + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row +{{- if .UsesCopyFrom }} + CopyFrom(ctx context.Context, tableName pgx.Identifier, columnNames []string, rowSrc pgx.CopyFromSource) (int64, error) +{{- end }} +{{- if .UsesBatch }} + SendBatch(context.Context, *pgx.Batch) pgx.BatchResults +{{- end }} +} + +{{ if .EmitMethodsWithDBArgument}} +func New() *Queries { + return &Queries{} +{{- else -}} +func New(db DBTX) *Queries { + return &Queries{db: db} +{{- end}} +} + +type Queries struct { + {{if not .EmitMethodsWithDBArgument}} + db DBTX + {{end}} +} + +{{if not .EmitMethodsWithDBArgument}} +func (q *Queries) WithTx(tx pgx.Tx) *Queries { + return &Queries{ + db: tx, + } +} +{{end}} +{{end}} diff --git a/internal/codegen/golang/templates/pgx/interfaceCode.tmpl b/internal/codegen/golang/templates/pgx/interfaceCode.tmpl new file mode 100644 index 0000000..cf7cd36 --- /dev/null +++ b/internal/codegen/golang/templates/pgx/interfaceCode.tmpl @@ -0,0 +1,73 @@ +{{define "interfaceCodePgx"}} + type Querier interface { + {{- $dbtxParam := .EmitMethodsWithDBArgument -}} + {{- range .GoQueries}} + {{- if and (eq .Cmd ":one") ($dbtxParam) }} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, db DBTX, {{.Arg.Pair}}) ({{.Ret.DefineType}}, error) + {{- else if eq .Cmd ":one" }} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, {{.Arg.Pair}}) ({{.Ret.DefineType}}, error) + {{- end}} + {{- if and (eq .Cmd ":many") ($dbtxParam) }} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, db DBTX, {{.Arg.Pair}}) ([]{{.Ret.DefineType}}, error) + {{- else if eq .Cmd ":many" }} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, {{.Arg.Pair}}) ([]{{.Ret.DefineType}}, error) + {{- end}} + {{- if and (eq .Cmd ":exec") ($dbtxParam) }} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, db DBTX, {{.Arg.Pair}}) error + {{- else if eq .Cmd ":exec" }} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, {{.Arg.Pair}}) error + {{- end}} + {{- if and (eq .Cmd ":execrows") ($dbtxParam) }} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, db DBTX, {{.Arg.Pair}}) (int64, error) + {{- else if eq .Cmd ":execrows" }} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, {{.Arg.Pair}}) (int64, error) + {{- end}} + {{- if and (eq .Cmd ":execresult") ($dbtxParam) }} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, db DBTX, {{.Arg.Pair}}) (pgconn.CommandTag, error) + {{- else if eq .Cmd ":execresult" }} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, {{.Arg.Pair}}) (pgconn.CommandTag, error) + {{- end}} + {{- if and (eq .Cmd ":copyfrom") ($dbtxParam) }} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, db DBTX, {{.Arg.SlicePair}}) (int64, error) + {{- else if eq .Cmd ":copyfrom" }} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, {{.Arg.SlicePair}}) (int64, error) + {{- end}} + {{- if and (or (eq .Cmd ":batchexec") (eq .Cmd ":batchmany") (eq .Cmd ":batchone")) ($dbtxParam) }} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, db DBTX, {{.Arg.SlicePair}}) *{{.MethodName}}BatchResults + {{- else if or (eq .Cmd ":batchexec") (eq .Cmd ":batchmany") (eq .Cmd ":batchone") }} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, {{.Arg.SlicePair}}) *{{.MethodName}}BatchResults + {{- end}} + + {{- end}} + } + + var _ Querier = (*Queries)(nil) +{{end}} diff --git a/internal/codegen/golang/templates/pgx/queryCode.tmpl b/internal/codegen/golang/templates/pgx/queryCode.tmpl new file mode 100644 index 0000000..59a88c8 --- /dev/null +++ b/internal/codegen/golang/templates/pgx/queryCode.tmpl @@ -0,0 +1,142 @@ +{{define "queryCodePgx"}} +{{range .GoQueries}} +{{if $.OutputQuery .SourceName}} +{{if and (ne .Cmd ":copyfrom") (ne (hasPrefix .Cmd ":batch") true)}} +const {{.ConstantName}} = {{$.Q}}-- name: {{.MethodName}} {{.Cmd}} +{{escape .SQL}} +{{$.Q}} +{{end}} + +{{if ne (hasPrefix .Cmd ":batch") true}} +{{if .Arg.EmitStruct}} +type {{.Arg.Type}} struct { {{- range .Arg.Struct.Fields}} + {{.Name}} {{.Type}} {{if .Tag}}{{$.Q}}{{.Tag}}{{$.Q}}{{end}} + {{- end}} +} +{{end}} + +{{if .Ret.EmitStruct}} +type {{.Ret.Type}} struct { {{- range .Ret.Struct.Fields}} + {{.Name}} {{.Type}} {{if .Tag}}{{$.Q}}{{.Tag}}{{$.Q}}{{end}} + {{- end}} +} +{{end}} +{{end}} + +{{if eq .Cmd ":one"}} +{{range .Comments}}//{{.}} +{{end -}} +{{- if $.EmitMethodsWithDBArgument -}} +func (q *Queries) {{.MethodName}}(ctx context.Context, db DBTX, {{.Arg.Pair}}) ({{.Ret.DefineType}}, error) { + row := db.QueryRow(ctx, {{.ConstantName}}, {{.Arg.Params}}) +{{- else -}} +func (q *Queries) {{.MethodName}}(ctx context.Context, {{.Arg.Pair}}) ({{.Ret.DefineType}}, error) { + row := q.db.QueryRow(ctx, {{.ConstantName}}, {{.Arg.Params}}) +{{- end}} + {{- if or (ne .Arg.Pair .Ret.Pair) (ne .Arg.DefineType .Ret.DefineType) }} + var {{.Ret.Name}} {{.Ret.Type}} + {{- end}} + err := row.Scan({{.Ret.Scan}}) + {{- if $.WrapErrors}} + if err != nil { + err = fmt.Errorf("query {{.MethodName}}: %w", err) + } + {{- end}} + return {{.Ret.ReturnName}}, err +} +{{end}} + +{{if eq .Cmd ":many"}} +{{range .Comments}}//{{.}} +{{end -}} +{{- if $.EmitMethodsWithDBArgument -}} +func (q *Queries) {{.MethodName}}(ctx context.Context, db DBTX, {{.Arg.Pair}}) ([]{{.Ret.DefineType}}, error) { + rows, err := db.Query(ctx, {{.ConstantName}}, {{.Arg.Params}}) +{{- else -}} +func (q *Queries) {{.MethodName}}(ctx context.Context, {{.Arg.Pair}}) ([]{{.Ret.DefineType}}, error) { + rows, err := q.db.Query(ctx, {{.ConstantName}}, {{.Arg.Params}}) +{{- end}} + if err != nil { + return nil, {{if $.WrapErrors}}fmt.Errorf("query {{.MethodName}}: %w", err){{else}}err{{end}} + } + defer rows.Close() + {{- if $.EmitEmptySlices}} + items := []{{.Ret.DefineType}}{} + {{else}} + var items []{{.Ret.DefineType}} + {{end -}} + for rows.Next() { + var {{.Ret.Name}} {{.Ret.Type}} + if err := rows.Scan({{.Ret.Scan}}); err != nil { + return nil, {{if $.WrapErrors}}fmt.Errorf("query {{.MethodName}}: %w", err){{else}}err{{end}} + } + items = append(items, {{.Ret.ReturnName}}) + } + if err := rows.Err(); err != nil { + return nil, {{if $.WrapErrors}}fmt.Errorf("query {{.MethodName}}: %w", err){{else}}err{{end}} + } + return items, nil +} +{{end}} + +{{if eq .Cmd ":exec"}} +{{range .Comments}}//{{.}} +{{end -}} +{{- if $.EmitMethodsWithDBArgument -}} +func (q *Queries) {{.MethodName}}(ctx context.Context, db DBTX, {{.Arg.Pair}}) error { + _, err := db.Exec(ctx, {{.ConstantName}}, {{.Arg.Params}}) +{{- else -}} +func (q *Queries) {{.MethodName}}(ctx context.Context, {{.Arg.Pair}}) error { + _, err := q.db.Exec(ctx, {{.ConstantName}}, {{.Arg.Params}}) +{{- end}} + {{- if $.WrapErrors }} + if err != nil { + return fmt.Errorf("query {{.MethodName}}: %w", err) + } + return nil + {{- else }} + return err + {{- end }} +} +{{end}} + +{{if eq .Cmd ":execrows"}} +{{range .Comments}}//{{.}} +{{end -}} +{{if $.EmitMethodsWithDBArgument -}} +func (q *Queries) {{.MethodName}}(ctx context.Context, db DBTX, {{.Arg.Pair}}) (int64, error) { + result, err := db.Exec(ctx, {{.ConstantName}}, {{.Arg.Params}}) +{{- else -}} +func (q *Queries) {{.MethodName}}(ctx context.Context, {{.Arg.Pair}}) (int64, error) { + result, err := q.db.Exec(ctx, {{.ConstantName}}, {{.Arg.Params}}) +{{- end}} + if err != nil { + return 0, {{if $.WrapErrors}}fmt.Errorf("query {{.MethodName}}: %w", err){{else}}err{{end}} + } + return result.RowsAffected(), nil +} +{{end}} + +{{if eq .Cmd ":execresult"}} +{{range .Comments}}//{{.}} +{{end -}} +{{- if $.EmitMethodsWithDBArgument -}} +func (q *Queries) {{.MethodName}}(ctx context.Context, db DBTX, {{.Arg.Pair}}) (pgconn.CommandTag, error) { + {{queryRetval .}} db.Exec(ctx, {{.ConstantName}}, {{.Arg.Params}}) +{{- else -}} +func (q *Queries) {{.MethodName}}(ctx context.Context, {{.Arg.Pair}}) (pgconn.CommandTag, error) { + {{queryRetval .}} q.db.Exec(ctx, {{.ConstantName}}, {{.Arg.Params}}) +{{- end}} + {{- if $.WrapErrors}} + if err != nil { + err = fmt.Errorf("query {{.MethodName}}: %w", err) + } + return result, err + {{- end}} +} +{{end}} + + +{{end}} +{{end}} +{{end}} diff --git a/internal/codegen/golang/templates/stdlib/dbCode.tmpl b/internal/codegen/golang/templates/stdlib/dbCode.tmpl new file mode 100644 index 0000000..771b1cc --- /dev/null +++ b/internal/codegen/golang/templates/stdlib/dbCode.tmpl @@ -0,0 +1,105 @@ +{{define "dbCodeTemplateStd"}} +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *sql.Row +} + +{{ if .EmitMethodsWithDBArgument}} +func New() *Queries { + return &Queries{} +{{- else -}} +func New(db DBTX) *Queries { + return &Queries{db: db} +{{- end}} +} + +{{if .EmitPreparedQueries}} +func Prepare(ctx context.Context, db DBTX) (*Queries, error) { + q := Queries{db: db} + var err error + {{- if eq (len .GoQueries) 0 }} + _ = err + {{- end }} + {{- range .GoQueries }} + if q.{{.FieldName}}, err = db.PrepareContext(ctx, {{.ConstantName}}); err != nil { + return nil, fmt.Errorf("error preparing query {{.MethodName}}: %w", err) + } + {{- end}} + return &q, nil +} + +func (q *Queries) Close() error { + var err error + {{- range .GoQueries }} + if q.{{.FieldName}} != nil { + if cerr := q.{{.FieldName}}.Close(); cerr != nil { + err = fmt.Errorf("error closing {{.FieldName}}: %w", cerr) + } + } + {{- end}} + return err +} + +func (q *Queries) exec(ctx context.Context, stmt *sql.Stmt, query string, args ...any) (sql.Result, error) { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).ExecContext(ctx, args...) + case stmt != nil: + return stmt.ExecContext(ctx, args...) + default: + return q.db.ExecContext(ctx, query, args...) + } +} + +func (q *Queries) query(ctx context.Context, stmt *sql.Stmt, query string, args ...any) (*sql.Rows, error) { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).QueryContext(ctx, args...) + case stmt != nil: + return stmt.QueryContext(ctx, args...) + default: + return q.db.QueryContext(ctx, query, args...) + } +} + +func (q *Queries) queryRow(ctx context.Context, stmt *sql.Stmt, query string, args ...any) (*sql.Row) { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).QueryRowContext(ctx, args...) + case stmt != nil: + return stmt.QueryRowContext(ctx, args...) + default: + return q.db.QueryRowContext(ctx, query, args...) + } +} +{{end}} + +type Queries struct { + {{- if not .EmitMethodsWithDBArgument}} + db DBTX + {{- end}} + + {{- if .EmitPreparedQueries}} + tx *sql.Tx + {{- range .GoQueries}} + {{.FieldName}} *sql.Stmt + {{- end}} + {{- end}} +} + +{{if not .EmitMethodsWithDBArgument}} +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + {{- if .EmitPreparedQueries}} + tx: tx, + {{- range .GoQueries}} + {{.FieldName}}: q.{{.FieldName}}, + {{- end}} + {{- end}} + } +} +{{end}} +{{end}} diff --git a/internal/codegen/golang/templates/stdlib/interfaceCode.tmpl b/internal/codegen/golang/templates/stdlib/interfaceCode.tmpl new file mode 100644 index 0000000..3cbefe6 --- /dev/null +++ b/internal/codegen/golang/templates/stdlib/interfaceCode.tmpl @@ -0,0 +1,63 @@ +{{define "interfaceCodeStd"}} + type Querier interface { + {{- $dbtxParam := .EmitMethodsWithDBArgument -}} + {{- range .GoQueries}} + {{- if and (eq .Cmd ":one") ($dbtxParam) }} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, db DBTX, {{.Arg.Pair}}) ({{.Ret.DefineType}}, error) + {{- else if eq .Cmd ":one"}} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, {{.Arg.Pair}}) ({{.Ret.DefineType}}, error) + {{- end}} + {{- if and (eq .Cmd ":many") ($dbtxParam) }} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, db DBTX, {{.Arg.Pair}}) ([]{{.Ret.DefineType}}, error) + {{- else if eq .Cmd ":many"}} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, {{.Arg.Pair}}) ([]{{.Ret.DefineType}}, error) + {{- end}} + {{- if and (eq .Cmd ":exec") ($dbtxParam) }} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, db DBTX, {{.Arg.Pair}}) error + {{- else if eq .Cmd ":exec"}} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, {{.Arg.Pair}}) error + {{- end}} + {{- if and (eq .Cmd ":execrows") ($dbtxParam) }} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, db DBTX, {{.Arg.Pair}}) (int64, error) + {{- else if eq .Cmd ":execrows"}} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, {{.Arg.Pair}}) (int64, error) + {{- end}} + {{- if and (eq .Cmd ":execlastid") ($dbtxParam) }} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, db DBTX, {{.Arg.Pair}}) (int64, error) + {{- else if eq .Cmd ":execlastid"}} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, {{.Arg.Pair}}) (int64, error) + {{- end}} + {{- if and (eq .Cmd ":execresult") ($dbtxParam) }} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, db DBTX, {{.Arg.Pair}}) (sql.Result, error) + {{- else if eq .Cmd ":execresult"}} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, {{.Arg.Pair}}) (sql.Result, error) + {{- end}} + {{- end}} + } + + var _ Querier = (*Queries)(nil) +{{end}} diff --git a/internal/codegen/golang/templates/stdlib/queryCode.tmpl b/internal/codegen/golang/templates/stdlib/queryCode.tmpl new file mode 100644 index 0000000..8fd67f1 --- /dev/null +++ b/internal/codegen/golang/templates/stdlib/queryCode.tmpl @@ -0,0 +1,171 @@ +{{define "queryCodeStd"}} +{{range .GoQueries}} +{{if $.OutputQuery .SourceName}} +const {{.ConstantName}} = {{$.Q}}-- name: {{.MethodName}} {{.Cmd}} +{{escape .SQL}} +{{$.Q}} + +{{if .Arg.EmitStruct}} +type {{.Arg.Type}} struct { {{- range .Arg.UniqueFields}} + {{.Name}} {{.Type}} {{if .Tag}}{{$.Q}}{{.Tag}}{{$.Q}}{{end}} + {{- end}} +} +{{end}} + +{{if .Ret.EmitStruct}} +type {{.Ret.Type}} struct { {{- range .Ret.Struct.Fields}} + {{.Name}} {{.Type}} {{if .Tag}}{{$.Q}}{{.Tag}}{{$.Q}}{{end}} + {{- end}} +} +{{end}} + +{{if eq .Cmd ":one"}} +{{range .Comments}}//{{.}} +{{end -}} +func (q *Queries) {{.MethodName}}(ctx context.Context, {{ dbarg }} {{.Arg.Pair}}) ({{.Ret.DefineType}}, error) { + {{- template "queryCodeStdExec" . }} + {{- if or (ne .Arg.Pair .Ret.Pair) (ne .Arg.DefineType .Ret.DefineType) }} + var {{.Ret.Name}} {{.Ret.Type}} + {{- end}} + err := row.Scan({{.Ret.Scan}}) + {{- if $.WrapErrors}} + if err != nil { + err = fmt.Errorf("query {{.MethodName}}: %w", err) + } + {{- end}} + return {{.Ret.ReturnName}}, err +} +{{end}} + +{{if eq .Cmd ":many"}} +{{range .Comments}}//{{.}} +{{end -}} +func (q *Queries) {{.MethodName}}(ctx context.Context, {{ dbarg }} {{.Arg.Pair}}) ([]{{.Ret.DefineType}}, error) { + {{- template "queryCodeStdExec" . }} + if err != nil { + return nil, {{if $.WrapErrors}}fmt.Errorf("query {{.MethodName}}: %w", err){{else}}err{{end}} + } + defer rows.Close() + {{- if $.EmitEmptySlices}} + items := []{{.Ret.DefineType}}{} + {{else}} + var items []{{.Ret.DefineType}} + {{end -}} + for rows.Next() { + var {{.Ret.Name}} {{.Ret.Type}} + if err := rows.Scan({{.Ret.Scan}}); err != nil { + return nil, {{if $.WrapErrors}}fmt.Errorf("query {{.MethodName}}: %w", err){{else}}err{{end}} + } + items = append(items, {{.Ret.ReturnName}}) + } + if err := rows.Close(); err != nil { + return nil, {{if $.WrapErrors}}fmt.Errorf("query {{.MethodName}}: %w", err){{else}}err{{end}} + } + if err := rows.Err(); err != nil { + return nil, {{if $.WrapErrors}}fmt.Errorf("query {{.MethodName}}: %w", err){{else}}err{{end}} + } + return items, nil +} +{{end}} + +{{if eq .Cmd ":exec"}} +{{range .Comments}}//{{.}} +{{end -}} +func (q *Queries) {{.MethodName}}(ctx context.Context, {{ dbarg }} {{.Arg.Pair}}) error { + {{- template "queryCodeStdExec" . }} + {{- if $.WrapErrors}} + if err != nil { + err = fmt.Errorf("query {{.MethodName}}: %w", err) + } + {{- end}} + return err +} +{{end}} + +{{if eq .Cmd ":execrows"}} +{{range .Comments}}//{{.}} +{{end -}} +func (q *Queries) {{.MethodName}}(ctx context.Context, {{ dbarg }} {{.Arg.Pair}}) (int64, error) { + {{- template "queryCodeStdExec" . }} + if err != nil { + return 0, {{if $.WrapErrors}}fmt.Errorf("query {{.MethodName}}: %w", err){{else}}err{{end}} + } + return result.RowsAffected() +} +{{end}} + +{{if eq .Cmd ":execlastid"}} +{{range .Comments}}//{{.}} +{{end -}} +func (q *Queries) {{.MethodName}}(ctx context.Context, {{ dbarg }} {{.Arg.Pair}}) (int64, error) { + {{- template "queryCodeStdExec" . }} + if err != nil { + return 0, {{if $.WrapErrors}}fmt.Errorf("query {{.MethodName}}: %w", err){{else}}err{{end}} + } + return result.LastInsertId() +} +{{end}} + +{{if eq .Cmd ":execresult"}} +{{range .Comments}}//{{.}} +{{end -}} +func (q *Queries) {{.MethodName}}(ctx context.Context, {{ dbarg }} {{.Arg.Pair}}) (sql.Result, error) { + {{- template "queryCodeStdExec" . }} + {{- if $.WrapErrors}} + if err != nil { + err = fmt.Errorf("query {{.MethodName}}: %w", err) + } + return result, err + {{- end}} +} +{{end}} + +{{end}} +{{end}} +{{end}} + +{{define "queryCodeStdExec"}} + {{- if .Arg.HasSqlcSlices }} + query := {{.ConstantName}} + var queryParams []any + {{- if .Arg.Struct }} + {{- $arg := .Arg }} + {{- range .Arg.Struct.Fields }} + {{- if .HasSqlcSlice }} + if len({{$arg.VariableForField .}}) > 0 { + for _, v := range {{$arg.VariableForField .}} { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:{{.Column.Name}}*/?", strings.Repeat(",?", len({{$arg.VariableForField .}}))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:{{.Column.Name}}*/?", "NULL", 1) + } + {{- else }} + queryParams = append(queryParams, {{$arg.VariableForField .}}) + {{- end }} + {{- end }} + {{- else }} + {{- /* Single argument parameter to this goroutine (they are not packed + in a struct), because .Arg.HasSqlcSlices further up above was true, + this section is 100% a slice (impossible to get here otherwise). + */}} + if len({{.Arg.Name}}) > 0 { + for _, v := range {{.Arg.Name}} { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:{{.Arg.Column.Name}}*/?", strings.Repeat(",?", len({{.Arg.Name}}))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:{{.Arg.Column.Name}}*/?", "NULL", 1) + } + {{- end }} + {{- if emitPreparedQueries }} + {{ queryRetval . }} {{ queryMethod . }}(ctx, nil, query, queryParams...) + {{- else}} + {{ queryRetval . }} {{ queryMethod . }}(ctx, query, queryParams...) + {{- end -}} + {{- else if emitPreparedQueries }} + {{- queryRetval . }} {{ queryMethod . }}(ctx, q.{{.FieldName}}, {{.ConstantName}}, {{.Arg.Params}}) + {{- else}} + {{- queryRetval . }} {{ queryMethod . }}(ctx, {{.ConstantName}}, {{.Arg.Params}}) + {{- end -}} +{{end}} diff --git a/internal/codegen/golang/templates/template.tmpl b/internal/codegen/golang/templates/template.tmpl new file mode 100644 index 0000000..bb54f25 --- /dev/null +++ b/internal/codegen/golang/templates/template.tmpl @@ -0,0 +1,254 @@ +{{define "dbFile"}} +{{if .BuildTags}} +//go:build {{.BuildTags}} + +{{end}}// Code generated by sqlc. DO NOT EDIT. +{{if not .OmitSqlcVersion}}// versions: +// sqlc {{.SqlcVersion}} +{{end}} + +package {{.Package}} + +{{ if hasImports .SourceName }} +import ( + {{range imports .SourceName}} + {{range .}}{{.}} + {{end}} + {{end}} +) +{{end}} + +{{template "dbCode" . }} +{{end}} + +{{define "dbCode"}} + +{{if .SQLDriver.IsPGX }} + {{- template "dbCodeTemplatePgx" .}} +{{else}} + {{- template "dbCodeTemplateStd" .}} +{{end}} + +{{end}} + +{{define "interfaceFile"}} +{{if .BuildTags}} +//go:build {{.BuildTags}} + +{{end}}// Code generated by sqlc. DO NOT EDIT. +{{if not .OmitSqlcVersion}}// versions: +// sqlc {{.SqlcVersion}} +{{end}} + +package {{.Package}} + +{{ if hasImports .SourceName }} +import ( + {{range imports .SourceName}} + {{range .}}{{.}} + {{end}} + {{end}} +) +{{end}} + +{{template "interfaceCode" . }} +{{end}} + +{{define "interfaceCode"}} + {{if .SQLDriver.IsPGX }} + {{- template "interfaceCodePgx" .}} + {{else}} + {{- template "interfaceCodeStd" .}} + {{end}} +{{end}} + +{{define "modelsFile"}} +{{if .BuildTags}} +//go:build {{.BuildTags}} + +{{end}}// Code generated by sqlc. DO NOT EDIT. +{{if not .OmitSqlcVersion}}// versions: +// sqlc {{.SqlcVersion}} +{{end}} + +package {{.ModelsPackage}} + +{{ if hasImports .SourceName }} +import ( + {{range imports .SourceName}} + {{range .}}{{.}} + {{end}} + {{end}} +) +{{end}} + +{{template "modelsCode" . }} +{{end}} + +{{define "modelsCode"}} +{{range .Enums}} +{{if .Comment}}{{comment .Comment}}{{end}} +type {{.Name}} string + +const ( + {{- range .Constants}} + {{.Name}} {{.Type}} = "{{.Value}}" + {{- end}} +) + +func (e *{{.Name}}) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = {{.Name}}(s) + case string: + *e = {{.Name}}(s) + default: + return fmt.Errorf("unsupported scan type for {{.Name}}: %T", src) + } + return nil +} + +type Null{{.Name}} struct { + {{.Name}} {{.Name}} {{if .NameTag}}{{$.Q}}{{.NameTag}}{{$.Q}}{{end}} + Valid bool {{if .ValidTag}}{{$.Q}}{{.ValidTag}}{{$.Q}}{{end}} // Valid is true if {{.Name}} is not NULL +} + +// Scan implements the Scanner interface. +func (ns *Null{{.Name}}) Scan(value any) error { + if value == nil { + ns.{{.Name}}, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.{{.Name}}.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns Null{{.Name}}) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.{{.Name}}), nil +} + + +{{ if $.EmitEnumValidMethod }} +func (e {{.Name}}) Valid() bool { + switch e { + case {{ range $idx, $name := .Constants }}{{ if ne $idx 0 }},{{ "\n" }}{{ end }}{{ .Name }}{{ end }}: + return true + } + return false +} +{{ end }} + +{{ if $.EmitAllEnumValues }} +func All{{ .Name }}Values() []{{ .Name }} { + return []{{ .Name }}{ {{ range .Constants}}{{ "\n" }}{{ .Name }},{{ end }} + } +} +{{ end }} +{{end}} + +{{range .Structs}} +{{if .Comment}}{{comment .Comment}}{{end}} +type {{.Name}} struct { {{- range .Fields}} + {{- if .Comment}} + {{comment .Comment}}{{else}} + {{- end}} + {{.Name}} {{.Type}} {{if .Tag}}{{$.Q}}{{.Tag}}{{$.Q}}{{end}} + {{- end}} +} +{{end}} +{{end}} + +{{define "queryFile"}} +{{if .BuildTags}} +//go:build {{.BuildTags}} + +{{end}}// Code generated by sqlc. DO NOT EDIT. +{{if not .OmitSqlcVersion}}// versions: +// sqlc {{.SqlcVersion}} +{{end}}// source: {{.SourceName}} + +package {{.Package}} + +{{ if hasImports .SourceName }} +import ( + {{range imports .SourceName}} + {{range .}}{{.}} + {{end}} + {{end}} +) +{{end}} + +{{template "queryCode" . }} +{{end}} + +{{define "queryCode"}} +{{if .SQLDriver.IsPGX }} + {{- template "queryCodePgx" .}} +{{else}} + {{- template "queryCodeStd" .}} +{{end}} +{{end}} + +{{define "copyfromFile"}} +{{if .BuildTags}} +//go:build {{.BuildTags}} + +{{end}}// Code generated by sqlc. DO NOT EDIT. +{{if not .OmitSqlcVersion}}// versions: +// sqlc {{.SqlcVersion}} +{{end}}// source: {{.SourceName}} + +package {{.Package}} + +{{ if hasImports .SourceName }} +import ( + {{range imports .SourceName}} + {{range .}}{{.}} + {{end}} + {{end}} +) +{{end}} + +{{template "copyfromCode" . }} +{{end}} + +{{define "copyfromCode"}} +{{if .SQLDriver.IsPGX }} + {{- template "copyfromCodePgx" .}} +{{else if .SQLDriver.IsGoSQLDriverMySQL }} + {{- template "copyfromCodeGoSqlDriver" .}} +{{end}} +{{end}} + +{{define "batchFile"}} +{{if .BuildTags}} +//go:build {{.BuildTags}} + +{{end}}// Code generated by sqlc. DO NOT EDIT. +{{if not .OmitSqlcVersion}}// versions: +// sqlc {{.SqlcVersion}} +{{end}}// source: {{.SourceName}} + +package {{.Package}} + +{{ if hasImports .SourceName }} +import ( + {{range imports .SourceName}} + {{range .}}{{.}} + {{end}} + {{end}} +) +{{end}} + +{{template "batchCode" . }} +{{end}} + +{{define "batchCode"}} +{{if .SQLDriver.IsPGX }} + {{- template "batchCodePgx" .}} +{{end}} +{{end}} diff --git a/internal/codegen/json/gen.go b/internal/codegen/json/gen.go new file mode 100644 index 0000000..ad797ef --- /dev/null +++ b/internal/codegen/json/gen.go @@ -0,0 +1,68 @@ +package json + +import ( + "bytes" + "context" + ejson "encoding/json" + "fmt" + + "google.golang.org/protobuf/encoding/protojson" + + "github.com/sqlc-dev/sqlc/internal/plugin" +) + +func parseOptions(req *plugin.GenerateRequest) (*opts, error) { + if len(req.PluginOptions) == 0 { + return new(opts), nil + } + + var options *opts + dec := ejson.NewDecoder(bytes.NewReader(req.PluginOptions)) + dec.DisallowUnknownFields() + if err := dec.Decode(&options); err != nil { + return options, fmt.Errorf("unmarshalling options: %s", err) + } + return options, nil +} + +func Generate(ctx context.Context, req *plugin.GenerateRequest) (*plugin.GenerateResponse, error) { + options, err := parseOptions(req) + if err != nil { + return nil, err + } + + indent := " " + if options.Indent != "" { + indent = options.Indent + } + + filename := "codegen_request.json" + if options.Filename != "" { + filename = options.Filename + } + + // The output of protojson has randomized whitespace + // https://github.com/golang/protobuf/issues/1082 + m := &protojson.MarshalOptions{ + EmitUnpopulated: true, + Indent: "", + UseProtoNames: true, + } + data, err := m.Marshal(req) + if err != nil { + return nil, err + } + var rm ejson.RawMessage = data + blob, err := ejson.MarshalIndent(rm, "", indent) + if err != nil { + return nil, err + } + return &plugin.GenerateResponse{ + Files: []*plugin.File{ + { + Name: filename, + Contents: append(blob, '\n'), + }, + }, + }, nil +} diff --git a/internal/codegen/json/opts.go b/internal/codegen/json/opts.go new file mode 100644 index 0000000..9b3654b --- /dev/null +++ b/internal/codegen/json/opts.go @@ -0,0 +1,7 @@ +package json + +type opts struct { + Out string `json:"out"` + Indent string `json:"indent,omitempty"` + Filename string `json:"filename,omitempty"` +} diff --git a/internal/codegen/sdk/sdk.go b/internal/codegen/sdk/sdk.go new file mode 100644 index 0000000..53e3fc6 --- /dev/null +++ b/internal/codegen/sdk/sdk.go @@ -0,0 +1,33 @@ +package sdk + +import ( + "github.com/sqlc-dev/sqlc/internal/pattern" + "github.com/sqlc-dev/sqlc/internal/plugin" +) + +func DataType(n *plugin.Identifier) string { + if n.Schema != "" { + return n.Schema + "." + n.Name + } else { + return n.Name + } +} + +func MatchString(pat, target string) bool { + matcher, err := pattern.MatchCompile(pat) + if err != nil { + panic(err) + } + return matcher.MatchString(target) +} + +func SameTableName(tableID, f *plugin.Identifier, defaultSchema string) bool { + if tableID == nil { + return false + } + schema := tableID.Schema + if tableID.Schema == "" { + schema = defaultSchema + } + return tableID.Catalog == f.Catalog && schema == f.Schema && tableID.Name == f.Name +} diff --git a/internal/codegen/sdk/utils.go b/internal/codegen/sdk/utils.go new file mode 100644 index 0000000..ec4a4e5 --- /dev/null +++ b/internal/codegen/sdk/utils.go @@ -0,0 +1,42 @@ +package sdk + +import ( + "strings" + "unicode" +) + +func LowerTitle(s string) string { + if s == "" { + return s + } + + a := []rune(s) + a[0] = unicode.ToLower(a[0]) + return string(a) +} + +func Title(s string) string { + return strings.Title(s) +} + +// Go string literals cannot contain backtick. If a string contains +// a backtick, replace it the following way: +// +// input: +// +// SELECT `group` FROM foo +// +// output: +// +// SELECT ` + "`" + `group` + "`" + ` FROM foo +// +// # The escaped string must be rendered inside an existing string literal +// +// A string cannot be escaped twice +func EscapeBacktick(s string) string { + return strings.Replace(s, "`", "`+\"`\"+`", -1) +} + +func DoubleSlashComment(s string) string { + return "// " + strings.ReplaceAll(s, "\n", "\n// ") +} diff --git a/internal/codegen/sdk/utils_test.go b/internal/codegen/sdk/utils_test.go new file mode 100644 index 0000000..e162448 --- /dev/null +++ b/internal/codegen/sdk/utils_test.go @@ -0,0 +1,28 @@ +package sdk + +import ( + "testing" +) + +func TestLowerTitle(t *testing.T) { + + // empty + if LowerTitle("") != "" { + t.Fatal("expected empty title to remain empty") + } + + // all lowercase + if LowerTitle("lowercase") != "lowercase" { + t.Fatal("expected no changes when input is all lowercase") + } + + // all uppercase + if LowerTitle("UPPERCASE") != "uPPERCASE" { + t.Fatal("expected first rune to be lower when input is all uppercase") + } + + // Title Case + if LowerTitle("Title Case") != "title Case" { + t.Fatal("expected first rune to be lower when input is Title Case") + } +} diff --git a/internal/compiler/analyze.go b/internal/compiler/analyze.go new file mode 100644 index 0000000..020f786 --- /dev/null +++ b/internal/compiler/analyze.go @@ -0,0 +1,214 @@ +package compiler + +import ( + "sort" + + analyzer "github.com/sqlc-dev/sqlc/internal/analysis" + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/source" + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/named" + "github.com/sqlc-dev/sqlc/internal/sql/preprocess" + "github.com/sqlc-dev/sqlc/internal/sql/validate" +) + +type analysis struct { + Table *ast.TableName + Columns []*Column + Parameters []Parameter + Named *named.ParamSet + Query string +} + +func convertTableName(id *analyzer.Identifier) *ast.TableName { + if id == nil { + return nil + } + return &ast.TableName{ + Catalog: id.Catalog, + Schema: id.Schema, + Name: id.Name, + } +} + +func convertTypeName(id *analyzer.Identifier) *ast.TypeName { + if id == nil { + return nil + } + return &ast.TypeName{ + Catalog: id.Catalog, + Schema: id.Schema, + Name: id.Name, + } +} + +func convertColumn(c *analyzer.Column) *Column { + length := int(c.Length) + return &Column{ + Name: c.Name, + OriginalName: c.OriginalName, + DataType: c.DataType, + NotNull: c.NotNull, + Unsigned: c.Unsigned, + IsArray: c.IsArray, + ArrayDims: int(c.ArrayDims), + Comment: c.Comment, + Length: &length, + IsNamedParam: c.IsNamedParam, + IsFuncCall: c.IsFuncCall, + Scope: c.Scope, + Table: convertTableName(c.Table), + TableAlias: c.TableAlias, + Type: convertTypeName(c.Type), + EmbedTable: convertTableName(c.EmbedTable), + IsSqlcSlice: c.IsSqlcSlice, + } +} + +func combineAnalysis(prev *analysis, a *analyzer.Analysis) *analysis { + var cols []*Column + for _, c := range a.Columns { + cols = append(cols, convertColumn(c)) + } + var params []Parameter + for _, p := range a.Params { + params = append(params, Parameter{ + Number: int(p.Number), + Column: convertColumn(p.Column), + }) + } + if len(prev.Columns) == len(cols) { + for i := range prev.Columns { + // Only override column types if the analyzer provides a specific type + // (not "any"), since the catalog-based inference may have better info + if cols[i].DataType != "any" { + prev.Columns[i].DataType = cols[i].DataType + prev.Columns[i].IsArray = cols[i].IsArray + prev.Columns[i].ArrayDims = cols[i].ArrayDims + } + } + } else { + embedding := false + for i := range prev.Columns { + if prev.Columns[i].EmbedTable != nil { + embedding = true + } + } + if !embedding { + prev.Columns = cols + } + } + if len(prev.Parameters) == len(params) { + for i := range prev.Parameters { + // Only override parameter types if the analyzer provides a specific type + // (not "any"), since the catalog-based inference may have better info + if params[i].Column.DataType != "any" { + prev.Parameters[i].Column.DataType = params[i].Column.DataType + prev.Parameters[i].Column.IsArray = params[i].Column.IsArray + prev.Parameters[i].Column.ArrayDims = params[i].Column.ArrayDims + } + } + } else { + prev.Parameters = params + } + return prev +} + +func (c *Compiler) analyzeQuery(raw *ast.RawStmt, query string, pre *preprocess.Statement) (*analysis, error) { + return c._analyzeQuery(raw, query, pre, true) +} + +func (c *Compiler) inferQuery(raw *ast.RawStmt, query string, pre *preprocess.Statement) (*analysis, error) { + return c._analyzeQuery(raw, query, pre, false) +} + +func (c *Compiler) _analyzeQuery(raw *ast.RawStmt, query string, pre *preprocess.Statement, failfast bool) (*analysis, error) { + errors := make([]error, 0) + check := func(err error) error { + if failfast { + return err + } + if err != nil { + errors = append(errors, err) + } + return nil + } + + dollar := pre.Dollar + if err := check(pre.ParamErr); err != nil { + return nil, err + } + + namedParams := pre.Params + + var table *ast.TableName + switch n := raw.Stmt.(type) { + case *ast.InsertStmt: + var err error + table, err = ParseTableName(n.Relation) + if err := check(err); err != nil { + return nil, err + } + if err := check(validate.InsertStmt(c.catalog, table, n)); err != nil { + return nil, err + } + } + + if err := check(validate.FuncCall(c.catalog, c.combo, raw)); err != nil { + return nil, err + } + + if err := check(validate.Slice(raw, pre.Slices)); err != nil { + return nil, err + } + rvs := rangeVars(raw.Stmt) + refs, errs := findParameters(raw.Stmt) + if len(errs) > 0 { + if failfast { + return nil, errs[0] + } + errors = append(errors, errs...) + } + refs = uniqueParamRefs(refs, dollar) + if c.conf.Engine == config.EngineMySQL || !dollar { + sort.Slice(refs, func(i, j int) bool { return refs[i].ref.Location < refs[j].ref.Location }) + } else { + sort.Slice(refs, func(i, j int) bool { return refs[i].ref.Number < refs[j].ref.Number }) + } + embeds := pre.Embeds + qc, err := c.buildQueryCatalog(c.catalog, raw.Stmt, embeds) + if err := check(err); err != nil { + return nil, err + } + + params, err := c.resolveCatalogRefs(qc, rvs, refs, namedParams, embeds) + if err := check(err); err != nil { + return nil, err + } + cols, err := c.outputColumns(qc, raw.Stmt) + if err := check(err); err != nil { + return nil, err + } + + edits, err := c.expand(qc, raw) + if check(err); err != nil { + return nil, err + } + expanded, err := source.Mutate(query, edits) + if err != nil { + return nil, err + } + + var rerr error + if len(errors) > 0 { + rerr = errors[0] + } + + return &analysis{ + Table: table, + Columns: cols, + Parameters: params, + Query: expanded, + Named: namedParams, + }, rerr +} diff --git a/internal/compiler/catalog_core.go b/internal/compiler/catalog_core.go new file mode 100644 index 0000000..7f2e262 --- /dev/null +++ b/internal/compiler/catalog_core.go @@ -0,0 +1,62 @@ +package compiler + +import ( + "strings" + + "github.com/sqlc-dev/sqlc/internal/core" + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/catalog" +) + +// coreResultCatalog dumps the core catalog into the legacy catalog shape a +// Result carries, so codegen sees the same table models either way a query +// set was analyzed. Only relations make the trip: codegen reads tables and +// their columns to build models, and none of the types, functions or +// operators the core catalog also holds. +func coreResultCatalog(c *core.Catalog) (*catalog.Catalog, error) { + cat := catalog.New("public") + namespaces, err := c.Namespaces() + if err != nil { + return nil, err + } + for _, ns := range namespaces { + schema := &catalog.Schema{Name: ns.Name} + tables, err := c.TablesInNamespace(ns.OID) + if err != nil { + return nil, err + } + for _, table := range tables { + cols, err := c.ClassCodegenColumns(table.OID) + if err != nil { + return nil, err + } + t := &catalog.Table{Rel: &ast.TableName{Schema: ns.Name, Name: table.Name}} + for _, col := range cols { + // Codegen reads a data type and an array flag, and renders + // a "[]" per dimension, so an array of arrays of integers + // is the type integer with two dimensions. + expr, err := c.TypeExprOf(col.TypeOID) + if err != nil { + return nil, err + } + inner := expr.Innermost() + column := &catalog.Column{ + Name: col.Name, + Type: ast.TypeName{Name: strings.TrimSuffix(inner.Name, " unsigned")}, + IsNotNull: col.NotNull, + IsArray: expr.IsArray(), + ArrayDims: expr.ArrayDims(), + IsUnsigned: strings.HasSuffix(inner.Name, " unsigned"), + } + if len(inner.Args) > 0 && inner.Args[0].Int != nil { + l := int(*inner.Args[0].Int) + column.Length = &l + } + t.Columns = append(t.Columns, column) + } + schema.Tables = append(schema.Tables, t) + } + cat.Schemas = append(cat.Schemas, schema) + } + return cat, nil +} diff --git a/internal/compiler/compat.go b/internal/compiler/compat.go new file mode 100644 index 0000000..097d889 --- /dev/null +++ b/internal/compiler/compat.go @@ -0,0 +1,137 @@ +package compiler + +import ( + "fmt" + "strings" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/astutils" +) + +// This is mainly copy-pasted from internal/postgresql/parse.go +func stringSlice(list *ast.List) []string { + items := []string{} + for _, item := range list.Items { + if n, ok := item.(*ast.String); ok { + items = append(items, n.Str) + } + } + return items +} + +type Relation struct { + Catalog string + Schema string + Name string +} + +func parseRelation(node ast.Node) (*Relation, error) { + switch n := node.(type) { + case *ast.Boolean: + if n == nil { + return nil, fmt.Errorf("unexpected nil in %T node", n) + } + return &Relation{Name: "bool"}, nil + + case *ast.List: + if n == nil { + return nil, fmt.Errorf("unexpected nil in %T node", n) + } + parts := stringSlice(n) + switch len(parts) { + case 1: + return &Relation{ + Name: parts[0], + }, nil + case 2: + return &Relation{ + Schema: parts[0], + Name: parts[1], + }, nil + case 3: + return &Relation{ + Catalog: parts[0], + Schema: parts[1], + Name: parts[2], + }, nil + default: + return nil, fmt.Errorf("invalid name: %s", astutils.Join(n, ".")) + } + + case *ast.RangeVar: + if n == nil { + return nil, fmt.Errorf("unexpected nil in %T node", n) + } + name := Relation{} + if n.Catalogname != nil { + name.Catalog = *n.Catalogname + } + if n.Schemaname != nil { + name.Schema = *n.Schemaname + } + if n.Relname != nil { + name.Name = *n.Relname + } + return &name, nil + + case *ast.TypeName: + if n == nil { + return nil, fmt.Errorf("unexpected nil in %T node", n) + } + if n.Names != nil { + return parseRelation(n.Names) + } else { + return &Relation{Name: n.Name}, nil + } + + default: + return nil, fmt.Errorf("unexpected node type: %T", node) + } +} + +func ParseTableName(node ast.Node) (*ast.TableName, error) { + rel, err := parseRelation(node) + if err != nil { + return nil, fmt.Errorf("parse table name: %w", err) + } + return &ast.TableName{ + Catalog: rel.Catalog, + Schema: rel.Schema, + Name: rel.Name, + }, nil +} + +func ParseTypeName(node ast.Node) (*ast.TypeName, error) { + rel, err := parseRelation(node) + if err != nil { + return nil, fmt.Errorf("parse type name: %w", err) + } + return &ast.TypeName{ + Catalog: rel.Catalog, + Schema: rel.Schema, + Name: rel.Name, + }, nil +} + +func ParseRelationString(name string) (*Relation, error) { + parts := strings.Split(name, ".") + switch len(parts) { + case 1: + return &Relation{ + Name: parts[0], + }, nil + case 2: + return &Relation{ + Schema: parts[0], + Name: parts[1], + }, nil + case 3: + return &Relation{ + Catalog: parts[0], + Schema: parts[1], + Name: parts[2], + }, nil + default: + return nil, fmt.Errorf("invalid name: %s", name) + } +} diff --git a/internal/compiler/compile.go b/internal/compiler/compile.go new file mode 100644 index 0000000..b6f703d --- /dev/null +++ b/internal/compiler/compile.go @@ -0,0 +1,300 @@ +package compiler + +import ( + "errors" + "fmt" + "io" + "os" + "path/filepath" + "runtime" + "strings" + + "golang.org/x/sync/errgroup" + + "github.com/sqlc-dev/sqlc/internal/core" + coreschema "github.com/sqlc-dev/sqlc/internal/core/schema" + "github.com/sqlc-dev/sqlc/internal/migrations" + "github.com/sqlc-dev/sqlc/internal/multierr" + "github.com/sqlc-dev/sqlc/internal/opts" + "github.com/sqlc-dev/sqlc/internal/rpc" + "github.com/sqlc-dev/sqlc/internal/source" + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/preprocess" + "github.com/sqlc-dev/sqlc/internal/sql/sqlerr" + "github.com/sqlc-dev/sqlc/internal/sql/sqlpath" +) + +// TODO: Rename this interface Engine +type Parser interface { + Parse(io.Reader) ([]ast.Statement, error) + CommentSyntax() source.CommentSyntax + IsReservedKeyword(string) bool +} + +// schemaFile is a schema file's contents, after the rewrites that are applied +// before any of it is parsed. +type schemaFile struct { + name string + contents string +} + +func (c *Compiler) parseCatalog(schemas []string) error { + paths, err := sqlpath.Glob(schemas) + if err != nil { + return err + } + + merr := multierr.New() + files := make([]schemaFile, 0, len(paths)) + for _, path := range paths { + blob, err := os.ReadFile(path) + if err != nil { + merr.Add(path, "", 0, err) + continue + } + contents := migrations.RemoveRollbackStatements(string(blob)) + contents = migrations.RemovePsqlMetaCommands(contents) + files = append(files, schemaFile{name: path, contents: contents}) + c.schema = append(c.schema, contents) + } + + if c.coreAnalysis { + // A schema file that could not be read is not part of the schema the + // action was keyed on, so there is no catalog to restore and nothing + // further to report. + if len(merr.Errs()) > 0 { + return merr + } + if err := c.parseCatalogCore(files, merr); err != nil { + return err + } + } else { + c.parseCatalogLegacy(files, merr) + } + + if len(merr.Errs()) > 0 { + return merr + } + return nil +} + +func (c *Compiler) parseCatalogLegacy(files []schemaFile, merr *multierr.Error) { + for _, file := range files { + stmts, err := c.parser.Parse(strings.NewReader(file.contents)) + if err != nil { + // A schema file and a query file are often the same file, so a + // query's sqlc syntax can fail here. Look for an explanation + // before reporting the syntax error it caused. + if reported := addSyntaxErrors(merr, file.name, file.contents, preprocess.File(c.conf.Engine, file.contents)); !reported { + merr.Add(file.name, file.contents, 0, err) + } + continue + } + + for i := range stmts { + if err := c.catalog.Update(stmts[i], c); err != nil { + merr.Add(file.name, file.contents, stmts[i].Pos(), err) + continue + } + } + } +} + +// parseCatalogCore builds the catalog the analysis core works against: the +// dialect's seed with the schema's DDL applied. The two are one cached action, +// so a run that has built this catalog before restores it and never parses the +// schema at all. +func (c *Compiler) parseCatalogCore(files []schemaFile, merr *multierr.Error) error { + contents := make([]string, 0, len(files)) + for _, file := range files { + contents = append(contents, file.contents) + } + + cat, err := core.NewCached(string(c.conf.Engine), contents, func(cat *core.Catalog) error { + for _, file := range files { + stmts, err := c.parser.Parse(strings.NewReader(file.contents)) + if err != nil { + // A schema file and a query file are often the same file, so a + // query's sqlc syntax can fail here. Look for an explanation + // before reporting the syntax error it caused. + if reported := addSyntaxErrors(merr, file.name, file.contents, preprocess.File(c.conf.Engine, file.contents)); !reported { + merr.Add(file.name, file.contents, 0, err) + } + continue + } + for i := range stmts { + if err := coreschema.Apply(cat, stmts[i].Raw); err != nil { + merr.Add(file.name, file.contents, stmts[i].Pos(), err) + continue + } + } + } + // A catalog the whole schema did not make it into is not the catalog + // this action describes, so it is not one to keep. + if len(merr.Errs()) > 0 { + return merr + } + return nil + }, c.coreDialect) + + if cat == nil { + return fmt.Errorf("%s: init catalog: %w", c.conf.Engine, err) + } + // Whatever apply reported is already in merr, which the caller returns. + c.coreCatalog = cat + + // Codegen consumes the catalog through the Result, in the legacy shape. + legacy, err := coreResultCatalog(cat) + if err != nil { + return fmt.Errorf("%s: dump catalog: %w", c.conf.Engine, err) + } + c.catalog = legacy + return nil +} + +// statement is a parsed query awaiting analysis, with what error reporting +// needs to place it back in the file it came from. +type statement struct { + filename string + src string + pp *preprocess.Result + raw *ast.RawStmt +} + +func (c *Compiler) parseQueries(o opts.Parser) (*Result, error) { + merr := multierr.New() + files, err := sqlpath.Glob(c.conf.Queries) + if err != nil { + return nil, err + } + + var stmts []statement + for _, filename := range files { + blob, err := os.ReadFile(filename) + if err != nil { + merr.Add(filename, "", 0, err) + continue + } + src := string(blob) + + // sqlc syntax is not SQL. Rewrite it to native placeholders before the + // engine parser ever sees the query, so parsers only handle SQL. + pp := preprocess.File(c.conf.Engine, src) + + parsed, err := c.parser.Parse(strings.NewReader(pp.Text)) + if err != nil { + if reported := addSyntaxErrors(merr, filename, src, pp); !reported { + merr.Add(filename, src, 0, err) + } + continue + } + for _, stmt := range parsed { + stmts = append(stmts, statement{filename: filename, src: src, pp: pp, raw: stmt.Raw}) + } + } + + queries, errs := c.analyzeStatements(stmts, o) + + var q []*Query + set := map[string]struct{}{} + for i, stmt := range stmts { + if err := errs[i]; err != nil { + var e *sqlerr.Error + loc := stmt.raw.Pos() + if errors.As(err, &e) && e.Location != 0 { + loc = e.Location + } + // Locations are reported against the rewritten query; map them + // back so errors point at what the user wrote. + loc = stmt.pp.Origin(loc) + if e != nil && e.Location != 0 { + e.Location = loc + } + merr.Add(stmt.filename, stmt.src, loc, err) + // If this rpc unauthenticated error bubbles up, then all future parsing/analysis will fail + if errors.Is(err, rpc.ErrUnauthenticated) { + return nil, merr + } + continue + } + query := queries[i] + if query == nil { + continue + } + query.Metadata.Filename = filepath.Base(stmt.filename) + queryName := query.Metadata.Name + if queryName != "" { + if _, exists := set[queryName]; exists { + merr.Add(stmt.filename, stmt.src, stmt.pp.Origin(stmt.raw.Pos()), fmt.Errorf("duplicate query name: %s", queryName)) + continue + } + set[queryName] = struct{}{} + } + q = append(q, query) + } + + if len(merr.Errs()) > 0 { + return nil, merr + } + if len(q) == 0 { + return nil, fmt.Errorf("no queries contained in paths %s", strings.Join(c.conf.Queries, ",")) + } + + return &Result{ + Catalog: c.catalog, + Queries: q, + }, nil +} + +// analyzeStatements analyzes each statement, returning the results in the +// order the statements were given so that queries and errors come out in +// source order however they were produced. +// +// The analysis core reads the catalog and nothing else, so its statements are +// analyzed concurrently. Every other path holds state that a second goroutine +// would race — a database connection, the legacy catalog — and stays serial. +func (c *Compiler) analyzeStatements(stmts []statement, o opts.Parser) ([]*Query, []error) { + queries := make([]*Query, len(stmts)) + errs := make([]error, len(stmts)) + + analyze := func(i int) { + queries[i], errs[i] = c.parseQuery(stmts[i].raw, stmts[i].pp, o) + } + + workers := runtime.GOMAXPROCS(0) + if !c.coreAnalysis || workers < 2 || len(stmts) < 2 { + for i := range stmts { + analyze(i) + } + return queries, errs + } + + var g errgroup.Group + g.SetLimit(workers) + for i := range stmts { + g.Go(func() error { + analyze(i) + return nil + }) + } + g.Wait() + return queries, errs +} + +func addSyntaxErrors(merr *multierr.Error, filename, src string, pp *preprocess.Result) bool { + var found bool + for _, stmt := range pp.Statements() { + if stmt.Err == nil { + continue + } + found = true + loc := pp.Origin(stmt.Start) + var e *sqlerr.Error + if errors.As(stmt.Err, &e) && e.Location != 0 { + loc = pp.Origin(e.Location) + e.Location = loc + } + merr.Add(filename, src, loc, stmt.Err) + } + return found +} diff --git a/internal/compiler/engine.go b/internal/compiler/engine.go new file mode 100644 index 0000000..959207b --- /dev/null +++ b/internal/compiler/engine.go @@ -0,0 +1,199 @@ +package compiler + +import ( + "context" + "fmt" + + "github.com/sqlc-dev/sqlc/internal/analyzer" + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/core" + "github.com/sqlc-dev/sqlc/internal/dbmanager" + "github.com/sqlc-dev/sqlc/internal/engine/clickhouse" + "github.com/sqlc-dev/sqlc/internal/engine/dolphin" + "github.com/sqlc-dev/sqlc/internal/engine/duckdb" + "github.com/sqlc-dev/sqlc/internal/engine/googlesql" + "github.com/sqlc-dev/sqlc/internal/engine/mssql" + "github.com/sqlc-dev/sqlc/internal/engine/postgresql" + pganalyze "github.com/sqlc-dev/sqlc/internal/engine/postgresql/analyzer" + "github.com/sqlc-dev/sqlc/internal/engine/sqlite" + sqliteanalyze "github.com/sqlc-dev/sqlc/internal/engine/sqlite/analyzer" + "github.com/sqlc-dev/sqlc/internal/opts" + "github.com/sqlc-dev/sqlc/internal/sql/catalog" +) + +type Compiler struct { + conf config.SQL + combo config.CombinedSettings + catalog *catalog.Catalog + parser Parser + result *Result + analyzer analyzer.Analyzer + client dbmanager.Client + selector selector + + coreCatalog *core.Catalog + + // coreAnalysis routes every engine through the core catalog and analyzer, + // and coreDialect seeds the catalog it does so with. The catalog itself is + // not built until the schema is loaded, because the two are cached + // together. + coreAnalysis bool + coreDialect core.Option + + // newParser builds a parser for the configured engine, and is set for + // every engine either path supports. The core path analyzes statements + // concurrently, and a parser holds enough state that two goroutines cannot + // share one, so a goroutine that has to parse something of its own — the + // query text it just rewrote — builds its own rather than taking c.parser. + newParser func() Parser + + schema []string +} + +// Option configures a Compiler. +type Option func(*Compiler) + +// WithCoreAnalysis analyzes queries with the core catalog and analyzer rather +// than each engine's own analysis path. ClickHouse and GoogleSQL always do; +// this opts the remaining engines in. +func WithCoreAnalysis() Option { + return func(c *Compiler) { c.coreAnalysis = true } +} + +func NewCompiler(conf config.SQL, combo config.CombinedSettings, parserOpts opts.Parser, options ...Option) (*Compiler, error) { + c := &Compiler{conf: conf, combo: combo} + for _, o := range options { + o(c) + } + + // ClickHouse, GoogleSQL, SQL Server and DuckDB have no legacy analysis + // path to fall back to. + switch conf.Engine { + case config.EngineClickHouse, config.EngineGoogleSQL, config.EngineMSSQL, config.EngineDuckDB: + c.coreAnalysis = true + } + if c.coreAnalysis { + if err := c.initCore(); err != nil { + return nil, err + } + return c, nil + } + + if conf.Database != nil && conf.Database.Managed { + client := dbmanager.NewClient(combo.Global.Servers) + c.client = client + } + + switch conf.Engine { + case config.EngineSQLite: + c.newParser = func() Parser { return sqlite.NewParser() } + c.catalog = sqlite.NewCatalog() + c.selector = newSQLiteSelector() + + if conf.Database != nil { + if conf.Analyzer.Database == nil || *conf.Analyzer.Database { + c.analyzer = analyzer.Cached( + sqliteanalyze.New(*conf.Database), + combo.Global, + *conf.Database, + ) + } + } + case config.EngineMySQL: + c.newParser = func() Parser { return dolphin.NewParser() } + c.catalog = dolphin.NewCatalog() + c.selector = newDefaultSelector() + case config.EnginePostgreSQL: + c.newParser = func() Parser { return postgresql.NewParser() } + c.catalog = postgresql.NewCatalog() + c.selector = newDefaultSelector() + + if conf.Database != nil { + if conf.Analyzer.Database == nil || *conf.Analyzer.Database { + c.analyzer = analyzer.Cached( + pganalyze.New(c.client, *conf.Database), + combo.Global, + *conf.Database, + ) + } + } + default: + return nil, fmt.Errorf("unknown engine: %s", conf.Engine) + } + c.parser = c.newParser() + return c, nil +} + +// initCore wires up the engine's parser and a core catalog seeded with its +// dialect. No legacy catalog and no analyzer connection are involved. +func (c *Compiler) initCore() error { + var dialect core.Option + switch c.conf.Engine { + case config.EngineSQLite: + c.newParser = func() Parser { return sqlite.NewParser() } + c.selector = newSQLiteSelector() + dialect = sqlite.Dialect() + case config.EngineMySQL: + c.newParser = func() Parser { return dolphin.NewParser() } + c.selector = newDefaultSelector() + dialect = dolphin.Dialect() + case config.EnginePostgreSQL: + c.newParser = func() Parser { return postgresql.NewParser() } + c.selector = newDefaultSelector() + dialect = postgresql.Dialect() + case config.EngineClickHouse: + c.newParser = func() Parser { return clickhouse.NewParser() } + c.selector = newDefaultSelector() + dialect = clickhouse.Dialect() + case config.EngineGoogleSQL: + c.newParser = func() Parser { return googlesql.NewParser() } + c.selector = newDefaultSelector() + dialect = googlesql.Dialect() + case config.EngineMSSQL: + c.newParser = func() Parser { return mssql.NewParser() } + c.selector = newDefaultSelector() + dialect = mssql.Dialect() + case config.EngineDuckDB: + c.newParser = func() Parser { return duckdb.NewParser() } + c.selector = newDefaultSelector() + dialect = duckdb.Dialect() + default: + return fmt.Errorf("unknown engine: %s", c.conf.Engine) + } + c.parser = c.newParser() + c.coreDialect = dialect + return nil +} + +func (c *Compiler) Catalog() *catalog.Catalog { + return c.catalog +} + +func (c *Compiler) ParseCatalog(schema []string) error { + return c.parseCatalog(schema) +} + +func (c *Compiler) ParseQueries(queries []string, o opts.Parser) error { + r, err := c.parseQueries(o) + if err != nil { + return err + } + c.result = r + return nil +} + +func (c *Compiler) Result() *Result { + return c.result +} + +func (c *Compiler) Close(ctx context.Context) { + if c.analyzer != nil { + c.analyzer.Close(ctx) + } + if c.client != nil { + c.client.Close(ctx) + } + if c.coreCatalog != nil { + c.coreCatalog.Close() + } +} diff --git a/internal/compiler/expand.go b/internal/compiler/expand.go new file mode 100644 index 0000000..8c8a490 --- /dev/null +++ b/internal/compiler/expand.go @@ -0,0 +1,211 @@ +package compiler + +import ( + "fmt" + "regexp" + "strings" + + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/source" + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/astutils" +) + +func (c *Compiler) expand(qc *QueryCatalog, raw *ast.RawStmt) ([]source.Edit, error) { + // Return early if there are no A_Star nodes to expand + stars := astutils.Search(raw, func(node ast.Node) bool { + _, ok := node.(*ast.A_Star) + return ok + }) + if len(stars.Items) == 0 { + return nil, nil + } + list := astutils.Search(raw, func(node ast.Node) bool { + switch node.(type) { + case *ast.DeleteStmt: + case *ast.InsertStmt: + case *ast.SelectStmt: + case *ast.UpdateStmt: + default: + return false + } + return true + }) + if len(list.Items) == 0 { + return nil, nil + } + var edits []source.Edit + for _, item := range list.Items { + edit, err := c.expandStmt(qc, raw, item) + if err != nil { + return nil, err + } + edits = append(edits, edit...) + } + return edits, nil +} + +var validPostgresIdent = regexp.MustCompile(`^[a-z_][a-z0-9_$]*$`) + +func (c *Compiler) quoteIdent(ident string) string { + if c.parser.IsReservedKeyword(ident) { + return c.quote(ident) + } + // SQL identifiers and key words must begin with a letter (a-z, but also + // letters with diacritical marks and non-Latin letters) or an underscore + // (_). Subsequent characters in an identifier or key word can be letters, + // underscores, digits (0-9), or dollar signs ($). + // + // https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS + if c.conf.Engine == config.EnginePostgreSQL { + // camelCase means the column is also camelCase + if strings.ToLower(ident) != ident { + return c.quote(ident) + } + if !validPostgresIdent.MatchString(strings.ToLower(ident)) { + return c.quote(ident) + } + } + return ident +} + +func (c *Compiler) quote(x string) string { + switch c.conf.Engine { + case config.EngineMySQL: + return "`" + x + "`" + default: + return "\"" + x + "\"" + } +} + +// starOldFunc measures how much of the query text a star reference occupies, +// so an edit replaces the reference and nothing else. Each part is measured +// both bare and quoted: an embed was rewritten to "table.*" in the query text, +// preserving the way the user quoted the table, so it is measured the same way +// as a star reference the user wrote. +func (c *Compiler) starOldFunc(parts []string) func(string) int { + old := make([]string, 0, len(parts)) + for _, p := range parts { + if p == "*" { + old = append(old, p) + } else { + old = append(old, c.quoteIdent(p)) + } + } + return 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 + } +} + +func (c *Compiler) expandStmt(qc *QueryCatalog, raw *ast.RawStmt, node ast.Node) ([]source.Edit, error) { + tables, err := c.sourceTables(qc, node) + if err != nil { + return nil, err + } + + // Virtual tables for the OLD and NEW aliases available in a RETURNING + // clause (PostgreSQL 18) + rtables, err := c.returningTables(qc, node) + if err != nil { + return nil, err + } + + var targets *ast.List + switch n := node.(type) { + case *ast.DeleteStmt: + targets = n.ReturningList + case *ast.InsertStmt: + targets = n.ReturningList + case *ast.SelectStmt: + targets = n.TargetList + case *ast.UpdateStmt: + targets = n.ReturningList + default: + return nil, fmt.Errorf("outputColumns: unsupported node type: %T", n) + } + + var edits []source.Edit + for _, target := range targets.Items { + res, ok := target.(*ast.ResTarget) + if !ok { + continue + } + ref, ok := res.Val.(*ast.ColumnRef) + if !ok { + continue + } + if !hasStarRef(ref) { + continue + } + var parts, cols []string + for _, f := range ref.Fields.Items { + switch field := f.(type) { + case *ast.String: + parts = append(parts, field.Str) + case *ast.A_Star: + parts = append(parts, "*") + default: + return nil, fmt.Errorf("unknown field in ColumnRef: %T", f) + } + } + scope := astutils.Join(ref.Fields, ".") + counts := map[string]int{} + if scope == "" { + for _, t := range tables { + for _, c := range t.Columns { + counts[c.Name] += 1 + } + } + } + starTables := tables + if vt := returningTableForScope(tables, rtables, scope); vt != nil { + starTables = []*Table{vt} + } + for _, t := range starTables { + if scope != "" && scope != t.Rel.Name { + continue + } + tableName := c.quoteIdent(t.Rel.Name) + scopeName := c.quoteIdent(scope) + for _, column := range t.Columns { + cname := column.Name + if res.Name != nil { + cname = *res.Name + } + cname = c.quoteIdent(cname) + if scope != "" { + cname = scopeName + "." + cname + } + if counts[cname] > 1 { + cname = tableName + "." + cname + } + + // This is important for SQLite in particular which needs to + // wrap jsonb column values with `json(colname)` so they're in a + // publicly usable format (i.e. not jsonb). + cname = c.selector.ColumnExpr(cname, column) + cols = append(cols, cname) + } + } + edits = append(edits, source.Edit{ + Location: res.Location - raw.StmtLocation, + OldFunc: c.starOldFunc(parts), + New: strings.Join(cols, ", "), + }) + } + + return edits, nil +} diff --git a/internal/compiler/expand_core.go b/internal/compiler/expand_core.go new file mode 100644 index 0000000..ab818c3 --- /dev/null +++ b/internal/compiler/expand_core.go @@ -0,0 +1,76 @@ +package compiler + +import ( + "strings" + + "github.com/sqlc-dev/sqlc/internal/core" + "github.com/sqlc-dev/sqlc/internal/source" + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +// expandCore rewrites the stars in a query's text with the columns the core +// analyzer resolved them to. The analyzer has already walked the statement and +// its subqueries, so there is nothing left to look up here: what remains is +// deciding how each name is written, which is the engine's business and not +// the core's. +func (c *Compiler) expandCore(raw *ast.RawStmt, stars []core.StarExpansion) []source.Edit { + if len(stars) == 0 { + return nil + } + edits := make([]source.Edit, 0, len(stars)) + seen := make(map[int]bool, len(stars)) + for _, star := range stars { + // The analyzer types an expression again when a later clause refers to + // the output name it was given, so "SELECT (SELECT * FROM t) AS x ... + // GROUP BY x" reports the star in the subquery once per pass. The + // passes agree on what the star covers, and editing the same reference + // twice would overlap, so only the first is kept. + if seen[star.Location] { + continue + } + seen[star.Location] = true + + // Everything before the star qualifies it: "foo.*" is scoped to foo, + // while a bare "*" covers every relation in the FROM clause. + scope := strings.Join(star.Fields[:len(star.Fields)-1], ".") + + // An unqualified star that covers more than one relation may name the + // same column twice, so those are written with their relation. + counts := map[string]int{} + if scope == "" { + for _, col := range star.Columns { + counts[col.Name]++ + } + } + + cols := make([]string, 0, len(star.Columns)) + for _, col := range star.Columns { + cname := col.Name + if star.Alias != "" { + cname = star.Alias + } + cname = c.quoteIdent(cname) + if scope != "" { + cname = c.quoteIdent(scope) + "." + cname + } + if counts[cname] > 1 { + cname = c.quoteIdent(col.Relation) + "." + cname + } + + // This is important for SQLite in particular which needs to wrap + // jsonb column values with `json(colname)` so they're in a publicly + // usable format (i.e. not jsonb). + cols = append(cols, c.selector.ColumnExpr(cname, &Column{ + Name: col.Name, + DataType: col.DataType, + })) + } + + edits = append(edits, source.Edit{ + Location: star.Location - raw.StmtLocation, + OldFunc: c.starOldFunc(star.Fields), + New: strings.Join(cols, ", "), + }) + } + return edits +} diff --git a/internal/compiler/find_params.go b/internal/compiler/find_params.go new file mode 100644 index 0000000..8199add --- /dev/null +++ b/internal/compiler/find_params.go @@ -0,0 +1,214 @@ +package compiler + +import ( + "fmt" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/astutils" +) + +func findParameters(root ast.Node) ([]paramRef, []error) { + refs := make([]paramRef, 0) + errors := make([]error, 0) + v := paramSearch{seen: make(map[int]struct{}), refs: &refs, errs: &errors} + astutils.Walk(v, root) + if len(*v.errs) > 0 { + return refs, *v.errs + } else { + return refs, nil + } +} + +type paramRef struct { + parent ast.Node + rv *ast.RangeVar + ref *ast.ParamRef + name string // Named parameter support +} + +type paramSearch struct { + parent ast.Node + rangeVar *ast.RangeVar + refs *[]paramRef + seen map[int]struct{} + errs *[]error + + // XXX: Gross state hack for limit + limitCount ast.Node + limitOffset ast.Node +} + +type limitCount struct { +} + +func (l *limitCount) Pos() int { + return 0 +} + +type limitOffset struct { +} + +func (l *limitOffset) Pos() int { + return 0 +} + +func (p paramSearch) Visit(node ast.Node) astutils.Visitor { + switch n := node.(type) { + + case *ast.A_Expr: + p.parent = node + + case *ast.BetweenExpr: + p.parent = node + + case *ast.CallStmt: + p.parent = n.FuncCall + + case *ast.DeleteStmt: + if n.LimitCount != nil { + p.limitCount = n.LimitCount + } + + case *ast.FuncCall: + p.parent = node + + case *ast.InsertStmt: + if s, ok := n.SelectStmt.(*ast.SelectStmt); ok { + for i, item := range s.TargetList.Items { + target, ok := item.(*ast.ResTarget) + if !ok { + continue + } + ref, ok := target.Val.(*ast.ParamRef) + if !ok { + continue + } + if len(n.Cols.Items) <= i { + *p.errs = append(*p.errs, fmt.Errorf("INSERT has more expressions than target columns")) + return p + } + *p.refs = append(*p.refs, paramRef{parent: n.Cols.Items[i], ref: ref, rv: n.Relation}) + p.seen[ref.Location] = struct{}{} + } + for _, item := range s.ValuesLists.Items { + vl, ok := item.(*ast.List) + if !ok { + continue + } + for i, v := range vl.Items { + ref, ok := v.(*ast.ParamRef) + if !ok { + continue + } + if len(n.Cols.Items) <= i { + *p.errs = append(*p.errs, fmt.Errorf("INSERT has more expressions than target columns")) + return p + } + *p.refs = append(*p.refs, paramRef{parent: n.Cols.Items[i], ref: ref, rv: n.Relation}) + p.seen[ref.Location] = struct{}{} + } + } + } + + case *ast.UpdateStmt: + for _, item := range n.TargetList.Items { + target, ok := item.(*ast.ResTarget) + if !ok { + continue + } + ref, ok := target.Val.(*ast.ParamRef) + if !ok { + continue + } + for _, relation := range n.Relations.Items { + rv, ok := relation.(*ast.RangeVar) + if !ok { + continue + } + *p.refs = append(*p.refs, paramRef{parent: target, ref: ref, rv: rv}) + } + p.seen[ref.Location] = struct{}{} + } + if n.LimitCount != nil { + p.limitCount = n.LimitCount + } + + case *ast.RangeVar: + p.rangeVar = n + + case *ast.ResTarget: + p.parent = node + + case *ast.SelectStmt: + if n.LimitCount != nil { + p.limitCount = n.LimitCount + } + if n.LimitOffset != nil { + p.limitOffset = n.LimitOffset + } + + case *ast.TypeCast: + p.parent = node + + case *ast.ParamRef: + parent := p.parent + + if count, ok := p.limitCount.(*ast.ParamRef); ok { + if n.Number == count.Number { + parent = &limitCount{} + } + } + + if offset, ok := p.limitOffset.(*ast.ParamRef); ok { + if n.Number == offset.Number { + parent = &limitOffset{} + } + } + if _, found := p.seen[n.Location]; found { + break + } + + // Special, terrible case for *ast.MultiAssignRef + set := true + if res, ok := parent.(*ast.ResTarget); ok { + if multi, ok := res.Val.(*ast.MultiAssignRef); ok { + set = false + if row, ok := multi.Source.(*ast.RowExpr); ok { + for i, arg := range row.Args.Items { + if ref, ok := arg.(*ast.ParamRef); ok { + if multi.Colno == i+1 && ref.Number == n.Number { + set = true + } + } + } + } + } + } + + if set { + *p.refs = append(*p.refs, paramRef{parent: parent, ref: n, rv: p.rangeVar}) + p.seen[n.Location] = struct{}{} + } + return nil + + case *ast.In: + if n.Sel == nil { + p.parent = node + } else { + if sel, ok := n.Sel.(*ast.SelectStmt); ok && sel.FromClause != nil && len(sel.FromClause.Items) > 0 { + from := sel.FromClause + if schema, ok := from.Items[0].(*ast.RangeVar); ok && schema != nil { + p.rangeVar = &ast.RangeVar{ + Catalogname: schema.Catalogname, + Schemaname: schema.Schemaname, + Relname: schema.Relname, + } + } + } + } + if _, ok := n.Expr.(*ast.ParamRef); ok { + p.Visit(n.Expr) + } + } + return p +} diff --git a/internal/compiler/output_columns.go b/internal/compiler/output_columns.go new file mode 100644 index 0000000..557fb7d --- /dev/null +++ b/internal/compiler/output_columns.go @@ -0,0 +1,812 @@ +package compiler + +import ( + "errors" + "fmt" + + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/astutils" + "github.com/sqlc-dev/sqlc/internal/sql/catalog" + "github.com/sqlc-dev/sqlc/internal/sql/lang" + "github.com/sqlc-dev/sqlc/internal/sql/sqlerr" +) + +// OutputColumns determines which columns a statement will output +func (c *Compiler) OutputColumns(stmt ast.Node) ([]*catalog.Column, error) { + qc, err := c.buildQueryCatalog(c.catalog, stmt, nil) + if err != nil { + return nil, err + } + cols, err := c.outputColumns(qc, stmt) + if err != nil { + return nil, err + } + + catCols := make([]*catalog.Column, 0, len(cols)) + for _, col := range cols { + catCols = append(catCols, &catalog.Column{ + Name: col.Name, + Type: ast.TypeName{Name: col.DataType}, + IsNotNull: col.NotNull, + IsUnsigned: col.Unsigned, + IsArray: col.IsArray, + ArrayDims: col.ArrayDims, + Comment: col.Comment, + Length: col.Length, + }) + } + return catCols, nil +} + +func hasStarRef(cf *ast.ColumnRef) bool { + for _, item := range cf.Fields.Items { + if _, ok := item.(*ast.A_Star); ok { + return true + } + } + return false +} + +// Compute the output columns for a statement. +// +// Return an error if column references are ambiguous +// Return an error if column references don't exist +func (c *Compiler) outputColumns(qc *QueryCatalog, node ast.Node) ([]*Column, error) { + tables, err := c.sourceTables(qc, node) + if err != nil { + return nil, err + } + + // Virtual tables for the OLD and NEW aliases available in a RETURNING + // clause (PostgreSQL 18) + rtables, err := c.returningTables(qc, node) + if err != nil { + return nil, err + } + + targets := &ast.List{} + switch n := node.(type) { + case *ast.DeleteStmt: + targets = n.ReturningList + case *ast.InsertStmt: + targets = n.ReturningList + case *ast.SelectStmt: + targets = n.TargetList + isUnion := len(targets.Items) == 0 && n.Larg != nil + + if n.GroupClause != nil { + for _, item := range n.GroupClause.Items { + if err := c.findColumnForNode(item, tables, targets); err != nil { + return nil, err + } + } + } + validateOrderBy := true + if c.conf.StrictOrderBy != nil { + validateOrderBy = *c.conf.StrictOrderBy + } + if !isUnion && validateOrderBy { + if n.SortClause != nil { + for _, item := range n.SortClause.Items { + sb, ok := item.(*ast.SortBy) + if !ok { + continue + } + if err := c.findColumnForNode(sb.Node, tables, targets); err != nil { + return nil, fmt.Errorf("%v: if you want to skip this validation, set 'strict_order_by' to false", err) + } + } + } + if n.WindowClause != nil { + for _, item := range n.WindowClause.Items { + sb, ok := item.(*ast.List) + if !ok { + continue + } + for _, single := range sb.Items { + caseExpr, ok := single.(*ast.CaseExpr) + if !ok { + continue + } + if err := c.findColumnForNode(caseExpr.Xpr, tables, targets); err != nil { + return nil, fmt.Errorf("%v: if you want to skip this validation, set 'strict_order_by' to false", err) + } + } + } + } + } + + // For UNION queries, targets is empty and we need to look for the + // columns in Largs. + if isUnion { + return c.outputColumns(qc, n.Larg) + } + case *ast.UpdateStmt: + targets = n.ReturningList + } + + var cols []*Column + + for _, target := range targets.Items { + res, ok := target.(*ast.ResTarget) + if !ok { + continue + } + switch n := res.Val.(type) { + + case *ast.A_Const: + name := "" + if res.Name != nil { + name = *res.Name + } + switch n.Val.(type) { + case *ast.String: + cols = append(cols, &Column{Name: name, DataType: "text", NotNull: true}) + case *ast.Integer: + cols = append(cols, &Column{Name: name, DataType: "int", NotNull: true}) + case *ast.Float: + cols = append(cols, &Column{Name: name, DataType: "float", NotNull: true}) + case *ast.Boolean: + cols = append(cols, &Column{Name: name, DataType: "bool", NotNull: true}) + default: + cols = append(cols, &Column{Name: name, DataType: "any", NotNull: false}) + } + + case *ast.A_Expr: + name := "" + if res.Name != nil { + name = *res.Name + } + switch op := astutils.Join(n.Name, ""); { + case lang.IsComparisonOperator(op): + // TODO: Generate a name for these operations + cols = append(cols, &Column{Name: name, DataType: "bool", NotNull: true}) + case lang.IsMathematicalOperator(op): + cols = append(cols, &Column{Name: name, DataType: "int", NotNull: true}) + default: + cols = append(cols, &Column{Name: name, DataType: "any", NotNull: false}) + } + + case *ast.BoolExpr: + name := "" + if res.Name != nil { + name = *res.Name + } + notNull := false + if len(n.Args.Items) == 1 { + switch n.Boolop { + case ast.BoolExprTypeIsNull, ast.BoolExprTypeIsNotNull: + notNull = true + case ast.BoolExprTypeNot: + sublink, ok := n.Args.Items[0].(*ast.SubLink) + if ok && sublink.SubLinkType == ast.EXISTS_SUBLINK { + notNull = true + if name == "" { + name = "not_exists" + } + } + } + } + cols = append(cols, &Column{Name: name, DataType: "bool", NotNull: notNull}) + + case *ast.CaseExpr: + name := "" + if res.Name != nil { + name = *res.Name + } + // TODO: The TypeCase and A_Const code has been copied from below. Instead, we + // need a recurse function to get the type of a node. + if tc, ok := n.Defresult.(*ast.TypeCast); ok { + if tc.TypeName == nil { + return nil, errors.New("no type name type cast") + } + name := "" + if ref, ok := tc.Arg.(*ast.ColumnRef); ok { + name = astutils.Join(ref.Fields, "_") + } + if res.Name != nil { + name = *res.Name + } + // TODO Validate column names + col := toColumn(tc.TypeName) + col.Name = name + cols = append(cols, col) + } else if aconst, ok := n.Defresult.(*ast.A_Const); ok { + switch aconst.Val.(type) { + case *ast.String: + cols = append(cols, &Column{Name: name, DataType: "text", NotNull: true}) + case *ast.Integer: + cols = append(cols, &Column{Name: name, DataType: "int", NotNull: true}) + case *ast.Float: + cols = append(cols, &Column{Name: name, DataType: "float", NotNull: true}) + case *ast.Boolean: + cols = append(cols, &Column{Name: name, DataType: "bool", NotNull: true}) + default: + cols = append(cols, &Column{Name: name, DataType: "any", NotNull: false}) + } + } else { + cols = append(cols, &Column{Name: name, DataType: "any", NotNull: false}) + } + + case *ast.CoalesceExpr: + name := "coalesce" + if res.Name != nil { + name = *res.Name + } + var firstColumn *Column + var shouldNotBeNull bool + for _, arg := range n.Args.Items { + if _, ok := arg.(*ast.A_Const); ok { + shouldNotBeNull = true + continue + } + if ref, ok := arg.(*ast.ColumnRef); ok { + columns, err := outputColumnRefs(res, tablesForRef(ref, tables, rtables), ref) + if err != nil { + return nil, err + } + for _, c := range columns { + if firstColumn == nil { + firstColumn = c + } + shouldNotBeNull = shouldNotBeNull || c.NotNull + } + } + } + if firstColumn != nil { + firstColumn.NotNull = shouldNotBeNull + firstColumn.skipTableRequiredCheck = true + cols = append(cols, firstColumn) + } else { + cols = append(cols, &Column{Name: name, DataType: "any", NotNull: false}) + } + + case *ast.ColumnRef: + if hasStarRef(n) { + + // add a column with a reference to an embedded table + if embed, ok := qc.embeds.Find(n.Location, res.Location); ok { + cols = append(cols, &Column{ + Name: embed.Table.Name, + EmbedTable: embed.Table, + }) + continue + } + + // TODO: This code is copied in func expand() + scope := astutils.Join(n.Fields, ".") + starTables := tables + if vt := returningTableForScope(tables, rtables, scope); vt != nil { + starTables = []*Table{vt} + } + for _, t := range starTables { + if scope != "" && scope != t.Rel.Name { + continue + } + for _, c := range t.Columns { + cname := c.Name + if res.Name != nil { + cname = *res.Name + } + cols = append(cols, &Column{ + Name: cname, + OriginalName: c.Name, + Type: c.Type, + Scope: scope, + Table: c.Table, + TableAlias: t.Rel.Name, + DataType: c.DataType, + NotNull: c.NotNull, + Unsigned: c.Unsigned, + IsArray: c.IsArray, + ArrayDims: c.ArrayDims, + Length: c.Length, + }) + } + } + continue + } + + columns, err := outputColumnRefs(res, tablesForRef(n, tables, rtables), n) + if err != nil { + return nil, err + } + cols = append(cols, columns...) + + case *ast.FuncCall: + rel := n.Func + name := rel.Name + if res.Name != nil { + name = *res.Name + } + fun, err := qc.catalog.ResolveFuncCall(n) + if err == nil { + cols = append(cols, &Column{ + Name: name, + DataType: dataType(fun.ReturnType), + NotNull: !fun.ReturnTypeNullable, + IsFuncCall: true, + }) + } else { + cols = append(cols, &Column{ + Name: name, + DataType: "any", + IsFuncCall: true, + }) + } + + case *ast.SubLink: + name := "exists" + if res.Name != nil { + name = *res.Name + } + switch n.SubLinkType { + case ast.EXISTS_SUBLINK: + cols = append(cols, &Column{Name: name, DataType: "bool", NotNull: true}) + case ast.EXPR_SUBLINK: + subcols, err := c.outputColumns(qc, n.Subselect) + if err != nil { + return nil, err + } + first := subcols[0] + if res.Name != nil { + first.Name = *res.Name + } + cols = append(cols, first) + default: + cols = append(cols, &Column{Name: name, DataType: "any", NotNull: false}) + } + + case *ast.TypeCast: + if n.TypeName == nil { + return nil, errors.New("no type name type cast") + } + name := "" + if ref, ok := n.Arg.(*ast.ColumnRef); ok { + name = astutils.Join(ref.Fields, "_") + } + if res.Name != nil { + name = *res.Name + } + // TODO Validate column names + col := toColumn(n.TypeName) + col.Name = name + // TODO Add correct, real type inference + if constant, ok := n.Arg.(*ast.A_Const); ok { + if _, ok := constant.Val.(*ast.Null); ok { + col.NotNull = false + } + } + cols = append(cols, col) + + case *ast.SelectStmt: + subcols, err := c.outputColumns(qc, n) + if err != nil { + return nil, err + } + first := subcols[0] + if res.Name != nil { + first.Name = *res.Name + } + cols = append(cols, first) + + default: + name := "" + if res.Name != nil { + name = *res.Name + } + cols = append(cols, &Column{Name: name, DataType: "any", NotNull: false}) + + } + } + + if n, ok := node.(*ast.SelectStmt); ok { + for _, col := range cols { + if !col.NotNull || col.Table == nil || col.skipTableRequiredCheck { + continue + } + for _, f := range n.FromClause.Items { + res := isTableRequired(f, col, tableRequired) + if res != tableNotFound { + col.NotNull = res == tableRequired + break + } + } + } + } + + return cols, nil +} + +const ( + tableNotFound = iota + tableRequired + tableOptional +) + +func isTableRequired(n ast.Node, col *Column, prior int) int { + switch n := n.(type) { + case *ast.RangeVar: + tableMatch := *n.Relname == col.Table.Name + aliasMatch := true + if n.Alias != nil && col.TableAlias != "" { + aliasMatch = *n.Alias.Aliasname == col.TableAlias + } + if aliasMatch && tableMatch { + return prior + } + case *ast.JoinExpr: + helper := func(l, r int) int { + if res := isTableRequired(n.Larg, col, l); res != tableNotFound { + return res + } + if res := isTableRequired(n.Rarg, col, r); res != tableNotFound { + return res + } + return tableNotFound + } + switch n.Jointype { + case ast.JoinTypeLeft: + return helper(tableRequired, tableOptional) + case ast.JoinTypeRight: + return helper(tableOptional, tableRequired) + case ast.JoinTypeFull: + return helper(tableOptional, tableOptional) + case ast.JoinTypeInner, ast.JoinTypeCross, ast.JoinTypeComma: + return helper(tableRequired, tableRequired) + } + case *ast.List: + for _, item := range n.Items { + if res := isTableRequired(item, col, prior); res != tableNotFound { + return res + } + } + } + + return tableNotFound +} + +type tableVisitor struct { + list ast.List +} + +func (r *tableVisitor) Visit(n ast.Node) astutils.Visitor { + switch n.(type) { + case *ast.RangeVar, *ast.RangeFunction: + r.list.Items = append(r.list.Items, n) + return r + case *ast.RangeSubselect: + r.list.Items = append(r.list.Items, n) + return nil + default: + return r + } +} + +// Compute the output columns for a statement. +// +// Return an error if column references are ambiguous +// Return an error if column references don't exist +// Return an error if a table is referenced twice +// Return an error if an unknown column is referenced +func (c *Compiler) sourceTables(qc *QueryCatalog, node ast.Node) ([]*Table, error) { + list := &ast.List{} + switch n := node.(type) { + case *ast.DeleteStmt: + if n.Relations != nil { + list = n.Relations + } else if n.FromClause != nil { + // Multi-table DELETE: walk FromClause to find tables + var tv tableVisitor + astutils.Walk(&tv, n.FromClause) + list = &tv.list + } + case *ast.InsertStmt: + list = &ast.List{ + Items: []ast.Node{n.Relation}, + } + case *ast.SelectStmt: + var tv tableVisitor + astutils.Walk(&tv, n.FromClause) + list = &tv.list + case *ast.TruncateStmt: + list = astutils.Search(n.Relations, func(node ast.Node) bool { + _, ok := node.(*ast.RangeVar) + return ok + }) + case *ast.RefreshMatViewStmt: + list = astutils.Search(n.Relation, func(node ast.Node) bool { + _, ok := node.(*ast.RangeVar) + return ok + }) + case *ast.UpdateStmt: + var tv tableVisitor + astutils.Walk(&tv, n.FromClause) + astutils.Walk(&tv, n.Relations) + list = &tv.list + } + + var tables []*Table + for _, item := range list.Items { + switch n := item.(type) { + + case *ast.RangeFunction: + var funcCall *ast.FuncCall + switch f := n.Functions.Items[0].(type) { + case *ast.List: + switch fi := f.Items[0].(type) { + case *ast.FuncCall: + funcCall = fi + case *ast.SQLValueFunction: + continue // TODO handle this correctly + default: + continue + } + case *ast.FuncCall: + funcCall = f + default: + return nil, fmt.Errorf("sourceTables: unsupported function call type %T", n.Functions.Items[0]) + } + + // If the function or table can't be found, don't error out. There + // are many queries that depend on functions unknown to sqlc. + fn, err := qc.GetFunc(funcCall.Func) + if err != nil { + continue + } + var table *Table + if fn.ReturnType != nil { + table, err = qc.GetTable(&ast.TableName{ + Catalog: fn.ReturnType.Catalog, + Schema: fn.ReturnType.Schema, + Name: fn.ReturnType.Name, + }) + } + if table == nil || err != nil { + if n.Alias != nil && len(n.Alias.Colnames.Items) > 0 { + table = &Table{} + for _, colName := range n.Alias.Colnames.Items { + table.Columns = append(table.Columns, &Column{ + Name: colName.(*ast.String).Str, + DataType: "any", + }) + } + } else { + colName := fn.Rel.Name + if n.Alias != nil { + colName = *n.Alias.Aliasname + } + table = &Table{ + Rel: &ast.TableName{ + Catalog: fn.Rel.Catalog, + Schema: fn.Rel.Schema, + Name: fn.Rel.Name, + }, + } + if len(fn.Outs) > 0 { + for _, arg := range fn.Outs { + table.Columns = append(table.Columns, &Column{ + Name: arg.Name, + DataType: arg.Type.Name, + }) + } + } + if fn.ReturnType != nil { + table.Columns = []*Column{ + { + Name: colName, + DataType: fn.ReturnType.Name, + }, + } + } + } + } + if n.Alias != nil { + table.Rel = &ast.TableName{ + Name: *n.Alias.Aliasname, + } + } + tables = append(tables, table) + + case *ast.RangeSubselect: + cols, err := c.outputColumns(qc, n.Subquery) + if err != nil { + return nil, err + } + + var tableName string + if n.Alias != nil { + tableName = *n.Alias.Aliasname + } + + tables = append(tables, &Table{ + Rel: &ast.TableName{ + Name: tableName, + }, + Columns: cols, + }) + + case *ast.RangeVar: + fqn, err := ParseTableName(n) + if err != nil { + return nil, err + } + if qc == nil { + return nil, fmt.Errorf("query catalog is empty") + } + table, cerr := qc.GetTable(fqn) + if cerr != nil { + // TODO: Update error location + // cerr.Location = n.Location + // return nil, *cerr + return nil, cerr + } + if n.Alias != nil { + table.Rel = &ast.TableName{ + Catalog: table.Rel.Catalog, + Schema: table.Rel.Schema, + Name: *n.Alias.Aliasname, + } + } + tables = append(tables, table) + + default: + return nil, fmt.Errorf("sourceTable: unsupported list item type: %T", n) + } + } + return tables, nil +} + +func outputColumnRefs(res *ast.ResTarget, tables []*Table, node *ast.ColumnRef) ([]*Column, error) { + parts := stringSlice(node.Fields) + 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 + } + for _, c := range t.Columns { + + if c.Name == name { + found += 1 + cname := c.Name + if res.Name != nil { + cname = *res.Name + } + cols = append(cols, &Column{ + Name: cname, + Type: c.Type, + Table: c.Table, + TableAlias: alias, + DataType: c.DataType, + NotNull: c.NotNull, + Unsigned: c.Unsigned, + IsArray: c.IsArray, + ArrayDims: c.ArrayDims, + Length: c.Length, + EmbedTable: c.EmbedTable, + OriginalName: c.Name, + }) + } + } + } + if found == 0 { + return nil, &sqlerr.Error{ + Code: "42703", + Message: fmt.Sprintf("column %q does not exist", name), + Location: res.Location, + } + } + if found > 1 { + return nil, &sqlerr.Error{ + Code: "42703", + Message: fmt.Sprintf("column reference %q is ambiguous", name), + Location: res.Location, + } + } + return cols, nil +} + +func (c *Compiler) findColumnForNode(item ast.Node, tables []*Table, targetList *ast.List) error { + ref, ok := item.(*ast.ColumnRef) + if !ok { + return nil + } + if c.isImplicitColumnRef(ref) { + return nil + } + return findColumnForRef(ref, tables, targetList) +} + +// isImplicitColumnRef reports whether ref names a column that every table in +// the dialect has without declaring it, and which therefore never appears in +// a catalog built from the schema. SQLite gives each ordinary table a rowid, +// reachable under three spellings. +func (c *Compiler) isImplicitColumnRef(ref *ast.ColumnRef) bool { + if c.conf.Engine != config.EngineSQLite { + return false + } + parts := stringSlice(ref.Fields) + if len(parts) == 0 { + return false + } + switch parts[len(parts)-1] { + case "rowid", "_rowid_", "oid": + return true + } + return false +} + +func findColumnForRef(ref *ast.ColumnRef, tables []*Table, targetList *ast.List) error { + parts := stringSlice(ref.Fields) + var alias, name string + if len(parts) == 1 { + name = parts[0] + } else if len(parts) == 2 { + alias = parts[0] + name = parts[1] + } + + var found int + for _, t := range tables { + if alias != "" && t.Rel.Name != alias { + continue + } + + // Find matching column + for _, c := range t.Columns { + if c.Name == name { + found++ + break + } + } + } + + // Find matching alias if necessary + if found == 0 { + for _, c := range targetList.Items { + resTarget, ok := c.(*ast.ResTarget) + if !ok { + continue + } + if resTarget.Name != nil && *resTarget.Name == name { + found++ + } + } + } + + if found == 0 { + return &sqlerr.Error{ + Code: "42703", + Message: fmt.Sprintf("column reference %q not found", name), + Location: ref.Location, + } + } + if found > 1 { + return &sqlerr.Error{ + Code: "42703", + Message: fmt.Sprintf("column reference %q is ambiguous", name), + Location: ref.Location, + } + } + + return nil +} diff --git a/internal/compiler/parse.go b/internal/compiler/parse.go new file mode 100644 index 0000000..0fcc7ce --- /dev/null +++ b/internal/compiler/parse.go @@ -0,0 +1,201 @@ +package compiler + +import ( + "context" + "errors" + "fmt" + "strings" + + "github.com/sqlc-dev/sqlc/internal/debug" + "github.com/sqlc-dev/sqlc/internal/metadata" + "github.com/sqlc-dev/sqlc/internal/opts" + "github.com/sqlc-dev/sqlc/internal/source" + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/astutils" + "github.com/sqlc-dev/sqlc/internal/sql/preprocess" + "github.com/sqlc-dev/sqlc/internal/sql/validate" + "github.com/sqlc-dev/sqlc/internal/sqlcdebug" +) + +var debugDumpAST = sqlcdebug.New("dumpast") + +func (c *Compiler) parseQuery(stmt ast.Node, pp *preprocess.Result, o opts.Parser) (*Query, error) { + raw, ok := stmt.(*ast.RawStmt) + if !ok { + return nil, errors.New("node is not a statement") + } + + // The preprocessor already replaced every sqlc.* construct with native SQL + // and recorded what it replaced. + pre := pp.Statement(raw.StmtLocation) + if pre.Err != nil { + return nil, pre.Err + } + + // Engines number bind parameters in whatever order they convert the AST. + // Restore the numbering the preprocessor assigned in source order. + renumberParams(raw, pre.Numbers) + + if c.coreCatalog != nil { + return c.parseQueryCore(raw, pp.Text, pre) + } + + ctx := context.Background() + + if debugDumpAST.Value() == "1" { + debug.Dump(stmt) + } + + rawSQL, err := source.Pluck(pp.Text, raw.StmtLocation, raw.StmtLen) + if err != nil { + return nil, err + } + if rawSQL == "" { + return nil, errors.New("missing semicolon at end of file") + } + + name, cmd, err := metadata.ParseQueryNameAndType(rawSQL, metadata.CommentSyntax(c.parser.CommentSyntax())) + if err != nil { + return nil, err + } + + if name == "" { + return nil, nil + } + + if err := validate.Cmd(raw.Stmt, name, cmd); err != nil { + return nil, err + } + + md := metadata.Metadata{ + Name: name, + Cmd: cmd, + } + + // TODO eventually can use this for name and type/cmd parsing too + cleanedComments, err := source.CleanedComments(rawSQL, c.parser.CommentSyntax()) + if err != nil { + return nil, err + } + + md.Params, md.Flags, md.RuleSkiplist, err = metadata.ParseCommentFlags(cleanedComments) + if err != nil { + return nil, err + } + + var anlys *analysis + if c.analyzer != nil { + inference, _ := c.inferQuery(raw, rawSQL, pre) + if inference == nil { + inference = &analysis{} + } + if inference.Query == "" { + inference.Query = rawSQL + } + + result, err := c.analyzer.Analyze(ctx, raw, inference.Query, c.schema, inference.Named) + if err != nil { + return nil, err + } + + // If the query uses star expansion, verify that it was edited. If not, + // return an error. + stars := astutils.Search(raw, func(node ast.Node) bool { + _, ok := node.(*ast.A_Star) + return ok + }) + hasStars := len(stars.Items) > 0 + unchanged := inference.Query == rawSQL + if unchanged && hasStars { + return nil, fmt.Errorf("star expansion failed for query") + } + + // FOOTGUN: combineAnalysis mutates inference + anlys = combineAnalysis(inference, result) + } else { + anlys, err = c.analyzeQuery(raw, rawSQL, pre) + if err != nil { + return nil, err + } + } + + expanded := anlys.Query + + // If the query string was edited, make sure the syntax is valid + if expanded != rawSQL { + if _, err := c.parser.Parse(strings.NewReader(expanded)); err != nil { + return nil, fmt.Errorf("edited query syntax is invalid: %w", err) + } + } + + trimmed, comments, err := source.StripComments(expanded) + if err != nil { + return nil, err + } + + md.Comments = comments + + return &Query{ + RawStmt: raw, + Metadata: md, + Params: anlys.Parameters, + Columns: anlys.Columns, + SQL: trimmed, + InsertIntoTable: anlys.Table, + }, nil +} + +// renumberParams applies the parameter numbers the preprocessor assigned, +// matching each node by the location of its placeholder in the query text. +func renumberParams(raw *ast.RawStmt, numbers map[int]int) { + if len(numbers) == 0 { + return + } + astutils.Walk(astutils.VisitorFunc(func(node ast.Node) { + ref, ok := node.(*ast.ParamRef) + if !ok { + return + } + if n, ok := numbers[ref.Location]; ok { + ref.Number = n + } + }), raw) +} + +func rangeVars(root ast.Node) []*ast.RangeVar { + var vars []*ast.RangeVar + find := astutils.VisitorFunc(func(node ast.Node) { + switch n := node.(type) { + case *ast.RangeVar: + vars = append(vars, n) + } + }) + astutils.Walk(find, root) + return vars +} + +func uniqueParamRefs(in []paramRef, dollar bool) []paramRef { + m := make(map[int]bool, len(in)) + o := make([]paramRef, 0, len(in)) + for _, v := range in { + if !m[v.ref.Number] { + m[v.ref.Number] = true + if v.ref.Number != 0 { + o = append(o, v) + } + } + } + if !dollar { + start := 1 + for _, v := range in { + if v.ref.Number == 0 { + for m[start] { + start++ + } + v.ref.Number = start + o = append(o, v) + } + } + } + return o +} diff --git a/internal/compiler/parse_core.go b/internal/compiler/parse_core.go new file mode 100644 index 0000000..4c36d7d --- /dev/null +++ b/internal/compiler/parse_core.go @@ -0,0 +1,165 @@ +package compiler + +import ( + "errors" + "fmt" + "strings" + + "github.com/sqlc-dev/sqlc/internal/core" + coreanalyzer "github.com/sqlc-dev/sqlc/internal/core/analyzer" + "github.com/sqlc-dev/sqlc/internal/metadata" + "github.com/sqlc-dev/sqlc/internal/source" + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/named" + "github.com/sqlc-dev/sqlc/internal/sql/preprocess" + "github.com/sqlc-dev/sqlc/internal/sql/validate" +) + +func (c *Compiler) parseQueryCore(raw *ast.RawStmt, src string, pre *preprocess.Statement) (*Query, error) { + rawSQL, err := source.Pluck(src, raw.StmtLocation, raw.StmtLen) + if err != nil { + return nil, err + } + if strings.TrimSpace(rawSQL) == "" { + return nil, errors.New("missing semicolon at end of file") + } + + name, cmd, err := metadata.ParseQueryNameAndType(rawSQL, metadata.CommentSyntax(c.parser.CommentSyntax())) + if err != nil { + return nil, err + } + if name == "" { + return nil, nil + } + if err := validate.Cmd(raw.Stmt, name, cmd); err != nil { + return nil, err + } + + md := metadata.Metadata{Name: name, Cmd: cmd} + cleanedComments, err := source.CleanedComments(rawSQL, c.parser.CommentSyntax()) + if err != nil { + return nil, err + } + md.Params, md.Flags, md.RuleSkiplist, err = metadata.ParseCommentFlags(cleanedComments) + if err != nil { + return nil, err + } + + if pre.ParamErr != nil { + return nil, pre.ParamErr + } + namedParams := pre.Params + expanded := rawSQL + + var cols []*Column + var params []Parameter + switch raw.Stmt.(type) { + case *ast.SelectStmt, *ast.InsertStmt, *ast.UpdateStmt, *ast.DeleteStmt: + res, err := coreanalyzer.Prepare(c.coreCatalog, raw) + if err != nil { + return nil, err + } + for _, col := range res.Columns { + cols = append(cols, coreColumn(col)) + } + for _, p := range res.Parameters { + params = append(params, Parameter{Number: p.Number, Column: coreParamColumn(p, namedParams)}) + } + expanded, err = source.Mutate(rawSQL, c.expandCore(raw, res.Stars)) + if err != nil { + return nil, err + } + } + + // If the query string was edited, make sure the syntax is valid + if expanded != rawSQL { + if _, err := c.newParser().Parse(strings.NewReader(expanded)); err != nil { + return nil, fmt.Errorf("edited query syntax is invalid: %w", err) + } + } + + trimmed, comments, err := source.StripComments(expanded) + if err != nil { + return nil, err + } + md.Comments = comments + + var insertTable *ast.TableName + if ins, ok := raw.Stmt.(*ast.InsertStmt); ok { + insertTable, _ = ParseTableName(ins.Relation) + } + + return &Query{ + RawStmt: raw, + Metadata: md, + Params: params, + Columns: cols, + SQL: trimmed, + InsertIntoTable: insertTable, + }, nil +} + +func coreColumn(c core.Column) *Column { + col := &Column{ + Name: c.Name, + DataType: c.DataType, + NotNull: c.NotNull, + IsArray: c.IsArray, + TypeExpr: c.Type, + } + describeType(col, c.Type) + if c.Source != nil && c.Source.Table != "" { + col.Table = &ast.TableName{Schema: c.Source.Schema, Name: c.Source.Table} + col.TableAlias = c.Source.TableAlias + col.OriginalName = c.Source.Column + } + return col +} + +// describeType fills in what codegen reads about a type from its +// expression: one array dimension per nesting, the length that is the +// innermost type's first integer argument (which is how a MySQL tinyint(1) +// is told from a tinyint), and whether the innermost type is unsigned. +func describeType(col *Column, t *core.TypeExpr) { + if t == nil { + if col.IsArray { + col.ArrayDims = 1 + } + return + } + col.ArrayDims = t.ArrayDims() + inner := t.Innermost() + if len(inner.Args) > 0 && inner.Args[0].Int != nil { + l := int(*inner.Args[0].Int) + col.Length = &l + } + col.Unsigned = strings.HasSuffix(inner.Name, " unsigned") +} + +func coreParamColumn(p core.Parameter, params *named.ParamSet) *Column { + col := &Column{ + Name: p.Name, + DataType: p.DataType, + NotNull: p.NotNull, + IsArray: p.IsArray, + TypeExpr: p.Type, + } + describeType(col, p.Type) + if p.Source != nil && p.Source.Table != "" { + col.Table = &ast.TableName{Schema: p.Source.Schema, Name: p.Source.Table} + col.OriginalName = p.Source.Column + } + if col.Name == "" && p.Source != nil { + col.Name = p.Source.Column + } + // Merge in what the user asked for: sqlc.narg() makes the parameter + // nullable and sqlc.slice() marks it as a slice, whichever way the + // analyzer typed it. + if param, isNamed := params.FetchMerge(p.Number, named.NewInferredParam(col.Name, p.NotNull)); isNamed { + col.Name = param.Name() + col.NotNull = param.NotNull() + col.IsSqlcSlice = param.IsSqlcSlice() + col.IsNamedParam = true + } + return col +} diff --git a/internal/compiler/query.go b/internal/compiler/query.go new file mode 100644 index 0000000..8753d5a --- /dev/null +++ b/internal/compiler/query.go @@ -0,0 +1,67 @@ +package compiler + +import ( + "github.com/sqlc-dev/sqlc/internal/core" + "github.com/sqlc-dev/sqlc/internal/metadata" + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/catalog" +) + +type Function struct { + Rel *ast.FuncName + ReturnType *ast.TypeName + Outs []*catalog.Argument +} + +type Table struct { + Rel *ast.TableName + Columns []*Column +} + +type Column struct { + Name string + OriginalName string + DataType string + NotNull bool + Unsigned bool + IsArray bool + ArrayDims int + Comment string + Length *int + IsNamedParam bool + IsFuncCall bool + + // XXX: Figure out what PostgreSQL calls `foo.id` + Scope string + Table *ast.TableName + TableAlias string + Type *ast.TypeName + EmbedTable *ast.TableName + + // TypeExpr is the type as the analysis core wrote it, with the + // arguments and nesting DataType and IsArray flatten away. It is unset + // on the legacy path. + TypeExpr *core.TypeExpr + + IsSqlcSlice bool // is this sqlc.slice() + + skipTableRequiredCheck bool +} + +type Query struct { + SQL string + Metadata metadata.Metadata + Columns []*Column + Params []Parameter + + // Needed for CopyFrom + InsertIntoTable *ast.TableName + + // Needed for vet + RawStmt *ast.RawStmt +} + +type Parameter struct { + Number int + Column *Column +} diff --git a/internal/compiler/query_catalog.go b/internal/compiler/query_catalog.go new file mode 100644 index 0000000..c497241 --- /dev/null +++ b/internal/compiler/query_catalog.go @@ -0,0 +1,109 @@ +package compiler + +import ( + "fmt" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/catalog" + "github.com/sqlc-dev/sqlc/internal/sql/preprocess" +) + +type QueryCatalog struct { + catalog *catalog.Catalog + ctes map[string]*Table + embeds preprocess.EmbedSet +} + +func (comp *Compiler) buildQueryCatalog(c *catalog.Catalog, node ast.Node, embeds preprocess.EmbedSet) (*QueryCatalog, error) { + var with *ast.WithClause + switch n := node.(type) { + case *ast.DeleteStmt: + with = n.WithClause + case *ast.InsertStmt: + with = n.WithClause + case *ast.UpdateStmt: + with = n.WithClause + case *ast.SelectStmt: + with = n.WithClause + default: + with = nil + } + qc := &QueryCatalog{catalog: c, ctes: map[string]*Table{}, embeds: embeds} + if with != nil { + for _, item := range with.Ctes.Items { + if cte, ok := item.(*ast.CommonTableExpr); ok { + cols, err := comp.outputColumns(qc, cte.Ctequery) + if err != nil { + return nil, err + } + var names []string + if cte.Aliascolnames != nil { + for _, item := range cte.Aliascolnames.Items { + if val, ok := item.(*ast.String); ok { + names = append(names, val.Str) + } else { + names = append(names, "") + } + } + } + rel := &ast.TableName{Name: *cte.Ctename} + for i := range cols { + cols[i].Table = rel + if len(names) > i { + cols[i].Name = names[i] + } + } + qc.ctes[*cte.Ctename] = &Table{ + Rel: rel, + Columns: cols, + } + } + } + } + return qc, nil +} + +func ConvertColumn(rel *ast.TableName, c *catalog.Column) *Column { + return &Column{ + Table: rel, + Name: c.Name, + DataType: dataType(&c.Type), + NotNull: c.IsNotNull, + Unsigned: c.IsUnsigned, + IsArray: c.IsArray, + ArrayDims: c.ArrayDims, + Type: &c.Type, + Length: c.Length, + } +} + +func (qc QueryCatalog) GetTable(rel *ast.TableName) (*Table, error) { + cte, exists := qc.ctes[rel.Name] + if exists { + return &Table{Rel: rel, Columns: cte.Columns}, nil + } + src, err := qc.catalog.GetTable(rel) + if err != nil { + return nil, err + } + var cols []*Column + for _, c := range src.Columns { + cols = append(cols, ConvertColumn(rel, c)) + } + return &Table{Rel: rel, Columns: cols}, nil +} + +func (qc QueryCatalog) GetFunc(rel *ast.FuncName) (*Function, error) { + funcs, err := qc.catalog.ListFuncsByName(rel) + if err != nil { + return nil, err + } + if len(funcs) == 0 { + return nil, fmt.Errorf("function not found: %s", rel.Name) + } + return &Function{ + Rel: rel, + Outs: funcs[0].OutArgs(), + ReturnType: funcs[0].ReturnType, + }, nil +} diff --git a/internal/compiler/resolve.go b/internal/compiler/resolve.go new file mode 100644 index 0000000..f47a01d --- /dev/null +++ b/internal/compiler/resolve.go @@ -0,0 +1,638 @@ +package compiler + +import ( + "fmt" + "log/slog" + "strconv" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/astutils" + "github.com/sqlc-dev/sqlc/internal/sql/catalog" + "github.com/sqlc-dev/sqlc/internal/sql/named" + "github.com/sqlc-dev/sqlc/internal/sql/preprocess" + "github.com/sqlc-dev/sqlc/internal/sql/sqlerr" +) + +func dataType(n *ast.TypeName) string { + if n.Schema != "" { + return n.Schema + "." + n.Name + } else { + return n.Name + } +} + +func (comp *Compiler) resolveCatalogRefs(qc *QueryCatalog, rvs []*ast.RangeVar, args []paramRef, params *named.ParamSet, embeds preprocess.EmbedSet) ([]Parameter, error) { + c := comp.catalog + + aliasMap := map[string]*ast.TableName{} + // TODO: Deprecate defaultTable + var defaultTable *ast.TableName + var tables []*ast.TableName + + typeMap := map[string]map[string]map[string]*catalog.Column{} + indexTable := func(table catalog.Table) error { + tables = append(tables, table.Rel) + if defaultTable == nil { + defaultTable = table.Rel + } + schema := table.Rel.Schema + if schema == "" { + schema = c.DefaultSchema + } + if _, exists := typeMap[schema]; !exists { + typeMap[schema] = map[string]map[string]*catalog.Column{} + } + typeMap[schema][table.Rel.Name] = map[string]*catalog.Column{} + for _, c := range table.Columns { + cc := c + typeMap[schema][table.Rel.Name][c.Name] = cc + } + return nil + } + + for _, rv := range rvs { + if rv.Relname == nil { + continue + } + fqn, err := ParseTableName(rv) + if err != nil { + return nil, err + } + if _, found := aliasMap[fqn.Name]; found { + continue + } + table, err := c.GetTable(fqn) + if err != nil { + if qc == nil { + continue + } + // If the table name doesn't exist, first check if it's a CTE + if _, qcerr := qc.GetTable(fqn); qcerr != nil { + return nil, err + } + continue + } + err = indexTable(table) + if err != nil { + return nil, err + } + if rv.Alias != nil { + aliasMap[*rv.Alias.Aliasname] = fqn + } + } + + // resolve a table for an embed + for _, embed := range embeds { + table, err := c.GetTable(embed.Table) + if err == nil { + embed.Table = table.Rel + continue + } + + if alias, ok := aliasMap[embed.Table.Name]; ok { + embed.Table = alias + continue + } + + return nil, fmt.Errorf("unable to resolve table with %q: %w", embed.Orig(), err) + } + + var a []Parameter + + addUnknownParam := func(ref paramRef) { + defaultP := named.NewInferredParam(ref.name, false) + p, isNamed := params.FetchMerge(ref.ref.Number, defaultP) + a = append(a, Parameter{ + Number: ref.ref.Number, + Column: &Column{ + Name: p.Name(), + DataType: "any", + IsNamedParam: isNamed, + }, + }) + } + + for _, ref := range args { + switch n := ref.parent.(type) { + + case *limitOffset: + defaultP := named.NewInferredParam("offset", true) + p, isNamed := params.FetchMerge(ref.ref.Number, defaultP) + a = append(a, Parameter{ + Number: ref.ref.Number, + Column: &Column{ + Name: p.Name(), + DataType: "integer", + NotNull: p.NotNull(), + IsNamedParam: isNamed, + }, + }) + + case *limitCount: + defaultP := named.NewInferredParam("limit", true) + p, isNamed := params.FetchMerge(ref.ref.Number, defaultP) + a = append(a, Parameter{ + Number: ref.ref.Number, + Column: &Column{ + Name: p.Name(), + DataType: "integer", + NotNull: p.NotNull(), + IsNamedParam: isNamed, + }, + }) + + case *ast.A_Expr: + // TODO: While this works for a wide range of simple expressions, + // more complicated expressions will cause this logic to fail. + list := astutils.Search(n.Lexpr, func(node ast.Node) bool { + _, ok := node.(*ast.ColumnRef) + return ok + }) + if len(list.Items) == 0 { + list = astutils.Search(n.Rexpr, func(node ast.Node) bool { + _, ok := node.(*ast.ColumnRef) + return ok + }) + } + + if len(list.Items) == 0 { + // TODO: Move this to database-specific engine package + dataType := "any" + if astutils.Join(n.Name, ".") == "||" { + dataType = "text" + } + + defaultP := named.NewParam("") + p, isNamed := params.FetchMerge(ref.ref.Number, defaultP) + a = append(a, Parameter{ + Number: ref.ref.Number, + Column: &Column{ + Name: p.Name(), + DataType: dataType, + IsNamedParam: isNamed, + NotNull: p.NotNull(), + IsSqlcSlice: p.IsSqlcSlice(), + }, + }) + continue + } + + switch node := list.Items[0].(type) { + case *ast.ColumnRef: + items := stringSlice(node.Fields) + var key, alias string + switch len(items) { + case 1: + key = items[0] + case 2: + alias = items[0] + key = items[1] + case 3: + // schema := items[0] + alias = items[1] + key = items[2] + default: + panic("too many field items: " + strconv.Itoa(len(items))) + } + + search := tables + if alias != "" { + if original, ok := aliasMap[alias]; ok { + search = []*ast.TableName{original} + } else { + var located bool + for _, fqn := range tables { + if fqn.Name == alias { + located = true + search = []*ast.TableName{fqn} + } + } + if !located { + return nil, &sqlerr.Error{ + Code: "42703", + Message: fmt.Sprintf("table alias %q does not exist", alias), + Location: node.Location, + } + } + } + } + + var found int + for _, table := range search { + schema := table.Schema + if schema == "" { + schema = c.DefaultSchema + } + if c, ok := typeMap[schema][table.Name][key]; ok { + found += 1 + if ref.name != "" { + key = ref.name + } + + defaultP := named.NewInferredParam(key, c.IsNotNull) + p, isNamed := params.FetchMerge(ref.ref.Number, defaultP) + a = append(a, Parameter{ + Number: ref.ref.Number, + Column: &Column{ + Name: p.Name(), + OriginalName: c.Name, + DataType: dataType(&c.Type), + NotNull: p.NotNull(), + Unsigned: c.IsUnsigned, + IsArray: c.IsArray, + ArrayDims: c.ArrayDims, + Length: c.Length, + Table: table, + IsNamedParam: isNamed, + IsSqlcSlice: p.IsSqlcSlice(), + }, + }) + } + } + + if found == 0 { + return nil, &sqlerr.Error{ + Code: "42703", + Message: fmt.Sprintf("column %q does not exist", key), + Location: node.Location, + } + } + if found > 1 { + return nil, &sqlerr.Error{ + Code: "42703", + Message: fmt.Sprintf("column reference %q is ambiguous", key), + Location: node.Location, + } + } + } + + case *ast.BetweenExpr: + if n == nil || n.Expr == nil || n.Left == nil || n.Right == nil { + fmt.Println("ast.BetweenExpr is nil") + continue + } + + var key string + if ref, ok := n.Expr.(*ast.ColumnRef); ok { + itemsCount := len(ref.Fields.Items) + if str, ok := ref.Fields.Items[itemsCount-1].(*ast.String); ok { + key = str.Str + } + } + + for _, table := range tables { + schema := table.Schema + if schema == "" { + schema = c.DefaultSchema + } + + if c, ok := typeMap[schema][table.Name][key]; ok { + defaultP := named.NewInferredParam(key, c.IsNotNull) + p, isNamed := params.FetchMerge(ref.ref.Number, defaultP) + var namePrefix string + if !isNamed { + if ref.ref == n.Left { + namePrefix = "from_" + } else if ref.ref == n.Right { + namePrefix = "to_" + } + } + + a = append(a, Parameter{ + Number: ref.ref.Number, + Column: &Column{ + Name: namePrefix + p.Name(), + DataType: dataType(&c.Type), + NotNull: p.NotNull(), + Unsigned: c.IsUnsigned, + IsArray: c.IsArray, + ArrayDims: c.ArrayDims, + Table: table, + IsNamedParam: isNamed, + IsSqlcSlice: p.IsSqlcSlice(), + }, + }) + } + } + + case *ast.FuncCall: + fun, err := c.ResolveFuncCall(n) + if err != nil { + // Synthesize a function on the fly to avoid returning with an error + // for an unknown Postgres function (e.g. defined in an extension) + var args []*catalog.Argument + for range n.Args.Items { + args = append(args, &catalog.Argument{ + Type: &ast.TypeName{Name: "any"}, + }) + } + fun = &catalog.Function{ + Name: n.Func.Name, + Args: args, + ReturnType: &ast.TypeName{Name: "any"}, + } + } + + var added bool + for i, item := range n.Args.Items { + funcName := fun.Name + var argName string + switch inode := item.(type) { + case *ast.ParamRef: + if inode.Number != ref.ref.Number { + continue + } + case *ast.TypeCast: + pr, ok := inode.Arg.(*ast.ParamRef) + if !ok { + continue + } + if pr.Number != ref.ref.Number { + continue + } + case *ast.NamedArgExpr: + pr, ok := inode.Arg.(*ast.ParamRef) + if !ok { + continue + } + if pr.Number != ref.ref.Number { + continue + } + if inode.Name != nil { + argName = *inode.Name + } + default: + continue + } + + if fun.Args == nil { + defaultName := funcName + if argName != "" { + defaultName = argName + } + + defaultP := named.NewInferredParam(defaultName, false) + p, isNamed := params.FetchMerge(ref.ref.Number, defaultP) + added = true + a = append(a, Parameter{ + Number: ref.ref.Number, + Column: &Column{ + Name: p.Name(), + DataType: "any", + IsNamedParam: isNamed, + NotNull: p.NotNull(), + IsSqlcSlice: p.IsSqlcSlice(), + }, + }) + continue + } + + var paramName string + var paramType *ast.TypeName + + if argName == "" { + if i < len(fun.Args) { + paramName = fun.Args[i].Name + paramType = fun.Args[i].Type + } + } else { + paramName = argName + for _, arg := range fun.Args { + if arg.Name == argName { + paramType = arg.Type + } + } + if paramType == nil { + panic(fmt.Sprintf("named argument %s has no type", paramName)) + } + } + if paramName == "" { + paramName = funcName + } + if paramType == nil { + paramType = &ast.TypeName{Name: ""} + } + + defaultP := named.NewInferredParam(paramName, true) + p, isNamed := params.FetchMerge(ref.ref.Number, defaultP) + added = true + a = append(a, Parameter{ + Number: ref.ref.Number, + Column: &Column{ + Name: p.Name(), + DataType: dataType(paramType), + NotNull: p.NotNull(), + IsNamedParam: isNamed, + IsSqlcSlice: p.IsSqlcSlice(), + }, + }) + } + + if fun.ReturnType == nil { + if !added { + addUnknownParam(ref) + } + continue + } + + table, err := c.GetTable(&ast.TableName{ + Catalog: fun.ReturnType.Catalog, + Schema: fun.ReturnType.Schema, + Name: fun.ReturnType.Name, + }) + if err != nil { + if !added { + addUnknownParam(ref) + } + continue + } + err = indexTable(table) + if err != nil { + return nil, err + } + + case *ast.ResTarget: + if n.Name == nil { + return nil, fmt.Errorf("*ast.ResTarget has nil name") + } + key := *n.Name + + var schema, rel string + // TODO: Deprecate defaultTable + if defaultTable != nil { + schema = defaultTable.Schema + rel = defaultTable.Name + } + if ref.rv != nil { + fqn, err := ParseTableName(ref.rv) + if err != nil { + return nil, err + } + schema = fqn.Schema + rel = fqn.Name + } + if schema == "" { + schema = c.DefaultSchema + } + + tableMap, ok := typeMap[schema][rel] + if !ok { + return nil, sqlerr.RelationNotFound(rel) + } + + if c, ok := tableMap[key]; ok { + defaultP := named.NewInferredParam(key, c.IsNotNull) + p, isNamed := params.FetchMerge(ref.ref.Number, defaultP) + a = append(a, Parameter{ + Number: ref.ref.Number, + Column: &Column{ + Name: p.Name(), + OriginalName: c.Name, + DataType: dataType(&c.Type), + NotNull: p.NotNull(), + Unsigned: c.IsUnsigned, + IsArray: c.IsArray, + ArrayDims: c.ArrayDims, + Table: &ast.TableName{Schema: schema, Name: rel}, + Length: c.Length, + IsNamedParam: isNamed, + IsSqlcSlice: p.IsSqlcSlice(), + }, + }) + } else { + return nil, &sqlerr.Error{ + Code: "42703", + Message: fmt.Sprintf("column %q does not exist", key), + Location: n.Location, + } + } + + case *ast.TypeCast: + if n.TypeName == nil { + return nil, fmt.Errorf("*ast.TypeCast has nil type name") + } + col := toColumn(n.TypeName) + defaultP := named.NewInferredParam(col.Name, col.NotNull) + p, isNamed := params.FetchMerge(ref.ref.Number, defaultP) + + col.Name = p.Name() + col.NotNull = p.NotNull() + col.IsNamedParam = isNamed + a = append(a, Parameter{ + Number: ref.ref.Number, + Column: col, + }) + + case *ast.ParamRef: + a = append(a, Parameter{Number: ref.ref.Number}) + + case *ast.In: + if n == nil || n.List == nil { + fmt.Println("ast.In is nil") + continue + } + + number := 0 + if pr, ok := n.List[0].(*ast.ParamRef); ok { + number = pr.Number + } + + location := 0 + var key, alias string + var items []string + + if left, ok := n.Expr.(*ast.ColumnRef); ok { + location = left.Location + items = stringSlice(left.Fields) + } else if left, ok := n.Expr.(*ast.ParamRef); ok { + if len(n.List) <= 0 { + continue + } + if right, ok := n.List[0].(*ast.ColumnRef); ok { + location = left.Location + items = stringSlice(right.Fields) + } else { + continue + } + } else { + continue + } + + switch len(items) { + case 1: + key = items[0] + case 2: + alias = items[0] + key = items[1] + default: + panic("too many field items: " + strconv.Itoa(len(items))) + } + + var found int + if n.Sel == nil { + search := tables + if alias != "" { + if original, ok := aliasMap[alias]; ok { + search = []*ast.TableName{original} + } else { + for _, fqn := range tables { + if fqn.Name == alias { + search = []*ast.TableName{fqn} + } + } + } + } + + for _, table := range search { + schema := table.Schema + if schema == "" { + schema = c.DefaultSchema + } + if c, ok := typeMap[schema][table.Name][key]; ok { + found += 1 + if ref.name != "" { + key = ref.name + } + defaultP := named.NewInferredParam(key, c.IsNotNull) + p, isNamed := params.FetchMerge(ref.ref.Number, defaultP) + a = append(a, Parameter{ + Number: number, + Column: &Column{ + Name: p.Name(), + OriginalName: c.Name, + DataType: dataType(&c.Type), + NotNull: c.IsNotNull, + Unsigned: c.IsUnsigned, + IsArray: c.IsArray, + ArrayDims: c.ArrayDims, + Table: table, + IsNamedParam: isNamed, + IsSqlcSlice: p.IsSqlcSlice(), + }, + }) + } + } + } + + if found == 0 { + return nil, &sqlerr.Error{ + Code: "42703", + Message: fmt.Sprintf("396: column %q does not exist", key), + Location: location, + } + } + if found > 1 { + return nil, &sqlerr.Error{ + Code: "42703", + Message: fmt.Sprintf("in same name column reference %q is ambiguous", key), + Location: location, + } + } + + default: + slog.Debug("unsupported reference type", "type", fmt.Sprintf("%T", n)) + addUnknownParam(ref) + } + } + return a, nil +} diff --git a/internal/compiler/result.go b/internal/compiler/result.go new file mode 100644 index 0000000..3647da6 --- /dev/null +++ b/internal/compiler/result.go @@ -0,0 +1,10 @@ +package compiler + +import ( + "github.com/sqlc-dev/sqlc/internal/sql/catalog" +) + +type Result struct { + Catalog *catalog.Catalog + Queries []*Query +} diff --git a/internal/compiler/returning.go b/internal/compiler/returning.go new file mode 100644 index 0000000..0a38abe --- /dev/null +++ b/internal/compiler/returning.go @@ -0,0 +1,138 @@ +package compiler + +import ( + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +// returningTables builds virtual tables for the OLD and NEW aliases that +// PostgreSQL 18 makes available in the RETURNING clause of INSERT, UPDATE and +// DELETE statements. Each alias exposes the columns of the statement's target +// table. For INSERT there is usually no old row and for DELETE there is no +// new row, so every column reached through those aliases becomes nullable. +func (c *Compiler) returningTables(qc *QueryCatalog, node ast.Node) ([]*Table, error) { + if c.conf.Engine != config.EnginePostgreSQL { + return nil, nil + } + + var rv *ast.RangeVar + var returning *ast.List + oldAlias, newAlias := "old", "new" + var oldNullable, newNullable bool + switch n := node.(type) { + case *ast.DeleteStmt: + rv = firstRangeVar(n.Relations) + returning = n.ReturningList + if n.ReturningOldAlias != "" { + oldAlias = n.ReturningOldAlias + } + if n.ReturningNewAlias != "" { + newAlias = n.ReturningNewAlias + } + // A deleted row has no new value + newNullable = true + case *ast.InsertStmt: + rv = n.Relation + returning = n.ReturningList + if n.ReturningOldAlias != "" { + oldAlias = n.ReturningOldAlias + } + if n.ReturningNewAlias != "" { + newAlias = n.ReturningNewAlias + } + // An inserted row has no old value, except when an ON CONFLICT + // clause updates an existing row instead + oldNullable = true + case *ast.UpdateStmt: + rv = firstRangeVar(n.Relations) + returning = n.ReturningList + if n.ReturningOldAlias != "" { + oldAlias = n.ReturningOldAlias + } + if n.ReturningNewAlias != "" { + newAlias = n.ReturningNewAlias + } + default: + return nil, nil + } + if rv == nil || returning == nil || len(returning.Items) == 0 { + return nil, nil + } + + fqn, err := ParseTableName(rv) + if err != nil { + return nil, err + } + + build := func(alias string, nullable bool) *Table { + table, err := qc.GetTable(fqn) + if err != nil { + // An unresolvable target table is reported by the regular + // source table lookup, so ignore the error here + return nil + } + table.Rel = &ast.TableName{Name: alias} + if nullable { + for _, col := range table.Columns { + col.NotNull = false + } + } + return table + } + + var tables []*Table + if t := build(oldAlias, oldNullable); t != nil { + tables = append(tables, t) + } + if t := build(newAlias, newNullable); t != nil { + tables = append(tables, t) + } + return tables, nil +} + +func firstRangeVar(list *ast.List) *ast.RangeVar { + if list == nil { + return nil + } + for _, item := range list.Items { + if rv, ok := item.(*ast.RangeVar); ok && rv != nil { + return rv + } + } + return nil +} + +// returningTableForScope returns the OLD or NEW virtual table named by scope. +// A source table with the same name shadows the virtual table, matching +// PostgreSQL, where the implicit aliases are only available when no relation +// in the query is already known under that name. +func returningTableForScope(tables, rtables []*Table, scope string) *Table { + if scope == "" { + return nil + } + for _, t := range tables { + if t.Rel.Name == scope { + return nil + } + } + for _, t := range rtables { + if t.Rel.Name == scope { + return t + } + } + return nil +} + +// tablesForRef resolves a column reference against the source tables, +// extended with the OLD or NEW virtual table when the reference is qualified +// with one of their names. +func tablesForRef(ref *ast.ColumnRef, tables, rtables []*Table) []*Table { + parts := stringSlice(ref.Fields) + if len(parts) != 2 { + return tables + } + if vt := returningTableForScope(tables, rtables, parts[0]); vt != nil { + return append(append([]*Table{}, tables...), vt) + } + return tables +} diff --git a/internal/compiler/selector.go b/internal/compiler/selector.go new file mode 100644 index 0000000..115c9eb --- /dev/null +++ b/internal/compiler/selector.go @@ -0,0 +1,48 @@ +package compiler + +import "strings" + +// selector is an interface used by a compiler for generating expressions for +// output columns in a `SELECT ...` or `RETURNING ...` statement. +// +// This interface is exclusively needed at the moment for SQLite, which must +// wrap output `jsonb` columns with a `json(column_name)` invocation so that a +// publicly consumable format (i.e. not jsonb) is returned. +type selector interface { + // ColumnExpr generates output to be used in a `SELECT ...` or `RETURNING + // ...` statement based on input column name and metadata. + ColumnExpr(name string, column *Column) string +} + +// defaultSelector is a selector implementation that does the simpliest possible +// pass through when generating column expressions. Its use is suitable for all +// database engines not requiring additional customization. +type defaultSelector struct{} + +func newDefaultSelector() *defaultSelector { + return &defaultSelector{} +} + +func (s *defaultSelector) ColumnExpr(name string, column *Column) string { + return name +} + +type sqliteSelector struct{} + +func newSQLiteSelector() *sqliteSelector { + return &sqliteSelector{} +} + +func (s *sqliteSelector) ColumnExpr(name string, column *Column) string { + // Under SQLite, neither json nor jsonb are real data types, and rather just + // of type blob, so database drivers just return whatever raw binary is + // stored as values. This is a problem for jsonb, which is considered an + // internal format to SQLite and no attempt should be made to parse it + // outside of the database itself. For jsonb columns in SQLite, wrap values + // in `json(col)` to coerce the internal binary format to JSON parsable by + // the user-space application. + if strings.EqualFold(column.DataType, "jsonb") { + return "json(" + name + ")" + } + return name +} diff --git a/internal/compiler/selector_test.go b/internal/compiler/selector_test.go new file mode 100644 index 0000000..e460dd2 --- /dev/null +++ b/internal/compiler/selector_test.go @@ -0,0 +1,35 @@ +package compiler + +import "testing" + +func TestSelector(t *testing.T) { + t.Parallel() + + selectorExpectColumnExpr := func(t *testing.T, selector selector, expected, name string, column *Column) { + if actual := selector.ColumnExpr(name, column); expected != actual { + t.Errorf("Expected %v, got %v for data type %v", expected, actual, column.DataType) + } + } + + t.Run("DefaultSelectorColumnExpr", func(t *testing.T) { + t.Parallel() + + selector := newDefaultSelector() + + selectorExpectColumnExpr(t, selector, "my_column", "my_column", &Column{DataType: "integer"}) + selectorExpectColumnExpr(t, selector, "my_column", "my_column", &Column{DataType: "json"}) + selectorExpectColumnExpr(t, selector, "my_column", "my_column", &Column{DataType: "jsonb"}) + selectorExpectColumnExpr(t, selector, "my_column", "my_column", &Column{DataType: "text"}) + }) + + t.Run("SQLiteSelectorColumnExpr", func(t *testing.T) { + t.Parallel() + + selector := newSQLiteSelector() + + selectorExpectColumnExpr(t, selector, "my_column", "my_column", &Column{DataType: "integer"}) + selectorExpectColumnExpr(t, selector, "my_column", "my_column", &Column{DataType: "json"}) + selectorExpectColumnExpr(t, selector, "json(my_column)", "my_column", &Column{DataType: "jsonb"}) + selectorExpectColumnExpr(t, selector, "my_column", "my_column", &Column{DataType: "text"}) + }) +} diff --git a/internal/compiler/to_column.go b/internal/compiler/to_column.go new file mode 100644 index 0000000..3267107 --- /dev/null +++ b/internal/compiler/to_column.go @@ -0,0 +1,33 @@ +package compiler + +import ( + "strings" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/astutils" +) + +func arrayDims(n *ast.TypeName) int { + if n == nil || n.ArrayBounds == nil { + return 0 + } + return len(n.ArrayBounds.Items) +} + +func toColumn(n *ast.TypeName) *Column { + if n == nil { + panic("can't build column for nil type name") + } + typ, err := ParseTypeName(n) + if err != nil { + panic("toColumn: " + err.Error()) + } + arrayDims := arrayDims(n) + return &Column{ + Type: typ, + DataType: strings.TrimPrefix(astutils.Join(n.Names, "."), "."), + NotNull: true, // XXX: How do we know if this should be null? + IsArray: arrayDims > 0, + ArrayDims: arrayDims, + } +} diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 0000000..8dc9c28 --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,239 @@ +package config + +import ( + "bytes" + "encoding/json" + "errors" + "io" + + "gopkg.in/yaml.v3" + + golang "github.com/sqlc-dev/sqlc/internal/codegen/golang/opts" +) + +type versionSetting struct { + Number string `json:"version" yaml:"version"` +} + +type Engine string + +type Paths []string + +func (p *Paths) UnmarshalJSON(data []byte) error { + if string(data[0]) == `[` { + var out []string + if err := json.Unmarshal(data, &out); err != nil { + return nil + } + *p = Paths(out) + return nil + } + var out string + if err := json.Unmarshal(data, &out); err != nil { + return nil + } + *p = Paths([]string{out}) + return nil +} + +func (p *Paths) UnmarshalYAML(unmarshal func(any) error) error { + out := []string{} + if sliceErr := unmarshal(&out); sliceErr != nil { + var ele string + if strErr := unmarshal(&ele); strErr != nil { + return strErr + } + out = []string{ele} + } + + *p = Paths(out) + return nil +} + +const ( + EngineMySQL Engine = "mysql" + EnginePostgreSQL Engine = "postgresql" + EngineSQLite Engine = "sqlite" + EngineClickHouse Engine = "clickhouse" + EngineGoogleSQL Engine = "googlesql" + EngineMSSQL Engine = "mssql" + EngineDuckDB Engine = "duckdb" +) + +type Config struct { + Version string `json:"version" yaml:"version"` + Cloud Cloud `json:"cloud" yaml:"cloud"` + Servers []Server `json:"servers" yaml:"servers"` + SQL []SQL `json:"sql" yaml:"sql"` + Overrides Overrides `json:"overrides" yaml:"overrides"` + Plugins []Plugin `json:"plugins" yaml:"plugins"` + Rules []Rule `json:"rules" yaml:"rules"` + Options map[string]yaml.Node `json:"options" yaml:"options"` +} + +type Server struct { + Name string `json:"name,omitempty" yaml:"name"` + Engine Engine `json:"engine,omitempty" yaml:"engine"` + URI string `json:"uri" yaml:"uri"` +} + +type Database struct { + URI string `json:"uri" yaml:"uri"` + Managed bool `json:"managed" yaml:"managed"` +} + +type Cloud struct { + Organization string `json:"organization" yaml:"organization"` + Project string `json:"project" yaml:"project"` + Hostname string `json:"hostname" yaml:"hostname"` + AuthToken string `json:"-" yaml:"-"` +} + +type Plugin struct { + Name string `json:"name" yaml:"name"` + Env []string `json:"env" yaml:"env"` + Process *struct { + Cmd string `json:"cmd" yaml:"cmd"` + Format string `json:"format" yaml:"format"` + } `json:"process" yaml:"process"` + WASM *struct { + URL string `json:"url" yaml:"url"` + SHA256 string `json:"sha256" yaml:"sha256"` + } `json:"wasm" yaml:"wasm"` +} + +type Rule struct { + Name string `json:"name" yaml:"name"` + Rule string `json:"rule" yaml:"rule"` + Msg string `json:"message" yaml:"message"` +} + +type Overrides struct { + Go *golang.GlobalOptions `json:"go,omitempty" yaml:"go"` +} + +type SQL struct { + Name string `json:"name" yaml:"name"` + Engine Engine `json:"engine,omitempty" yaml:"engine"` + Schema Paths `json:"schema" yaml:"schema"` + Queries Paths `json:"queries" yaml:"queries"` + Database *Database `json:"database" yaml:"database"` + StrictFunctionChecks bool `json:"strict_function_checks" yaml:"strict_function_checks"` + StrictOrderBy *bool `json:"strict_order_by" yaml:"strict_order_by"` + Gen SQLGen `json:"gen" yaml:"gen"` + Codegen []Codegen `json:"codegen" yaml:"codegen"` + Rules []string `json:"rules" yaml:"rules"` + Analyzer Analyzer `json:"analyzer" yaml:"analyzer"` +} + +type Analyzer struct { + Database *bool `json:"database" yaml:"database"` +} + +// TODO: Figure out a better name for this +type Codegen struct { + Out string `json:"out" yaml:"out"` + Plugin string `json:"plugin" yaml:"plugin"` + Options yaml.Node `json:"options" yaml:"options"` +} + +type SQLGen struct { + Go *golang.Options `json:"go,omitempty" yaml:"go"` + JSON *SQLJSON `json:"json,omitempty" yaml:"json"` +} + +type SQLJSON struct { + Out string `json:"out" yaml:"out"` + Indent string `json:"indent,omitempty" yaml:"indent"` + Filename string `json:"filename,omitempty" yaml:"filename"` +} + +var ErrMissingEngine = errors.New("unknown engine") +var ErrMissingVersion = errors.New("no version number") +var ErrNoOutPath = errors.New("no output path") +var ErrNoPackagePath = errors.New("missing package path") +var ErrNoPackages = errors.New("no packages") +var ErrNoQuerierType = errors.New("no querier emit type enabled") +var ErrUnknownEngine = errors.New("invalid engine") +var ErrUnknownVersion = errors.New("invalid version number") + +var ErrPluginBuiltin = errors.New("a built-in plugin with that name already exists") +var ErrPluginNoName = errors.New("missing plugin name") +var ErrPluginExists = errors.New("a plugin with that name already exists") +var ErrPluginNotFound = errors.New("no plugin found") +var ErrPluginNoType = errors.New("plugin: field `process` or `wasm` required") +var ErrPluginBothTypes = errors.New("plugin: `process` and `wasm` cannot both be defined") +var ErrPluginProcessNoCmd = errors.New("plugin: missing process command") + +var ErrInvalidDatabase = errors.New("database must be managed or have a non-empty URI") +var ErrManagedDatabaseNoProject = errors.New(`managed databases require a cloud project + +If you don't have a project, you can create one from the sqlc Cloud +dashboard at https://dashboard.sqlc.dev/. If you have a project, ensure +you've set its id as the value of the "project" field within the "cloud" +section of your sqlc configuration. The id will look similar to +"01HA8TWGMYPHK0V2GGMB3R2TP9".`) +var ErrManagedDatabaseNoAuthToken = errors.New(`managed databases require an auth token + +If you don't have an auth token, you can create one from the sqlc Cloud +dashboard at https://dashboard.sqlc.dev/. If you have an auth token, ensure +you've set it as the value of the SQLC_AUTH_TOKEN environment variable.`) + +func ParseConfig(rd io.Reader) (Config, error) { + var buf bytes.Buffer + var config Config + var version versionSetting + + ver := io.TeeReader(rd, &buf) + dec := yaml.NewDecoder(ver) + if err := dec.Decode(&version); err != nil { + return config, err + } + if version.Number == "" { + return config, ErrMissingVersion + } + var err error + switch version.Number { + case "1": + config, err = v1ParseConfig(&buf) + if err != nil { + return config, err + } + case "2": + config, err = v2ParseConfig(&buf) + if err != nil { + return config, err + } + default: + return config, ErrUnknownVersion + } + err = config.addEnvVars() + if err != nil { + return config, err + } + return config, nil +} + +type CombinedSettings struct { + Global Config + Package SQL + Go golang.Options + JSON SQLJSON + + // TODO: Combine these into a more usable type + Codegen Codegen +} + +func Combine(conf Config, pkg SQL) CombinedSettings { + cs := CombinedSettings{ + Global: conf, + Package: pkg, + } + if pkg.Gen.Go != nil { + cs.Go = *pkg.Gen.Go + } + if pkg.Gen.JSON != nil { + cs.JSON = *pkg.Gen.JSON + } + return cs +} diff --git a/internal/config/config_test.go b/internal/config/config_test.go new file mode 100644 index 0000000..57211d6 --- /dev/null +++ b/internal/config/config_test.go @@ -0,0 +1,91 @@ +package config + +import ( + "strings" + "testing" + + "github.com/google/go-cmp/cmp" +) + +const missingVersion = `{ +}` + +const missingPackages = `{ + "version": "1" +}` + +const unknownVersion = `{ + "version": "foo" +}` + +const unknownFields = `{ + "version": "1", + "foo": "bar" +}` + +func TestBadConfigs(t *testing.T) { + for _, test := range []struct { + name string + err string + json string + }{ + { + "missing version", + "no version number", + missingVersion, + }, + { + "missing packages", + "no packages", + missingPackages, + }, + { + "unknown version", + "invalid version number", + unknownVersion, + }, + { + "unknown fields", + `yaml: unmarshal errors: + line 3: field foo not found in type config.V1GenerateSettings`, + unknownFields, + }, + } { + tt := test + t.Run(tt.name, func(t *testing.T) { + _, err := ParseConfig(strings.NewReader(tt.json)) + if err == nil { + t.Fatalf("expected err; got nil") + } + if diff := cmp.Diff(err.Error(), tt.err); diff != "" { + t.Errorf("differed (-want +got):\n%s", diff) + } + }) + } +} + +const validConfigOne = `{ + "version": "1" + "packages": [] +}` + +func FuzzConfig(f *testing.F) { + f.Add(validConfigOne) + f.Fuzz(func(t *testing.T, orig string) { + ParseConfig(strings.NewReader(orig)) + }) +} + +func TestInvalidConfig(t *testing.T) { + err := Validate(&Config{ + SQL: []SQL{{ + Database: &Database{ + URI: "", + Managed: false, + }, + }}, + }) + if err == nil { + t.Errorf("expected err; got nil") + } +} diff --git a/internal/config/convert/convert.go b/internal/config/convert/convert.go new file mode 100644 index 0000000..a1fd288 --- /dev/null +++ b/internal/config/convert/convert.go @@ -0,0 +1,84 @@ +package convert + +import ( + "encoding/json" + "fmt" + "strconv" + + "gopkg.in/yaml.v3" +) + +func gen(n *yaml.Node) (any, error) { + switch n.Kind { + + case yaml.MappingNode: + nn := map[string]any{} + for i, _ := range n.Content { + if i%2 == 0 { + k := n.Content[i] + v, err := gen(n.Content[i+1]) + if err != nil { + return nil, err + } + nn[k.Value] = v + } + } + return nn, nil + + case yaml.SequenceNode: + nn := []any{} + for i, _ := range n.Content { + v, err := gen(n.Content[i]) + if err != nil { + return nil, err + } + nn = append(nn, v) + } + return nn, nil + + case yaml.ScalarNode: + switch n.Tag { + + case "!!bool": + return strconv.ParseBool(n.Value) + + case "!!float": + return strconv.ParseFloat(n.Value, 64) + + case "!!int": + return strconv.Atoi(n.Value) + + case "!!null": + return nil, nil + + case "!!str": + return n.Value, nil + + default: + return n.Value, nil + + } + + case yaml.AliasNode: + return gen(n.Alias) + + default: + return nil, fmt.Errorf("unknown yaml value: %s (%s)", n.Value, n.Tag) + + } +} + +func YAMLtoJSON(n yaml.Node) ([]byte, error) { + if n.Kind == 0 { + return []byte{}, nil + } + iface, err := gen(&n) + if err != nil { + return nil, err + } + blob, err := json.Marshal(iface) + if err != nil { + return nil, err + } + return blob, nil +} diff --git a/internal/config/convert/convert_test.go b/internal/config/convert/convert_test.go new file mode 100644 index 0000000..11e62ba --- /dev/null +++ b/internal/config/convert/convert_test.go @@ -0,0 +1,47 @@ +package convert + +import ( + "testing" + + "gopkg.in/yaml.v3" +) + +const anchor = ` +sql: + - schema: query.sql + queries: query.sql + engine: postgresql + codegen: + - out: gateway/src/gateway/services/organization + plugin: py + options: &base-options + query_parameter_limit: 1 + package: gateway + output_models_file_name: null + emit_module: true + emit_generators: false + emit_async: true + + - schema: query.sql + queries: query.sql + engine: postgresql + codegen: + - out: gateway/src/gateway/services/project + plugin: py + options: *base-options +` + +type config struct { + SQL yaml.Node `yaml:"sql"` +} + +func TestAlias(t *testing.T) { + var a config + err := yaml.Unmarshal([]byte(anchor), &a) + if err != nil { + t.Fatal(err) + } + if _, err := gen(&a.SQL); err != nil { + t.Fatal(err) + } +} diff --git a/internal/config/env.go b/internal/config/env.go new file mode 100644 index 0000000..0c608aa --- /dev/null +++ b/internal/config/env.go @@ -0,0 +1,17 @@ +package config + +import ( + "fmt" + "os" + "strings" +) + +func (c *Config) addEnvVars() error { + authToken := os.Getenv("SQLC_AUTH_TOKEN") + if authToken != "" && !strings.HasPrefix(authToken, "sqlc_") { + return fmt.Errorf("$SQLC_AUTH_TOKEN doesn't start with \"sqlc_\"") + } + c.Cloud.AuthToken = authToken + + return nil +} diff --git a/internal/config/v_one.go b/internal/config/v_one.go new file mode 100644 index 0000000..fa1a4d8 --- /dev/null +++ b/internal/config/v_one.go @@ -0,0 +1,196 @@ +package config + +import ( + "fmt" + "io" + "path/filepath" + + yaml "gopkg.in/yaml.v3" + + golang "github.com/sqlc-dev/sqlc/internal/codegen/golang/opts" +) + +type V1GenerateSettings struct { + Version string `json:"version" yaml:"version"` + Cloud Cloud `json:"cloud" yaml:"cloud"` + Packages []v1PackageSettings `json:"packages" yaml:"packages"` + Overrides []golang.Override `json:"overrides,omitempty" yaml:"overrides,omitempty"` + Rename map[string]string `json:"rename,omitempty" yaml:"rename,omitempty"` + Rules []Rule `json:"rules" yaml:"rules"` +} + +type v1PackageSettings struct { + Name string `json:"name" yaml:"name"` + Engine Engine `json:"engine,omitempty" yaml:"engine"` + Database *Database `json:"database,omitempty" yaml:"database"` + Analyzer Analyzer `json:"analyzer" yaml:"analyzer"` + Path string `json:"path" yaml:"path"` + Schema Paths `json:"schema" yaml:"schema"` + Queries Paths `json:"queries" yaml:"queries"` + EmitInterface bool `json:"emit_interface" yaml:"emit_interface"` + EmitJSONTags bool `json:"emit_json_tags" yaml:"emit_json_tags"` + JsonTagsIDUppercase bool `json:"json_tags_id_uppercase" yaml:"json_tags_id_uppercase"` + EmitDBTags bool `json:"emit_db_tags" yaml:"emit_db_tags"` + EmitPreparedQueries bool `json:"emit_prepared_queries" yaml:"emit_prepared_queries"` + EmitExactTableNames bool `json:"emit_exact_table_names,omitempty" yaml:"emit_exact_table_names"` + EmitEmptySlices bool `json:"emit_empty_slices,omitempty" yaml:"emit_empty_slices"` + EmitExportedQueries bool `json:"emit_exported_queries,omitempty" yaml:"emit_exported_queries"` + EmitResultStructPointers bool `json:"emit_result_struct_pointers" yaml:"emit_result_struct_pointers"` + EmitParamsStructPointers bool `json:"emit_params_struct_pointers" yaml:"emit_params_struct_pointers"` + EmitMethodsWithDBArgument bool `json:"emit_methods_with_db_argument" yaml:"emit_methods_with_db_argument"` + EmitPointersForNullTypes bool `json:"emit_pointers_for_null_types" yaml:"emit_pointers_for_null_types"` + EmitPointersForNullEnumTypes *bool `json:"emit_pointers_for_null_enum_types,omitempty" yaml:"emit_pointers_for_null_enum_types"` + EmitEnumValidMethod bool `json:"emit_enum_valid_method,omitempty" yaml:"emit_enum_valid_method"` + EmitAllEnumValues bool `json:"emit_all_enum_values,omitempty" yaml:"emit_all_enum_values"` + EmitSqlAsComment bool `json:"emit_sql_as_comment,omitempty" yaml:"emit_sql_as_comment"` + JSONTagsCaseStyle string `json:"json_tags_case_style,omitempty" yaml:"json_tags_case_style"` + SQLPackage string `json:"sql_package" yaml:"sql_package"` + SQLDriver string `json:"sql_driver" yaml:"sql_driver"` + Overrides []golang.Override `json:"overrides" yaml:"overrides"` + OutputBatchFileName string `json:"output_batch_file_name,omitempty" yaml:"output_batch_file_name"` + OutputDBFileName string `json:"output_db_file_name,omitempty" yaml:"output_db_file_name"` + OutputModelsFileName string `json:"output_models_file_name,omitempty" yaml:"output_models_file_name"` + OutputModelsPath string `json:"output_models_path,omitempty" yaml:"output_models_path"` + OutputModelsPackage string `json:"output_models_package,omitempty" yaml:"output_models_package"` + OutputModelsImport string `json:"output_models_import,omitempty" yaml:"output_models_import"` + OutputModelsEmit *bool `json:"output_models_emit,omitempty" yaml:"output_models_emit"` + OutputQuerierFileName string `json:"output_querier_file_name,omitempty" yaml:"output_querier_file_name"` + OutputCopyFromFileName string `json:"output_copyfrom_file_name,omitempty" yaml:"output_copyfrom_file_name"` + OutputFilesSuffix string `json:"output_files_suffix,omitempty" yaml:"output_files_suffix"` + StrictFunctionChecks bool `json:"strict_function_checks" yaml:"strict_function_checks"` + StrictOrderBy *bool `json:"strict_order_by" yaml:"strict_order_by"` + QueryParameterLimit *int32 `json:"query_parameter_limit,omitempty" yaml:"query_parameter_limit"` + OmitSqlcVersion bool `json:"omit_sqlc_version,omitempty" yaml:"omit_sqlc_version"` + OmitUnusedStructs bool `json:"omit_unused_structs,omitempty" yaml:"omit_unused_structs"` + Rules []string `json:"rules" yaml:"rules"` + BuildTags string `json:"build_tags,omitempty" yaml:"build_tags"` +} + +func v1ParseConfig(rd io.Reader) (Config, error) { + dec := yaml.NewDecoder(rd) + dec.KnownFields(true) + var settings V1GenerateSettings + var config Config + if err := dec.Decode(&settings); err != nil { + return config, err + } + if settings.Version == "" { + return config, ErrMissingVersion + } + if settings.Version != "1" { + return config, ErrUnknownVersion + } + if len(settings.Packages) == 0 { + return config, ErrNoPackages + } + if err := settings.ValidateGlobalOverrides(); err != nil { + return config, err + } + for j := range settings.Packages { + if settings.Packages[j].Path == "" { + return config, ErrNoPackagePath + } + + if settings.Packages[j].Name == "" { + settings.Packages[j].Name = filepath.Base(settings.Packages[j].Path) + } + + if settings.Packages[j].Engine == "" { + settings.Packages[j].Engine = EnginePostgreSQL + } + } + + return settings.Translate(), nil +} + +func (c *V1GenerateSettings) ValidateGlobalOverrides() error { + engines := map[Engine]struct{}{} + for _, pkg := range c.Packages { + if _, ok := engines[pkg.Engine]; !ok { + engines[pkg.Engine] = struct{}{} + } + } + + usesMultipleEngines := len(engines) > 1 + for _, oride := range c.Overrides { + if usesMultipleEngines && oride.Engine == "" { + return fmt.Errorf(`the "engine" field is required for global type overrides because your configuration uses multiple database engines`) + } + } + return nil +} + +func (c *V1GenerateSettings) Translate() Config { + conf := Config{ + Version: c.Version, + Cloud: c.Cloud, + Rules: c.Rules, + } + + for _, pkg := range c.Packages { + if pkg.StrictOrderBy == nil { + defaultValue := true + pkg.StrictOrderBy = &defaultValue + } + conf.SQL = append(conf.SQL, SQL{ + Name: pkg.Name, + Engine: pkg.Engine, + Database: pkg.Database, + Schema: pkg.Schema, + Queries: pkg.Queries, + Rules: pkg.Rules, + Analyzer: pkg.Analyzer, + Gen: SQLGen{ + Go: &golang.Options{ + EmitInterface: pkg.EmitInterface, + EmitJsonTags: pkg.EmitJSONTags, + JsonTagsIdUppercase: pkg.JsonTagsIDUppercase, + EmitDbTags: pkg.EmitDBTags, + EmitPreparedQueries: pkg.EmitPreparedQueries, + EmitExactTableNames: pkg.EmitExactTableNames, + EmitEmptySlices: pkg.EmitEmptySlices, + EmitExportedQueries: pkg.EmitExportedQueries, + EmitResultStructPointers: pkg.EmitResultStructPointers, + EmitParamsStructPointers: pkg.EmitParamsStructPointers, + EmitMethodsWithDbArgument: pkg.EmitMethodsWithDBArgument, + EmitPointersForNullTypes: pkg.EmitPointersForNullTypes, + EmitPointersForNullEnumTypes: pkg.EmitPointersForNullEnumTypes, + EmitEnumValidMethod: pkg.EmitEnumValidMethod, + EmitAllEnumValues: pkg.EmitAllEnumValues, + EmitSqlAsComment: pkg.EmitSqlAsComment, + Package: pkg.Name, + Out: pkg.Path, + SqlPackage: pkg.SQLPackage, + SqlDriver: pkg.SQLDriver, + Overrides: pkg.Overrides, + JsonTagsCaseStyle: pkg.JSONTagsCaseStyle, + OutputBatchFileName: pkg.OutputBatchFileName, + OutputDbFileName: pkg.OutputDBFileName, + OutputModelsFileName: pkg.OutputModelsFileName, + OutputModelsPath: pkg.OutputModelsPath, + OutputModelsPackage: pkg.OutputModelsPackage, + OutputModelsImport: pkg.OutputModelsImport, + OutputModelsEmit: pkg.OutputModelsEmit, + OutputQuerierFileName: pkg.OutputQuerierFileName, + OutputCopyfromFileName: pkg.OutputCopyFromFileName, + OutputFilesSuffix: pkg.OutputFilesSuffix, + QueryParameterLimit: pkg.QueryParameterLimit, + OmitSqlcVersion: pkg.OmitSqlcVersion, + OmitUnusedStructs: pkg.OmitUnusedStructs, + BuildTags: pkg.BuildTags, + }, + }, + StrictFunctionChecks: pkg.StrictFunctionChecks, + StrictOrderBy: pkg.StrictOrderBy, + }) + } + + if len(c.Overrides) > 0 || len(c.Rename) > 0 { + conf.Overrides.Go = &golang.GlobalOptions{ + Overrides: c.Overrides, + Rename: c.Rename, + } + } + + return conf +} diff --git a/internal/config/v_one.json b/internal/config/v_one.json new file mode 100644 index 0000000..20435d1 --- /dev/null +++ b/internal/config/v_one.json @@ -0,0 +1,361 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "type": "object", + "required": [ + "version" + ], + "properties": { + "version": { + "const": "1" + }, + "cloud": { + "type": "object", + "properties": { + "organization": { + "type": "string" + }, + "project": { + "type": "string" + }, + "hostname": { + "type": "string" + } + } + }, + "packages": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "required": [ + "engine" + ], + "properties": { + "engine": { + "enum": [ + "postgresql", + "mysql", + "sqlite" + ] + }, + "schema": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "queries": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "database": { + "type": "object", + "properties": { + "uri": { + "type": "string" + }, + "managed": { + "type": "boolean" + } + } + }, + "analyzer": { + "type": "object", + "properties": { + "database": { + "type": "boolean" + } + } + }, + "strict_function_checks": { + "type": "boolean" + }, + "strict_order_by": { + "type": "boolean" + }, + "emit_interface": { + "type": "boolean" + }, + "emit_json_tags": { + "type": "boolean" + }, + "json_tags_id_uppercase": { + "type": "boolean" + }, + "emit_db_tags": { + "type": "boolean" + }, + "emit_prepared_queries": { + "type": "boolean" + }, + "emit_exact_table_names": { + "type": "boolean" + }, + "emit_empty_slices": { + "type": "boolean" + }, + "emit_exported_queries": { + "type": "boolean" + }, + "emit_result_struct_pointers": { + "type": "boolean" + }, + "emit_params_struct_pointers": { + "type": "boolean" + }, + "emit_methods_with_db_argument": { + "type": "boolean" + }, + "emit_pointers_for_null_types": { + "type": "boolean" + }, + "emit_pointers_for_null_enum_types": { + "type": "boolean" + }, + "emit_enum_valid_method": { + "type": "boolean" + }, + "emit_all_enum_values": { + "type": "boolean" + }, + "emit_sql_as_comment": { + "type": "boolean" + }, + "build_tags": { + "type": "string" + }, + "json_tags_case_style": { + "type": "string" + }, + "package": { + "type": "string" + }, + "out": { + "type": "string" + }, + "overrides": { + "type": "array", + "items": { + "type": "object", + "properties": { + "go_type": { + "oneOf": [ + { + "type": "object", + "properties": { + "import": { + "type": "string" + }, + "package": { + "type": "string" + }, + "type": { + "type": "string" + }, + "pointer": { + "type": "boolean" + }, + "slice": { + "type": "boolean" + }, + "spec": { + "type": "string" + }, + "builtin": { + "type": "boolean" + } + } + }, + { + "type": "string" + } + ] + }, + "go_struct_tag": { + "type": "string" + }, + "db_type": { + "type": "string" + }, + "engine": { + "enum": [ + "postgresql", + "mysql", + "sqlite" + ] + }, + "nullable": { + "type": "boolean" + }, + "unsigned": { + "type": "boolean" + }, + "column": { + "type": "string" + } + } + } + }, + "sql_package": { + "type": "string" + }, + "sql_driver": { + "type": "string" + }, + "output_batch_file_name": { + "type": "string" + }, + "output_db_file_name": { + "type": "string" + }, + "output_models_file_name": { + "type": "string" + }, + "output_models_path": { + "type": "string" + }, + "output_models_package": { + "type": "string" + }, + "output_models_import": { + "type": "string" + }, + "output_models_emit": { + "type": "boolean" + }, + "output_querier_file_name": { + "type": "string" + }, + "output_copyfrom_file_name": { + "type": "string" + }, + "output_files_suffix": { + "type": "string" + }, + "inflection_exclude_table_names": { + "type": "array", + "items": { + "type": "string" + } + }, + "query_parameter_limit": { + "type": "integer" + }, + "omit_unused_structs": { + "type": "boolean" + }, + "rules": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "overrides": { + "type": "array", + "items": { + "type": "object", + "properties": { + "go_type": { + "oneOf": [ + { + "type": "object", + "properties": { + "import": { + "type": "string" + }, + "package": { + "type": "string" + }, + "type": { + "type": "string" + }, + "pointer": { + "type": "boolean" + }, + "slice": { + "type": "boolean" + }, + "spec": { + "type": "string" + }, + "builtin": { + "type": "boolean" + } + } + }, + { + "type": "string" + } + ] + }, + "go_struct_tag": { + "type": "string" + }, + "db_type": { + "type": "string" + }, + "engine": { + "enum": [ + "postgresql", + "mysql", + "sqlite" + ] + }, + "nullable": { + "type": "boolean" + }, + "unsigned": { + "type": "boolean" + }, + "column": { + "type": "string" + } + } + } + } + }, + "rename": { + "type": "object", + "patternProperties": { + ".*": { + "type": "string" + } + } + }, + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "rule": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } +} diff --git a/internal/config/v_two.go b/internal/config/v_two.go new file mode 100644 index 0000000..0fe22ff --- /dev/null +++ b/internal/config/v_two.go @@ -0,0 +1,109 @@ +package config + +import ( + "fmt" + "io" + + yaml "gopkg.in/yaml.v3" +) + +func v2ParseConfig(rd io.Reader) (Config, error) { + dec := yaml.NewDecoder(rd) + dec.KnownFields(true) + var conf Config + if err := dec.Decode(&conf); err != nil { + return conf, err + } + if conf.Version == "" { + return conf, ErrMissingVersion + } + if conf.Version != "2" { + return conf, ErrUnknownVersion + } + if len(conf.SQL) == 0 { + return conf, ErrNoPackages + } + if err := conf.validateGlobalOverrides(); err != nil { + return conf, err + } + // TODO: Store built-in plugins somewhere else + builtins := map[string]struct{}{ + "go": {}, + "json": {}, + } + plugins := map[string]struct{}{} + for i := range conf.Plugins { + if conf.Plugins[i].Name == "" { + return conf, ErrPluginNoName + } + if _, ok := builtins[conf.Plugins[i].Name]; ok { + return conf, ErrPluginBuiltin + } + if _, ok := plugins[conf.Plugins[i].Name]; ok { + return conf, ErrPluginExists + } + if conf.Plugins[i].Process == nil && conf.Plugins[i].WASM == nil { + return conf, ErrPluginNoType + } + if conf.Plugins[i].Process != nil && conf.Plugins[i].WASM != nil { + return conf, ErrPluginBothTypes + } + if conf.Plugins[i].Process != nil { + if conf.Plugins[i].Process.Cmd == "" { + return conf, ErrPluginProcessNoCmd + } + } + plugins[conf.Plugins[i].Name] = struct{}{} + } + for j := range conf.SQL { + if conf.SQL[j].Engine == "" { + return conf, ErrMissingEngine + } + if conf.SQL[j].Gen.Go != nil { + if conf.SQL[j].Gen.Go.Out == "" { + return conf, ErrNoPackagePath + } + } + if conf.SQL[j].Gen.JSON != nil { + if conf.SQL[j].Gen.JSON.Out == "" { + return conf, ErrNoOutPath + } + } + for _, cg := range conf.SQL[j].Codegen { + if cg.Plugin == "" { + return conf, ErrPluginNoName + } + if cg.Out == "" { + return conf, ErrNoOutPath + } + // TODO: Allow the use of built-in codegen from here + if _, ok := plugins[cg.Plugin]; !ok { + return conf, ErrPluginNotFound + } + } + if conf.SQL[j].StrictOrderBy == nil { + defaultValidate := true + conf.SQL[j].StrictOrderBy = &defaultValidate + } + } + return conf, nil +} + +func (c *Config) validateGlobalOverrides() error { + engines := map[Engine]struct{}{} + for _, pkg := range c.SQL { + if _, ok := engines[pkg.Engine]; !ok { + engines[pkg.Engine] = struct{}{} + } + } + if c.Overrides.Go == nil { + return nil + } + usesMultipleEngines := len(engines) > 1 + for _, oride := range c.Overrides.Go.Overrides { + if usesMultipleEngines && oride.Engine == "" { + return fmt.Errorf(`the "engine" field is required for global type overrides because your configuration uses multiple database engines`) + } + } + return nil +} diff --git a/internal/config/v_two.json b/internal/config/v_two.json new file mode 100644 index 0000000..3728ece --- /dev/null +++ b/internal/config/v_two.json @@ -0,0 +1,463 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "type": "object", + "required": [ + "version" + ], + "properties": { + "version": { + "const": "2" + }, + "cloud": { + "type": "object", + "properties": { + "organization": { + "type": "string" + }, + "project": { + "type": "string" + }, + "hostname": { + "type": "string" + } + } + }, + "sql": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "required": [ + "engine" + ], + "properties": { + "name": { + "type": "string" + }, + "engine": { + "enum": [ + "postgresql", + "mysql", + "sqlite" + ] + }, + "schema": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "queries": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "database": { + "type": "object", + "properties": { + "uri": { + "type": "string" + }, + "managed": { + "type": "boolean" + } + } + }, + "analyzer": { + "type": "object", + "properties": { + "database": { + "type": "boolean" + } + } + }, + "strict_function_checks": { + "type": "boolean" + }, + "strict_order_by": { + "type": "boolean" + }, + "gen": { + "type": "object", + "properties": { + "go": { + "type": "object", + "properties": { + "emit_interface": { + "type": "boolean" + }, + "emit_json_tags": { + "type": "boolean" + }, + "json_tags_id_uppercase": { + "type": "boolean" + }, + "emit_db_tags": { + "type": "boolean" + }, + "emit_prepared_queries": { + "type": "boolean" + }, + "emit_exact_table_names": { + "type": "boolean" + }, + "emit_empty_slices": { + "type": "boolean" + }, + "emit_exported_queries": { + "type": "boolean" + }, + "emit_result_struct_pointers": { + "type": "boolean" + }, + "emit_params_struct_pointers": { + "type": "boolean" + }, + "emit_methods_with_db_argument": { + "type": "boolean" + }, + "emit_pointers_for_null_types": { + "type": "boolean" + }, + "emit_pointers_for_null_enum_types": { + "type": "boolean" + }, + "emit_enum_valid_method": { + "type": "boolean" + }, + "emit_all_enum_values": { + "type": "boolean" + }, + "emit_sql_as_comment": { + "type": "boolean" + }, + "build_tags": { + "type": "string" + }, + "json_tags_case_style": { + "type": "string" + }, + "package": { + "type": "string" + }, + "out": { + "type": "string" + }, + "overrides": { + "type": "array", + "items": { + "type": "object", + "properties": { + "go_type": { + "oneOf": [ + { + "type": "object", + "properties": { + "import": { + "type": "string" + }, + "package": { + "type": "string" + }, + "type": { + "type": "string" + }, + "pointer": { + "type": "boolean" + }, + "slice": { + "type": "boolean" + }, + "spec": { + "type": "string" + }, + "builtin": { + "type": "boolean" + } + } + }, + { + "type": "string" + } + ] + }, + "go_struct_tag": { + "type": "string" + }, + "db_type": { + "type": "string" + }, + "engine": { + "enum": [ + "postgresql", + "mysql", + "sqlite" + ] + }, + "nullable": { + "type": "boolean" + }, + "unsigned": { + "type": "boolean" + }, + "column": { + "type": "string" + } + } + } + } + }, + "rename": { + "type": "object", + "patternProperties": { + ".*": { + "type": "string" + } + } + }, + "sql_package": { + "type": "string" + }, + "sql_driver": { + "type": "string" + }, + "output_batch_file_name": { + "type": "string" + }, + "output_db_file_name": { + "type": "string" + }, + "output_models_file_name": { + "type": "string" + }, + "output_models_path": { + "type": "string" + }, + "output_models_package": { + "type": "string" + }, + "output_models_import": { + "type": "string" + }, + "output_models_emit": { + "type": "boolean" + }, + "output_querier_file_name": { + "type": "string" + }, + "output_copyfrom_file_name": { + "type": "string" + }, + "output_files_suffix": { + "type": "string" + }, + "inflection_exclude_table_names": { + "type": "array", + "items": { + "type": "string" + } + }, + "query_parameter_limit": { + "type": "integer" + }, + "omit_unused_structs": { + "type": "boolean" + } + }, + "json": { + "type": "object", + "properties": { + "out": { + "type": "string" + }, + "indent": { + "type": "string" + }, + "filename": { + "type": "string" + } + } + } + } + }, + "codegen": { + "type": "array", + "items": { + "type": "object", + "properties": { + "out": { + "type": "string" + }, + "plugin": { + "type": "string" + }, + "options": { + "type": "object" + } + } + } + }, + "rules": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "overrides": { + "type": "object", + "properties": { + "go": { + "type": "object", + "properties": { + "overrides": { + "type": "array", + "items": { + "type": "object", + "properties": { + "go_type": { + "oneOf": [ + { + "type": "object", + "properties": { + "import": { + "type": "string" + }, + "package": { + "type": "string" + }, + "type": { + "type": "string" + }, + "pointer": { + "type": "boolean" + }, + "slice": { + "type": "boolean" + }, + "spec": { + "type": "string" + }, + "builtin": { + "type": "boolean" + } + } + }, + { + "type": "string" + } + ] + }, + "go_struct_tag": { + "type": "string" + }, + "db_type": { + "type": "string" + }, + "engine": { + "enum": [ + "postgresql", + "mysql", + "sqlite" + ] + }, + "nullable": { + "type": "boolean" + }, + "unsigned": { + "type": "boolean" + }, + "column": { + "type": "string" + } + } + } + }, + "rename": { + "type": "object", + "patternProperties": { + ".*": { + "type": "string" + } + } + } + } + } + } + }, + "plugins": { + "type": "array", + "items": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "minLength": 1 + }, + "env": { + "type": "array", + "items": { + "type": "string" + } + }, + "process": { + "type": "object", + "properties": { + "cmd": { + "type": "string" + } + } + }, + "wasm": { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "sha256": { + "type": "string" + } + } + } + } + } + }, + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "rule": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } +} diff --git a/internal/config/validate.go b/internal/config/validate.go new file mode 100644 index 0000000..fadef4f --- /dev/null +++ b/internal/config/validate.go @@ -0,0 +1,12 @@ +package config + +func Validate(c *Config) error { + for _, sql := range c.SQL { + if sql.Database != nil { + if sql.Database.URI == "" && !sql.Database.Managed { + return ErrInvalidDatabase + } + } + } + return nil +} diff --git a/internal/constants/query.go b/internal/constants/query.go new file mode 100644 index 0000000..a572c56 --- /dev/null +++ b/internal/constants/query.go @@ -0,0 +1,12 @@ +package constants + +// Flags +const ( + QueryFlagParam = "@param" + QueryFlagSqlcVetDisable = "@sqlc-vet-disable" +) + +// Rules +const ( + QueryRuleDbPrepare = "sqlc/db-prepare" +) diff --git a/internal/core/analysis.go b/internal/core/analysis.go new file mode 100644 index 0000000..b0854bf --- /dev/null +++ b/internal/core/analysis.go @@ -0,0 +1,82 @@ +package core + +type Command string + +const ( + CommandSelect Command = "SELECT" + CommandInsert Command = "INSERT" + CommandUpdate Command = "UPDATE" + CommandDelete Command = "DELETE" +) + +type PrepareResult struct { + Command Command `json:"command,omitempty"` + Columns []Column `json:"columns"` + Parameters []Parameter `json:"parameters"` + Stars []StarExpansion `json:"stars,omitempty"` +} + +// StarExpansion is what a star in a target list stands for. The analyzer +// resolves the reference against the query's scope and reports the columns it +// covers; rewriting the query text with them is the caller's to do, since only +// it knows how the engine quotes an identifier. +type StarExpansion struct { + // Location is where the target the star belongs to starts, measured the + // way the AST measures a node: from the beginning of the file the + // statement was parsed from. + Location int `json:"location"` + + // Fields is the reference as it was written, with the star as its last + // element: ["*"] for a bare star and ["foo", "*"] for a qualified one. + Fields []string `json:"fields"` + + // Alias is the output name the target was given, if any. + Alias string `json:"alias,omitempty"` + + Columns []StarColumn `json:"columns"` +} + +// StarColumn is a single column a star expanded to. +type StarColumn struct { + // Relation is the name the column's relation goes by in the query, which + // is its alias when it was given one. + Relation string `json:"relation,omitempty"` + Name string `json:"name"` + DataType string `json:"data_type,omitempty"` +} + +type ColumnSource struct { + Schema string `json:"schema,omitempty"` + Table string `json:"table,omitempty"` + TableAlias string `json:"table_alias,omitempty"` + Column string `json:"column,omitempty"` +} + +type Column struct { + Name string `json:"name"` + DataType string `json:"data_type"` + // Type is the column's type as an expression, carrying what DataType + // and IsArray flatten away: arguments, nesting and inner nullability. + Type *TypeExpr `json:"type,omitempty"` + TypeOID int64 `json:"type_oid,omitempty"` + NotNull bool `json:"not_null"` + IsArray bool `json:"is_array,omitempty"` + SourceClassOID int64 `json:"source_class_oid,omitempty"` + SourceAttributeOID int64 `json:"source_attribute_oid,omitempty"` + Source *ColumnSource `json:"source,omitempty"` + DeclType string `json:"decl_type,omitempty"` + IsPrimaryKey bool `json:"is_primary_key,omitempty"` + IsUnique bool `json:"is_unique,omitempty"` + IsAutoIncrement bool `json:"is_auto_increment,omitempty"` +} + +type Parameter struct { + Number int `json:"number"` + Name string `json:"name,omitempty"` + DataType string `json:"data_type,omitempty"` + Type *TypeExpr `json:"type,omitempty"` + TypeOID int64 `json:"type_oid,omitempty"` + NotNull bool `json:"not_null"` + IsArray bool `json:"is_array,omitempty"` + Source *ColumnSource `json:"source,omitempty"` +} diff --git a/internal/core/analyzer/analyzer.go b/internal/core/analyzer/analyzer.go new file mode 100644 index 0000000..98076c4 --- /dev/null +++ b/internal/core/analyzer/analyzer.go @@ -0,0 +1,389 @@ +package analyzer + +import ( + "fmt" + + "github.com/sqlc-dev/sqlc/internal/core" + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +func Prepare(cat *core.Catalog, stmt ast.Node) (core.PrepareResult, error) { + if rs, ok := stmt.(*ast.RawStmt); ok { + stmt = rs.Stmt + } + a := &analyzer{ + cat: cat, + params: map[int]core.Parameter{}, + stars: &[]core.StarExpansion{}, + } + switch s := stmt.(type) { + case *ast.SelectStmt: + if err := a.analyzeSelect(s); err != nil { + return core.PrepareResult{}, err + } + a.command = core.CommandSelect + case *ast.InsertStmt: + if err := a.analyzeInsert(s); err != nil { + return core.PrepareResult{}, err + } + a.command = core.CommandInsert + case *ast.UpdateStmt: + if err := a.analyzeUpdate(s); err != nil { + return core.PrepareResult{}, err + } + a.command = core.CommandUpdate + case *ast.DeleteStmt: + if err := a.analyzeDelete(s); err != nil { + return core.PrepareResult{}, err + } + a.command = core.CommandDelete + default: + return core.PrepareResult{}, fmt.Errorf("analyzer: unsupported statement %T", stmt) + } + return a.result(), nil +} + +type analyzer struct { + cat *core.Catalog + scope *scope + columns []core.Column + params map[int]core.Parameter + command core.Command + + // outer is the scope of the query this one is nested in, which a + // correlated subquery refers to. + outer *scope + + // ctes are the relations a WITH clause defined, visible to this query and + // to the ones nested in it. + ctes map[string]scopeRel + + // aliases are the names the target list gives its expressions. GROUP BY, + // HAVING and ORDER BY may refer to a result column by its output name. + aliases map[string]ast.Node + + // resolving guards against an alias that refers to itself. + resolving map[string]bool + + // stars are the expansions every star in the statement asked for, shared + // with the analyzers of the queries nested in it so one statement reports + // all of them. + stars *[]core.StarExpansion +} + +func (a *analyzer) recordStar(s core.StarExpansion) { + if a.stars == nil { + return + } + *a.stars = append(*a.stars, s) +} + +// subquery analyzes a nested SELECT. It shares the parameter set, so a +// placeholder inside the subquery is reported with the rest, and it sees this +// query's scope, so a correlated reference resolves. +func (a *analyzer) subquery(s *ast.SelectStmt) (*analyzer, error) { + sub := &analyzer{ + cat: a.cat, + params: a.params, + outer: a.scope, + ctes: a.ctes, + stars: a.stars, + } + if err := sub.analyzeSelect(s); err != nil { + return nil, err + } + return sub, nil +} + +func (a *analyzer) subqueryColumns(s *ast.SelectStmt) ([]core.Column, error) { + sub, err := a.subquery(s) + if err != nil { + return nil, err + } + return sub.columns, nil +} + +// derivedRel turns a subquery's result columns into a relation, so that the +// query selecting from it resolves columns the same way as from a table. +func derivedRel(alias string, cols []core.Column) scopeRel { + rel := scopeRel{alias: alias, cols: make([]core.ClassColumn, 0, len(cols))} + for _, col := range cols { + rel.cols = append(rel.cols, core.ClassColumn{ + AttOID: col.SourceAttributeOID, + Name: col.Name, + TypeOID: col.TypeOID, + Type: col.Type.WithNullable(false), + NotNull: col.NotNull, + }) + } + return rel +} + +func (a *analyzer) result() core.PrepareResult { + // A placeholder nothing constrained takes the dialect's type for one, when + // the dialect has such a type. + if oid, ok := a.cat.UntypedTypeOID(); ok { + for n, p := range a.params { + if p.TypeOID == 0 && p.Type == nil { + t := exprType{typeOID: oid, nullable: true} + p.TypeOID = oid + p.DataType, p.IsArray = a.typeNameOf(t) + p.NotNull = false + p.Type = a.typeExprOf(t) + a.params[n] = p + } + } + } + res := core.PrepareResult{ + Command: a.command, + Columns: a.columns, + Parameters: orderedParams(a.params), + } + if a.stars != nil { + res.Stars = *a.stars + } + return res +} + +func orderedParams(m map[int]core.Parameter) []core.Parameter { + if len(m) == 0 { + return nil + } + maxN := 0 + for n := range m { + if n > maxN { + maxN = n + } + } + out := make([]core.Parameter, 0, len(m)) + for i := 1; i <= maxN; i++ { + if p, ok := m[i]; ok { + out = append(out, p) + } + } + return out +} + +func (a *analyzer) analyzeSelect(s *ast.SelectStmt) error { + if err := a.bindCTEs(s.WithClause); err != nil { + return err + } + + // A set operation reports the columns of its first branch. The other + // branches still get analyzed, for the placeholders they hold. + if s.Larg != nil && s.Rarg != nil { + if err := a.analyzeSetOperation(s); err != nil { + return err + } + return nil + } + + sc, err := a.buildScope(s.FromClause) + if err != nil { + return err + } + a.scope = sc + + a.bindAliases(s.TargetList) + + for _, item := range listItems(s.FromClause) { + if err := a.typeJoinConditions(item); err != nil { + return fmt.Errorf("join: %w", err) + } + } + + if s.WhereClause != nil { + if _, err := a.typeExpr(s.WhereClause); err != nil { + return fmt.Errorf("where: %w", err) + } + } + if items := listItems(s.GroupClause); items != nil { + for _, g := range items { + if _, err := a.typeExpr(g); err != nil { + return fmt.Errorf("group by: %w", err) + } + } + } + if s.HavingClause != nil { + if _, err := a.typeExpr(s.HavingClause); err != nil { + return fmt.Errorf("having: %w", err) + } + } + + targets := listItems(s.TargetList) + if targets == nil { + // A VALUES list produces rows without naming columns. + if s.ValuesLists != nil { + return a.typeValuesLists(s.ValuesLists) + } + return fmt.Errorf("select: empty target list") + } + a.columns = make([]core.Column, 0, len(targets)) + for _, t := range targets { + rt, ok := t.(*ast.ResTarget) + if !ok { + continue + } + if err := a.projectTarget(rt); err != nil { + return err + } + } + for _, item := range listItems(s.SortClause) { + if sb, ok := item.(*ast.SortBy); ok { + if _, err := a.typeExpr(sb.Node); err != nil { + return fmt.Errorf("order by: %w", err) + } + } + } + for _, n := range []ast.Node{s.LimitCount, s.LimitOffset} { + if err := a.typeLimit(n); err != nil { + return fmt.Errorf("limit: %w", err) + } + } + return nil +} + +// typeLimit types a LIMIT or OFFSET count. A bare placeholder there holds +// whatever the dialect counts rows in. +func (a *analyzer) typeLimit(n ast.Node) error { + if n == nil { + return nil + } + if pr, ok := n.(*ast.ParamRef); ok { + oid, err := a.cat.LimitTypeOID() + if err != nil { + return err + } + a.inferParam(pr.Number, exprType{typeOID: oid}) + return nil + } + _, err := a.typeExpr(n) + return err +} + +func (a *analyzer) typeValuesLists(l *ast.List) error { + for _, row := range listItems(l) { + if _, err := a.typeExpr(row); err != nil { + return err + } + } + return nil +} + +// analyzeSetOperation types both sides of UNION, INTERSECT or EXCEPT and +// reports the first branch's columns, the way the databases name the result. +func (a *analyzer) analyzeSetOperation(s *ast.SelectStmt) error { + left, err := a.subquery(s.Larg) + if err != nil { + return err + } + if _, err := a.subquery(s.Rarg); err != nil { + return err + } + a.columns = left.columns + a.scope = left.scope + return nil +} + +// bindCTEs analyzes a WITH clause, making each common table expression +// available to the query as a relation. +func (a *analyzer) bindCTEs(with *ast.WithClause) error { + if with == nil { + return nil + } + for _, item := range listItems(with.Ctes) { + cte, ok := item.(*ast.CommonTableExpr) + if !ok || cte.Ctename == nil { + continue + } + sel, ok := cte.Ctequery.(*ast.SelectStmt) + if !ok { + continue + } + cols, err := a.subqueryColumns(sel) + if err != nil { + return fmt.Errorf("with %s: %w", *cte.Ctename, err) + } + rel := derivedRel(*cte.Ctename, cols) + renameColumns(&rel, cte.Aliascolnames) + if a.ctes == nil { + a.ctes = map[string]scopeRel{} + } + a.ctes[*cte.Ctename] = rel + } + return nil +} + +// bindAliases records the output names the target list assigns, so a later +// clause can refer to a result column by name. +func (a *analyzer) bindAliases(targets *ast.List) { + for _, item := range listItems(targets) { + rt, ok := item.(*ast.ResTarget) + if !ok || rt.Name == nil || *rt.Name == "" { + continue + } + if a.aliases == nil { + a.aliases = map[string]ast.Node{} + } + a.aliases[*rt.Name] = rt.Val + } +} + +// typeAlias types the expression an output name stands for, which is how a +// GROUP BY or HAVING clause refers to a result column. +func (a *analyzer) typeAlias(name string) (exprType, bool, error) { + val, ok := a.aliases[name] + if !ok || a.resolving[name] { + return exprType{}, false, nil + } + if a.resolving == nil { + a.resolving = map[string]bool{} + } + a.resolving[name] = true + defer delete(a.resolving, name) + + t, err := a.typeExpr(val) + if err != nil { + return exprType{}, false, err + } + return t, true, nil +} + +// renameColumns applies the column aliases a derived relation was declared +// with, as in "WITH t(a, b) AS (...)". +func renameColumns(rel *scopeRel, names *ast.List) { + for i, item := range listItems(names) { + if i >= len(rel.cols) { + break + } + if s, ok := item.(*ast.String); ok && s.Str != "" { + rel.cols[i].Name = s.Str + } + } +} + +func listItems(l *ast.List) []ast.Node { + if l == nil { + return nil + } + return l.Items +} + +func (a *analyzer) typeJoinConditions(item ast.Node) error { + je, ok := item.(*ast.JoinExpr) + if !ok { + return nil + } + if err := a.typeJoinConditions(je.Larg); err != nil { + return err + } + if err := a.typeJoinConditions(je.Rarg); err != nil { + return err + } + if je.Quals != nil { + if _, err := a.typeExpr(je.Quals); err != nil { + return fmt.Errorf("ON: %w", err) + } + } + return nil +} diff --git a/internal/core/analyzer/bench_test.go b/internal/core/analyzer/bench_test.go new file mode 100644 index 0000000..8d6bc6a --- /dev/null +++ b/internal/core/analyzer/bench_test.go @@ -0,0 +1,110 @@ +package analyzer_test + +import ( + "strings" + "testing" + + "github.com/sqlc-dev/sqlc/internal/core" + "github.com/sqlc-dev/sqlc/internal/core/analyzer" + coreschema "github.com/sqlc-dev/sqlc/internal/core/schema" + "github.com/sqlc-dev/sqlc/internal/engine/googlesql" + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +const benchSchema = ` +CREATE TABLE users ( + id INT64 NOT NULL, + name STRING NOT NULL, + bio STRING, +) PRIMARY KEY (id); + +CREATE TABLE posts ( + id INT64 NOT NULL, + user_id INT64 NOT NULL, + title STRING(255), + created TIMESTAMP NOT NULL, +) PRIMARY KEY (id); +` + +const benchQueries = ` +SELECT * FROM users; +SELECT COUNT(*) AS total FROM users; +SELECT u.name, p.* FROM users u JOIN posts p ON p.user_id = u.id WHERE u.name = @name; +SELECT id, name, bio FROM users WHERE id = @id AND name = @name; +SELECT p.title, p.created FROM posts p WHERE p.user_id = @uid AND p.title = @t; +` + +func parseAll(t testing.TB, src string) []ast.Node { + p := googlesql.NewParser() + stmts, err := p.Parse(strings.NewReader(src)) + if err != nil { + t.Fatal(err) + } + out := make([]ast.Node, 0, len(stmts)) + for i := range stmts { + out = append(out, stmts[i].Raw) + } + return out +} + +// parseQueries mirrors the compiler pipeline. GoogleSQL is not preprocessed — +// "@name" is native syntax the converter turns into a ParamRef — so parsing is +// all it takes. +func parseQueries(t testing.TB, src string) []ast.Node { + return parseAll(t, src) +} + +func newBenchCatalog(t testing.TB) (*core.Catalog, []ast.Node) { + cat, err := core.New(googlesql.Dialect()) + if err != nil { + t.Fatal(err) + } + for _, n := range parseAll(t, benchSchema) { + if err := coreschema.Apply(cat, n); err != nil { + t.Fatal(err) + } + } + return cat, parseQueries(t, benchQueries) +} + +// BenchmarkCatalogNew measures per-compile catalog setup: open the SQLite +// catalog, install the schema, and run the dialect seed. +func BenchmarkCatalogNew(b *testing.B) { + for b.Loop() { + cat, err := core.New(googlesql.Dialect()) + if err != nil { + b.Fatal(err) + } + cat.Close() + } +} + +// BenchmarkApplySchema measures loading user DDL into the catalog. +func BenchmarkApplySchema(b *testing.B) { + stmts := parseAll(b, benchSchema) + for b.Loop() { + cat, err := core.New(googlesql.Dialect()) + if err != nil { + b.Fatal(err) + } + for _, n := range stmts { + if err := coreschema.Apply(cat, n); err != nil { + b.Fatal(err) + } + } + cat.Close() + } +} + +// BenchmarkPrepare measures steady-state query analysis against a warm catalog. +func BenchmarkPrepare(b *testing.B) { + cat, queries := newBenchCatalog(b) + defer cat.Close() + for b.Loop() { + for _, q := range queries { + if _, err := analyzer.Prepare(cat, q); err != nil { + b.Fatal(err) + } + } + } +} diff --git a/internal/core/analyzer/dml.go b/internal/core/analyzer/dml.go new file mode 100644 index 0000000..8f188b8 --- /dev/null +++ b/internal/core/analyzer/dml.go @@ -0,0 +1,211 @@ +package analyzer + +import ( + "fmt" + + "github.com/sqlc-dev/sqlc/internal/core" + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +func (a *analyzer) analyzeInsert(s *ast.InsertStmt) error { + if s.Relation == nil { + return fmt.Errorf("insert: missing relation") + } + rel, err := a.bindRangeVar(s.Relation) + if err != nil { + return err + } + a.scope = &scope{rels: []scopeRel{rel}} + + targets, err := insertTargets(rel, s.Cols) + if err != nil { + return err + } + if err := a.bindInsertValues(s.SelectStmt, rel, targets); err != nil { + return err + } + return a.projectReturning(s.ReturningList) +} + +func (a *analyzer) analyzeUpdate(s *ast.UpdateStmt) error { + if err := a.bindCTEs(s.WithClause); err != nil { + return err + } + sc, err := a.relationScope(s.Relations, s.FromClause, nil) + if err != nil { + return err + } + a.scope = sc + target := sc.rels[0] + + for _, item := range listItems(s.TargetList) { + rt, ok := item.(*ast.ResTarget) + if !ok || rt.Name == nil { + continue + } + col, ok := findColumn(target, *rt.Name) + if !ok { + return fmt.Errorf("unknown column %q", *rt.Name) + } + if err := a.bindValue(target, &col, rt.Val); err != nil { + return fmt.Errorf("set %s: %w", *rt.Name, err) + } + } + + if s.WhereClause != nil { + if _, err := a.typeExpr(s.WhereClause); err != nil { + return fmt.Errorf("where: %w", err) + } + } + return a.projectReturning(s.ReturningList) +} + +func (a *analyzer) analyzeDelete(s *ast.DeleteStmt) error { + if err := a.bindCTEs(s.WithClause); err != nil { + return err + } + sc, err := a.relationScope(s.Relations, s.UsingClause, s.FromClause) + if err != nil { + return err + } + a.scope = sc + + if s.WhereClause != nil { + if _, err := a.typeExpr(s.WhereClause); err != nil { + return fmt.Errorf("where: %w", err) + } + } + return a.projectReturning(s.ReturningList) +} + +// relationScope builds the scope a DML statement operates on: the relations it +// targets, whatever a USING or FROM clause joins in, and — for the engines that +// report a multi-table DELETE that way — a single FROM node. +func (a *analyzer) relationScope(relations, extra *ast.List, from ast.Node) (*scope, error) { + sc := &scope{} + defer a.binding(sc)() + for _, item := range listItems(relations) { + if err := a.appendFromItem(sc, item); err != nil { + return nil, err + } + } + for _, item := range listItems(extra) { + if err := a.appendFromItem(sc, item); err != nil { + return nil, err + } + } + if from != nil { + if err := a.appendFromItem(sc, from); err != nil { + return nil, err + } + } + if len(sc.rels) == 0 { + return nil, fmt.Errorf("missing target relation") + } + return sc, nil +} + +func insertTargets(rel scopeRel, cols *ast.List) ([]core.ClassColumn, error) { + items := listItems(cols) + if len(items) == 0 { + out := make([]core.ClassColumn, 0, len(rel.cols)) + for _, col := range rel.cols { + if !col.Hidden { + out = append(out, col) + } + } + return out, nil + } + out := make([]core.ClassColumn, 0, len(items)) + for _, item := range items { + rt, ok := item.(*ast.ResTarget) + if !ok || rt.Name == nil { + return nil, fmt.Errorf("insert: unsupported column target %T", item) + } + col, ok := findColumn(rel, *rt.Name) + if !ok { + return nil, fmt.Errorf("unknown column %q", *rt.Name) + } + out = append(out, col) + } + return out, nil +} + +func (a *analyzer) bindInsertValues(n ast.Node, rel scopeRel, targets []core.ClassColumn) error { + if n == nil { + return nil + } + sel, ok := n.(*ast.SelectStmt) + if !ok { + return fmt.Errorf("insert: unsupported source %T", n) + } + // INSERT ... SELECT inserts whatever the query returns. The rows are not + // the statement's result, but the query still holds placeholders. + if sel.ValuesLists == nil { + _, err := a.subqueryColumns(sel) + return err + } + for _, row := range listItems(sel.ValuesLists) { + values, ok := row.(*ast.List) + if !ok { + continue + } + for i, v := range values.Items { + var target *core.ClassColumn + if i < len(targets) { + target = &targets[i] + } + if err := a.bindValue(rel, target, v); err != nil { + return err + } + } + } + return nil +} + +func (a *analyzer) bindValue(rel scopeRel, target *core.ClassColumn, v ast.Node) error { + if target != nil { + switch value := v.(type) { + case *ast.ParamRef: + a.inferParam(value.Number, columnType(rel, *target)) + return nil + case *ast.A_Const: + return nil + } + } + _, err := a.typeExpr(v) + return err +} + +func (a *analyzer) projectReturning(l *ast.List) error { + for _, item := range listItems(l) { + rt, ok := item.(*ast.ResTarget) + if !ok { + continue + } + if err := a.projectTarget(rt); err != nil { + return err + } + } + return nil +} + +func findColumn(rel scopeRel, name string) (core.ClassColumn, bool) { + for _, col := range rel.cols { + if col.Name == name { + return col, true + } + } + return core.ClassColumn{}, false +} + +func columnType(rel scopeRel, col core.ClassColumn) exprType { + return exprType{ + typeOID: col.TypeOID, + expr: col.Type, + nullable: !col.NotNull, + sourceClassOID: rel.classOID, + sourceAttributeOID: col.AttOID, + sourceTableAlias: rel.alias, + } +} diff --git a/internal/core/analyzer/expr.go b/internal/core/analyzer/expr.go new file mode 100644 index 0000000..8305222 --- /dev/null +++ b/internal/core/analyzer/expr.go @@ -0,0 +1,1038 @@ +package analyzer + +import ( + "fmt" + "slices" + "strings" + + "github.com/sqlc-dev/sqlc/internal/core" + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +type exprType struct { + // typeOID is the type's row: the instance when the catalog holds one, + // else the family, else 0 for a type no dialect seeded and no schema + // declared. + typeOID int64 + // expr is the whole expression when it says more than the row does — a + // cast to numeric(5, 1) when only numeric is a row — or names a type + // the catalog does not hold. Analysis never adds a type: it reports the + // expression the query used and carries on, so a query can be analyzed + // against a catalog it cannot write to. + expr *core.TypeExpr + nullable bool + sourceClassOID int64 + sourceAttributeOID int64 + sourceTableAlias string +} + +func (a *analyzer) typeExpr(n ast.Node) (exprType, error) { + switch e := n.(type) { + case nil: + return exprType{}, nil + + case *ast.TODO: + return exprType{}, nil + + case *ast.A_Const: + return a.typeConst(e) + + case *ast.ColumnRef: + return a.typeColumnRef(e) + + case *ast.ParamRef: + return a.typeParamRef(e) + + case *ast.A_Expr: + return a.typeAExpr(e) + + case *ast.BoolExpr: + return a.typeBoolExpr(e) + + case *ast.FuncCall: + return a.typeFuncCall(e) + + case *ast.TypeCast: + return a.typeTypeCast(e) + + case *ast.NullTest: + if _, err := a.typeExpr(e.Arg); err != nil { + return exprType{}, err + } + return a.boolType(false) + + case *ast.In: + return a.typeIn(e) + + case *ast.BetweenExpr: + return a.typeBetween(e) + + case *ast.CaseExpr: + return a.typeCase(e) + + case *ast.CoalesceExpr: + return a.typeCoalesce(e) + + case *ast.MinMaxExpr: + return a.typeFirstOf(listItems(e.Args), false) + + case *ast.A_ArrayExpr: + return a.typeArrayExpr(e) + + case *ast.SubLink: + return a.typeSubLink(e) + + case *ast.CollateExpr: + return a.typeExpr(e.Arg) + + case *ast.IntervalExpr: + // A dialect with no interval type of its own leaves it untyped. + oid, err := a.cat.TypeOID("interval") + if err != nil { + return exprType{}, nil + } + return exprType{typeOID: oid}, nil + + // A user variable and an ordinal in GROUP BY / ORDER BY carry no type of + // their own, and neither is something to resolve. + case *ast.VariableExpr, *ast.Integer, *ast.String, *ast.Float: + return exprType{}, nil + + case *ast.List: + for _, item := range listItems(e) { + if _, err := a.typeExpr(item); err != nil { + return exprType{}, err + } + } + return exprType{}, nil + } + return exprType{}, fmt.Errorf("typeExpr: unsupported %T", n) +} + +func (a *analyzer) typeConst(c *ast.A_Const) (exprType, error) { + switch v := c.Val.(type) { + case *ast.Integer: + _ = v + oid, err := a.cat.ConstTypeOID(core.ConstInteger) + if err != nil { + return exprType{}, err + } + return exprType{typeOID: oid}, nil + case *ast.Float: + oid, err := a.cat.ConstTypeOID(core.ConstFloat) + if err != nil { + return exprType{}, err + } + return exprType{typeOID: oid}, nil + case *ast.String: + oid, err := a.cat.ConstTypeOID(core.ConstString) + if err != nil { + return exprType{}, err + } + return exprType{typeOID: oid}, nil + case *ast.Boolean: + return a.boolType(false) + case *ast.Null, nil: + return exprType{nullable: true}, nil + } + return exprType{}, fmt.Errorf("typeConst: unsupported %T", c.Val) +} + +func (a *analyzer) boolType(nullable bool) (exprType, error) { + oid, err := a.cat.BoolTypeOID() + if err != nil { + return exprType{}, err + } + return exprType{typeOID: oid, nullable: nullable}, nil +} + +func (a *analyzer) typeColumnRef(c *ast.ColumnRef) (exprType, error) { + parts := flattenFields(c.Fields) + if len(parts) == 0 { + return exprType{}, fmt.Errorf("column ref: empty") + } + relation := "" + column := parts[0] + if len(parts) >= 2 { + relation = parts[0] + column = parts[1] + } + rel, col, ok, err := a.resolveColumn(relation, column) + if err != nil { + return exprType{}, err + } + // A dotted name may be a column's own, as ClickHouse names the columns + // a Nested column stores as n.a. + if !ok && relation != "" { + rel, col, ok, err = a.resolveColumn("", relation+"."+column) + if err != nil { + return exprType{}, err + } + } + if !ok { + if relation != "" { + return exprType{}, fmt.Errorf("unknown column %q.%q", relation, column) + } + // The name may be one the target list assigned rather than one a + // relation offers. + if t, ok, err := a.typeAlias(column); err != nil || ok { + return t, err + } + return exprType{}, fmt.Errorf("unknown column %q", column) + } + return columnType(rel, col), nil +} + +func flattenFields(fields *ast.List) []string { + if fields == nil { + return nil + } + out := make([]string, 0, len(fields.Items)) + for _, item := range fields.Items { + switch v := item.(type) { + case *ast.String: + out = append(out, v.Str) + case *ast.A_Star: + out = append(out, "*") + return out + } + } + return out +} + +func (a *analyzer) typeParamRef(p *ast.ParamRef) (exprType, error) { + cur, ok := a.params[p.Number] + if !ok { + cur = core.Parameter{Number: p.Number, Name: p.Name} + a.params[p.Number] = cur + } + return exprType{typeOID: cur.TypeOID, expr: cur.Type.WithNullable(false), nullable: !cur.NotNull}, nil +} + +func (a *analyzer) inferParam(number int, t exprType) { + cur, ok := a.params[number] + if !ok { + cur = core.Parameter{Number: number} + } + typed := cur.TypeOID == 0 && cur.Type == nil && (t.typeOID != 0 || t.expr != nil) + if typed { + cur.TypeOID = t.typeOID + cur.DataType, cur.IsArray = a.typeNameOf(t) + cur.NotNull = !t.nullable + cur.Type = a.typeExprOf(t) + } + if cur.Source == nil && t.sourceAttributeOID != 0 { + ad, err := a.cat.LookupAttribute(t.sourceAttributeOID) + if err == nil { + cur.Source = &core.ColumnSource{ + Schema: ad.Schema, + Table: ad.Table, + TableAlias: t.sourceTableAlias, + Column: ad.Column, + } + } + } + a.params[number] = cur +} + +// nameParamAfter names a placeholder compared with a function call after +// the function, the way a placeholder compared with a column is named after +// the column. +func (a *analyzer) nameParamAfter(number int, other ast.Node) { + fc, ok := other.(*ast.FuncCall) + if !ok { + return + } + cur := a.params[number] + if cur.Name == "" && cur.Source == nil { + cur.Name = funcCallName(fc) + a.params[number] = cur + } +} + +func (a *analyzer) typeAExpr(e *ast.A_Expr) (exprType, error) { + // Not every engine classifies its operators, so a zero kind is a plain + // operator application rather than an unset field. LIKE and its relatives + // name a real operator too, so they resolve the same way. + switch e.Kind { + case ast.A_Expr_Kind_OP, ast.A_Expr_Kind_LIKE, ast.A_Expr_Kind_ILIKE, ast.A_Expr_Kind_SIMILAR, 0: + case ast.A_Expr_Kind_OP_ANY, ast.A_Expr_Kind_OP_ALL: + return a.typeQuantifiedExpr(e) + case ast.A_Expr_Kind_IN, ast.A_Expr_Kind_BETWEEN, ast.A_Expr_Kind_NOT_BETWEEN, + ast.A_Expr_Kind_BETWEEN_SYM, ast.A_Expr_Kind_NOT_BETWEEN_SYM: + return a.typePredicateList(e) + case ast.A_Expr_Kind_DISTINCT, ast.A_Expr_Kind_NOT_DISTINCT: + return a.typeComparison(e) + case ast.A_Expr_Kind_NULLIF: + return a.typeNullIf(e) + default: + return exprType{}, fmt.Errorf("a_expr: unsupported kind %v", e.Kind) + } + opName := normalizeOperator(opNameFromList(e.Name)) + if opName == "" { + return exprType{}, fmt.Errorf("a_expr: unnamed operator") + } + + // Engines that do not have a dedicated boolean node report AND and OR as + // operators. They combine predicates whatever the dialect. + if opName == "AND" || opName == "OR" { + if _, err := a.typeExpr(e.Lexpr); err != nil { + return exprType{}, err + } + if _, err := a.typeExpr(e.Rexpr); err != nil { + return exprType{}, err + } + return a.boolType(false) + } + + leftT, err := a.typeExpr(e.Lexpr) + if err != nil { + return exprType{}, err + } + // The postfix null tests SQLite has — x ISNULL, x NOTNULL, x NOT NULL — + // arrive as operators with no right operand, and are predicates that + // are never NULL. + if e.Rexpr == nil && isNullTest(opName) { + return a.boolType(false) + } + rightT, err := a.typeExpr(e.Rexpr) + if err != nil { + return exprType{}, err + } + + if pr, ok := e.Lexpr.(*ast.ParamRef); ok && rightT.typeOID != 0 { + a.inferParam(pr.Number, rightT) + a.nameParamAfter(pr.Number, e.Rexpr) + leftT = rightT + } else if pr := castParamRef(e.Lexpr); pr != nil { + a.inferParam(pr.Number, rightT) + a.nameParamAfter(pr.Number, e.Rexpr) + } + if pr, ok := e.Rexpr.(*ast.ParamRef); ok && leftT.typeOID != 0 { + a.inferParam(pr.Number, leftT) + a.nameParamAfter(pr.Number, e.Lexpr) + rightT = leftT + } else if pr := castParamRef(e.Rexpr); pr != nil { + a.inferParam(pr.Number, leftT) + a.nameParamAfter(pr.Number, e.Lexpr) + } + + overload, err := a.resolveOperator(opName, leftT, rightT) + if err != nil { + return exprType{}, err + } + // An operator's result is NULL when an operand is, except for IS and + // IS NOT, which test for NULL rather than propagate it: x IS NULL and + // x IS y are never NULL, whatever x and y are. + return exprType{ + typeOID: overload.ResultTypeOID, + nullable: (leftT.nullable || rightT.nullable) && !isNullTest(opName), + }, nil +} + +// castParamRef is the placeholder a cast wraps, as ClickHouse's {p:UInt64} +// is written, or nil. The cast has typed it already; what it is compared +// with still names it and says which column it stands in for. +func castParamRef(n ast.Node) *ast.ParamRef { + tc, ok := n.(*ast.TypeCast) + if !ok { + return nil + } + pr, _ := tc.Arg.(*ast.ParamRef) + return pr +} + +// isNullTest reports whether an operator compares with NULL as a value +// rather than propagating it, so that its result is never NULL. +func isNullTest(opName string) bool { + switch opName { + case "IS", "IS NOT", "ISNULL", "NOTNULL", "NOT NULL": + return true + } + return false +} + +// typeQuantifiedExpr types "x = ANY($1)" and "x > ALL(...)": the right side +// holds values of the left side's type, and the result is a predicate. +func (a *analyzer) typeQuantifiedExpr(e *ast.A_Expr) (exprType, error) { + leftT, err := a.typeExpr(e.Lexpr) + if err != nil { + return exprType{}, err + } + if err := a.typeOperands(e.Rexpr, leftT); err != nil { + return exprType{}, err + } + return a.boolType(false) +} + +// typePredicateList types IN and BETWEEN, where the right side is a list of +// values compared against the left. +func (a *analyzer) typePredicateList(e *ast.A_Expr) (exprType, error) { + leftT, err := a.typeExpr(e.Lexpr) + if err != nil { + return exprType{}, err + } + if l, ok := e.Rexpr.(*ast.List); ok { + for _, item := range listItems(l) { + if err := a.typeOperands(item, leftT); err != nil { + return exprType{}, err + } + } + return a.boolType(false) + } + if err := a.typeOperands(e.Rexpr, leftT); err != nil { + return exprType{}, err + } + return a.boolType(false) +} + +// typeIn types the IN node the engines that have one report, where the values +// compared against are held apart from the expression. +func (a *analyzer) typeIn(e *ast.In) (exprType, error) { + leftT, err := a.typeExpr(e.Expr) + if err != nil { + return exprType{}, err + } + for _, item := range e.List { + if err := a.typeOperands(item, leftT); err != nil { + return exprType{}, err + } + } + // "x IN (SELECT ...)" compares x against the subquery's column, and the + // subquery's own placeholders are reported with the rest. + if sel, ok := e.Sel.(*ast.SelectStmt); ok { + cols, err := a.subqueryColumns(sel) + if err != nil { + return exprType{}, err + } + if pr, ok := e.Expr.(*ast.ParamRef); ok && len(cols) > 0 { + if err := a.typeOperands(pr, columnExprType(cols[0])); err != nil { + return exprType{}, err + } + } + } + return a.boolType(false) +} + +// typeBetween types the BETWEEN node the engines that have one report. +func (a *analyzer) typeBetween(e *ast.BetweenExpr) (exprType, error) { + leftT, err := a.typeExpr(e.Expr) + if err != nil { + return exprType{}, err + } + for _, bound := range []ast.Node{e.Left, e.Right} { + if err := a.typeOperands(bound, leftT); err != nil { + return exprType{}, err + } + } + return a.boolType(false) +} + +// typeCase types CASE. Its result is the first branch's, and it is nullable +// unless every branch and the default are. +func (a *analyzer) typeCase(e *ast.CaseExpr) (exprType, error) { + argT, err := a.typeExpr(e.Arg) + if err != nil { + return exprType{}, err + } + results := make([]ast.Node, 0, len(listItems(e.Args))+1) + for _, item := range listItems(e.Args) { + when, ok := item.(*ast.CaseWhen) + if !ok { + continue + } + // "CASE x WHEN y" compares y against x; "CASE WHEN y" is a predicate. + if e.Arg != nil { + if err := a.typeOperands(when.Expr, argT); err != nil { + return exprType{}, err + } + } else if _, err := a.typeExpr(when.Expr); err != nil { + return exprType{}, err + } + results = append(results, when.Result) + } + if e.Defresult != nil { + results = append(results, e.Defresult) + } + t, err := a.typeFirstOf(results, e.Defresult == nil) + if err != nil { + return exprType{}, err + } + return t, nil +} + +// typeCoalesce types COALESCE, which is its first typed argument's type and +// is null only when every argument is. +func (a *analyzer) typeCoalesce(e *ast.CoalesceExpr) (exprType, error) { + var out exprType + found := false + nullable := true + for _, n := range listItems(e.Args) { + t, err := a.typeExpr(n) + if err != nil { + return exprType{}, err + } + if !found && (t.typeOID != 0 || t.expr != nil) { + // The result is an expression's, not the column's it came from. + out = exprType{typeOID: t.typeOID, expr: t.expr} + found = true + } + nullable = nullable && t.nullable + } + out.nullable = nullable + return out, nil +} + +// typeFirstOf types a set of alternative results, taking the first one that has +// a type. The result is nullable when any alternative is, or when the caller +// says the set is not exhaustive. +func (a *analyzer) typeFirstOf(nodes []ast.Node, nullable bool) (exprType, error) { + var out exprType + found := false + for _, n := range nodes { + t, err := a.typeExpr(n) + if err != nil { + return exprType{}, err + } + if !found && (t.typeOID != 0 || t.expr != nil) { + out = t + found = true + } + nullable = nullable || t.nullable + } + out.nullable = nullable + return out, nil +} + +// typeArrayExpr types ARRAY[...], whose type is an array of its elements'. +func (a *analyzer) typeArrayExpr(e *ast.A_ArrayExpr) (exprType, error) { + elemT, err := a.typeFirstOf(listItems(e.Elements), false) + if err != nil { + return exprType{}, err + } + element := a.exprOf(elemT) + if element == nil { + return exprType{}, nil + } + return a.lookupType(core.Array(element.WithNullable(false))), nil +} + +// lookupType is the type an expression refers to: its row when the catalog +// holds one, its family's row when it holds only that, and the expression +// alone when it holds neither. +func (a *analyzer) lookupType(t *core.TypeExpr) exprType { + if t == nil { + return exprType{} + } + found, ok := a.cat.LookupTypeExpr(t) + if !ok { + return exprType{expr: t.WithNullable(false)} + } + out := exprType{typeOID: found.OID} + if found.OID == found.FamilyOID && len(found.Expr.Args) > 0 { + out.expr = found.Expr + } + return out +} + +// namedType is the type a name refers to, or the name itself when the catalog +// has no such type. +func (a *analyzer) namedType(name string) exprType { + return a.lookupType(core.ParseTypeExpr(name)) +} + +// exprOf is a type's expression: the one the analysis carries, or the one +// its row stands for. It is a copy, and nil for an untyped expression. +func (a *analyzer) exprOf(t exprType) *core.TypeExpr { + if t.expr != nil { + return t.expr.Clone() + } + if t.typeOID == 0 { + return nil + } + e, err := a.cat.TypeExprOf(t.typeOID) + if err != nil { + return nil + } + return e +} + +// typeExprOf writes a type as the expression a result reports, with the +// expression's own nullability set from the analysis. +func (a *analyzer) typeExprOf(t exprType) *core.TypeExpr { + e := a.exprOf(t) + if e == nil { + return nil + } + e.Nullable = t.nullable + return e +} + +// typeNameOf reports a type's innermost family name and whether the type is +// an array, which is the flat view the legacy compiler reads. +func (a *analyzer) typeNameOf(t exprType) (string, bool) { + e := a.exprOf(t) + if e == nil { + return "", false + } + // MySQL's unsigned families are their own types, but codegen reads + // the signed family and an unsigned flag, which the bridge derives + // from the expression. + return strings.TrimSuffix(e.Innermost().Name, " unsigned"), e.IsArray() +} + +// columnExprType is the type a result column of a nested query has, as an +// operand of the query around it. +func columnExprType(col core.Column) exprType { + return exprType{typeOID: col.TypeOID, expr: col.Type.WithNullable(false), nullable: !col.NotNull} +} + +// familyOID is the row everything about a type is registered on: the end of +// its resolution chain. +func (a *analyzer) familyOID(oid int64) int64 { + chain := a.cat.ResolutionChain(oid) + return chain[len(chain)-1] +} + +// typeSubLink types a subquery used as an expression: EXISTS and IN yield a +// predicate, and a scalar subquery yields its first column. +func (a *analyzer) typeSubLink(e *ast.SubLink) (exprType, error) { + if _, err := a.typeExpr(e.Testexpr); err != nil { + return exprType{}, err + } + sel, ok := e.Subselect.(*ast.SelectStmt) + if !ok { + if e.SubLinkType == ast.EXPR_SUBLINK || e.SubLinkType == ast.ARRAY_SUBLINK { + return exprType{nullable: true}, nil + } + return a.boolType(false) + } + cols, err := a.subqueryColumns(sel) + if err != nil { + return exprType{}, err + } + switch e.SubLinkType { + case ast.EXPR_SUBLINK, ast.ARRAY_SUBLINK: + if len(cols) == 0 { + return exprType{nullable: true}, nil + } + // A subquery that matches no row yields NULL. + t := columnExprType(cols[0]) + t.nullable = true + return t, nil + default: + return a.boolType(false) + } +} + +// typeComparison types IS DISTINCT FROM and its negation, which compare any two +// values and never return NULL. +func (a *analyzer) typeComparison(e *ast.A_Expr) (exprType, error) { + leftT, err := a.typeExpr(e.Lexpr) + if err != nil { + return exprType{}, err + } + rightT, err := a.typeExpr(e.Rexpr) + if err != nil { + return exprType{}, err + } + if err := a.typeOperands(e.Rexpr, leftT); err != nil { + return exprType{}, err + } + if err := a.typeOperands(e.Lexpr, rightT); err != nil { + return exprType{}, err + } + return a.boolType(false) +} + +// typeNullIf types NULLIF(x, y), which is x, made nullable. +func (a *analyzer) typeNullIf(e *ast.A_Expr) (exprType, error) { + leftT, err := a.typeExpr(e.Lexpr) + if err != nil { + return exprType{}, err + } + if err := a.typeOperands(e.Rexpr, leftT); err != nil { + return exprType{}, err + } + leftT.nullable = true + return leftT, nil +} + +// typeOperands types a node standing opposite one of known type, giving a bare +// placeholder that type. +func (a *analyzer) typeOperands(n ast.Node, other exprType) error { + if pr, ok := n.(*ast.ParamRef); ok { + // Registering the placeholder first keeps the name its syntax gave + // it, as ClickHouse's {name:Type} does. + if _, err := a.typeParamRef(pr); err != nil { + return err + } + if other.typeOID != 0 || other.expr != nil { + a.inferParam(pr.Number, other) + } + return nil + } + _, err := a.typeExpr(n) + return err +} + +// normalizeOperator upper-cases a word operator ("like", "is not") so that the +// spelling a user wrote matches the one a dialect seeded. Symbolic operators +// are already canonical. +func normalizeOperator(name string) string { + for _, r := range name { + if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') { + return strings.ToUpper(name) + } + } + return name +} + +func opNameFromList(l *ast.List) string { + if l == nil { + return "" + } + parts := make([]string, 0, len(l.Items)) + for _, item := range l.Items { + if s, ok := item.(*ast.String); ok { + parts = append(parts, s.Str) + } + } + return strings.Join(parts, ".") +} + +// resolveOperator finds the overload of an operator over two operand types. +// An operator is registered on a family, so an operand that is an instance, +// an alias or a domain is looked up along its resolution chain: numeric(10, +// 2) + numeric(5, 1) resolves on numeric. +func (a *analyzer) resolveOperator(name string, leftT, rightT exprType) (core.OperatorOverload, error) { + leftChain := a.cat.ResolutionChain(leftT.typeOID) + rightChain := a.cat.ResolutionChain(rightT.typeOID) + all, err := a.cat.FindOperators(name, 0, 0) + if err != nil { + return core.OperatorOverload{}, err + } + // The operator's overloads are read once; the pairs along the two + // chains are tried against them in order, nearest first. + byOperands := make(map[[2]int64]core.OperatorOverload, len(all)) + for _, ov := range all { + key := [2]int64{ov.LeftTypeOID, ov.RightTypeOID} + if _, seen := byOperands[key]; !seen { + byOperands[key] = ov + } + } + for _, l := range leftChain { + for _, r := range rightChain { + if ov, ok := byOperands[[2]int64{l, r}]; ok && l != 0 && r != 0 { + return ov, nil + } + } + } + leftOID := leftChain[len(leftChain)-1] + rightOID := rightChain[len(rightChain)-1] + + for _, ov := range all { + if leftOID != 0 && ov.LeftTypeOID != 0 && leftOID != ov.LeftTypeOID { + ok, _ := a.cat.CastAllowed(leftOID, ov.LeftTypeOID, "i") + if !ok { + continue + } + } + if rightOID != 0 && ov.RightTypeOID != 0 && rightOID != ov.RightTypeOID { + ok, _ := a.cat.CastAllowed(rightOID, ov.RightTypeOID, "i") + if !ok { + continue + } + } + if (leftOID == 0) != (ov.LeftTypeOID == 0) { + continue + } + if (rightOID == 0) != (ov.RightTypeOID == 0) { + continue + } + return ov, nil + } + + // No dialect declares every operator over every type — extensions add + // them, and an operator over a type the schema declared may never have + // been registered. Rather than fail the query, assume the shape the + // operator's name implies: a comparison yields a boolean and anything + // else yields the type it was applied to. + if a.cat.IsComparisonOperator(name) { + boolOID, err := a.cat.BoolTypeOID() + if err != nil { + return core.OperatorOverload{}, err + } + return core.OperatorOverload{Name: name, ResultTypeOID: boolOID}, nil + } + result := leftOID + if result == 0 { + result = rightOID + } + return core.OperatorOverload{Name: name, ResultTypeOID: result}, nil +} + +func (a *analyzer) typeBoolExpr(b *ast.BoolExpr) (exprType, error) { + for _, item := range listItems(b.Args) { + if _, err := a.typeExpr(item); err != nil { + return exprType{}, err + } + } + return a.boolType(false) +} + +func (a *analyzer) typeFuncCall(f *ast.FuncCall) (exprType, error) { + name := funcCallName(f) + if name == "" { + return exprType{}, fmt.Errorf("func call: missing name") + } + + if f.AggStar && (name == "count" || name == "count.*") { + if overloads, err := a.cat.FindProcs("count", nil); err == nil && len(overloads) > 0 { + return exprType{typeOID: overloads[0].ReturnTypeOID, nullable: overloads[0].ReturnNullable}, nil + } + oid, err := a.cat.TypeOID("bigint") + if err != nil { + return exprType{}, err + } + return exprType{typeOID: oid, nullable: false}, nil + } + + args := listItems(f.Args) + argTypes := make([]exprType, 0, len(args)) + argOIDs := make([]int64, 0, len(args)) + anyNullable := false + for _, arg := range args { + t, err := a.typeExpr(arg) + if err != nil { + return exprType{}, err + } + argTypes = append(argTypes, t) + argOIDs = append(argOIDs, t.typeOID) + anyNullable = anyNullable || t.nullable + } + + overloads, err := a.cat.FindProcs(name, nil) + if err != nil { + return exprType{}, err + } + if len(overloads) == 0 { + // A dialect's function list is never complete — extensions add to it, + // and so does the user. An unknown function leaves the result untyped + // rather than failing the query. + return exprType{nullable: true}, nil + } + p := a.pickOverload(overloads, argOIDs) + // An argument that is a bare placeholder takes the parameter's type, + // unless the parameter is polymorphic and says nothing. + for i, arg := range args { + if i >= len(p.ArgTypes) { + break + } + if a.isPolymorphicOID(p.ArgTypes[i]) { + continue + } + if err := a.typeOperands(arg, exprType{typeOID: p.ArgTypes[i]}); err != nil { + return exprType{}, err + } + } + ret := a.returnType(p, argTypes) + // A result that depends on an argument's value is spelled by the seed + // as a template over the arguments, filled in from the call. + if computed := a.returnTemplate(p, args, argTypes); computed != nil { + ret = a.lookupType(computed) + } + ret.nullable = p.ReturnNullable + if !p.NeverNull && anyNullable && a.cat.PropagatesNullable() { + ret.nullable = true + } + return ret, nil +} + +// returnTemplate fills a seed's return template — Decimal(18, $2) — from +// the call: a $n that stands for an integer literal takes its value, and +// one that stands for a typed argument takes its type. A template that +// cannot be filled leaves the answer to the catalog. +func (a *analyzer) returnTemplate(p core.ProcOverload, args []ast.Node, argTypes []exprType) *core.TypeExpr { + if p.ReturnTemplate == "" { + return nil + } + template := core.ParseTypeExpr(p.ReturnTemplate) + fill := func(arg core.TypeArg) (core.TypeArg, bool) { + n, ok := argIndex(arg.Type.Name) + if !ok || n >= len(args) { + return core.TypeArg{}, false + } + if c, ok := args[n].(*ast.A_Const); ok { + if lit, ok := c.Val.(*ast.Integer); ok { + v := lit.Ival + return core.TypeArg{Label: arg.Label, Int: &v}, true + } + if lit, ok := c.Val.(*ast.String); ok { + v := lit.Str + return core.TypeArg{Label: arg.Label, String: &v}, true + } + } + if t := a.exprOf(argTypes[n]); t != nil { + return core.TypeArg{Label: arg.Label, Type: t.WithNullable(false)}, true + } + return core.TypeArg{}, false + } + for i, arg := range template.Args { + if arg.Type == nil || !strings.HasPrefix(arg.Type.Name, "$") { + continue + } + filled, ok := fill(arg) + if !ok { + return nil + } + template.Args[i] = filled + } + return template +} + +// returnType resolves a polymorphic return type — max(anyelement), or a +// seed's "$2" for the type of the second argument — to the type the call was +// made with. +func (a *analyzer) returnType(p core.ProcOverload, argTypes []exprType) exprType { + if p.ReturnTypeOID == 0 || len(argTypes) == 0 { + return exprType{typeOID: p.ReturnTypeOID} + } + name, err := a.cat.TypeName(p.ReturnTypeOID) + if err != nil { + return exprType{typeOID: p.ReturnTypeOID} + } + if n, ok := argIndex(name); ok { + if n < len(argTypes) { + return exprType{typeOID: argTypes[n].typeOID, expr: argTypes[n].expr} + } + return exprType{} + } + if isPolymorphic(name) && (argTypes[0].typeOID != 0 || argTypes[0].expr != nil) { + return exprType{typeOID: argTypes[0].typeOID, expr: argTypes[0].expr} + } + return exprType{typeOID: p.ReturnTypeOID} +} + +// argIndex reads a seed's "$n" pseudo-type as the zero-based index of the +// argument whose type it stands for. +func argIndex(typeName string) (int, bool) { + rest, ok := strings.CutPrefix(typeName, "$") + if !ok { + return 0, false + } + n := 0 + for _, r := range rest { + if r < '0' || r > '9' { + return 0, false + } + n = n*10 + int(r-'0') + } + if n == 0 { + return 0, false + } + return n - 1, true +} + +// isPolymorphicOID reports whether a parameter type accepts any argument. +func (a *analyzer) isPolymorphicOID(oid int64) bool { + if oid == 0 { + return true + } + name, err := a.cat.TypeName(oid) + if err != nil { + return false + } + if _, ok := argIndex(name); ok { + return true + } + return isPolymorphic(name) +} + +func isPolymorphic(typeName string) bool { + switch typeName { + case "any", "anyelement", "anyarray", "anynonarray", "anyenum", "anyrange", + "anymultirange", "anycompatible", "anycompatiblearray", + "anycompatiblenonarray", "anycompatiblerange": + return true + } + return false +} + +// pickOverload chooses the overload whose parameters the call's arguments +// match best: an exact type match on a parameter beats a match on the +// argument's family, which beats a polymorphic parameter, which beats a +// mismatch, and any overload of the right arity beats one of the wrong +// arity. +func (a *analyzer) pickOverload(overloads []core.ProcOverload, argTypes []int64) core.ProcOverload { + best := -1 + bestScore := -1 + chains := make([][]int64, len(argTypes)) + for j, oid := range argTypes { + if oid != 0 { + chains[j] = a.cat.ResolutionChain(oid) + } + } + for i := range overloads { + ov := &overloads[i] + if len(ov.ArgTypes) != len(argTypes) { + continue + } + score := 0 + for j, oid := range argTypes { + switch { + case oid != 0 && oid == ov.ArgTypes[j]: + score += 3 + case oid != 0 && slices.Contains(chains[j], ov.ArgTypes[j]): + score += 2 + case a.isPolymorphicOID(ov.ArgTypes[j]): + score += 1 + } + } + if score > bestScore { + best, bestScore = i, score + } + } + if best >= 0 { + return overloads[best] + } + return overloads[0] +} + +func funcCallName(f *ast.FuncCall) string { + if f.Funcname != nil { + return opNameFromList(f.Funcname) + } + if f.Func != nil { + return strings.ToLower(f.Func.Name) + } + return "" +} + +func (a *analyzer) typeTypeCast(c *ast.TypeCast) (exprType, error) { + if c.TypeName == nil { + return exprType{}, fmt.Errorf("cast: missing target type") + } + target := core.TypeExprOfTypeName(c.TypeName) + if target == nil { + return exprType{}, fmt.Errorf("cast: missing target type") + } + t := a.lookupType(target) + // A cast is how a query says what an otherwise untyped placeholder + // holds, and a placeholder so typed is not null unless the type says + // otherwise, as ClickHouse's Nullable(String) does. Anything else + // cast is NULL when it was NULL before, or when the type says so. + t.nullable = target.Nullable + if pr, ok := c.Arg.(*ast.ParamRef); ok { + if err := a.typeOperands(pr, t); err != nil { + return exprType{}, err + } + return t, nil + } + arg, err := a.typeExpr(c.Arg) + if err != nil { + return exprType{}, err + } + t.nullable = t.nullable || arg.nullable + return t, nil +} diff --git a/internal/core/analyzer/projection.go b/internal/core/analyzer/projection.go new file mode 100644 index 0000000..17fc3cb --- /dev/null +++ b/internal/core/analyzer/projection.go @@ -0,0 +1,169 @@ +package analyzer + +import ( + "slices" + "strings" + + "github.com/sqlc-dev/sqlc/internal/core" + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +func (a *analyzer) projectTarget(rt *ast.ResTarget) error { + // A column reference's field list is flattened once here and threaded + // through the star check, the star expansion and the output name. + var fields []string + if cr, ok := rt.Val.(*ast.ColumnRef); ok { + fields = flattenFields(cr.Fields) + if isStar(fields) { + a.emitStar(rt, fields) + return nil + } + } + + t, err := a.typeExpr(rt.Val) + if err != nil { + return err + } + // A placeholder selected directly is named by its alias and, when nothing + // constrains it, typed as the dialect types such a placeholder. + if pr, ok := rt.Val.(*ast.ParamRef); ok { + if rt.Name != nil && *rt.Name != "" { + if p := a.params[pr.Number]; p.Name == "" { + p.Name = *rt.Name + a.params[pr.Number] = p + } + } + if t.typeOID == 0 && t.expr == nil { + if oid, ok := a.cat.UntypedTypeOID(); ok { + t = exprType{typeOID: oid, nullable: true} + } + } + } + col := core.Column{ + Name: targetName(rt, fields), + TypeOID: t.typeOID, + NotNull: !t.nullable, + SourceClassOID: t.sourceClassOID, + SourceAttributeOID: t.sourceAttributeOID, + } + col.DataType, col.IsArray = a.typeNameOf(t) + col.Type = a.typeExprOf(t) + a.decorateSource(&col, t.sourceAttributeOID, t.sourceTableAlias) + if rt.Name == nil || *rt.Name == "" { + // A column whose own name is dotted, as ClickHouse's n.a is, is + // reported under that name rather than its last part. + if col.Source != nil && strings.Contains(col.Source.Column, ".") { + col.Name = col.Source.Column + } + a.qualifyDuplicate(&col, t.sourceTableAlias) + } + a.columns = append(a.columns, col) + return nil +} + +// qualifyDuplicate names a column after its relation when an earlier result +// column from another relation already has its name, in a dialect that +// does so. +func (a *analyzer) qualifyDuplicate(col *core.Column, alias string) { + if alias == "" || !a.cat.QualifiesDuplicateColumns() { + return + } + for _, prev := range a.columns { + if prev.Name != col.Name { + continue + } + prevAlias := "" + if prev.Source != nil { + prevAlias = prev.Source.TableAlias + } + if prevAlias != alias { + col.Name = alias + "." + col.Name + return + } + } +} + +func (a *analyzer) decorateSource(col *core.Column, attOID int64, tableAlias string) { + if attOID == 0 { + return + } + ad, err := a.cat.LookupAttribute(attOID) + if err != nil { + return + } + col.Source = &core.ColumnSource{ + Schema: ad.Schema, + Table: ad.Table, + TableAlias: tableAlias, + Column: ad.Column, + } + col.DeclType = ad.DeclType + col.IsPrimaryKey = ad.IsPrimaryKey + col.IsUnique = ad.IsUnique + col.IsAutoIncrement = ad.AutoIncrement +} + +// targetName picks the output name for a target. fields is the already +// flattened field list when rt.Val is a column reference, and nil otherwise. +func targetName(rt *ast.ResTarget, fields []string) string { + if rt.Name != nil && *rt.Name != "" { + return *rt.Name + } + if len(fields) > 0 { + return fields[len(fields)-1] + } + if fc, ok := rt.Val.(*ast.FuncCall); ok { + if name := funcCallName(fc); name != "" { + return name + } + } + return "?column?" +} + +func isStar(fields []string) bool { + return len(fields) > 0 && fields[len(fields)-1] == "*" +} + +func (a *analyzer) emitStar(rt *ast.ResTarget, fields []string) { + relName := "" + if len(fields) > 1 { + relName = fields[0] + } + // The star is reported along with the columns it covers, so the query text + // can be rewritten to name them. + star := core.StarExpansion{Location: rt.Location, Fields: fields} + if rt.Name != nil { + star.Alias = *rt.Name + } + for _, rel := range a.scope.rels { + if relName != "" && rel.alias != relName { + continue + } + a.columns = slices.Grow(a.columns, len(rel.cols)) + star.Columns = slices.Grow(star.Columns, len(rel.cols)) + for _, c := range rel.cols { + if c.Hidden { + continue + } + col := core.Column{ + Name: c.Name, + TypeOID: c.TypeOID, + NotNull: c.NotNull, + SourceClassOID: rel.classOID, + SourceAttributeOID: c.AttOID, + } + t := exprType{typeOID: c.TypeOID, expr: c.Type, nullable: !c.NotNull} + col.DataType, col.IsArray = a.typeNameOf(t) + col.Type = a.typeExprOf(t) + a.decorateSource(&col, c.AttOID, rel.alias) + a.qualifyDuplicate(&col, rel.alias) + a.columns = append(a.columns, col) + star.Columns = append(star.Columns, core.StarColumn{ + Relation: rel.alias, + Name: c.Name, + DataType: col.DataType, + }) + } + } + a.recordStar(star) +} diff --git a/internal/core/analyzer/scope.go b/internal/core/analyzer/scope.go new file mode 100644 index 0000000..020d3d1 --- /dev/null +++ b/internal/core/analyzer/scope.go @@ -0,0 +1,243 @@ +package analyzer + +import ( + "fmt" + + "github.com/sqlc-dev/sqlc/internal/core" + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +type scope struct { + rels []scopeRel +} + +type scopeRel struct { + alias string + classOID int64 + // cols is the catalog's column list, held as-is rather than copied into a + // scope-local column type. + cols []core.ClassColumn +} + +func (a *analyzer) buildScope(from *ast.List) (*scope, error) { + items := listItems(from) + sc := &scope{rels: make([]scopeRel, 0, len(items))} + defer a.binding(sc)() + for _, item := range items { + if err := a.appendFromItem(sc, item); err != nil { + return nil, err + } + } + return sc, nil +} + +// binding makes the scope under construction the one the analyzer resolves +// against, and returns the func that puts back the scope it replaced. A FROM +// item can refer to the ones before it — a set-returning function takes its +// arguments from them — so binding an item has to see what is bound so far +// rather than no scope at all. +func (a *analyzer) binding(sc *scope) func() { + prev := a.scope + a.scope = sc + return func() { a.scope = prev } +} + +func (a *analyzer) appendFromItem(sc *scope, item ast.Node) error { + switch v := item.(type) { + case *ast.RangeVar: + rel, err := a.bindRangeVar(v) + if err != nil { + return err + } + sc.rels = append(sc.rels, rel) + return nil + case *ast.JoinExpr: + if err := a.appendFromItem(sc, v.Larg); err != nil { + return err + } + return a.appendFromItem(sc, v.Rarg) + case *ast.RangeFunction: + rel, err := a.bindRangeFunction(v) + if err != nil { + return err + } + sc.rels = append(sc.rels, rel) + return nil + case *ast.RangeSubselect: + rel, err := a.bindRangeSubselect(v) + if err != nil { + return err + } + sc.rels = append(sc.rels, rel) + return nil + case *ast.List: + // Some engines report a comma-separated FROM as a nested list. + for _, item := range listItems(v) { + if err := a.appendFromItem(sc, item); err != nil { + return err + } + } + return nil + default: + return fmt.Errorf("scope: unsupported FROM item %T", item) + } +} + +// bindRangeFunction binds a function called in FROM. A set-returning function +// stands in for a relation of a single column named after it. +func (a *analyzer) bindRangeFunction(rf *ast.RangeFunction) (scopeRel, error) { + call := findFuncCall(rf.Functions) + if call == nil { + return scopeRel{}, fmt.Errorf("range function: no function call") + } + name := funcCallName(call) + overloads, err := a.cat.FindProcs(name, nil) + if err != nil { + return scopeRel{}, err + } + if len(overloads) == 0 { + return scopeRel{}, fmt.Errorf("unknown function %q", name) + } + + // The arguments are typed against the scope built so far, which is what + // gives a placeholder passed to the function its type. + if _, err := a.typeFuncCall(call); err != nil { + return scopeRel{}, err + } + + p := overloads[0] + rel := scopeRel{ + alias: name, + cols: []core.ClassColumn{{Name: name, TypeOID: p.ReturnTypeOID, NotNull: !p.ReturnNullable}}, + } + if rf.Alias != nil && rf.Alias.Aliasname != nil && *rf.Alias.Aliasname != "" { + rel.alias = *rf.Alias.Aliasname + } + return rel, nil +} + +func findFuncCall(l *ast.List) *ast.FuncCall { + for _, item := range listItems(l) { + switch v := item.(type) { + case *ast.FuncCall: + return v + case *ast.List: + if call := findFuncCall(v); call != nil { + return call + } + } + } + return nil +} + +// bindRangeSubselect binds a subquery used as a relation in FROM. +func (a *analyzer) bindRangeSubselect(rs *ast.RangeSubselect) (scopeRel, error) { + sel, ok := rs.Subquery.(*ast.SelectStmt) + if !ok { + return scopeRel{}, fmt.Errorf("subquery: unsupported %T", rs.Subquery) + } + cols, err := a.subqueryColumns(sel) + if err != nil { + return scopeRel{}, err + } + alias := "" + if rs.Alias != nil && rs.Alias.Aliasname != nil { + alias = *rs.Alias.Aliasname + } + rel := derivedRel(alias, cols) + if rs.Alias != nil { + renameColumns(&rel, rs.Alias.Colnames) + } + return rel, nil +} + +func (a *analyzer) bindRangeVar(rv *ast.RangeVar) (scopeRel, error) { + if rv.Relname == nil { + return scopeRel{}, fmt.Errorf("range var: missing relation name") + } + relName := *rv.Relname + + // A WITH clause defines a relation that shadows nothing but is not in the + // catalog, so it is resolved before one. + if cte, ok := a.ctes[relName]; ok && (rv.Schemaname == nil || *rv.Schemaname == "") { + if rv.Alias != nil && rv.Alias.Aliasname != nil && *rv.Alias.Aliasname != "" { + cte.alias = *rv.Alias.Aliasname + } + return cte, nil + } + + schema := "" + if rv.Schemaname != nil { + schema = *rv.Schemaname + } + if schema == "" { + schema = "public" + } + nsOID, err := a.cat.NamespaceOID(schema) + if err != nil { + return scopeRel{}, fmt.Errorf("schema %q: %w", schema, err) + } + classOID, err := a.cat.ClassOID(nsOID, relName) + if err != nil { + return scopeRel{}, fmt.Errorf("relation %q.%q: %w", schema, relName, err) + } + rel := scopeRel{ + alias: relName, + classOID: classOID, + } + if rv.Alias != nil && rv.Alias.Aliasname != nil && *rv.Alias.Aliasname != "" { + rel.alias = *rv.Alias.Aliasname + } + + cols, err := a.cat.ClassColumns(classOID) + if err != nil { + return scopeRel{}, err + } + rel.cols = cols + return rel, nil +} + +// resolveColumn finds a column in this query's scope, falling back to the scope +// of the query it is nested in, which is what a correlated subquery refers to. +func (a *analyzer) resolveColumn(relation, column string) (scopeRel, core.ClassColumn, bool, error) { + rel, col, ok, err := a.scope.resolveColumn(relation, column) + if err != nil || ok { + return rel, col, ok, err + } + if a.outer != nil { + return a.outer.resolveColumn(relation, column) + } + return rel, col, false, nil +} + +// resolveColumn finds the single column named column, optionally qualified by +// relation. It reports an error when more than one relation in scope offers +// that name. +func (s *scope) resolveColumn(relation, column string) (rel scopeRel, col core.ClassColumn, ok bool, err error) { + // A statement whose scope is not built yet offers no columns. Report the + // column as unresolved and let the caller say so, rather than crashing on + // the way to the same answer. + if s == nil { + return rel, col, false, nil + } + found := 0 + for _, r := range s.rels { + if relation != "" && r.alias != relation { + continue + } + for _, c := range r.cols { + if c.Name != column { + continue + } + found++ + if found > 1 { + return scopeRel{}, core.ClassColumn{}, false, fmt.Errorf("ambiguous column reference %q", column) + } + rel, col = r, c + } + } + if found == 0 { + return scopeRel{}, core.ClassColumn{}, false, nil + } + return rel, col, true, nil +} diff --git a/internal/core/attribute.go b/internal/core/attribute.go new file mode 100644 index 0000000..9c2a927 --- /dev/null +++ b/internal/core/attribute.go @@ -0,0 +1,287 @@ +package core + +import ( + "context" + "fmt" + + "github.com/sqlc-dev/sqlc/internal/core/catalogdb" +) + +type AttributeSpec struct { + ClassOID int64 + Name string + TypeOID int64 + Num int + NotNull bool + HasDefault bool + DeclType string + AutoIncrement bool + IsPrimaryKey bool + IsUnique bool + // Hidden columns resolve by name but stay out of a star expansion and + // the relation's model, like the column an sqlite fts5 table names + // after itself. + Hidden bool +} + +func (c *Catalog) CreateAttributeSpec(s AttributeSpec) error { + err := c.q.CreateAttribute(context.Background(), catalogdb.CreateAttributeParams{ + ClassOid: s.ClassOID, + Name: s.Name, + TypeOid: s.TypeOID, + NotNull: boolToInt64(s.NotNull), + HasDefault: boolToInt64(s.HasDefault), + Num: int64(s.Num), + DeclType: s.DeclType, + AutoIncrement: boolToInt64(s.AutoIncrement), + IsPrimaryKey: boolToInt64(s.IsPrimaryKey), + IsUnique: boolToInt64(s.IsUnique), + Hidden: boolToInt64(s.Hidden), + }) + if err != nil { + return fmt.Errorf("create attribute %q on class %d: %w", s.Name, s.ClassOID, err) + } + return nil +} + +func (c *Catalog) CreateAttribute(classOID int64, name string, typeOID int64, notNull bool, hasDefault bool, num int) error { + return c.CreateAttributeSpec(AttributeSpec{ + ClassOID: classOID, + Name: name, + TypeOID: typeOID, + Num: num, + NotNull: notNull, + HasDefault: hasDefault, + }) +} + +// DropAttribute removes a column from a relation. +func (c *Catalog) DropAttribute(classOID int64, name string) error { + err := c.q.DeleteAttribute(context.Background(), catalogdb.DeleteAttributeParams{ + ClassOid: classOID, + Name: name, + }) + if err != nil { + return fmt.Errorf("drop attribute %q on class %d: %w", name, classOID, err) + } + return nil +} + +// RenameAttribute renames a column. +func (c *Catalog) RenameAttribute(classOID int64, name, newName string) error { + err := c.q.RenameAttribute(context.Background(), catalogdb.RenameAttributeParams{ + ClassOid: classOID, + Name: name, + NewName: newName, + }) + if err != nil { + return fmt.Errorf("rename attribute %q on class %d: %w", name, classOID, err) + } + return nil +} + +// SetAttributeType changes a column's type. +func (c *Catalog) SetAttributeType(classOID int64, name string, typeOID int64, declType string) error { + err := c.q.SetAttributeType(context.Background(), catalogdb.SetAttributeTypeParams{ + ClassOid: classOID, + Name: name, + TypeOid: typeOID, + DeclType: declType, + }) + if err != nil { + return fmt.Errorf("set type of attribute %q on class %d: %w", name, classOID, err) + } + return nil +} + +// SetAttributeNotNull records whether a column accepts NULL. +func (c *Catalog) SetAttributeNotNull(classOID int64, name string, notNull bool) error { + err := c.q.SetAttributeNotNull(context.Background(), catalogdb.SetAttributeNotNullParams{ + ClassOid: classOID, + Name: name, + NotNull: boolToInt64(notNull), + }) + if err != nil { + return fmt.Errorf("set null of attribute %q on class %d: %w", name, classOID, err) + } + return nil +} + +// NextAttributeNum is the ordinal a column added to the relation takes. +func (c *Catalog) NextAttributeNum(classOID int64) (int, error) { + num, err := c.q.MaxAttributeNum(context.Background(), classOID) + if err != nil { + return 0, fmt.Errorf("attribute count for class %d: %w", classOID, err) + } + return int(num) + 1, nil +} + +func (c *Catalog) SetAttributePrimaryKey(classOID int64, columns []string) error { + ctx := context.Background() + for _, name := range columns { + err := c.q.SetAttributePrimaryKey(ctx, catalogdb.SetAttributePrimaryKeyParams{ + ClassOid: classOID, + Name: name, + }) + if err != nil { + return fmt.Errorf("mark pk %s on class %d: %w", name, classOID, err) + } + } + return nil +} + +func (c *Catalog) SetAttributeUnique(classOID int64, columns []string) error { + ctx := context.Background() + for _, name := range columns { + err := c.q.SetAttributeUnique(ctx, catalogdb.SetAttributeUniqueParams{ + ClassOid: classOID, + Name: name, + }) + if err != nil { + return fmt.Errorf("mark unique %s on class %d: %w", name, classOID, err) + } + } + return nil +} + +type ColumnInfo struct { + Name string + TypeName string + TypeOID int64 + NotNull bool + DeclType string + AutoIncrement bool + IsPrimaryKey bool + IsUnique bool + AttributeOID int64 + ClassOID int64 +} + +func (c *Catalog) ResolveColumn(table, column string) (*ColumnInfo, error) { + r, err := c.q.ResolveColumn(context.Background(), catalogdb.ResolveColumnParams{ + TableName: table, + ColumnName: column, + }) + if err != nil { + return nil, fmt.Errorf("resolve %s.%s: %w", table, column, err) + } + info := ColumnInfo{ + AttributeOID: r.Oid, + ClassOID: r.ClassOid, + Name: r.Name, + TypeName: r.TypeName, + TypeOID: r.TypeOid, + NotNull: r.NotNull != 0, + DeclType: r.DeclType, + AutoIncrement: r.AutoIncrement != 0, + IsPrimaryKey: r.IsPrimaryKey != 0, + IsUnique: r.IsUnique != 0, + } + return &info, nil +} + +func (c *Catalog) TableColumns(table string) ([]ColumnInfo, error) { + rows, err := c.q.TableColumns(context.Background(), table) + if err != nil { + return nil, fmt.Errorf("table columns %q: %w", table, err) + } + cols := make([]ColumnInfo, 0, len(rows)) + for _, r := range rows { + cols = append(cols, ColumnInfo{ + AttributeOID: r.Oid, + ClassOID: r.ClassOid, + Name: r.Name, + TypeName: r.TypeName, + TypeOID: r.TypeOid, + NotNull: r.NotNull != 0, + DeclType: r.DeclType, + AutoIncrement: r.AutoIncrement != 0, + IsPrimaryKey: r.IsPrimaryKey != 0, + IsUnique: r.IsUnique != 0, + }) + } + return cols, nil +} + +type ClassColumn struct { + AttOID int64 + Name string + TypeOID int64 + // Type is the column's type as an expression, set for a column of a + // derived relation whose type the catalog holds no row for, or holds + // only the family of. + Type *TypeExpr + NotNull bool + Hidden bool +} + +// ClassColumns returns a relation's columns in ordinal order. +func (c *Catalog) ClassColumns(classOID int64) ([]ClassColumn, error) { + rows, err := c.q.ClassAttributes(context.Background(), classOID) + if err != nil { + return nil, fmt.Errorf("class columns %d: %w", classOID, err) + } + out := make([]ClassColumn, 0, len(rows)) + for _, r := range rows { + out = append(out, ClassColumn{ + AttOID: r.Oid, + Name: r.Name, + TypeOID: r.TypeOid, + NotNull: r.NotNull != 0, + Hidden: r.Hidden != 0, + }) + } + return out, nil +} + +type CodegenColumn struct { + Name string + TypeOID int64 + NotNull bool +} + +func (c *Catalog) ClassCodegenColumns(classOID int64) ([]CodegenColumn, error) { + rows, err := c.q.ListClassColumns(context.Background(), classOID) + if err != nil { + return nil, fmt.Errorf("class codegen columns %d: %w", classOID, err) + } + out := make([]CodegenColumn, 0, len(rows)) + for _, r := range rows { + out = append(out, CodegenColumn{ + Name: r.ColumnName, + TypeOID: r.TypeOid, + NotNull: r.NotNull != 0, + }) + } + return out, nil +} + +type AttributeDetails struct { + Schema string + Table string + Column string + Num int + DeclType string + AutoIncrement bool + IsPrimaryKey bool + IsUnique bool + NotNull bool +} + +func (c *Catalog) LookupAttribute(attOID int64) (AttributeDetails, error) { + r, err := c.q.LookupAttribute(context.Background(), attOID) + if err != nil { + return AttributeDetails{}, fmt.Errorf("lookup attribute %d: %w", attOID, err) + } + return AttributeDetails{ + Schema: r.SchemaName, + Table: r.TableName, + Column: r.ColumnName, + Num: int(r.Num), + DeclType: r.DeclType, + AutoIncrement: r.AutoIncrement != 0, + IsPrimaryKey: r.IsPrimaryKey != 0, + IsUnique: r.IsUnique != 0, + NotNull: r.NotNull != 0, + }, nil +} diff --git a/internal/core/cache.go b/internal/core/cache.go new file mode 100644 index 0000000..34591da --- /dev/null +++ b/internal/core/cache.go @@ -0,0 +1,161 @@ +package core + +import ( + "context" + "database/sql" + "errors" + "fmt" + "log/slog" + + "github.com/ncruces/go-sqlite3" + "github.com/ncruces/go-sqlite3/ext/serdes" + + "github.com/sqlc-dev/sqlc/internal/cache" + "github.com/sqlc-dev/sqlc/internal/core/catalogdb" +) + +// The name of the sole output blob a CoreCatalog action produces. +const catalogOutput = "catalog.db" + +// rawConn is the driver's escape hatch to the SQLite connection underneath a +// database/sql connection, which the serialization API needs. +type rawConn interface { + Raw() *sqlite3.Conn +} + +// NewCached returns the catalog a dialect and a schema produce, restored from +// the cache when a run has produced it before. +// +// Producing one means seeding the dialect — thousands of rows, since +// PostgreSQL's functions and system catalogs alone run to five figures — and +// then parsing the schema and applying its DDL. The result is the same every +// time, so the finished database is stored in the cache and opened directly on +// the next run, turning all of that work into opening a file. +// It is a single action: the dialect and the schema together are what the +// catalog is, so they are one key, and a hit means apply is never called. +// +// The dialect data is embedded in the sqlc binary, whose digest is an input to +// every action, so the dialect only has to be named. The schema is hashed in +// the order it is applied, since DDL order decides what the catalog holds. +// +// A catalog whose apply fails is returned but not cached, so that a caller can +// report the failure against the catalog it got. A nil catalog means the +// catalog could not be created at all. A cache that cannot be opened, read or +// written is not an error: the catalog is simply built the long way. +func NewCached(dialect string, schema []string, apply func(*Catalog) error, opts ...Option) (*Catalog, error) { + store, action := openAction(dialect, schema) + if store != nil { + defer store.Close() + if cat, err := restore(store, action); err == nil { + return cat, nil + } else if !errors.Is(err, cache.ErrNotFound) { + slog.Debug("restoring the catalog from the cache failed", "err", err) + } + } + + cat, err := New(opts...) + if err != nil { + return nil, err + } + if err := apply(cat); err != nil { + return cat, err + } + if store != nil { + if err := save(store, action, cat); err != nil { + slog.Debug("saving the catalog to the cache failed", "err", err) + } + } + return cat, nil +} + +// openAction opens the cache and digests the action that produces a catalog. A +// nil store means the cache is unavailable and the catalog has to be built. +func openAction(dialect string, schema []string) (*cache.Cache, cache.Digest) { + store, err := cache.Open() + if err != nil { + slog.Debug("opening the cache failed", "err", err) + return nil, cache.Digest{} + } + action := store.NewAction("CoreCatalog").AddInput("dialect", []byte(dialect)) + for _, s := range schema { + action.AddInput("schema", []byte(s)) + } + return store, action.Digest() +} + +// restore opens the catalog a previous run cached. The stored blob is opened +// where it lies rather than copied: analysis only ever reads the catalog, so +// every run that wants this one reads the same file. +func restore(store *cache.Cache, action cache.Digest) (*Catalog, error) { + result, err := store.Actions.Get(action) + if err != nil { + return nil, err + } + path, ok := store.CAS.Filename(result.Outputs[catalogOutput]) + if !ok { + return nil, cache.ErrNotFound + } + + db, err := openFile(path) + if err != nil { + return nil, err + } + + stmts := newStmtCache(db) + cat := &Catalog{db: db, stmts: stmts, q: catalogdb.New(stmts)} + + // The seeds recorded the dialect on the catalog as they ran. A restored + // catalog reads it back from the database instead. + row, err := cat.q.SeededDialect(context.Background()) + if err != nil { + cat.Close() + return nil, fmt.Errorf("core: restored catalog has no dialect: %w", err) + } + cat.dialectOID = row.Oid + return cat, nil +} + +// save stores a finished catalog for the next run. +func save(store *cache.Cache, action cache.Digest, cat *Catalog) error { + blob, err := serialize(cat.db) + if err != nil { + return err + } + digest, err := store.CAS.Put(blob) + if err != nil { + return err + } + return store.Actions.Put(action, &cache.ActionResult{ + Outputs: map[string]cache.Digest{catalogOutput: digest}, + }) +} + +// serialize returns the bytes a database being built in memory would be +// written to disk as, which is what gets stored. +func serialize(db *sql.DB) ([]byte, error) { + var blob []byte + err := withRawConn(db, func(c *sqlite3.Conn) error { + var err error + blob, err = serdes.Serialize(c, "main") + return err + }) + if err != nil { + return nil, fmt.Errorf("core: serialize catalog: %w", err) + } + return blob, nil +} + +func withRawConn(db *sql.DB, fn func(*sqlite3.Conn) error) error { + conn, err := db.Conn(context.Background()) + if err != nil { + return err + } + defer conn.Close() + return conn.Raw(func(driverConn any) error { + r, ok := driverConn.(rawConn) + if !ok { + return fmt.Errorf("driver does not expose its SQLite connection") + } + return fn(r.Raw()) + }) +} diff --git a/internal/core/cast.go b/internal/core/cast.go new file mode 100644 index 0000000..408663b --- /dev/null +++ b/internal/core/cast.go @@ -0,0 +1,69 @@ +package core + +import ( + "context" + "fmt" + + "github.com/sqlc-dev/sqlc/internal/core/catalogdb" +) + +type CastSpec struct { + SourceTypeOID int64 + TargetTypeOID int64 + ProcOID int64 + Context string + DialectOID int64 +} + +func (c *Catalog) CreateCast(cs CastSpec) error { + if cs.Context == "" { + cs.Context = "e" + } + err := c.q.CreateCast(context.Background(), catalogdb.CreateCastParams{ + SourceTypeOid: cs.SourceTypeOID, + TargetTypeOid: cs.TargetTypeOID, + ProcOid: nullInt64(cs.ProcOID), + Context: cs.Context, + DialectOid: nullInt64(cs.DialectOID), + }) + if err != nil { + return fmt.Errorf("create cast %d->%d: %w", cs.SourceTypeOID, cs.TargetTypeOID, err) + } + return nil +} + +func (c *Catalog) FindCast(src, tgt int64) (CastSpec, bool, error) { + row, err := c.q.FindCast(context.Background(), catalogdb.FindCastParams{ + SourceTypeOid: src, + TargetTypeOid: tgt, + }) + if err != nil { + return CastSpec{}, false, nil + } + return CastSpec{ + SourceTypeOID: row.SourceTypeOid, + TargetTypeOID: row.TargetTypeOid, + ProcOID: orZero(row.ProcOid), + Context: row.Context, + DialectOID: orZero(row.DialectOid), + }, true, nil +} + +func (c *Catalog) CastAllowed(src, tgt int64, ctx string) (bool, error) { + if src == tgt { + return true, nil + } + cs, ok, err := c.FindCast(src, tgt) + if err != nil || !ok { + return false, err + } + switch ctx { + case "i": + return cs.Context == "i", nil + case "a": + return cs.Context == "i" || cs.Context == "a", nil + case "e": + return true, nil + } + return false, fmt.Errorf("unknown cast context %q", ctx) +} diff --git a/internal/core/catalog.go b/internal/core/catalog.go new file mode 100644 index 0000000..334dcdb --- /dev/null +++ b/internal/core/catalog.go @@ -0,0 +1,189 @@ +package core + +import ( + "context" + "database/sql" + "fmt" + "runtime" + + "github.com/sqlc-dev/sqlc/internal/core/catalogdb" + "github.com/sqlc-dev/sqlc/internal/core/catalogdef" + + _ "github.com/ncruces/go-sqlite3/driver" +) + +//go:generate go run github.com/sqlc-dev/sqlc/cmd/sqlc generate + +type Catalog struct { + db *sql.DB + stmts *stmtCache + q *catalogdb.Queries + + // dialectOID is the dialect this catalog was seeded with. A catalog is + // built for one dialect, so dialect-wide lookups need no other input. + dialectOID int64 + + // loadExtension applies a named extension's seed, installed by the + // dialect's seed for the engines that ship extension data. It runs at most + // once per extension name: a schema is free to say CREATE EXTENSION twice. + loadExtension func(name string) error + extensions map[string]bool + + // types remembers the rows and expressions looked up so far, and rules + // what the dialect does to a type before storing it. + types typeCache + rules rules +} + +type Option func(*Catalog) error + +func WithSeed(fn func(*Catalog) error) Option { + return func(c *Catalog) error { return fn(c) } +} + +func New(opts ...Option) (*Catalog, error) { + db, err := openDB() + if err != nil { + return nil, err + } + + // catalogdef.Schema is a batch of DDL statements, so it goes to the + // connection directly rather than through the prepared-statement cache. + if _, err := db.Exec(catalogdef.Schema); err != nil { + db.Close() + return nil, fmt.Errorf("core: init schema: %w", err) + } + + stmts := newStmtCache(db) + c := &Catalog{db: db, stmts: stmts, q: catalogdb.New(stmts)} + + // Run the seeds inside one transaction rather than paying a commit for each + // of the hundreds of rows a dialect registers. + ctx := context.Background() + if err := stmts.begin(ctx); err != nil { + db.Close() + return nil, fmt.Errorf("core: begin setup: %w", err) + } + if err := c.setup(opts); err != nil { + stmts.rollback() + db.Close() + return nil, err + } + if err := stmts.commit(); err != nil { + db.Close() + return nil, fmt.Errorf("core: commit setup: %w", err) + } + return c, nil +} + +// openFile opens a catalog held in a file, read only. The file is named after +// the hash of its contents, so it can never change under a reader: SQLite is +// told as much, which lets any number of processes share it with no locking +// and no copy. +func openFile(path string) (*sql.DB, error) { + db, err := sql.Open("sqlite3", "file:"+path+"?mode=ro&immutable=1") + if err != nil { + return nil, fmt.Errorf("core: open catalog %s: %w", path, err) + } + // An immutable file has no locking to contend for, so queries analyzed + // concurrently each get their own connection rather than queueing on one. + db.SetMaxOpenConns(runtime.GOMAXPROCS(0)) + db.SetMaxIdleConns(runtime.GOMAXPROCS(0)) + db.SetConnMaxIdleTime(0) + db.SetConnMaxLifetime(0) + return db, nil +} + +// pinPool holds a catalog being built to a single connection that is never +// retired: every ":memory:" connection is its own empty database, so a second +// one would see a catalog with no tables in it. +func pinPool(db *sql.DB) { + db.SetMaxOpenConns(1) + db.SetMaxIdleConns(1) + db.SetConnMaxIdleTime(0) + db.SetConnMaxLifetime(0) +} + +// openDB opens the empty SQLite database a catalog is built in. +func openDB() (*sql.DB, error) { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + return nil, fmt.Errorf("core: open catalog: %w", err) + } + pinPool(db) + + // The catalog being built is scratch state that is never read back from + // disk, so durability buys nothing and costs a journal write per statement. + // Foreign keys are declared in the schema as documentation but not + // enforced: dialect seeds carry dangling references (a proc whose return + // type was never registered), and enforcement would also charge an index + // lookup per seeded row. The driver compiles SQLite with enforcement on by + // default, so it is switched off explicitly. + for _, pragma := range []string{ + "PRAGMA journal_mode = OFF", + "PRAGMA synchronous = OFF", + "PRAGMA foreign_keys = OFF", + } { + if _, err := db.Exec(pragma); err != nil { + db.Close() + return nil, fmt.Errorf("core: %s: %w", pragma, err) + } + } + return db, nil +} + +func (c *Catalog) setup(opts []Option) error { + if err := c.bootstrap(); err != nil { + return fmt.Errorf("core: bootstrap: %w", err) + } + for i, opt := range opts { + if err := opt(c); err != nil { + return fmt.Errorf("core: option %d: %w", i, err) + } + } + return nil +} + +func (c *Catalog) Close() error { + err := c.stmts.Close() + if cerr := c.db.Close(); err == nil { + err = cerr + } + return err +} + +func (c *Catalog) DB() *sql.DB { + return c.db +} + +func (c *Catalog) bootstrap() error { + _, err := c.CreateNamespace("public") + return err +} + +// SeededDialectOID returns the dialect this catalog was seeded with, which is +// what anything registered after seeding — an extension's types and functions +// — records as its dialect. +func (c *Catalog) SeededDialectOID() int64 { + return c.dialectOID +} + +// SetExtensionLoader installs the function CREATE EXTENSION calls to apply an +// extension's seed. A dialect without extension data leaves it unset. +func (c *Catalog) SetExtensionLoader(fn func(name string) error) { + c.loadExtension = fn +} + +// LoadExtension applies the named extension's seed to the catalog. An +// extension already applied, or a dialect with no loader, contributes +// nothing; an extension the loader does not know is the loader's to ignore. +func (c *Catalog) LoadExtension(name string) error { + if c.loadExtension == nil || c.extensions[name] { + return nil + } + if c.extensions == nil { + c.extensions = map[string]bool{} + } + c.extensions[name] = true + return c.loadExtension(name) +} diff --git a/internal/core/catalogdb/db.go b/internal/core/catalogdb/db.go new file mode 100644 index 0000000..8ad3680 --- /dev/null +++ b/internal/core/catalogdb/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package catalogdb + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/core/catalogdb/models.go b/internal/core/catalogdb/models.go new file mode 100644 index 0000000..9c10385 --- /dev/null +++ b/internal/core/catalogdb/models.go @@ -0,0 +1,142 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package catalogdb + +import ( + "database/sql" +) + +type SqlAttribute struct { + Oid int64 + ClassOid int64 + Name string + TypeOid int64 + NotNull int64 + HasDefault int64 + Num int64 + DeclType string + AutoIncrement int64 + IsPrimaryKey int64 + IsUnique int64 + Hidden int64 +} + +type SqlCast struct { + SourceTypeOid int64 + TargetTypeOid int64 + ProcOid sql.NullInt64 + Context string + DialectOid sql.NullInt64 +} + +type SqlClass struct { + Oid int64 + NamespaceOid int64 + Name string + Kind string +} + +type SqlConstraint struct { + Oid int64 + ClassOid int64 + Name string + Kind string + Columns string +} + +type SqlDialect struct { + Oid int64 + Name string +} + +type SqlDialectFlag struct { + DialectOid int64 + Key string + Value string +} + +type SqlNamespace struct { + Oid int64 + Name string +} + +type SqlOperator struct { + Oid int64 + NamespaceOid sql.NullInt64 + DialectOid sql.NullInt64 + Name string + LeftTypeOid sql.NullInt64 + RightTypeOid sql.NullInt64 + ResultTypeOid int64 + ProcOid sql.NullInt64 + CommutatorOid sql.NullInt64 + NegatorOid sql.NullInt64 +} + +type SqlProc struct { + Oid int64 + NamespaceOid sql.NullInt64 + DialectOid sql.NullInt64 + Name string + Kind string + ReturnTypeOid int64 + ReturnSet int64 + ReturnNullable int64 + ReturnTemplate string + Strict int64 + VariadicKind string +} + +type SqlProcArg struct { + ProcOid int64 + Ord int64 + Name string + TypeOid int64 + Mode string + HasDefault int64 +} + +type SqlType struct { + Oid int64 + NamespaceOid int64 + DialectOid sql.NullInt64 + Name string + Expr string + Typtype string + Category sql.NullString + Preferred int64 + FamilyOid sql.NullInt64 + ElementOid sql.NullInt64 + BaseOid sql.NullInt64 + CanonicalOid sql.NullInt64 + NotNull int64 +} + +type SqlTypeAffinity struct { + DialectOid int64 + Ord int64 + Words string + TypeOid int64 +} + +type SqlTypeArg struct { + TypeOid int64 + Ord int64 + Label string + ArgTypeOid sql.NullInt64 + Nullable int64 + IntValue sql.NullInt64 + BoolValue sql.NullInt64 + StringValue sql.NullString + Ident sql.NullString +} + +type SqlTypeRewrite struct { + DialectOid int64 + Ord int64 + Pattern string + Template string + Cond string +} diff --git a/internal/core/catalogdb/query.sql.go b/internal/core/catalogdb/query.sql.go new file mode 100644 index 0000000..ba4ee02 --- /dev/null +++ b/internal/core/catalogdb/query.sql.go @@ -0,0 +1,1445 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package catalogdb + +import ( + "context" + "database/sql" + "strings" +) + +const classAttributes = `-- name: ClassAttributes :many +SELECT oid, name, type_oid, not_null, hidden +FROM sql_attribute +WHERE class_oid = ? +ORDER BY num +` + +type ClassAttributesRow struct { + Oid int64 + Name string + TypeOid int64 + NotNull int64 + Hidden int64 +} + +func (q *Queries) ClassAttributes(ctx context.Context, classOid int64) ([]ClassAttributesRow, error) { + rows, err := q.db.QueryContext(ctx, classAttributes, classOid) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ClassAttributesRow + for rows.Next() { + var i ClassAttributesRow + if err := rows.Scan( + &i.Oid, + &i.Name, + &i.TypeOid, + &i.NotNull, + &i.Hidden, + ); 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 classOID = `-- name: ClassOID :one +SELECT oid FROM sql_class WHERE namespace_oid = ? AND name = ? +` + +type ClassOIDParams struct { + NamespaceOid int64 + Name string +} + +func (q *Queries) ClassOID(ctx context.Context, arg ClassOIDParams) (int64, error) { + row := q.db.QueryRowContext(ctx, classOID, arg.NamespaceOid, arg.Name) + var oid int64 + err := row.Scan(&oid) + return oid, err +} + +const classOIDByName = `-- name: ClassOIDByName :one +SELECT oid FROM sql_class WHERE name = ? LIMIT 1 +` + +func (q *Queries) ClassOIDByName(ctx context.Context, name string) (int64, error) { + row := q.db.QueryRowContext(ctx, classOIDByName, name) + var oid int64 + err := row.Scan(&oid) + return oid, err +} + +const createAttribute = `-- name: CreateAttribute :exec + +INSERT INTO sql_attribute ( + class_oid, name, type_oid, not_null, has_default, num, + decl_type, auto_increment, is_primary_key, is_unique, hidden +) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) +` + +type CreateAttributeParams struct { + ClassOid int64 + Name string + TypeOid int64 + NotNull int64 + HasDefault int64 + Num int64 + DeclType string + AutoIncrement int64 + IsPrimaryKey int64 + IsUnique int64 + Hidden int64 +} + +// ============================= sql_attribute =========================== +func (q *Queries) CreateAttribute(ctx context.Context, arg CreateAttributeParams) error { + _, err := q.db.ExecContext(ctx, createAttribute, + arg.ClassOid, + arg.Name, + arg.TypeOid, + arg.NotNull, + arg.HasDefault, + arg.Num, + arg.DeclType, + arg.AutoIncrement, + arg.IsPrimaryKey, + arg.IsUnique, + arg.Hidden, + ) + return err +} + +const createCast = `-- name: CreateCast :exec + +INSERT INTO sql_cast (source_type_oid, target_type_oid, proc_oid, context, dialect_oid) +VALUES (?, ?, ?, ?, ?) +` + +type CreateCastParams struct { + SourceTypeOid int64 + TargetTypeOid int64 + ProcOid sql.NullInt64 + Context string + DialectOid sql.NullInt64 +} + +// =============================== sql_cast ============================== +func (q *Queries) CreateCast(ctx context.Context, arg CreateCastParams) error { + _, err := q.db.ExecContext(ctx, createCast, + arg.SourceTypeOid, + arg.TargetTypeOid, + arg.ProcOid, + arg.Context, + arg.DialectOid, + ) + return err +} + +const createClass = `-- name: CreateClass :execlastid + +INSERT INTO sql_class (namespace_oid, name, kind) VALUES (?, ?, ?) +` + +type CreateClassParams struct { + NamespaceOid int64 + Name string + Kind string +} + +// =============================== sql_class ============================= +func (q *Queries) CreateClass(ctx context.Context, arg CreateClassParams) (int64, error) { + result, err := q.db.ExecContext(ctx, createClass, arg.NamespaceOid, arg.Name, arg.Kind) + if err != nil { + return 0, err + } + return result.LastInsertId() +} + +const createConstraint = `-- name: CreateConstraint :exec + +INSERT INTO sql_constraint (class_oid, name, kind, columns) VALUES (?, ?, ?, ?) +` + +type CreateConstraintParams struct { + ClassOid int64 + Name string + Kind string + Columns string +} + +// ============================ sql_constraint =========================== +func (q *Queries) CreateConstraint(ctx context.Context, arg CreateConstraintParams) error { + _, err := q.db.ExecContext(ctx, createConstraint, + arg.ClassOid, + arg.Name, + arg.Kind, + arg.Columns, + ) + return err +} + +const createDialect = `-- name: CreateDialect :execlastid + +INSERT INTO sql_dialect (name) VALUES (?) +` + +// ============================== sql_dialect ============================ +func (q *Queries) CreateDialect(ctx context.Context, name string) (int64, error) { + result, err := q.db.ExecContext(ctx, createDialect, name) + if err != nil { + return 0, err + } + return result.LastInsertId() +} + +const createNamespace = `-- name: CreateNamespace :execlastid + + +INSERT INTO sql_namespace (name) VALUES (?) +` + +// Queries against sqlc's own sql_* catalog tables, compiled by sqlc's +// SQLite engine. Regenerate with `go generate ./internal/core/...`. +// ============================ sql_namespace ============================ +func (q *Queries) CreateNamespace(ctx context.Context, name string) (int64, error) { + result, err := q.db.ExecContext(ctx, createNamespace, name) + if err != nil { + return 0, err + } + return result.LastInsertId() +} + +const createOperator = `-- name: CreateOperator :execlastid + +INSERT INTO sql_operator + (namespace_oid, dialect_oid, name, + left_type_oid, right_type_oid, result_type_oid, proc_oid) +VALUES (?, ?, ?, ?, ?, ?, ?) +` + +type CreateOperatorParams struct { + NamespaceOid sql.NullInt64 + DialectOid sql.NullInt64 + Name string + LeftTypeOid sql.NullInt64 + RightTypeOid sql.NullInt64 + ResultTypeOid int64 + ProcOid sql.NullInt64 +} + +// ============================= sql_operator ============================ +func (q *Queries) CreateOperator(ctx context.Context, arg CreateOperatorParams) (int64, error) { + result, err := q.db.ExecContext(ctx, createOperator, + arg.NamespaceOid, + arg.DialectOid, + arg.Name, + arg.LeftTypeOid, + arg.RightTypeOid, + arg.ResultTypeOid, + arg.ProcOid, + ) + if err != nil { + return 0, err + } + return result.LastInsertId() +} + +const createProc = `-- name: CreateProc :execlastid + +INSERT INTO sql_proc + (namespace_oid, dialect_oid, name, kind, + return_type_oid, return_set, return_nullable, return_template, strict, variadic_kind) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) +` + +type CreateProcParams struct { + NamespaceOid sql.NullInt64 + DialectOid sql.NullInt64 + Name string + Kind string + ReturnTypeOid int64 + ReturnSet int64 + ReturnNullable int64 + ReturnTemplate string + Strict int64 + VariadicKind string +} + +// =============================== sql_proc ============================== +func (q *Queries) CreateProc(ctx context.Context, arg CreateProcParams) (int64, error) { + result, err := q.db.ExecContext(ctx, createProc, + arg.NamespaceOid, + arg.DialectOid, + arg.Name, + arg.Kind, + arg.ReturnTypeOid, + arg.ReturnSet, + arg.ReturnNullable, + arg.ReturnTemplate, + arg.Strict, + arg.VariadicKind, + ) + if err != nil { + return 0, err + } + return result.LastInsertId() +} + +const createProcArg = `-- name: CreateProcArg :exec +INSERT INTO sql_proc_arg (proc_oid, ord, name, type_oid, mode, has_default) +VALUES (?, ?, ?, ?, ?, ?) +` + +type CreateProcArgParams struct { + ProcOid int64 + Ord int64 + Name string + TypeOid int64 + Mode string + HasDefault int64 +} + +func (q *Queries) CreateProcArg(ctx context.Context, arg CreateProcArgParams) error { + _, err := q.db.ExecContext(ctx, createProcArg, + arg.ProcOid, + arg.Ord, + arg.Name, + arg.TypeOid, + arg.Mode, + arg.HasDefault, + ) + return err +} + +const createType = `-- name: CreateType :execlastid + +INSERT INTO sql_type + (name, expr, typtype, category, preferred, namespace_oid, dialect_oid, + family_oid, element_oid, base_oid, canonical_oid, not_null) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) +` + +type CreateTypeParams struct { + Name string + Expr string + Typtype string + Category sql.NullString + Preferred int64 + NamespaceOid int64 + DialectOid sql.NullInt64 + FamilyOid sql.NullInt64 + ElementOid sql.NullInt64 + BaseOid sql.NullInt64 + CanonicalOid sql.NullInt64 + NotNull int64 +} + +// =============================== sql_type ============================== +func (q *Queries) CreateType(ctx context.Context, arg CreateTypeParams) (int64, error) { + result, err := q.db.ExecContext(ctx, createType, + arg.Name, + arg.Expr, + arg.Typtype, + arg.Category, + arg.Preferred, + arg.NamespaceOid, + arg.DialectOid, + arg.FamilyOid, + arg.ElementOid, + arg.BaseOid, + arg.CanonicalOid, + arg.NotNull, + ) + if err != nil { + return 0, err + } + return result.LastInsertId() +} + +const createTypeAffinity = `-- name: CreateTypeAffinity :exec +INSERT INTO sql_type_affinity (dialect_oid, ord, words, type_oid) +VALUES (?, ?, ?, ?) +` + +type CreateTypeAffinityParams struct { + DialectOid int64 + Ord int64 + Words string + TypeOid int64 +} + +func (q *Queries) CreateTypeAffinity(ctx context.Context, arg CreateTypeAffinityParams) error { + _, err := q.db.ExecContext(ctx, createTypeAffinity, + arg.DialectOid, + arg.Ord, + arg.Words, + arg.TypeOid, + ) + return err +} + +const createTypeArg = `-- name: CreateTypeArg :exec +INSERT INTO sql_type_arg + (type_oid, ord, label, arg_type_oid, nullable, int_value, bool_value, string_value, ident) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) +` + +type CreateTypeArgParams struct { + TypeOid int64 + Ord int64 + Label string + ArgTypeOid sql.NullInt64 + Nullable int64 + IntValue sql.NullInt64 + BoolValue sql.NullInt64 + StringValue sql.NullString + Ident sql.NullString +} + +func (q *Queries) CreateTypeArg(ctx context.Context, arg CreateTypeArgParams) error { + _, err := q.db.ExecContext(ctx, createTypeArg, + arg.TypeOid, + arg.Ord, + arg.Label, + arg.ArgTypeOid, + arg.Nullable, + arg.IntValue, + arg.BoolValue, + arg.StringValue, + arg.Ident, + ) + return err +} + +const createTypeRewrite = `-- name: CreateTypeRewrite :exec +INSERT INTO sql_type_rewrite (dialect_oid, ord, pattern, template, cond) +VALUES (?, ?, ?, ?, ?) +` + +type CreateTypeRewriteParams struct { + DialectOid int64 + Ord int64 + Pattern string + Template string + Cond string +} + +func (q *Queries) CreateTypeRewrite(ctx context.Context, arg CreateTypeRewriteParams) error { + _, err := q.db.ExecContext(ctx, createTypeRewrite, + arg.DialectOid, + arg.Ord, + arg.Pattern, + arg.Template, + arg.Cond, + ) + return err +} + +const deleteAttribute = `-- name: DeleteAttribute :exec +DELETE FROM sql_attribute WHERE class_oid = ? AND name = ? +` + +type DeleteAttributeParams struct { + ClassOid int64 + Name string +} + +func (q *Queries) DeleteAttribute(ctx context.Context, arg DeleteAttributeParams) error { + _, err := q.db.ExecContext(ctx, deleteAttribute, arg.ClassOid, arg.Name) + return err +} + +const deleteAttributesByClass = `-- name: DeleteAttributesByClass :exec +DELETE FROM sql_attribute WHERE class_oid = ? +` + +func (q *Queries) DeleteAttributesByClass(ctx context.Context, classOid int64) error { + _, err := q.db.ExecContext(ctx, deleteAttributesByClass, classOid) + return err +} + +const deleteClass = `-- name: DeleteClass :exec +DELETE FROM sql_class WHERE oid = ? +` + +func (q *Queries) DeleteClass(ctx context.Context, oid int64) error { + _, err := q.db.ExecContext(ctx, deleteClass, oid) + return err +} + +const dialectFlag = `-- name: DialectFlag :one +SELECT value FROM sql_dialect_flag WHERE dialect_oid = ? AND key = ? +` + +type DialectFlagParams struct { + DialectOid int64 + Key string +} + +func (q *Queries) DialectFlag(ctx context.Context, arg DialectFlagParams) (string, error) { + row := q.db.QueryRowContext(ctx, dialectFlag, arg.DialectOid, arg.Key) + var value string + err := row.Scan(&value) + return value, err +} + +const dialectOID = `-- name: DialectOID :one +SELECT oid FROM sql_dialect WHERE name = ? +` + +func (q *Queries) DialectOID(ctx context.Context, name string) (int64, error) { + row := q.db.QueryRowContext(ctx, dialectOID, name) + var oid int64 + err := row.Scan(&oid) + return oid, err +} + +const findCast = `-- name: FindCast :one +SELECT source_type_oid, target_type_oid, proc_oid, context, dialect_oid +FROM sql_cast +WHERE source_type_oid = ? AND target_type_oid = ? +` + +type FindCastParams struct { + SourceTypeOid int64 + TargetTypeOid int64 +} + +func (q *Queries) FindCast(ctx context.Context, arg FindCastParams) (SqlCast, error) { + row := q.db.QueryRowContext(ctx, findCast, arg.SourceTypeOid, arg.TargetTypeOid) + var i SqlCast + err := row.Scan( + &i.SourceTypeOid, + &i.TargetTypeOid, + &i.ProcOid, + &i.Context, + &i.DialectOid, + ) + return i, err +} + +const findOperators = `-- name: FindOperators :many +SELECT oid, name, left_type_oid, right_type_oid, result_type_oid, proc_oid +FROM sql_operator +WHERE name = ?1 + AND (?2 = 0 OR left_type_oid = ?2) + AND (?3 = 0 OR right_type_oid = ?3) +` + +type FindOperatorsParams struct { + Name string + LeftTypeOid any + RightTypeOid any +} + +type FindOperatorsRow struct { + Oid int64 + Name string + LeftTypeOid sql.NullInt64 + RightTypeOid sql.NullInt64 + ResultTypeOid int64 + ProcOid sql.NullInt64 +} + +func (q *Queries) FindOperators(ctx context.Context, arg FindOperatorsParams) ([]FindOperatorsRow, error) { + rows, err := q.db.QueryContext(ctx, findOperators, arg.Name, arg.LeftTypeOid, arg.RightTypeOid) + if err != nil { + return nil, err + } + defer rows.Close() + var items []FindOperatorsRow + for rows.Next() { + var i FindOperatorsRow + if err := rows.Scan( + &i.Oid, + &i.Name, + &i.LeftTypeOid, + &i.RightTypeOid, + &i.ResultTypeOid, + &i.ProcOid, + ); 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 findProcsAnyNamespace = `-- name: FindProcsAnyNamespace :many +SELECT oid, name, kind, return_type_oid, return_nullable, return_template +FROM sql_proc +WHERE name = ? +` + +type FindProcsAnyNamespaceRow struct { + Oid int64 + Name string + Kind string + ReturnTypeOid int64 + ReturnNullable int64 + ReturnTemplate string +} + +func (q *Queries) FindProcsAnyNamespace(ctx context.Context, name string) ([]FindProcsAnyNamespaceRow, error) { + rows, err := q.db.QueryContext(ctx, findProcsAnyNamespace, name) + if err != nil { + return nil, err + } + defer rows.Close() + var items []FindProcsAnyNamespaceRow + for rows.Next() { + var i FindProcsAnyNamespaceRow + if err := rows.Scan( + &i.Oid, + &i.Name, + &i.Kind, + &i.ReturnTypeOid, + &i.ReturnNullable, + &i.ReturnTemplate, + ); 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 findProcsInNamespaces = `-- name: FindProcsInNamespaces :many +SELECT oid, name, kind, return_type_oid, return_nullable, return_template +FROM sql_proc +WHERE name = ?1 + AND namespace_oid IN (/*SLICE:namespace_oids*/?) +` + +type FindProcsInNamespacesParams struct { + Name string + NamespaceOids []sql.NullInt64 +} + +type FindProcsInNamespacesRow struct { + Oid int64 + Name string + Kind string + ReturnTypeOid int64 + ReturnNullable int64 + ReturnTemplate string +} + +func (q *Queries) FindProcsInNamespaces(ctx context.Context, arg FindProcsInNamespacesParams) ([]FindProcsInNamespacesRow, error) { + query := findProcsInNamespaces + var queryParams []any + queryParams = append(queryParams, arg.Name) + if len(arg.NamespaceOids) > 0 { + for _, v := range arg.NamespaceOids { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:namespace_oids*/?", strings.Repeat(",?", len(arg.NamespaceOids))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:namespace_oids*/?", "NULL", 1) + } + rows, err := q.db.QueryContext(ctx, query, queryParams...) + if err != nil { + return nil, err + } + defer rows.Close() + var items []FindProcsInNamespacesRow + for rows.Next() { + var i FindProcsInNamespacesRow + if err := rows.Scan( + &i.Oid, + &i.Name, + &i.Kind, + &i.ReturnTypeOid, + &i.ReturnNullable, + &i.ReturnTemplate, + ); 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 listClassColumns = `-- name: ListClassColumns :many +SELECT a.name AS column_name, a.type_oid, a.not_null +FROM sql_attribute a +JOIN sql_type t ON t.oid = a.type_oid +WHERE a.class_oid = ? AND a.hidden = 0 +ORDER BY a.num +` + +type ListClassColumnsRow struct { + ColumnName string + TypeOid int64 + NotNull int64 +} + +func (q *Queries) ListClassColumns(ctx context.Context, classOid int64) ([]ListClassColumnsRow, error) { + rows, err := q.db.QueryContext(ctx, listClassColumns, classOid) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListClassColumnsRow + for rows.Next() { + var i ListClassColumnsRow + if err := rows.Scan(&i.ColumnName, &i.TypeOid, &i.NotNull); 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 listNamespaces = `-- name: ListNamespaces :many +SELECT oid, name FROM sql_namespace ORDER BY oid +` + +func (q *Queries) ListNamespaces(ctx context.Context) ([]SqlNamespace, error) { + rows, err := q.db.QueryContext(ctx, listNamespaces) + if err != nil { + return nil, err + } + defer rows.Close() + var items []SqlNamespace + for rows.Next() { + var i SqlNamespace + if err := rows.Scan(&i.Oid, &i.Name); 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 listTablesInNamespace = `-- name: ListTablesInNamespace :many +SELECT oid, name FROM sql_class +WHERE namespace_oid = ? AND kind = 'r' +ORDER BY oid +` + +type ListTablesInNamespaceRow struct { + Oid int64 + Name string +} + +func (q *Queries) ListTablesInNamespace(ctx context.Context, namespaceOid int64) ([]ListTablesInNamespaceRow, error) { + rows, err := q.db.QueryContext(ctx, listTablesInNamespace, namespaceOid) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListTablesInNamespaceRow + for rows.Next() { + var i ListTablesInNamespaceRow + if err := rows.Scan(&i.Oid, &i.Name); 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 listTypeAffinities = `-- name: ListTypeAffinities :many +SELECT words, type_oid FROM sql_type_affinity +WHERE dialect_oid = ? ORDER BY ord +` + +type ListTypeAffinitiesRow struct { + Words string + TypeOid int64 +} + +func (q *Queries) ListTypeAffinities(ctx context.Context, dialectOid int64) ([]ListTypeAffinitiesRow, error) { + rows, err := q.db.QueryContext(ctx, listTypeAffinities, dialectOid) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListTypeAffinitiesRow + for rows.Next() { + var i ListTypeAffinitiesRow + if err := rows.Scan(&i.Words, &i.TypeOid); 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 listTypeRewrites = `-- name: ListTypeRewrites :many +SELECT pattern, template, cond FROM sql_type_rewrite +WHERE dialect_oid = ? ORDER BY ord +` + +type ListTypeRewritesRow struct { + Pattern string + Template string + Cond string +} + +func (q *Queries) ListTypeRewrites(ctx context.Context, dialectOid int64) ([]ListTypeRewritesRow, error) { + rows, err := q.db.QueryContext(ctx, listTypeRewrites, dialectOid) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListTypeRewritesRow + for rows.Next() { + var i ListTypeRewritesRow + if err := rows.Scan(&i.Pattern, &i.Template, &i.Cond); 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 lookupAttribute = `-- name: LookupAttribute :one +SELECT ns.name AS schema_name, cls.name AS table_name, a.name AS column_name, a.num, + a.decl_type, a.auto_increment, a.is_primary_key, a.is_unique, a.not_null +FROM sql_attribute a +JOIN sql_class cls ON cls.oid = a.class_oid +JOIN sql_namespace ns ON ns.oid = cls.namespace_oid +WHERE a.oid = ? +` + +type LookupAttributeRow struct { + SchemaName string + TableName string + ColumnName string + Num int64 + DeclType string + AutoIncrement int64 + IsPrimaryKey int64 + IsUnique int64 + NotNull int64 +} + +func (q *Queries) LookupAttribute(ctx context.Context, oid int64) (LookupAttributeRow, error) { + row := q.db.QueryRowContext(ctx, lookupAttribute, oid) + var i LookupAttributeRow + err := row.Scan( + &i.SchemaName, + &i.TableName, + &i.ColumnName, + &i.Num, + &i.DeclType, + &i.AutoIncrement, + &i.IsPrimaryKey, + &i.IsUnique, + &i.NotNull, + ) + return i, err +} + +const lookupType = `-- name: LookupType :one +SELECT oid, namespace_oid, name, expr, category, typtype, preferred, + family_oid, element_oid, base_oid, canonical_oid, not_null +FROM sql_type +WHERE oid = ? +` + +type LookupTypeRow struct { + Oid int64 + NamespaceOid int64 + Name string + Expr string + Category sql.NullString + Typtype string + Preferred int64 + FamilyOid sql.NullInt64 + ElementOid sql.NullInt64 + BaseOid sql.NullInt64 + CanonicalOid sql.NullInt64 + NotNull int64 +} + +func (q *Queries) LookupType(ctx context.Context, oid int64) (LookupTypeRow, error) { + row := q.db.QueryRowContext(ctx, lookupType, oid) + var i LookupTypeRow + err := row.Scan( + &i.Oid, + &i.NamespaceOid, + &i.Name, + &i.Expr, + &i.Category, + &i.Typtype, + &i.Preferred, + &i.FamilyOid, + &i.ElementOid, + &i.BaseOid, + &i.CanonicalOid, + &i.NotNull, + ) + return i, err +} + +const maxAttributeNum = `-- name: MaxAttributeNum :one +SELECT CAST(COALESCE(MAX(num), 0) AS INTEGER) AS num FROM sql_attribute WHERE class_oid = ? +` + +func (q *Queries) MaxAttributeNum(ctx context.Context, classOid int64) (int64, error) { + row := q.db.QueryRowContext(ctx, maxAttributeNum, classOid) + var num int64 + err := row.Scan(&num) + return num, err +} + +const namespaceOID = `-- name: NamespaceOID :one +SELECT oid FROM sql_namespace WHERE name = ? +` + +func (q *Queries) NamespaceOID(ctx context.Context, name string) (int64, error) { + row := q.db.QueryRowContext(ctx, namespaceOID, name) + var oid int64 + err := row.Scan(&oid) + return oid, err +} + +const procArgTypes = `-- name: ProcArgTypes :many +SELECT type_oid FROM sql_proc_arg +WHERE proc_oid = ? AND mode IN ('i', 'b', 'v') +ORDER BY ord +` + +func (q *Queries) ProcArgTypes(ctx context.Context, procOid int64) ([]int64, error) { + rows, err := q.db.QueryContext(ctx, procArgTypes, procOid) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var type_oid int64 + if err := rows.Scan(&type_oid); err != nil { + return nil, err + } + items = append(items, type_oid) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const renameAttribute = `-- name: RenameAttribute :exec +UPDATE sql_attribute SET name = ?1 +WHERE class_oid = ?2 AND name = ?3 +` + +type RenameAttributeParams struct { + NewName string + ClassOid int64 + Name string +} + +func (q *Queries) RenameAttribute(ctx context.Context, arg RenameAttributeParams) error { + _, err := q.db.ExecContext(ctx, renameAttribute, arg.NewName, arg.ClassOid, arg.Name) + return err +} + +const renameClass = `-- name: RenameClass :exec +UPDATE sql_class SET name = ?1 WHERE oid = ?2 +` + +type RenameClassParams struct { + NewName string + Oid int64 +} + +func (q *Queries) RenameClass(ctx context.Context, arg RenameClassParams) error { + _, err := q.db.ExecContext(ctx, renameClass, arg.NewName, arg.Oid) + return err +} + +const resolveColumn = `-- name: ResolveColumn :one +SELECT a.oid, a.class_oid, a.name, t.name AS type_name, a.type_oid, a.not_null, + a.decl_type, a.auto_increment, a.is_primary_key, a.is_unique +FROM sql_attribute a +JOIN sql_class c ON c.oid = a.class_oid +JOIN sql_type t ON t.oid = a.type_oid +WHERE c.name = ?1 AND a.name = ?2 +` + +type ResolveColumnParams struct { + TableName string + ColumnName string +} + +type ResolveColumnRow struct { + Oid int64 + ClassOid int64 + Name string + TypeName string + TypeOid int64 + NotNull int64 + DeclType string + AutoIncrement int64 + IsPrimaryKey int64 + IsUnique int64 +} + +func (q *Queries) ResolveColumn(ctx context.Context, arg ResolveColumnParams) (ResolveColumnRow, error) { + row := q.db.QueryRowContext(ctx, resolveColumn, arg.TableName, arg.ColumnName) + var i ResolveColumnRow + err := row.Scan( + &i.Oid, + &i.ClassOid, + &i.Name, + &i.TypeName, + &i.TypeOid, + &i.NotNull, + &i.DeclType, + &i.AutoIncrement, + &i.IsPrimaryKey, + &i.IsUnique, + ) + return i, err +} + +const seededDialect = `-- name: SeededDialect :one +SELECT oid, name FROM sql_dialect ORDER BY oid LIMIT 1 +` + +// The dialect a catalog was seeded with. A catalog is built for exactly one, +// so a restored catalog finds it without being told its name. +func (q *Queries) SeededDialect(ctx context.Context) (SqlDialect, error) { + row := q.db.QueryRowContext(ctx, seededDialect) + var i SqlDialect + err := row.Scan(&i.Oid, &i.Name) + return i, err +} + +const setAttributeNotNull = `-- name: SetAttributeNotNull :exec +UPDATE sql_attribute SET not_null = ?1 +WHERE class_oid = ?2 AND name = ?3 +` + +type SetAttributeNotNullParams struct { + NotNull int64 + ClassOid int64 + Name string +} + +func (q *Queries) SetAttributeNotNull(ctx context.Context, arg SetAttributeNotNullParams) error { + _, err := q.db.ExecContext(ctx, setAttributeNotNull, arg.NotNull, arg.ClassOid, arg.Name) + return err +} + +const setAttributePrimaryKey = `-- name: SetAttributePrimaryKey :exec +UPDATE sql_attribute SET is_primary_key = 1, not_null = 1 +WHERE class_oid = ? AND name = ? +` + +type SetAttributePrimaryKeyParams struct { + ClassOid int64 + Name string +} + +func (q *Queries) SetAttributePrimaryKey(ctx context.Context, arg SetAttributePrimaryKeyParams) error { + _, err := q.db.ExecContext(ctx, setAttributePrimaryKey, arg.ClassOid, arg.Name) + return err +} + +const setAttributeType = `-- name: SetAttributeType :exec +UPDATE sql_attribute SET type_oid = ?1, decl_type = ?2 +WHERE class_oid = ?3 AND name = ?4 +` + +type SetAttributeTypeParams struct { + TypeOid int64 + DeclType string + ClassOid int64 + Name string +} + +func (q *Queries) SetAttributeType(ctx context.Context, arg SetAttributeTypeParams) error { + _, err := q.db.ExecContext(ctx, setAttributeType, + arg.TypeOid, + arg.DeclType, + arg.ClassOid, + arg.Name, + ) + return err +} + +const setAttributeUnique = `-- name: SetAttributeUnique :exec +UPDATE sql_attribute SET is_unique = 1 +WHERE class_oid = ? AND name = ? +` + +type SetAttributeUniqueParams struct { + ClassOid int64 + Name string +} + +func (q *Queries) SetAttributeUnique(ctx context.Context, arg SetAttributeUniqueParams) error { + _, err := q.db.ExecContext(ctx, setAttributeUnique, arg.ClassOid, arg.Name) + return err +} + +const setDialectFlag = `-- name: SetDialectFlag :exec +INSERT INTO sql_dialect_flag (dialect_oid, key, value) +VALUES (?, ?, ?) +ON CONFLICT(dialect_oid, key) DO UPDATE SET value = excluded.value +` + +type SetDialectFlagParams struct { + DialectOid int64 + Key string + Value string +} + +func (q *Queries) SetDialectFlag(ctx context.Context, arg SetDialectFlagParams) error { + _, err := q.db.ExecContext(ctx, setDialectFlag, arg.DialectOid, arg.Key, arg.Value) + return err +} + +const tableColumns = `-- name: TableColumns :many +SELECT a.oid, a.class_oid, a.name, t.name AS type_name, a.type_oid, a.not_null, + a.decl_type, a.auto_increment, a.is_primary_key, a.is_unique +FROM sql_attribute a +JOIN sql_class c ON c.oid = a.class_oid +JOIN sql_type t ON t.oid = a.type_oid +WHERE c.name = ? +ORDER BY a.num +` + +type TableColumnsRow struct { + Oid int64 + ClassOid int64 + Name string + TypeName string + TypeOid int64 + NotNull int64 + DeclType string + AutoIncrement int64 + IsPrimaryKey int64 + IsUnique int64 +} + +func (q *Queries) TableColumns(ctx context.Context, name string) ([]TableColumnsRow, error) { + rows, err := q.db.QueryContext(ctx, tableColumns, name) + if err != nil { + return nil, err + } + defer rows.Close() + var items []TableColumnsRow + for rows.Next() { + var i TableColumnsRow + if err := rows.Scan( + &i.Oid, + &i.ClassOid, + &i.Name, + &i.TypeName, + &i.TypeOid, + &i.NotNull, + &i.DeclType, + &i.AutoIncrement, + &i.IsPrimaryKey, + &i.IsUnique, + ); 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 typeArgs = `-- name: TypeArgs :many +SELECT ord, label, arg_type_oid, nullable, int_value, bool_value, string_value, ident +FROM sql_type_arg +WHERE type_oid = ? +ORDER BY ord +` + +type TypeArgsRow struct { + Ord int64 + Label string + ArgTypeOid sql.NullInt64 + Nullable int64 + IntValue sql.NullInt64 + BoolValue sql.NullInt64 + StringValue sql.NullString + Ident sql.NullString +} + +func (q *Queries) TypeArgs(ctx context.Context, typeOid int64) ([]TypeArgsRow, error) { + rows, err := q.db.QueryContext(ctx, typeArgs, typeOid) + if err != nil { + return nil, err + } + defer rows.Close() + var items []TypeArgsRow + for rows.Next() { + var i TypeArgsRow + if err := rows.Scan( + &i.Ord, + &i.Label, + &i.ArgTypeOid, + &i.Nullable, + &i.IntValue, + &i.BoolValue, + &i.StringValue, + &i.Ident, + ); 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 typeNameByOID = `-- name: TypeNameByOID :one +SELECT name FROM sql_type WHERE oid = ? +` + +func (q *Queries) TypeNameByOID(ctx context.Context, oid int64) (string, error) { + row := q.db.QueryRowContext(ctx, typeNameByOID, oid) + var name string + err := row.Scan(&name) + return name, err +} + +const typeOIDByExpr = `-- name: TypeOIDByExpr :one +SELECT t.oid +FROM sql_type t +JOIN sql_namespace ns ON ns.oid = t.namespace_oid +WHERE t.expr = ?1 +ORDER BY + CASE ns.name + WHEN 'pg_catalog' THEN 0 + WHEN 'public' THEN 1 + ELSE 2 + END, + ns.name +LIMIT 1 +` + +func (q *Queries) TypeOIDByExpr(ctx context.Context, expr string) (int64, error) { + row := q.db.QueryRowContext(ctx, typeOIDByExpr, expr) + var oid int64 + err := row.Scan(&oid) + return oid, err +} + +const typeOIDByExprInNamespace = `-- name: TypeOIDByExprInNamespace :one +SELECT oid FROM sql_type WHERE namespace_oid = ? AND expr = ? +` + +type TypeOIDByExprInNamespaceParams struct { + NamespaceOid int64 + Expr string +} + +func (q *Queries) TypeOIDByExprInNamespace(ctx context.Context, arg TypeOIDByExprInNamespaceParams) (int64, error) { + row := q.db.QueryRowContext(ctx, typeOIDByExprInNamespace, arg.NamespaceOid, arg.Expr) + var oid int64 + err := row.Scan(&oid) + return oid, err +} + +const typeOIDByName = `-- name: TypeOIDByName :one +SELECT t.oid +FROM sql_type t +JOIN sql_namespace ns ON ns.oid = t.namespace_oid +WHERE t.name = ?1 AND t.family_oid IS NULL +ORDER BY + CASE ns.name + WHEN 'pg_catalog' THEN 0 + WHEN 'public' THEN 1 + ELSE 2 + END, + ns.name +LIMIT 1 +` + +// The family spelled name: an instance carries its family's name too, and +// is found by its expression instead. +func (q *Queries) TypeOIDByName(ctx context.Context, name string) (int64, error) { + row := q.db.QueryRowContext(ctx, typeOIDByName, name) + var oid int64 + err := row.Scan(&oid) + return oid, err +} + +const typeOIDByNameInNamespace = `-- name: TypeOIDByNameInNamespace :one +SELECT oid FROM sql_type +WHERE namespace_oid = ? AND name = ? AND family_oid IS NULL +` + +type TypeOIDByNameInNamespaceParams struct { + NamespaceOid int64 + Name string +} + +func (q *Queries) TypeOIDByNameInNamespace(ctx context.Context, arg TypeOIDByNameInNamespaceParams) (int64, error) { + row := q.db.QueryRowContext(ctx, typeOIDByNameInNamespace, arg.NamespaceOid, arg.Name) + var oid int64 + err := row.Scan(&oid) + return oid, err +} + +const typeOIDsByNameInNamespaces = `-- name: TypeOIDsByNameInNamespaces :many +SELECT oid, namespace_oid FROM sql_type +WHERE name = ?1 AND family_oid IS NULL + AND namespace_oid IN (/*SLICE:namespace_oids*/?) +` + +type TypeOIDsByNameInNamespacesParams struct { + Name string + NamespaceOids []int64 +} + +type TypeOIDsByNameInNamespacesRow struct { + Oid int64 + NamespaceOid int64 +} + +func (q *Queries) TypeOIDsByNameInNamespaces(ctx context.Context, arg TypeOIDsByNameInNamespacesParams) ([]TypeOIDsByNameInNamespacesRow, error) { + query := typeOIDsByNameInNamespaces + var queryParams []any + queryParams = append(queryParams, arg.Name) + if len(arg.NamespaceOids) > 0 { + for _, v := range arg.NamespaceOids { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:namespace_oids*/?", strings.Repeat(",?", len(arg.NamespaceOids))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:namespace_oids*/?", "NULL", 1) + } + rows, err := q.db.QueryContext(ctx, query, queryParams...) + if err != nil { + return nil, err + } + defer rows.Close() + var items []TypeOIDsByNameInNamespacesRow + for rows.Next() { + var i TypeOIDsByNameInNamespacesRow + if err := rows.Scan(&i.Oid, &i.NamespaceOid); 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 typeOIDsInCategory = `-- name: TypeOIDsInCategory :many +SELECT oid FROM sql_type +WHERE dialect_oid = ? AND category = ? + AND family_oid IS NULL AND canonical_oid IS NULL +ORDER BY oid +` + +type TypeOIDsInCategoryParams struct { + DialectOid sql.NullInt64 + Category sql.NullString +} + +// The families of a category: an instance inherits its family's category +// and an alias stands for the row it points at, so neither is listed. +func (q *Queries) TypeOIDsInCategory(ctx context.Context, arg TypeOIDsInCategoryParams) ([]int64, error) { + rows, err := q.db.QueryContext(ctx, typeOIDsInCategory, arg.DialectOid, arg.Category) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var oid int64 + if err := rows.Scan(&oid); err != nil { + return nil, err + } + items = append(items, oid) + } + 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/core/catalogdef/embed.go b/internal/core/catalogdef/embed.go new file mode 100644 index 0000000..416961f --- /dev/null +++ b/internal/core/catalogdef/embed.go @@ -0,0 +1,6 @@ +package catalogdef + +import _ "embed" + +//go:embed schema.sql +var Schema string diff --git a/internal/core/catalogdef/query.sql b/internal/core/catalogdef/query.sql new file mode 100644 index 0000000..2c56ac5 --- /dev/null +++ b/internal/core/catalogdef/query.sql @@ -0,0 +1,284 @@ +-- Queries against sqlc's own sql_* catalog tables, compiled by sqlc's +-- SQLite engine. Regenerate with `go generate ./internal/core/...`. + +-- ============================ sql_namespace ============================ + +-- name: CreateNamespace :execlastid +INSERT INTO sql_namespace (name) VALUES (?); + +-- name: NamespaceOID :one +SELECT oid FROM sql_namespace WHERE name = ?; + +-- name: ListNamespaces :many +SELECT oid, name FROM sql_namespace ORDER BY oid; + +-- ============================== sql_dialect ============================ + +-- name: CreateDialect :execlastid +INSERT INTO sql_dialect (name) VALUES (?); + +-- name: DialectOID :one +SELECT oid FROM sql_dialect WHERE name = ?; + +-- name: SeededDialect :one +-- The dialect a catalog was seeded with. A catalog is built for exactly one, +-- so a restored catalog finds it without being told its name. +SELECT oid, name FROM sql_dialect ORDER BY oid LIMIT 1; + +-- name: SetDialectFlag :exec +INSERT INTO sql_dialect_flag (dialect_oid, key, value) +VALUES (?, ?, ?) +ON CONFLICT(dialect_oid, key) DO UPDATE SET value = excluded.value; + +-- name: DialectFlag :one +SELECT value FROM sql_dialect_flag WHERE dialect_oid = ? AND key = ?; + +-- =============================== sql_type ============================== + +-- name: CreateType :execlastid +INSERT INTO sql_type + (name, expr, typtype, category, preferred, namespace_oid, dialect_oid, + family_oid, element_oid, base_oid, canonical_oid, not_null) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + +-- name: CreateTypeArg :exec +INSERT INTO sql_type_arg + (type_oid, ord, label, arg_type_oid, nullable, int_value, bool_value, string_value, ident) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?); + +-- name: TypeArgs :many +SELECT ord, label, arg_type_oid, nullable, int_value, bool_value, string_value, ident +FROM sql_type_arg +WHERE type_oid = ? +ORDER BY ord; + +-- name: TypeOIDByExpr :one +SELECT t.oid +FROM sql_type t +JOIN sql_namespace ns ON ns.oid = t.namespace_oid +WHERE t.expr = sqlc.arg(expr) +ORDER BY + CASE ns.name + WHEN 'pg_catalog' THEN 0 + WHEN 'public' THEN 1 + ELSE 2 + END, + ns.name +LIMIT 1; + +-- name: TypeOIDsByNameInNamespaces :many +SELECT oid, namespace_oid FROM sql_type +WHERE name = sqlc.arg(name) AND family_oid IS NULL + AND namespace_oid IN (sqlc.slice(namespace_oids)); + +-- name: TypeOIDByNameInNamespace :one +SELECT oid FROM sql_type +WHERE namespace_oid = ? AND name = ? AND family_oid IS NULL; + +-- name: TypeOIDByExprInNamespace :one +SELECT oid FROM sql_type WHERE namespace_oid = ? AND expr = ?; + +-- name: TypeOIDByName :one +-- The family spelled name: an instance carries its family's name too, and +-- is found by its expression instead. +SELECT t.oid +FROM sql_type t +JOIN sql_namespace ns ON ns.oid = t.namespace_oid +WHERE t.name = sqlc.arg(name) AND t.family_oid IS NULL +ORDER BY + CASE ns.name + WHEN 'pg_catalog' THEN 0 + WHEN 'public' THEN 1 + ELSE 2 + END, + ns.name +LIMIT 1; + +-- name: TypeNameByOID :one +SELECT name FROM sql_type WHERE oid = ?; + +-- name: TypeOIDsInCategory :many +-- The families of a category: an instance inherits its family's category +-- and an alias stands for the row it points at, so neither is listed. +SELECT oid FROM sql_type +WHERE dialect_oid = ? AND category = ? + AND family_oid IS NULL AND canonical_oid IS NULL +ORDER BY oid; + +-- name: LookupType :one +SELECT oid, namespace_oid, name, expr, category, typtype, preferred, + family_oid, element_oid, base_oid, canonical_oid, not_null +FROM sql_type +WHERE oid = ?; + +-- name: CreateTypeRewrite :exec +INSERT INTO sql_type_rewrite (dialect_oid, ord, pattern, template, cond) +VALUES (?, ?, ?, ?, ?); + +-- name: ListTypeRewrites :many +SELECT pattern, template, cond FROM sql_type_rewrite +WHERE dialect_oid = ? ORDER BY ord; + +-- name: CreateTypeAffinity :exec +INSERT INTO sql_type_affinity (dialect_oid, ord, words, type_oid) +VALUES (?, ?, ?, ?); + +-- name: ListTypeAffinities :many +SELECT words, type_oid FROM sql_type_affinity +WHERE dialect_oid = ? ORDER BY ord; + +-- =============================== sql_class ============================= + +-- name: CreateClass :execlastid +INSERT INTO sql_class (namespace_oid, name, kind) VALUES (?, ?, ?); + +-- name: ClassOID :one +SELECT oid FROM sql_class WHERE namespace_oid = ? AND name = ?; + +-- name: ClassOIDByName :one +SELECT oid FROM sql_class WHERE name = ? LIMIT 1; + +-- name: ListTablesInNamespace :many +SELECT oid, name FROM sql_class +WHERE namespace_oid = ? AND kind = 'r' +ORDER BY oid; + +-- name: DeleteClass :exec +DELETE FROM sql_class WHERE oid = ?; + +-- name: RenameClass :exec +UPDATE sql_class SET name = sqlc.arg(new_name) WHERE oid = sqlc.arg(oid); + +-- ============================= sql_attribute =========================== + +-- name: CreateAttribute :exec +INSERT INTO sql_attribute ( + class_oid, name, type_oid, not_null, has_default, num, + decl_type, auto_increment, is_primary_key, is_unique, hidden +) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + +-- name: SetAttributePrimaryKey :exec +UPDATE sql_attribute SET is_primary_key = 1, not_null = 1 +WHERE class_oid = ? AND name = ?; + +-- name: SetAttributeUnique :exec +UPDATE sql_attribute SET is_unique = 1 +WHERE class_oid = ? AND name = ?; + +-- name: DeleteAttributesByClass :exec +DELETE FROM sql_attribute WHERE class_oid = ?; + +-- name: DeleteAttribute :exec +DELETE FROM sql_attribute WHERE class_oid = ? AND name = ?; + +-- name: RenameAttribute :exec +UPDATE sql_attribute SET name = sqlc.arg(new_name) +WHERE class_oid = sqlc.arg(class_oid) AND name = sqlc.arg(name); + +-- name: SetAttributeType :exec +UPDATE sql_attribute SET type_oid = sqlc.arg(type_oid), decl_type = sqlc.arg(decl_type) +WHERE class_oid = sqlc.arg(class_oid) AND name = sqlc.arg(name); + +-- name: SetAttributeNotNull :exec +UPDATE sql_attribute SET not_null = sqlc.arg(not_null) +WHERE class_oid = sqlc.arg(class_oid) AND name = sqlc.arg(name); + +-- name: MaxAttributeNum :one +SELECT CAST(COALESCE(MAX(num), 0) AS INTEGER) AS num FROM sql_attribute WHERE class_oid = ?; + +-- name: ResolveColumn :one +SELECT a.oid, a.class_oid, a.name, t.name AS type_name, a.type_oid, a.not_null, + a.decl_type, a.auto_increment, a.is_primary_key, a.is_unique +FROM sql_attribute a +JOIN sql_class c ON c.oid = a.class_oid +JOIN sql_type t ON t.oid = a.type_oid +WHERE c.name = sqlc.arg(table_name) AND a.name = sqlc.arg(column_name); + +-- name: TableColumns :many +SELECT a.oid, a.class_oid, a.name, t.name AS type_name, a.type_oid, a.not_null, + a.decl_type, a.auto_increment, a.is_primary_key, a.is_unique +FROM sql_attribute a +JOIN sql_class c ON c.oid = a.class_oid +JOIN sql_type t ON t.oid = a.type_oid +WHERE c.name = ? +ORDER BY a.num; + +-- name: ClassAttributes :many +SELECT oid, name, type_oid, not_null, hidden +FROM sql_attribute +WHERE class_oid = ? +ORDER BY num; + +-- name: ListClassColumns :many +SELECT a.name AS column_name, a.type_oid, a.not_null +FROM sql_attribute a +JOIN sql_type t ON t.oid = a.type_oid +WHERE a.class_oid = ? AND a.hidden = 0 +ORDER BY a.num; + +-- name: LookupAttribute :one +SELECT ns.name AS schema_name, cls.name AS table_name, a.name AS column_name, a.num, + a.decl_type, a.auto_increment, a.is_primary_key, a.is_unique, a.not_null +FROM sql_attribute a +JOIN sql_class cls ON cls.oid = a.class_oid +JOIN sql_namespace ns ON ns.oid = cls.namespace_oid +WHERE a.oid = ?; + +-- ============================ sql_constraint =========================== + +-- name: CreateConstraint :exec +INSERT INTO sql_constraint (class_oid, name, kind, columns) VALUES (?, ?, ?, ?); + +-- =============================== sql_proc ============================== + +-- name: CreateProc :execlastid +INSERT INTO sql_proc + (namespace_oid, dialect_oid, name, kind, + return_type_oid, return_set, return_nullable, return_template, strict, variadic_kind) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + +-- name: CreateProcArg :exec +INSERT INTO sql_proc_arg (proc_oid, ord, name, type_oid, mode, has_default) +VALUES (?, ?, ?, ?, ?, ?); + +-- name: ProcArgTypes :many +SELECT type_oid FROM sql_proc_arg +WHERE proc_oid = ? AND mode IN ('i', 'b', 'v') +ORDER BY ord; + +-- name: FindProcsAnyNamespace :many +SELECT oid, name, kind, return_type_oid, return_nullable, return_template +FROM sql_proc +WHERE name = ?; + +-- name: FindProcsInNamespaces :many +SELECT oid, name, kind, return_type_oid, return_nullable, return_template +FROM sql_proc +WHERE name = sqlc.arg(name) + AND namespace_oid IN (sqlc.slice(namespace_oids)); + +-- ============================= sql_operator ============================ + +-- name: CreateOperator :execlastid +INSERT INTO sql_operator + (namespace_oid, dialect_oid, name, + left_type_oid, right_type_oid, result_type_oid, proc_oid) +VALUES (?, ?, ?, ?, ?, ?, ?); + +-- name: FindOperators :many +SELECT oid, name, left_type_oid, right_type_oid, result_type_oid, proc_oid +FROM sql_operator +WHERE name = sqlc.arg(name) + AND (sqlc.arg(left_type_oid) = 0 OR left_type_oid = sqlc.arg(left_type_oid)) + AND (sqlc.arg(right_type_oid) = 0 OR right_type_oid = sqlc.arg(right_type_oid)); + +-- =============================== sql_cast ============================== + +-- name: CreateCast :exec +INSERT INTO sql_cast (source_type_oid, target_type_oid, proc_oid, context, dialect_oid) +VALUES (?, ?, ?, ?, ?); + +-- name: FindCast :one +SELECT source_type_oid, target_type_oid, proc_oid, context, dialect_oid +FROM sql_cast +WHERE source_type_oid = ? AND target_type_oid = ?; diff --git a/internal/core/catalogdef/schema.sql b/internal/core/catalogdef/schema.sql new file mode 100644 index 0000000..26c7043 --- /dev/null +++ b/internal/core/catalogdef/schema.sql @@ -0,0 +1,227 @@ +-- sql_namespace: schemas / namespaces +CREATE TABLE sql_namespace ( + oid INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL UNIQUE +); + +-- sql_dialect: registered SQL dialects (postgresql, sqlite, mysql, ...). +CREATE TABLE sql_dialect ( + oid INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL UNIQUE +); + +-- sql_dialect_flag: per-dialect configuration knobs (case-folding, +-- identifier quoting, alias scoping rules, etc.). Values are opaque +-- strings; the analyzer interprets them per key. +CREATE TABLE sql_dialect_flag ( + dialect_oid INTEGER NOT NULL REFERENCES sql_dialect(oid), + key TEXT NOT NULL, + value TEXT NOT NULL, + PRIMARY KEY (dialect_oid, key) +); + +-- sql_type: data types, one row per type expression. Modeled on pg_type, +-- with the arguments PostgreSQL keeps as a typmod on the use site held in +-- the row instead. +-- +-- A row is a family — a name the dialect or the schema declares: numeric, +-- array, mood — or an instance, a family applied to arguments: numeric(10, 2), +-- array(integer). expr is the canonical spelling of the whole expression and +-- the row's identity; name is the family's name, on an instance too, so a +-- lookup by name finds the family and an instance points at it. +-- +-- typtype: 'b'ase | 'c'omposite | 'd'omain | 'e'num | 'p'seudo | 'r'ange +-- category: 'N'umeric | 'S'tring | 'B'oolean | 'D'atetime | 'A'rray | +-- 'C'omposite | 'E'num | 'U'serdef | 'X'unknown +-- preferred: tie-breaker for implicit cast resolution within a category +-- family_oid: NULL on a family; the family on an instance +-- element_oid: what the type holds: an array's element, a map's value, +-- a range's subtype +-- base_oid: what the type stands on: a domain's or alias type's base, +-- a wrapper's inner type, a SQLite spelling's affinity +-- canonical_oid: the row the engine reports this one as: an alias spelling +-- points at the type it names +-- not_null: a domain or alias type declared NOT NULL +-- dialect_oid: NULL = standard / shared across dialects +CREATE TABLE sql_type ( + oid INTEGER PRIMARY KEY AUTOINCREMENT, + namespace_oid INTEGER NOT NULL REFERENCES sql_namespace(oid), + dialect_oid INTEGER REFERENCES sql_dialect(oid), + name TEXT NOT NULL, + expr TEXT NOT NULL, + typtype TEXT NOT NULL DEFAULT 'b', + category TEXT, + preferred INTEGER NOT NULL DEFAULT 0, + family_oid INTEGER REFERENCES sql_type(oid), + element_oid INTEGER REFERENCES sql_type(oid), + base_oid INTEGER REFERENCES sql_type(oid), + canonical_oid INTEGER REFERENCES sql_type(oid), + not_null INTEGER NOT NULL DEFAULT 0, + UNIQUE (namespace_oid, expr) +); +CREATE INDEX idx_sql_type_name ON sql_type(name); + +-- sql_type_arg: the arguments of an instance, or the fields, labels or +-- members of a declared composite, enum or set, in order. Exactly one of +-- arg_type_oid, int_value, bool_value, string_value and ident is set. +-- label: a struct field, tuple element or enum label +-- nullable: the argument type is nullable at this position, as the inner +-- type of Array(Nullable(String)) is +-- ident: a bare word that is not a type: max, sum, day to second +CREATE TABLE sql_type_arg ( + type_oid INTEGER NOT NULL REFERENCES sql_type(oid), + ord INTEGER NOT NULL, + label TEXT NOT NULL DEFAULT '', + arg_type_oid INTEGER REFERENCES sql_type(oid), + nullable INTEGER NOT NULL DEFAULT 0, + int_value INTEGER, + bool_value INTEGER, + string_value TEXT, + ident TEXT, + PRIMARY KEY (type_oid, ord) +); + +-- sql_type_rewrite: the rewrites a dialect applies to a type before it is +-- interned, in order, which are how a dialect stores what only it spells: +-- SQL Server keeps float(24) as real and a bare decimal as decimal(18,0), +-- ClickHouse keeps Decimal32(4) as Decimal(9, 4). pattern is a type +-- expression whose arguments may be $1, $2... binding whatever stands there; +-- template is the expression the match becomes, with the bindings +-- substituted; cond bounds a binding, as "$1 <= 24" does. +CREATE TABLE sql_type_rewrite ( + dialect_oid INTEGER NOT NULL REFERENCES sql_dialect(oid), + ord INTEGER NOT NULL, + pattern TEXT NOT NULL, + template TEXT NOT NULL, + cond TEXT NOT NULL DEFAULT '', + PRIMARY KEY (dialect_oid, ord) +); + +-- sql_type_affinity: the rule a dialect resolves an unseeded type family +-- by, in order: the first row one of whose words the family's name +-- contains names the type it stands on, and a row with no words is the +-- default. SQLite gives every declared spelling one of five affinities +-- this way. +CREATE TABLE sql_type_affinity ( + dialect_oid INTEGER NOT NULL REFERENCES sql_dialect(oid), + ord INTEGER NOT NULL, + words TEXT NOT NULL DEFAULT '', -- comma-separated, upper case + type_oid INTEGER NOT NULL REFERENCES sql_type(oid), + PRIMARY KEY (dialect_oid, ord) +); + +-- sql_class: relations (tables, views, indexes). +-- kind: 'r' = table, 'v' = view, 'i' = index, 'c' = composite type, 'f' = foreign +CREATE TABLE sql_class ( + oid INTEGER PRIMARY KEY AUTOINCREMENT, + namespace_oid INTEGER NOT NULL REFERENCES sql_namespace(oid), + name TEXT NOT NULL, + kind TEXT NOT NULL DEFAULT 'r', + UNIQUE(namespace_oid, name) +); + +-- sql_attribute: columns of a relation. +-- decl_type: the type as the schema spelled it, before +-- canonicalization (VARCHAR(10), BIGINT UNSIGNED), which +-- is what a formatter prints back and what SQLite reports. +-- auto_increment: rowid alias (sqlite INTEGER PRIMARY KEY), AUTOINCREMENT, +-- pg serial/bigserial/identity, mysql AUTO_INCREMENT. +-- is_primary_key: this column participates in the relation's primary key. +-- Set both for inline-column PK and for table-level PK. +-- is_unique: column has a UNIQUE constraint or a single-column UNIQUE +-- table constraint. +-- hidden: resolvable by name but absent from a star expansion and +-- from the relation's model, like the column an sqlite +-- fts5 table names after itself. +CREATE TABLE sql_attribute ( + oid INTEGER PRIMARY KEY AUTOINCREMENT, + class_oid INTEGER NOT NULL REFERENCES sql_class(oid), + name TEXT NOT NULL, + type_oid INTEGER NOT NULL REFERENCES sql_type(oid), + not_null INTEGER NOT NULL DEFAULT 0, + has_default INTEGER NOT NULL DEFAULT 0, + num INTEGER NOT NULL, -- ordinal position (1-based) + decl_type TEXT NOT NULL DEFAULT '', + auto_increment INTEGER NOT NULL DEFAULT 0, + is_primary_key INTEGER NOT NULL DEFAULT 0, + is_unique INTEGER NOT NULL DEFAULT 0, + hidden INTEGER NOT NULL DEFAULT 0, + UNIQUE(class_oid, name), + UNIQUE(class_oid, num) +); + +-- sql_constraint: constraints on a relation. +-- kind: 'p' = primary key, 'f' = foreign key, 'u' = unique, 'c' = check +CREATE TABLE sql_constraint ( + oid INTEGER PRIMARY KEY AUTOINCREMENT, + class_oid INTEGER NOT NULL REFERENCES sql_class(oid), + name TEXT NOT NULL DEFAULT '', + kind TEXT NOT NULL, + columns TEXT NOT NULL DEFAULT '' -- comma-separated attribute nums +); + +-- sql_proc: functions, aggregates, window functions, procedures. +-- Modeled on pg_proc. +-- kind: 'f' = function, 'a' = aggregate, 'w' = window, 'p' = procedure +-- variadic_kind: 'n' = none, 'a' = array (VARIADIC any[]), 'v' = variadic-any +-- return_set: 1 if SETOF / table-returning +-- return_template: the result as an expression over the call's arguments, +-- when it depends on their values: Decimal(18, $2) for +-- toDecimal64(x, s). Empty for a result the type says. +CREATE TABLE sql_proc ( + oid INTEGER PRIMARY KEY AUTOINCREMENT, + namespace_oid INTEGER REFERENCES sql_namespace(oid), + dialect_oid INTEGER REFERENCES sql_dialect(oid), + name TEXT NOT NULL, + kind TEXT NOT NULL DEFAULT 'f', + return_type_oid INTEGER NOT NULL REFERENCES sql_type(oid), + return_set INTEGER NOT NULL DEFAULT 0, + return_nullable INTEGER NOT NULL DEFAULT 1, + return_template TEXT NOT NULL DEFAULT '', + strict INTEGER NOT NULL DEFAULT 0, + variadic_kind TEXT NOT NULL DEFAULT 'n' +); + +-- sql_proc_arg: ordered argument list for a proc. +-- mode: 'i' = in, 'o' = out, 'b' = both, 't' = table, 'v' = variadic +CREATE TABLE sql_proc_arg ( + proc_oid INTEGER NOT NULL REFERENCES sql_proc(oid), + ord INTEGER NOT NULL, + name TEXT NOT NULL DEFAULT '', + type_oid INTEGER NOT NULL REFERENCES sql_type(oid), + mode TEXT NOT NULL DEFAULT 'i', + has_default INTEGER NOT NULL DEFAULT 0, + PRIMARY KEY (proc_oid, ord) +); + +-- sql_operator: operator overloads. +-- left_type_oid is NULL for prefix unary; right_type_oid is NULL for postfix. +CREATE TABLE sql_operator ( + oid INTEGER PRIMARY KEY AUTOINCREMENT, + namespace_oid INTEGER REFERENCES sql_namespace(oid), + dialect_oid INTEGER REFERENCES sql_dialect(oid), + name TEXT NOT NULL, + left_type_oid INTEGER REFERENCES sql_type(oid), + right_type_oid INTEGER REFERENCES sql_type(oid), + result_type_oid INTEGER NOT NULL REFERENCES sql_type(oid), + proc_oid INTEGER REFERENCES sql_proc(oid), + commutator_oid INTEGER REFERENCES sql_operator(oid), + negator_oid INTEGER REFERENCES sql_operator(oid) +); + +-- sql_cast: type coercion rules. +-- context: 'i' = implicit, 'a' = assignment-only, 'e' = explicit-only +-- proc_oid NULL = binary-coercible (no function needed) +CREATE TABLE sql_cast ( + source_type_oid INTEGER NOT NULL REFERENCES sql_type(oid), + target_type_oid INTEGER NOT NULL REFERENCES sql_type(oid), + proc_oid INTEGER REFERENCES sql_proc(oid), + context TEXT NOT NULL DEFAULT 'e', + dialect_oid INTEGER REFERENCES sql_dialect(oid), + PRIMARY KEY (source_type_oid, target_type_oid) +); + +-- Resolution-speed indexes. +CREATE INDEX idx_sql_proc_name ON sql_proc(name, namespace_oid); +CREATE INDEX idx_sql_operator_name ON sql_operator(name, left_type_oid, right_type_oid); +CREATE INDEX idx_sql_attribute_name ON sql_attribute(name); diff --git a/internal/core/class.go b/internal/core/class.go new file mode 100644 index 0000000..7f3e140 --- /dev/null +++ b/internal/core/class.go @@ -0,0 +1,78 @@ +package core + +import ( + "context" + "fmt" + + "github.com/sqlc-dev/sqlc/internal/core/catalogdb" +) + +func (c *Catalog) CreateClass(namespaceOID int64, name string, kind string) (int64, error) { + oid, err := c.q.CreateClass(context.Background(), catalogdb.CreateClassParams{ + NamespaceOid: namespaceOID, + Name: name, + Kind: kind, + }) + if err != nil { + return 0, fmt.Errorf("create class %q: %w", name, err) + } + return oid, nil +} + +func (c *Catalog) ClassOID(namespaceOID int64, name string) (int64, error) { + oid, err := c.q.ClassOID(context.Background(), catalogdb.ClassOIDParams{ + NamespaceOid: namespaceOID, + Name: name, + }) + if err != nil { + return 0, fmt.Errorf("class %q: %w", name, err) + } + return oid, nil +} + +func (c *Catalog) ClassOIDByName(name string) (int64, error) { + oid, err := c.q.ClassOIDByName(context.Background(), name) + if err != nil { + return 0, fmt.Errorf("class %q: %w", name, err) + } + return oid, nil +} + +func (c *Catalog) DropClass(classOID int64) error { + ctx := context.Background() + if err := c.q.DeleteAttributesByClass(ctx, classOID); err != nil { + return fmt.Errorf("drop class %d attributes: %w", classOID, err) + } + if err := c.q.DeleteClass(ctx, classOID); err != nil { + return fmt.Errorf("drop class %d: %w", classOID, err) + } + return nil +} + +func (c *Catalog) RenameClass(classOID int64, name string) error { + err := c.q.RenameClass(context.Background(), catalogdb.RenameClassParams{ + Oid: classOID, + NewName: name, + }) + if err != nil { + return fmt.Errorf("rename class %d: %w", classOID, err) + } + return nil +} + +type ClassInfo struct { + OID int64 + Name string +} + +func (c *Catalog) TablesInNamespace(namespaceOID int64) ([]ClassInfo, error) { + rows, err := c.q.ListTablesInNamespace(context.Background(), namespaceOID) + if err != nil { + return nil, fmt.Errorf("list tables in namespace %d: %w", namespaceOID, err) + } + out := make([]ClassInfo, 0, len(rows)) + for _, r := range rows { + out = append(out, ClassInfo{OID: r.Oid, Name: r.Name}) + } + return out, nil +} diff --git a/internal/core/constraint.go b/internal/core/constraint.go new file mode 100644 index 0000000..d75e3c2 --- /dev/null +++ b/internal/core/constraint.go @@ -0,0 +1,21 @@ +package core + +import ( + "context" + "fmt" + + "github.com/sqlc-dev/sqlc/internal/core/catalogdb" +) + +func (c *Catalog) CreateConstraint(classOID int64, name string, kind string, columns string) error { + err := c.q.CreateConstraint(context.Background(), catalogdb.CreateConstraintParams{ + ClassOid: classOID, + Name: name, + Kind: kind, + Columns: columns, + }) + if err != nil { + return fmt.Errorf("create constraint %q on class %d: %w", name, classOID, err) + } + return nil +} diff --git a/internal/core/db.go b/internal/core/db.go new file mode 100644 index 0000000..1f58522 --- /dev/null +++ b/internal/core/db.go @@ -0,0 +1,171 @@ +package core + +import ( + "context" + "database/sql" + "sync" +) + +// stmtCache is a catalogdb.DBTX that keeps one prepared statement per distinct +// query string. +// +// The catalog runs the same dozen or so statements over and over — seeding a +// dialect is hundreds of inserts through a handful of queries, and analysis +// issues one lookup per table, column, type, operator and function a statement +// touches. Handing the raw *sql.DB to catalogdb means SQLite re-parses and +// re-plans that SQL text on every call, which dominated both paths. Preparing +// once and rebinding is the whole win. +// +// Statements live for the lifetime of the catalog and are released by Close. +type stmtCache struct { + db *sql.DB + + mu sync.RWMutex + stmts map[string]*sql.Stmt + + // While a transaction is open every statement must be prepared on the + // transaction's own connection: the catalog pins the pool to a single + // connection, so reaching for the *sql.DB mid-transaction would block + // forever waiting for a connection the transaction already holds. These + // statements are owned by the transaction and die with it. + tx *sql.Tx + txStmts map[string]*sql.Stmt +} + +func newStmtCache(db *sql.DB) *stmtCache { + return &stmtCache{db: db, stmts: make(map[string]*sql.Stmt)} +} + +func (c *stmtCache) prepared(ctx context.Context, query string) (*sql.Stmt, error) { + c.mu.RLock() + tx, cache := c.tx, c.stmts + if tx != nil { + cache = c.txStmts + } + stmt, ok := cache[query] + c.mu.RUnlock() + if ok { + return stmt, nil + } + + if tx != nil { + stmt, err := tx.PrepareContext(ctx, query) + if err != nil { + return nil, err + } + c.mu.Lock() + defer c.mu.Unlock() + // Bail out if the transaction ended while we were preparing; the + // statement is dead either way. + if c.tx != tx { + return stmt, nil + } + if existing, ok := c.txStmts[query]; ok { + stmt.Close() + return existing, nil + } + c.txStmts[query] = stmt + return stmt, nil + } + + stmt, err := c.db.PrepareContext(ctx, query) + if err != nil { + return nil, err + } + + c.mu.Lock() + defer c.mu.Unlock() + // Another goroutine may have prepared the same query while we were not + // holding the lock; keep the winner so each query has a single statement. + if existing, ok := c.stmts[query]; ok { + stmt.Close() + return existing, nil + } + c.stmts[query] = stmt + return stmt, nil +} + +func (c *stmtCache) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) { + stmt, err := c.prepared(ctx, query) + if err != nil { + return nil, err + } + return stmt.ExecContext(ctx, args...) +} + +func (c *stmtCache) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) { + stmt, err := c.prepared(ctx, query) + if err != nil { + return nil, err + } + return stmt.QueryContext(ctx, args...) +} + +func (c *stmtCache) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row { + stmt, err := c.prepared(ctx, query) + if err != nil { + // *sql.Row carries an error but has no exported constructor, so fall + // back to the unprepared path and let it report the failure on Scan. + return c.db.QueryRowContext(ctx, query, args...) + } + return stmt.QueryRowContext(ctx, args...) +} + +// PrepareContext returns a statement owned by the caller; it is deliberately +// not cached, since the caller is responsible for closing it. +func (c *stmtCache) PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) { + return c.db.PrepareContext(ctx, query) +} + +// begin opens a transaction that every subsequent statement runs inside, until +// commit or rollback. Batching writes this way saves SQLite a commit per +// statement, which is most of the cost of installing a dialect seed. +func (c *stmtCache) begin(ctx context.Context) error { + tx, err := c.db.BeginTx(ctx, nil) + if err != nil { + return err + } + c.mu.Lock() + c.tx = tx + c.txStmts = make(map[string]*sql.Stmt) + c.mu.Unlock() + return nil +} + +// endTx detaches the current transaction and returns it, or nil if none is +// open. The transaction's statements are released along with it. +func (c *stmtCache) endTx() *sql.Tx { + c.mu.Lock() + defer c.mu.Unlock() + tx := c.tx + c.tx, c.txStmts = nil, nil + return tx +} + +func (c *stmtCache) commit() error { + if tx := c.endTx(); tx != nil { + return tx.Commit() + } + return nil +} + +func (c *stmtCache) rollback() { + if tx := c.endTx(); tx != nil { + tx.Rollback() + } +} + +func (c *stmtCache) Close() error { + c.rollback() + + c.mu.Lock() + defer c.mu.Unlock() + var firstErr error + for query, stmt := range c.stmts { + if err := stmt.Close(); err != nil && firstErr == nil { + firstErr = err + } + delete(c.stmts, query) + } + return firstErr +} diff --git a/internal/core/dialect.go b/internal/core/dialect.go new file mode 100644 index 0000000..e192c44 --- /dev/null +++ b/internal/core/dialect.go @@ -0,0 +1,210 @@ +package core + +import ( + "context" + "fmt" + "slices" + "strings" + + "github.com/sqlc-dev/sqlc/internal/core/catalogdb" +) + +func (c *Catalog) CreateDialect(name string) (int64, error) { + oid, err := c.q.CreateDialect(context.Background(), name) + if err != nil { + return 0, fmt.Errorf("create dialect %q: %w", name, err) + } + c.dialectOID = oid + return oid, nil +} + +func (c *Catalog) DialectOID(name string) (int64, error) { + oid, err := c.q.DialectOID(context.Background(), name) + if err != nil { + return 0, fmt.Errorf("dialect %q: %w", name, err) + } + return oid, nil +} + +func (c *Catalog) SetDialectFlag(dialectOID int64, key, value string) error { + err := c.q.SetDialectFlag(context.Background(), catalogdb.SetDialectFlagParams{ + DialectOid: dialectOID, + Key: key, + Value: value, + }) + if err != nil { + return fmt.Errorf("set dialect flag %s.%s: %w", key, value, err) + } + return nil +} + +func (c *Catalog) DialectFlag(dialectOID int64, key string) (string, error) { + value, err := c.q.DialectFlag(context.Background(), catalogdb.DialectFlagParams{ + DialectOid: dialectOID, + Key: key, + }) + if err != nil { + return "", nil + } + return value, nil +} + +// FlagComparisonOperators holds the dialect's comparison operators as a +// comma-separated list, so that a type declared by a schema can be given the +// same ones the seeded types have. +const FlagComparisonOperators = "operators.comparison" + +// FlagBoolType holds the type a comparison or predicate yields, when it is +// not the type a boolean literal has: ClickHouse compares to UInt8 while +// writing true as Bool. +const FlagBoolType = "types.bool" + +// FlagLimitType holds the type a LIMIT or OFFSET count has, which is what a +// placeholder in one is typed as. +const FlagLimitType = "types.limit" + +// FlagUntypedType holds the type a placeholder takes when nothing in the +// query constrains it, for a dialect that gives such a placeholder one. +const FlagUntypedType = "types.untyped" + +// FlagPropagateNullable is set when a function's result is nullable whenever +// one of its arguments is, the way ClickHouse's ordinary functions behave. +const FlagPropagateNullable = "functions.propagate_nullable" + +// FlagQualifyDuplicateColumns is set for a dialect that names a result +// column after its relation when an earlier result column from another +// relation has the same name, as ClickHouse names the second id of a join +// e.id. +const FlagQualifyDuplicateColumns = "columns.qualify_duplicates" + +// FlagDefaultSchema holds the schema the dialect puts an unqualified object +// in, when that is not the catalog's own default: a type in it is reported +// without its schema. +const FlagDefaultSchema = "schema.default" + +// FlagCastCategories holds the categories whose types are all implicitly +// castable to one another, as the dialect's seed declared them, so that a type +// arriving after the seed — an extension's, say — can join its category. +const FlagCastCategories = "casts.categories" + +// Constant kinds. A literal in a query has no declared type, so each dialect +// names the type its literals take on. +const ( + ConstInteger = "integer" + ConstFloat = "float" + ConstString = "string" + ConstBool = "bool" +) + +// defaultConstTypes are the PostgreSQL type names, used by any dialect that +// does not name its own. +var defaultConstTypes = map[string]string{ + ConstInteger: "int4", + ConstFloat: "numeric", + ConstString: "text", + ConstBool: "bool", +} + +// IsComparisonOperator reports whether the dialect counts name among the +// operators that compare two values and yield a boolean. +func (c *Catalog) IsComparisonOperator(name string) bool { + if c.dialectOID == 0 { + return false + } + ops, _ := c.DialectFlag(c.dialectOID, FlagComparisonOperators) + if ops == "" { + return false + } + return slices.Contains(strings.Split(ops, ","), name) +} + +// SetConstType records the type a literal of the given kind takes on in this +// dialect. +func (c *Catalog) SetConstType(dialectOID int64, kind, typeName string) error { + return c.SetDialectFlag(dialectOID, "const."+kind, typeName) +} + +// ConstTypeOID returns the type a literal of the given kind takes on. +func (c *Catalog) ConstTypeOID(kind string) (int64, error) { + if c.dialectOID != 0 { + if name, _ := c.DialectFlag(c.dialectOID, "const."+kind); name != "" { + return c.TypeOID(name) + } + } + name, ok := defaultConstTypes[kind] + if !ok { + return 0, fmt.Errorf("unknown constant kind %q", kind) + } + return c.TypeOID(name) +} + +// BoolTypeOID returns the type a comparison or predicate yields. +func (c *Catalog) BoolTypeOID() (int64, error) { + if c.dialectOID != 0 { + if name, _ := c.DialectFlag(c.dialectOID, FlagBoolType); name != "" { + return c.TypeOID(name) + } + } + return c.ConstTypeOID(ConstBool) +} + +// LimitTypeOID returns the type a LIMIT or OFFSET count has, falling back to +// the type of an integer literal. +func (c *Catalog) LimitTypeOID() (int64, error) { + if c.dialectOID != 0 { + if name, _ := c.DialectFlag(c.dialectOID, FlagLimitType); name != "" { + return c.TypeOID(name) + } + } + return c.ConstTypeOID(ConstInteger) +} + +// UntypedTypeOID returns the type an unconstrained placeholder takes, and +// whether the dialect gives it one at all. +func (c *Catalog) UntypedTypeOID() (int64, bool) { + if c.dialectOID == 0 { + return 0, false + } + name, _ := c.DialectFlag(c.dialectOID, FlagUntypedType) + if name == "" { + return 0, false + } + oid, err := c.TypeOID(name) + if err != nil { + return 0, false + } + return oid, true +} + +// PropagatesNullable reports whether a function's result is nullable +// whenever one of its arguments is. +func (c *Catalog) PropagatesNullable() bool { + if c.dialectOID == 0 { + return false + } + v, _ := c.DialectFlag(c.dialectOID, FlagPropagateNullable) + return v == "true" +} + +// QualifiesDuplicateColumns reports whether a result column that repeats an +// earlier one's name from another relation is named after its relation. +func (c *Catalog) QualifiesDuplicateColumns() bool { + if c.dialectOID == 0 { + return false + } + v, _ := c.DialectFlag(c.dialectOID, FlagQualifyDuplicateColumns) + return v == "true" +} + +// DefaultNamespaces lists the namespaces a type is reported from without +// qualification: the catalog's default, PostgreSQL's system catalog, and +// the dialect's own default schema when it names one. +func (c *Catalog) DefaultNamespaces() []string { + out := []string{"public", "pg_catalog"} + if c.dialectOID != 0 { + if name, _ := c.DialectFlag(c.dialectOID, FlagDefaultSchema); name != "" { + out = append(out, name) + } + } + return out +} diff --git a/internal/core/namespace.go b/internal/core/namespace.go new file mode 100644 index 0000000..b594053 --- /dev/null +++ b/internal/core/namespace.go @@ -0,0 +1,39 @@ +package core + +import ( + "context" + "fmt" +) + +func (c *Catalog) CreateNamespace(name string) (int64, error) { + oid, err := c.q.CreateNamespace(context.Background(), name) + if err != nil { + return 0, fmt.Errorf("create namespace %q: %w", name, err) + } + return oid, nil +} + +func (c *Catalog) NamespaceOID(name string) (int64, error) { + oid, err := c.q.NamespaceOID(context.Background(), name) + if err != nil { + return 0, fmt.Errorf("namespace %q: %w", name, err) + } + return oid, nil +} + +type NamespaceInfo struct { + OID int64 + Name string +} + +func (c *Catalog) Namespaces() ([]NamespaceInfo, error) { + rows, err := c.q.ListNamespaces(context.Background()) + if err != nil { + return nil, fmt.Errorf("list namespaces: %w", err) + } + out := make([]NamespaceInfo, 0, len(rows)) + for _, r := range rows { + out = append(out, NamespaceInfo{OID: r.Oid, Name: r.Name}) + } + return out, nil +} diff --git a/internal/core/operator.go b/internal/core/operator.go new file mode 100644 index 0000000..784ea89 --- /dev/null +++ b/internal/core/operator.go @@ -0,0 +1,68 @@ +package core + +import ( + "context" + "fmt" + + "github.com/sqlc-dev/sqlc/internal/core/catalogdb" +) + +type OperatorSpec struct { + Name string + NamespaceOID int64 + DialectOID int64 + LeftTypeOID int64 + RightTypeOID int64 + ResultTypeOID int64 + ProcOID int64 +} + +func (c *Catalog) CreateOperator(o OperatorSpec) (int64, error) { + oid, err := c.q.CreateOperator(context.Background(), catalogdb.CreateOperatorParams{ + NamespaceOid: nullInt64(o.NamespaceOID), + DialectOid: nullInt64(o.DialectOID), + Name: o.Name, + LeftTypeOid: nullInt64(o.LeftTypeOID), + RightTypeOid: nullInt64(o.RightTypeOID), + ResultTypeOid: o.ResultTypeOID, + ProcOid: nullInt64(o.ProcOID), + }) + if err != nil { + return 0, fmt.Errorf("create operator %q: %w", o.Name, err) + } + return oid, nil +} + +type OperatorOverload struct { + OID int64 + Name string + LeftTypeOID int64 + RightTypeOID int64 + ResultTypeOID int64 + ProcOID int64 +} + +// FindOperators returns the overloads of name matching the given operand types, +// where a zero OID means "any". +func (c *Catalog) FindOperators(name string, leftTypeOID, rightTypeOID int64) ([]OperatorOverload, error) { + rows, err := c.q.FindOperators(context.Background(), catalogdb.FindOperatorsParams{ + Name: name, + LeftTypeOid: leftTypeOID, + RightTypeOid: rightTypeOID, + }) + if err != nil { + return nil, fmt.Errorf("find operators %q: %w", name, err) + } + out := make([]OperatorOverload, 0, len(rows)) + for _, r := range rows { + out = append(out, OperatorOverload{ + OID: r.Oid, + Name: r.Name, + LeftTypeOID: orZero(r.LeftTypeOid), + RightTypeOID: orZero(r.RightTypeOid), + ResultTypeOID: r.ResultTypeOid, + ProcOID: orZero(r.ProcOid), + }) + } + return out, nil +} diff --git a/internal/core/proc.go b/internal/core/proc.go new file mode 100644 index 0000000..28bf32c --- /dev/null +++ b/internal/core/proc.go @@ -0,0 +1,173 @@ +package core + +import ( + "context" + "database/sql" + "fmt" + "strings" + + "github.com/sqlc-dev/sqlc/internal/core/catalogdb" +) + +type ProcSpec struct { + Name string + NamespaceOID int64 + DialectOID int64 + Kind string + ReturnTypeOID int64 + ReturnSet bool + ReturnNullable bool + // NeverNull marks a function whose result is never NULL even when an + // argument is, in a dialect that otherwise propagates nullability. + NeverNull bool + // ReturnTemplate is the result as an expression over the call's + // arguments, when it depends on their values: Decimal(18, $2) for + // toDecimal64(x, s). + ReturnTemplate string + Strict bool + VariadicKind string + Args []ProcArg +} + +// The proc table stores nullability as one integer: 0 leaves it to the +// dialect's rule, 1 is always nullable and 2 is never nullable. +const ( + nullableDefault int64 = 0 + nullableAlways int64 = 1 + nullableNever int64 = 2 +) + +type ProcArg struct { + Name string + TypeOID int64 + Mode string + HasDefault bool +} + +func (c *Catalog) CreateProc(p ProcSpec) (int64, error) { + if p.Kind == "" { + p.Kind = "f" + } + if p.VariadicKind == "" { + p.VariadicKind = "n" + } + ctx := context.Background() + procOID, err := c.q.CreateProc(ctx, catalogdb.CreateProcParams{ + NamespaceOid: nullInt64(p.NamespaceOID), + DialectOid: nullInt64(p.DialectOID), + Name: strings.ToLower(p.Name), + Kind: p.Kind, + ReturnTypeOid: p.ReturnTypeOID, + ReturnSet: boolToInt64(p.ReturnSet), + ReturnNullable: returnNullable(p), + ReturnTemplate: p.ReturnTemplate, + Strict: boolToInt64(p.Strict), + VariadicKind: p.VariadicKind, + }) + if err != nil { + return 0, fmt.Errorf("create proc %q: %w", p.Name, err) + } + for i, a := range p.Args { + mode := a.Mode + if mode == "" { + mode = "i" + } + err := c.q.CreateProcArg(ctx, catalogdb.CreateProcArgParams{ + ProcOid: procOID, + Ord: int64(i + 1), + Name: a.Name, + TypeOid: a.TypeOID, + Mode: mode, + HasDefault: boolToInt64(a.HasDefault), + }) + if err != nil { + return 0, fmt.Errorf("create proc %q arg %d: %w", p.Name, i+1, err) + } + } + return procOID, nil +} + +func returnNullable(p ProcSpec) int64 { + switch { + case p.NeverNull: + return nullableNever + case p.ReturnNullable: + return nullableAlways + } + return nullableDefault +} + +type ProcOverload struct { + OID int64 + Name string + Kind string + ReturnTypeOID int64 + ReturnNullable bool + NeverNull bool + ReturnTemplate string + ArgTypes []int64 +} + +// FindProcs returns the overloads of name, optionally restricted to the given +// namespaces. +func (c *Catalog) FindProcs(name string, namespaceOIDs []int64) ([]ProcOverload, error) { + ctx := context.Background() + lname := strings.ToLower(name) + + var out []ProcOverload + if len(namespaceOIDs) == 0 { + rows, err := c.q.FindProcsAnyNamespace(ctx, lname) + if err != nil { + return nil, fmt.Errorf("find procs %q: %w", name, err) + } + out = make([]ProcOverload, 0, len(rows)) + for _, r := range rows { + out = append(out, ProcOverload{ + OID: r.Oid, + Name: r.Name, + Kind: r.Kind, + ReturnTypeOID: r.ReturnTypeOid, + ReturnNullable: r.ReturnNullable == nullableAlways, + NeverNull: r.ReturnNullable == nullableNever, + ReturnTemplate: r.ReturnTemplate, + }) + } + } else { + nss := make([]sql.NullInt64, len(namespaceOIDs)) + for i, ns := range namespaceOIDs { + nss[i] = sql.NullInt64{Int64: ns, Valid: true} + } + rows, err := c.q.FindProcsInNamespaces(ctx, catalogdb.FindProcsInNamespacesParams{ + Name: lname, + NamespaceOids: nss, + }) + if err != nil { + return nil, fmt.Errorf("find procs %q: %w", name, err) + } + out = make([]ProcOverload, 0, len(rows)) + for _, r := range rows { + out = append(out, ProcOverload{ + OID: r.Oid, + Name: r.Name, + Kind: r.Kind, + ReturnTypeOID: r.ReturnTypeOid, + ReturnNullable: r.ReturnNullable == nullableAlways, + NeverNull: r.ReturnNullable == nullableNever, + ReturnTemplate: r.ReturnTemplate, + }) + } + } + + for i := range out { + argTypes, err := c.procArgTypes(out[i].OID) + if err != nil { + return nil, err + } + out[i].ArgTypes = argTypes + } + return out, nil +} + +func (c *Catalog) procArgTypes(procOID int64) ([]int64, error) { + return c.q.ProcArgTypes(context.Background(), procOID) +} diff --git a/internal/core/rewrite.go b/internal/core/rewrite.go new file mode 100644 index 0000000..352afe9 --- /dev/null +++ b/internal/core/rewrite.go @@ -0,0 +1,361 @@ +package core + +import ( + "context" + "fmt" + "strconv" + "strings" + "sync" + + "github.com/sqlc-dev/sqlc/internal/core/catalogdb" +) + +// A dialect describes, as data, what it does to a type before storing it. +// The seed loads three kinds of it from dialect.json: rewrites, which turn +// one expression into another (float(24) into real, a bare decimal into +// decimal(18, 0)); identifier words and positions, which say where a bare +// word is a word rather than a type (the max of nvarchar(max), the +// function of SimpleAggregateFunction(sum, UInt64)); and an affinity rule, +// which says what a family the schema declares and the seed does not list +// stands on. None of it is code, so an engine adds a dialect by writing +// files. + +// FlagIdents holds the words that are identifiers wherever they stand as a +// type argument, comma-separated. +const FlagIdents = "types.idents" + +// FlagIdentArgs holds the argument positions that are identifiers in a +// family, as "family:1,2;family:1". +const FlagIdentArgs = "types.ident_args" + +// typeRewrite is one rewrite, parsed: a pattern whose $n arguments bind +// whatever stands there, a template the bindings are substituted into, and +// a condition on a binding. +type typeRewrite struct { + pattern *TypeExpr + template *TypeExpr + cond rewriteCond +} + +// rewriteCond bounds an integer binding: "$1 <= 24". +type rewriteCond struct { + binding string + op string + value int64 +} + +// rules is what the catalog knows of its dialect's rewriting, read from the +// tables once and kept. The seed invalidates it as it adds to them. +type rules struct { + mu sync.Mutex + loaded bool + rewrites []typeRewrite + idents map[string]bool + identArgs map[string][]int +} + +func (c *Catalog) invalidateRules() { + c.rules.mu.Lock() + c.rules.loaded = false + c.rules.mu.Unlock() +} + +// loadRules reads the dialect's rewrites and identifier settings. +func (c *Catalog) loadRules() (*rules, error) { + r := &c.rules + r.mu.Lock() + defer r.mu.Unlock() + if r.loaded { + return r, nil + } + r.rewrites, r.idents, r.identArgs = nil, map[string]bool{}, map[string][]int{} + if c.dialectOID == 0 { + r.loaded = true + return r, nil + } + rows, err := c.q.ListTypeRewrites(context.Background(), c.dialectOID) + if err != nil { + return nil, fmt.Errorf("type rewrites: %w", err) + } + for _, row := range rows { + rw := typeRewrite{pattern: ParseTypeExpr(row.Pattern), template: ParseTypeExpr(row.Template)} + if row.Cond != "" { + cond, err := parseRewriteCond(row.Cond) + if err != nil { + return nil, fmt.Errorf("type rewrite %q: %w", row.Pattern, err) + } + rw.cond = cond + } + r.rewrites = append(r.rewrites, rw) + } + if idents, _ := c.DialectFlag(c.dialectOID, FlagIdents); idents != "" { + for _, w := range strings.Split(idents, ",") { + r.idents[strings.ToLower(strings.TrimSpace(w))] = true + } + } + if identArgs, _ := c.DialectFlag(c.dialectOID, FlagIdentArgs); identArgs != "" { + for _, entry := range strings.Split(identArgs, ";") { + family, positions, ok := strings.Cut(entry, ":") + if !ok { + continue + } + for _, p := range strings.Split(positions, ",") { + if n, err := strconv.Atoi(strings.TrimSpace(p)); err == nil { + family = strings.ToLower(strings.TrimSpace(family)) + r.identArgs[family] = append(r.identArgs[family], n) + } + } + } + } + r.loaded = true + return r, nil +} + +// parseRewriteCond reads "$1 <= 24". +func parseRewriteCond(s string) (rewriteCond, error) { + fields := strings.Fields(s) + if len(fields) != 3 || !strings.HasPrefix(fields[0], "$") { + return rewriteCond{}, fmt.Errorf("condition %q: want \"$n op value\"", s) + } + switch fields[1] { + case "<", "<=", "=", ">=", ">", "!=": + default: + return rewriteCond{}, fmt.Errorf("condition %q: unknown operator", s) + } + v, err := strconv.ParseInt(fields[2], 10, 64) + if err != nil { + return rewriteCond{}, fmt.Errorf("condition %q: %w", s, err) + } + return rewriteCond{binding: fields[0], op: fields[1], value: v}, nil +} + +func (cond rewriteCond) holds(bindings map[string]TypeArg) bool { + if cond.binding == "" { + return true + } + a, ok := bindings[cond.binding] + if !ok || a.Int == nil { + return false + } + switch cond.op { + case "<": + return *a.Int < cond.value + case "<=": + return *a.Int <= cond.value + case "=": + return *a.Int == cond.value + case ">=": + return *a.Int >= cond.value + case ">": + return *a.Int > cond.value + case "!=": + return *a.Int != cond.value + } + return false +} + +// AddTypeRewrite records a rewrite of the catalog's dialect, applied after +// the ones recorded before it. +func (c *Catalog) AddTypeRewrite(ord int, pattern, template, cond string) error { + err := c.q.CreateTypeRewrite(context.Background(), catalogdb.CreateTypeRewriteParams{ + DialectOid: c.dialectOID, + Ord: int64(ord), + Pattern: pattern, + Template: template, + Cond: cond, + }) + if err != nil { + return fmt.Errorf("type rewrite %q: %w", pattern, err) + } + c.invalidateRules() + return nil +} + +// AddTypeAffinity records the next step of the dialect's affinity rule: a +// family whose name contains one of words, upper-cased, stands on typeOID. +// No words is the default that ends the rule. +func (c *Catalog) AddTypeAffinity(ord int, words []string, typeOID int64) error { + err := c.q.CreateTypeAffinity(context.Background(), catalogdb.CreateTypeAffinityParams{ + DialectOid: c.dialectOID, + Ord: int64(ord), + Words: strings.ToUpper(strings.Join(words, ",")), + TypeOid: typeOID, + }) + if err != nil { + return fmt.Errorf("type affinity %d: %w", ord, err) + } + return nil +} + +// userTypeBase is the type an unseeded family stands on by the dialect's +// affinity rule, or 0 when the dialect has none or none of it matches. +func (c *Catalog) userTypeBase(name string) (int64, error) { + if c.dialectOID == 0 { + return 0, nil + } + rows, err := c.q.ListTypeAffinities(context.Background(), c.dialectOID) + if err != nil { + return 0, fmt.Errorf("type affinities: %w", err) + } + upper := strings.ToUpper(name) + for _, row := range rows { + if row.Words == "" { + return row.TypeOid, nil + } + for _, w := range strings.Split(row.Words, ",") { + if w != "" && strings.Contains(upper, w) { + return row.TypeOid, nil + } + } + } + return 0, nil +} + +// canonicalize applies the dialect's identifier settings and rewrites to +// an expression: the first rewrite whose pattern matches is applied, and +// its result is not rewritten again. A rewrite names a family as the +// dialect spells it, so an expression spelled with an alias — dec(10) for +// a rule on decimal — is tried again with the alias resolved. +func (c *Catalog) canonicalize(t *TypeExpr) (*TypeExpr, error) { + r, err := c.loadRules() + if err != nil { + return nil, err + } + t = r.identify(t) + if len(r.rewrites) == 0 { + return t, nil + } + if out, ok := r.rewrite(t); ok { + return out, nil + } + if canonical, ok := c.canonicalFamilyName(t.Name); ok && !strings.EqualFold(canonical, t.Name) { + resolved := t.Clone() + resolved.Name = canonical + if out, ok := r.rewrite(resolved); ok { + return out, nil + } + } + return t, nil +} + +// rewrite applies the first rewrite whose pattern matches the expression. +func (r *rules) rewrite(t *TypeExpr) (*TypeExpr, bool) { + name := strings.ToLower(t.Name) + for _, rw := range r.rewrites { + if strings.ToLower(rw.pattern.Name) != name || len(rw.pattern.Args) != len(t.Args) { + continue + } + bindings, ok := matchArgs(rw.pattern.Args, t.Args) + if !ok || !rw.cond.holds(bindings) { + continue + } + out := substitute(rw.template, bindings) + out.Nullable = t.Nullable + return out, true + } + return nil, false +} + +// canonicalFamilyName is the name the catalog spells a family by, with +// aliases resolved, or false when the name is not a family it holds. +func (c *Catalog) canonicalFamilyName(name string) (string, bool) { + oid, err := c.familyOIDByQualifiedName(strings.ToLower(strings.TrimSpace(name))) + if err != nil { + return "", false + } + if oid, err = c.canonicalOID(oid); err != nil { + return "", false + } + info, err := c.LookupType(oid) + if err != nil { + return "", false + } + return c.qualifiedName(info), true +} + +// identify turns the bare words the dialect calls identifiers into +// identifier arguments. +func (r *rules) identify(t *TypeExpr) *TypeExpr { + if len(t.Args) == 0 || (len(r.idents) == 0 && len(r.identArgs) == 0) { + return t + } + positions := r.identArgs[strings.ToLower(t.Name)] + var out *TypeExpr + for i, a := range t.Args { + if a.Type == nil || len(a.Type.Args) != 0 { + continue + } + word := strings.ToLower(a.Type.Name) + if !r.idents[word] && !containsInt(positions, i+1) { + continue + } + if out == nil { + out = t.Clone() + } + out.Args[i] = TypeArg{Label: a.Label, Ident: &word} + } + if out == nil { + return t + } + return out +} + +func containsInt(list []int, n int) bool { + for _, v := range list { + if v == n { + return true + } + } + return false +} + +// matchArgs matches a pattern's arguments against an expression's, binding +// each $n to what stands in its place and requiring a literal to be equal. +func matchArgs(pattern, args []TypeArg) (map[string]TypeArg, bool) { + bindings := map[string]TypeArg{} + for i, p := range pattern { + a := args[i] + switch { + case p.Type != nil && strings.HasPrefix(p.Type.Name, "$"): + bindings[p.Type.Name] = a + case p.Type != nil: + if a.Type == nil || !strings.EqualFold(a.Type.Name, p.Type.Name) { + return nil, false + } + case p.Int != nil: + if a.Int == nil || *a.Int != *p.Int { + return nil, false + } + case p.String != nil: + if a.String == nil || *a.String != *p.String { + return nil, false + } + case p.Ident != nil: + if a.Ident == nil || *a.Ident != *p.Ident { + return nil, false + } + default: + return nil, false + } + } + return bindings, true +} + +// substitute fills a template's $n arguments from the bindings. +func substitute(template *TypeExpr, bindings map[string]TypeArg) *TypeExpr { + out := template.Clone() + for i, a := range out.Args { + if a.Type != nil && strings.HasPrefix(a.Type.Name, "$") { + if bound, ok := bindings[a.Type.Name]; ok { + label := a.Label + out.Args[i] = bound + if label != "" { + out.Args[i].Label = label + } + } + } else if a.Type != nil { + out.Args[i].Type = substitute(a.Type, bindings) + } + } + return out +} diff --git a/internal/core/schema/schema.go b/internal/core/schema/schema.go new file mode 100644 index 0000000..e96d8db --- /dev/null +++ b/internal/core/schema/schema.go @@ -0,0 +1,570 @@ +package schema + +import ( + "fmt" + "strings" + + "github.com/sqlc-dev/sqlc/internal/core" + "github.com/sqlc-dev/sqlc/internal/core/analyzer" + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +func Apply(cat *core.Catalog, n ast.Node) error { + switch v := n.(type) { + case nil: + return nil + case *ast.RawStmt: + return Apply(cat, v.Stmt) + case *ast.List: + for _, it := range v.Items { + if err := Apply(cat, it); err != nil { + return err + } + } + return nil + case *ast.CreateTableStmt: + return applyCreateTable(cat, v) + case *ast.DropTableStmt: + return applyDropTable(cat, v) + case *ast.CreateEnumStmt: + return applyCreateEnum(cat, v) + case *ast.CreateDomainStmt: + return applyCreateDomain(cat, v) + case *ast.CompositeTypeStmt: + return applyCompositeType(cat, v) + case *ast.CreateRangeStmt: + return applyCreateRange(cat, v) + case *ast.CreateExtensionStmt: + if v.Extname == nil { + return nil + } + return cat.LoadExtension(*v.Extname) + case *ast.CreateFunctionStmt: + return applyCreateFunction(cat, v) + case *ast.AlterTableStmt: + return applyAlterTable(cat, v) + case *ast.RenameColumnStmt: + return applyRenameColumn(cat, v) + case *ast.RenameTableStmt: + return applyRenameTable(cat, v) + case *ast.ViewStmt: + return applyView(cat, v.View, v.Aliases, v.Query, v.Replace) + case *ast.CreateTableAsStmt: + if v.Into == nil { + return nil + } + return applyView(cat, v.Into.Rel, v.Into.ColNames, v.Query, false) + } + return nil +} + +// applyView records a view, or a table created from a query, as a relation +// whose columns are the ones its query selects. +func applyView(cat *core.Catalog, rel *ast.RangeVar, aliases *ast.List, query ast.Node, replace bool) error { + if rel == nil || rel.Relname == nil { + return fmt.Errorf("create view with nil name") + } + name := *rel.Relname + schema := "" + if rel.Schemaname != nil { + schema = *rel.Schemaname + } + nsOID, err := resolveOrCreateNamespace(cat, schema) + if err != nil { + return err + } + if existing, err := cat.ClassOID(nsOID, name); err == nil { + if !replace { + return fmt.Errorf("relation %q already exists", name) + } + if err := cat.DropClass(existing); err != nil { + return err + } + } + + sel, ok := query.(*ast.SelectStmt) + if !ok { + return fmt.Errorf("view %q: unsupported query %T", name, query) + } + res, err := analyzer.Prepare(cat, sel) + if err != nil { + return fmt.Errorf("view %q: %w", name, err) + } + + classOID, err := cat.CreateClass(nsOID, name, "v") + if err != nil { + return err + } + names := listStrings(aliases) + for i, col := range res.Columns { + colName := col.Name + if i < len(names) { + colName = names[i] + } + typeOID := col.TypeOID + if typeOID == 0 { + typeOID, err = cat.ResolveTypeName("any") + if err != nil { + return err + } + } + if err := cat.CreateAttributeSpec(core.AttributeSpec{ + ClassOID: classOID, + Name: colName, + TypeOID: typeOID, + Num: i + 1, + NotNull: col.NotNull, + DeclType: col.DataType, + }); err != nil { + return fmt.Errorf("view %s.%s: %w", name, colName, err) + } + } + return nil +} + +func listStrings(l *ast.List) []string { + if l == nil { + return nil + } + out := make([]string, 0, len(l.Items)) + for _, item := range l.Items { + if s, ok := item.(*ast.String); ok { + out = append(out, s.Str) + } + } + return out +} + +func applyCreateTable(cat *core.Catalog, stmt *ast.CreateTableStmt) error { + if stmt.Name == nil { + return fmt.Errorf("create table with nil name") + } + // A virtual table's module is the dialect's word for the extension it + // needs, the way CREATE EXTENSION is PostgreSQL's. + if stmt.Using != "" { + if err := cat.LoadExtension(stmt.Using); err != nil { + return err + } + } + nsOID, err := resolveOrCreateNamespace(cat, stmt.Name.Schema) + if err != nil { + return err + } + if _, err := cat.ClassOID(nsOID, stmt.Name.Name); err == nil { + if stmt.IfNotExists { + return nil + } + return fmt.Errorf("relation %q already exists", stmt.Name.Name) + } + classOID, err := cat.CreateClass(nsOID, stmt.Name.Name, "r") + if err != nil { + return err + } + for i, col := range stmt.Cols { + if col == nil || col.TypeName == nil { + return fmt.Errorf("column %d on %q: missing type", i+1, stmt.Name.Name) + } + typeOID, err := columnTypeOID(cat, col) + if err != nil { + return fmt.Errorf("column %s.%s: %w", stmt.Name.Name, col.Colname, err) + } + if err := cat.CreateAttributeSpec(core.AttributeSpec{ + ClassOID: classOID, + Name: col.Colname, + TypeOID: typeOID, + Num: i + 1, + NotNull: col.IsNotNull || col.PrimaryKey || typeNotNull(cat, typeOID), + IsPrimaryKey: col.PrimaryKey, + DeclType: declType(col.TypeName), + Hidden: col.IsHidden, + }); err != nil { + return fmt.Errorf("attr %s.%s: %w", stmt.Name.Name, col.Colname, err) + } + } + return nil +} + +func applyDropTable(cat *core.Catalog, stmt *ast.DropTableStmt) error { + for _, tn := range stmt.Tables { + if tn == nil { + continue + } + nsOID, err := cat.NamespaceOID(nsName(tn.Schema)) + if err != nil { + if stmt.IfExists { + continue + } + return err + } + classOID, err := cat.ClassOID(nsOID, tn.Name) + if err != nil { + if stmt.IfExists { + continue + } + return fmt.Errorf("drop table %q: %w", tn.Name, err) + } + if err := cat.DropClass(classOID); err != nil { + return fmt.Errorf("drop table %q: %w", tn.Name, err) + } + } + return nil +} + +func applyAlterTable(cat *core.Catalog, stmt *ast.AlterTableStmt) error { + table := stmt.Table + if table == nil && stmt.Relation != nil { + table = rangeVarTableName(stmt.Relation) + } + classOID, err := lookupClass(cat, table) + if err != nil { + if stmt.MissingOk { + return nil + } + return err + } + for _, item := range listItems(stmt.Cmds) { + cmd, ok := item.(*ast.AlterTableCmd) + if !ok { + continue + } + switch cmd.Subtype { + case ast.AT_AddColumn: + if cmd.Def == nil { + continue + } + typeOID, err := columnTypeOID(cat, cmd.Def) + if err != nil { + return err + } + num, err := cat.NextAttributeNum(classOID) + if err != nil { + return err + } + if err := cat.CreateAttributeSpec(core.AttributeSpec{ + ClassOID: classOID, + Name: cmd.Def.Colname, + TypeOID: typeOID, + Num: num, + NotNull: cmd.Def.IsNotNull || cmd.Def.PrimaryKey || typeNotNull(cat, typeOID), + IsPrimaryKey: cmd.Def.PrimaryKey, + DeclType: declType(cmd.Def.TypeName), + }); err != nil { + return err + } + case ast.AT_DropColumn: + if cmd.Name == nil { + continue + } + if err := cat.DropAttribute(classOID, *cmd.Name); err != nil { + return err + } + case ast.AT_AlterColumnType: + if cmd.Def == nil { + continue + } + name := cmd.Def.Colname + if cmd.Name != nil && *cmd.Name != "" { + name = *cmd.Name + } + typeOID, err := columnTypeOID(cat, cmd.Def) + if err != nil { + return err + } + if err := cat.SetAttributeType(classOID, name, typeOID, declType(cmd.Def.TypeName)); err != nil { + return err + } + // An engine that reports a column's whole new definition also + // reports whether it still accepts NULL. + if cmd.Def.IsNotNull { + if err := cat.SetAttributeNotNull(classOID, name, true); err != nil { + return err + } + } + case ast.AT_SetNotNull, ast.AT_DropNotNull: + if cmd.Name == nil { + continue + } + if err := cat.SetAttributeNotNull(classOID, *cmd.Name, cmd.Subtype == ast.AT_SetNotNull); err != nil { + return err + } + } + } + return nil +} + +func applyRenameColumn(cat *core.Catalog, stmt *ast.RenameColumnStmt) error { + if stmt.Col == nil || stmt.NewName == nil { + return nil + } + classOID, err := lookupClass(cat, stmt.Table) + if err != nil { + if stmt.MissingOk { + return nil + } + return err + } + // Engines report the column either as a field list or as a bare name. + name := stmt.Col.Name + if names := listStrings(stmt.Col.Fields); len(names) > 0 { + name = names[len(names)-1] + } + if name == "" { + return nil + } + return cat.RenameAttribute(classOID, name, *stmt.NewName) +} + +func applyRenameTable(cat *core.Catalog, stmt *ast.RenameTableStmt) error { + if stmt.NewName == nil { + return nil + } + classOID, err := lookupClass(cat, stmt.Table) + if err != nil { + if stmt.MissingOk { + return nil + } + return err + } + return cat.RenameClass(classOID, *stmt.NewName) +} + +func lookupClass(cat *core.Catalog, table *ast.TableName) (int64, error) { + if table == nil { + return 0, fmt.Errorf("missing table name") + } + nsOID, err := cat.NamespaceOID(nsName(table.Schema)) + if err != nil { + return 0, err + } + return cat.ClassOID(nsOID, table.Name) +} + +func rangeVarTableName(rv *ast.RangeVar) *ast.TableName { + tn := &ast.TableName{} + if rv.Schemaname != nil { + tn.Schema = *rv.Schemaname + } + if rv.Relname != nil { + tn.Name = *rv.Relname + } + return tn +} + +func listItems(l *ast.List) []ast.Node { + if l == nil { + return nil + } + return l.Items +} + +// applyCreateEnum records an enum as a type whose arguments are its labels, +// in order, the way pg_enum keeps them. +func applyCreateEnum(cat *core.Catalog, stmt *ast.CreateEnumStmt) error { + if stmt.TypeName == nil { + return fmt.Errorf("create type with nil name") + } + name := declaredTypeName(stmt.TypeName) + if name == "" { + return fmt.Errorf("create type with empty name") + } + if cat.TypeDeclared(name) { + return nil + } + var labels []core.TypeArg + for _, label := range listStrings(stmt.Vals) { + l := label + labels = append(labels, core.TypeArg{String: &l}) + } + _, err := cat.CreateTypeWithArgs(core.TypeSpec{Name: name, Typtype: "e", Category: "E"}, labels) + return err +} + +// applyCreateDomain records a domain: a type of its own that stands on its +// base, which is what it resolves through, and that may forbid NULL. +func applyCreateDomain(cat *core.Catalog, stmt *ast.CreateDomainStmt) error { + name := strings.ToLower(strings.Join(listStrings(stmt.Domainname), ".")) + if name == "" || stmt.TypeName == nil { + return fmt.Errorf("create domain: missing name or type") + } + if cat.TypeDeclared(name) { + return nil + } + baseOID, err := cat.ResolveType(stmt.TypeName) + if err != nil { + return fmt.Errorf("domain %q: %w", name, err) + } + base, err := cat.LookupType(baseOID) + if err != nil { + return err + } + notNull := false + for _, item := range listItems(stmt.Constraints) { + if con, ok := item.(*ast.Constraint); ok && con.Contype == ast.ConstrTypeNotNull { + notNull = true + } + } + _, err = cat.CreateTypeWithArgs(core.TypeSpec{ + Name: name, + Typtype: "d", + Category: base.Category, + BaseOID: baseOID, + NotNull: notNull, + }, nil) + return err +} + +// applyCompositeType records a composite type as a type whose arguments are +// its fields, labelled by name. +func applyCompositeType(cat *core.Catalog, stmt *ast.CompositeTypeStmt) error { + if stmt.TypeName == nil { + return fmt.Errorf("create type with nil name") + } + name := declaredTypeName(stmt.TypeName) + if name == "" { + return fmt.Errorf("create type with empty name") + } + if cat.TypeDeclared(name) { + return nil + } + var fields []core.TypeArg + for _, item := range listItems(stmt.Coldeflist) { + col, ok := item.(*ast.ColumnDef) + if !ok || col.TypeName == nil { + continue + } + t := core.ColumnTypeExpr(col) + if t == nil { + continue + } + fields = append(fields, core.TypeArg{Label: col.Colname, Type: t}) + } + _, err := cat.CreateTypeWithArgs(core.TypeSpec{Name: name, Typtype: "c", Category: "C"}, fields) + return err +} + +// applyCreateRange records a range type over its subtype, which is what a +// bound of it has. +func applyCreateRange(cat *core.Catalog, stmt *ast.CreateRangeStmt) error { + name := strings.ToLower(strings.Join(listStrings(stmt.TypeName), ".")) + if name == "" { + return fmt.Errorf("create type with empty name") + } + if cat.TypeDeclared(name) { + return nil + } + spec := core.TypeSpec{Name: name, Typtype: "r", Category: "R"} + for _, item := range listItems(stmt.Params) { + def, ok := item.(*ast.DefElem) + if !ok || def.Defname == nil || *def.Defname != "subtype" { + continue + } + tn, ok := def.Arg.(*ast.TypeName) + if !ok { + continue + } + oid, err := cat.ResolveType(tn) + if err != nil { + return fmt.Errorf("range %q: %w", name, err) + } + spec.ElementOID = oid + } + _, err := cat.CreateTypeWithArgs(spec, nil) + return err +} + +// declaredTypeName is the name a CREATE TYPE gives, qualified by its schema +// when it names one. +func declaredTypeName(tn *ast.TypeName) string { + t := core.TypeExprOfTypeName(tn) + if t == nil { + return "" + } + if tn.Schema != "" && !strings.Contains(t.Name, ".") { + return strings.ToLower(tn.Schema) + "." + t.Name + } + return t.Name +} + +func applyCreateFunction(cat *core.Catalog, stmt *ast.CreateFunctionStmt) error { + // A procedure returns nothing, so there is no result for a query to + // select and nothing worth recording. + if stmt.Func == nil || stmt.Func.Name == "" || stmt.ReturnType == nil { + return nil + } + returnOID, err := cat.ResolveType(stmt.ReturnType) + if err != nil { + return fmt.Errorf("function %q: %w", stmt.Func.Name, err) + } + var args []core.ProcArg + if stmt.Params != nil { + for _, item := range stmt.Params.Items { + p, ok := item.(*ast.FuncParam) + if !ok { + continue + } + switch p.Mode { + case ast.FuncParamOut, ast.FuncParamTable: + continue + } + argOID, err := cat.ResolveType(p.Type) + if err != nil { + return fmt.Errorf("function %q: %w", stmt.Func.Name, err) + } + arg := core.ProcArg{TypeOID: argOID, HasDefault: p.DefExpr != nil} + if p.Name != nil { + arg.Name = *p.Name + } + args = append(args, arg) + } + } + _, err = cat.CreateProc(core.ProcSpec{ + Name: stmt.Func.Name, + ReturnTypeOID: returnOID, + ReturnSet: stmt.ReturnType != nil && stmt.ReturnType.Setof, + Args: args, + }) + return err +} + +func nsName(schema string) string { + if schema == "" { + return "public" + } + return schema +} + +func resolveOrCreateNamespace(cat *core.Catalog, schema string) (int64, error) { + name := nsName(schema) + if oid, err := cat.NamespaceOID(name); err == nil { + return oid, nil + } + return cat.CreateNamespace(name) +} + +// typeNotNull reports whether a column of the type can never be NULL +// because the type itself says so, as a domain declared NOT NULL does. +func typeNotNull(cat *core.Catalog, typeOID int64) bool { + info, err := cat.LookupType(typeOID) + return err == nil && info.NotNull +} + +// columnTypeOID interns a column's type and returns its row. +func columnTypeOID(cat *core.Catalog, col *ast.ColumnDef) (int64, error) { + t := core.ColumnTypeExpr(col) + if t == nil { + return 0, fmt.Errorf("missing type name") + } + return cat.ResolveTypeExpr(t) +} + +// declType is the type as the schema spelled it: an engine that folds or +// reduces the name for the catalog keeps the full spelling alongside. +func declType(tn *ast.TypeName) string { + if tn == nil { + return "" + } + if tn.Spelling != "" { + return tn.Spelling + } + return tn.Name +} diff --git a/internal/core/seed/extension.go b/internal/core/seed/extension.go new file mode 100644 index 0000000..c0f3689 --- /dev/null +++ b/internal/core/seed/extension.go @@ -0,0 +1,134 @@ +package seed + +import ( + "fmt" + "io/fs" + "path" + "strings" + + "github.com/sqlc-dev/sqlc/internal/core" +) + +// applyExtension applies the extension directory dir, relative to the +// dialect, to a catalog that has already been seeded. Unlike the dialect's +// own seed, an extension lands in a catalog full of types, so everything it +// names is resolved against what is there before being created. +func applyExtension(cat *core.Catalog, fsys fs.FS, dir string) error { + name := path.Base(dir) + sub, err := fs.Sub(fsys, dir) + if err != nil { + return fmt.Errorf("seed: extension %s: %w", name, err) + } + e := &extension{cat: cat} + if err := stream(sub, TypesFile, e.addType); err != nil { + return fmt.Errorf("extension %s: %w", name, err) + } + if err := stream(sub, FunctionsFile, e.addFunction); err != nil { + return fmt.Errorf("extension %s: %w", name, err) + } + return nil +} + +type extension struct { + cat *core.Catalog +} + +// addType registers a type the extension defines. The type joins the +// dialect's rules the way a type declared by a schema does: it gains the +// comparison operators, and implicit casts to the types of its category when +// the dialect's seed declared that category mutually castable. +func (e *extension) addType(t Type) error { + for _, name := range append([]string{t.Name}, t.Aliases...) { + if _, err := e.cat.TypeOID(name); err == nil { + // The dialect, or an earlier extension, already ships this type. + continue + } + oid, err := e.cat.CreateUserType(name, t.Category) + if err != nil { + return fmt.Errorf("type %q: %w", name, err) + } + if err := e.categoryCasts(oid, t.Category); err != nil { + return fmt.Errorf("type %q: %w", name, err) + } + } + return nil +} + +// categoryCasts makes a new type implicitly castable to and from the types +// already in its category, under the same rule the dialect's seed applied to +// the types it was born with. +func (e *extension) categoryCasts(oid int64, category string) error { + categories, err := e.cat.DialectFlag(e.cat.SeededDialectOID(), core.FlagCastCategories) + if err != nil || categories == "" { + return err + } + if categories != "*" && !strings.Contains(categories, category) { + return nil + } + peers, err := e.cat.TypeOIDsInCategory(category) + if err != nil { + return err + } + for _, peer := range peers { + if peer == oid { + continue + } + for _, cast := range [][2]int64{{oid, peer}, {peer, oid}} { + if err := e.cat.CreateCast(core.CastSpec{ + SourceTypeOID: cast[0], + TargetTypeOID: cast[1], + Context: "i", + DialectOID: e.cat.SeededDialectOID(), + }); err != nil { + return err + } + } + } + return nil +} + +func (e *extension) addFunction(fn Function) error { + returnOID, err := e.funcType(fn.Returns) + if err != nil { + return fmt.Errorf("function %q: %w", fn.Name, err) + } + args := make([]core.ProcArg, 0, len(fn.Args)) + for _, a := range fn.Args { + // An out or table parameter is part of the result, not the call. + switch a.Mode { + case "o", "t": + continue + } + argOID, err := e.funcType(a.Type) + if err != nil { + return fmt.Errorf("function %q: %w", fn.Name, err) + } + args = append(args, core.ProcArg{ + Name: a.Name, + TypeOID: argOID, + Mode: a.Mode, + HasDefault: a.HasDefault, + }) + } + _, err = e.cat.CreateProc(core.ProcSpec{ + Name: fn.Name, + DialectOID: e.cat.SeededDialectOID(), + Kind: fn.Kind, + ReturnTypeOID: returnOID, + ReturnNullable: fn.Nullable, + Args: args, + }) + if err != nil { + return fmt.Errorf("function %q: %w", fn.Name, err) + } + return nil +} + +// funcType resolves a type a function signature names, registering the ones +// no seed bothered to list the way the dialect's own function list does. +func (e *extension) funcType(name string) (int64, error) { + if name == "" { + return 0, nil + } + return e.cat.ResolvePseudoTypeExpr(core.ParseTypeExpr(name)) +} diff --git a/internal/core/seed/seed.go b/internal/core/seed/seed.go new file mode 100644 index 0000000..e14f17a --- /dev/null +++ b/internal/core/seed/seed.go @@ -0,0 +1,965 @@ +// Package seed builds a core catalog for a SQL dialect from a declarative +// description of its type system: the types it defines, the operators and +// casts between them, and the functions it ships with. +// +// A dialect is a directory which each engine package embeds and hands to +// Dialect: +// +// dialect.json what the dialect is called and the rules it is built by +// types.jsonl the types it defines +// operators.jsonl operator overloads beyond the ones the rules generate +// casts.jsonl casts beyond the ones the rules generate +// functions.jsonl the functions it ships with +// relations.jsonl the system tables and views it ships with +// +// The lists are JSONL — one record per line — and are applied as they are +// read, so a dialect whose function list runs to thousands of entries is never +// held in memory as a whole. Any of the lists may be left out. +// +// A dialect may also hold an extensions/ directory with one directory per +// extension, each a smaller bundle of the same files, applied when a schema +// says CREATE EXTENSION — or, for a dialect whose settings map virtual table +// modules to extensions, CREATE VIRTUAL TABLE ... USING. +package seed + +import ( + "bufio" + "encoding/json" + "errors" + "fmt" + "io" + "io/fs" + "path" + "slices" + "strconv" + "strings" + + "github.com/sqlc-dev/sqlc/internal/core" + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/catalog" +) + +// The files a dialect directory is made of. +const ( + SettingsFile = "dialect.json" + TypesFile = "types.jsonl" + OperatorsFile = "operators.jsonl" + CastsFile = "casts.jsonl" + FunctionsFile = "functions.jsonl" + RelationsFile = "relations.jsonl" +) + +// ExtensionsDir is the directory under a dialect holding one directory per +// extension the dialect knows. +const ExtensionsDir = "extensions" + +// Settings is dialect.json: what the dialect is called and the rules that +// generate its operators and casts. +type Settings struct { + // Dialect is the name recorded in the catalog, e.g. "postgresql". + Dialect string `json:"dialect"` + + // Const names the type each kind of literal takes on, keyed by the + // core.Const* constants. Kinds left out fall back to PostgreSQL's names. + Const map[string]string `json:"const,omitempty"` + + // Bool names the type comparisons return. + Bool string `json:"bool,omitempty"` + + // Limit names the type a LIMIT or OFFSET count has, which is what a + // placeholder in one is typed as. Unset, it is the integer literal's. + Limit string `json:"limit,omitempty"` + + // Untyped names the type a placeholder takes when nothing in the query + // constrains it. Unset, such a placeholder stays untyped. + Untyped string `json:"untyped,omitempty"` + + // PropagateNullable makes a function's result nullable whenever one of + // its arguments is, the way ClickHouse's ordinary functions behave, + // unless the function is seeded as never null. + PropagateNullable bool `json:"propagate_nullable,omitempty"` + + // QualifyDuplicateColumns names a result column after its relation when + // an earlier result column from another relation has the same name, as + // ClickHouse names the second id of a join e.id. + QualifyDuplicateColumns bool `json:"qualify_duplicate_columns,omitempty"` + + // Comparison operators are registered as (T, T) -> Bool for every type in + // ComparisonCategories. + Comparison []string `json:"comparison,omitempty"` + ComparisonCategories string `json:"comparison_categories,omitempty"` + + // Arithmetic operators are registered as (T, T) -> T for every type in + // ArithmeticCategories. + Arithmetic []string `json:"arithmetic,omitempty"` + ArithmeticCategories string `json:"arithmetic_categories,omitempty"` + + // CastCategories lists the categories whose types are all implicitly + // castable to one another, so that an operator on two spellings of the + // same kind of value resolves. "*" makes every seeded type implicitly + // castable to every other, for dialects that compare across categories. + CastCategories string `json:"cast_categories,omitempty"` + + // Modules names the extension a virtual table module belongs to, for a + // dialect whose schemas say CREATE VIRTUAL TABLE ... USING rather than + // CREATE EXTENSION: SQLite's fts5 module comes with the functions its + // enable_fts5 compile option adds. + Modules map[string]string `json:"modules,omitempty"` + + // DefaultSchema names the schema a dialect puts an unqualified object + // in when it is not the catalog's own default: SQL Server's dbo, + // DuckDB's main. A type in it is reported unqualified. + DefaultSchema string `json:"default_schema,omitempty"` + + // Rewrites are what the dialect does to a type before storing it, in + // order: the first whose pattern matches applies. A pattern's $1, $2 + // bind whatever stands there, the template is what the match becomes, + // and Where bounds a binding, as "$1 <= 24" does. + Rewrites []Rewrite `json:"rewrites,omitempty"` + + // Idents are the words that are identifiers wherever they stand as a + // type argument, such as the max of nvarchar(max), and IdentArgs the + // argument positions, counted from one, that are identifiers in a + // family, such as the first of SimpleAggregateFunction(sum, UInt64). + Idents []string `json:"idents,omitempty"` + IdentArgs map[string][]int `json:"ident_args,omitempty"` + + // Affinity is the rule a type family the schema declares and the seed + // does not list stands on, in order: the first whose words the name + // contains names the base, and one with no words is the default. + Affinity []Affinity `json:"affinity,omitempty"` + + // Alias says what an alias in types.jsonl is. "canonical", the default, + // makes it another spelling of the type, which a column declared with + // it is reported as, the way PostgreSQL reports int as integer. "base" + // makes it a type of its own that stands on the one it aliases, which + // is how SQLite keeps a column's declared spelling while comparing it + // by its affinity. + Alias string `json:"alias,omitempty"` + + // fsys is the dialect directory the settings were read from. + fsys fs.FS +} + +// Rewrite is one rewrite of a type expression. +type Rewrite struct { + From string `json:"from"` + To string `json:"to"` + Where string `json:"where,omitempty"` +} + +// Affinity is one step of the rule an unseeded family stands on. +type Affinity struct { + Contains []string `json:"contains,omitempty"` + Type string `json:"type"` +} + +// Type is a type family the dialect defines. Aliases are other spellings of +// it that a schema may use in a column definition; each becomes a row that +// points at the type, as an alias of it or as a type standing on it, +// depending on the dialect's Alias setting. +type Type struct { + Name string `json:"name"` + Category string `json:"category"` + Aliases []string `json:"aliases,omitempty"` + // Base names the family this one stands on, which must be listed + // before it: MySQL's bigint unsigned is a type of its own that + // resolves as a bigint where nothing takes it as itself. + Base string `json:"base,omitempty"` +} + +// Operator is a single operator overload. +type Operator struct { + Name string `json:"name"` + Left string `json:"left"` + Right string `json:"right"` + Result string `json:"result"` +} + +// Cast is a single cast between two types. Context is 'i'mplicit, 'a'ssignment +// or 'e'xplicit. +type Cast struct { + Source string `json:"source"` + Target string `json:"target"` + Context string `json:"context,omitempty"` +} + +// Function is a function the dialect ships with. Kind is 'f'unction, +// 'a'ggregate, 'w'indow or 'p'rocedure. +type Function struct { + Name string `json:"name,omitempty"` + Kind string `json:"kind,omitempty"` + Args []Arg `json:"args,omitempty"` + // Returns names the result type, or "$1", "$2"... for the type of that + // argument, or an expression over the arguments — Decimal(18, $2) — + // for a result that depends on an argument's value. + Returns string `json:"returns"` + Nullable bool `json:"nullable,omitempty"` + // NeverNull marks a result that is never NULL even when an argument + // is, in a dialect that propagates nullability. + NeverNull bool `json:"never_null,omitempty"` +} + +// Relation is a table or view the dialect ships with, such as one of +// PostgreSQL's system catalogs. Kind is 'r' for a table or 'v' for a view, and +// defaults to a table. +type Relation struct { + // Catalog is the database the relation belongs to, which PostgreSQL + // reports for its own schemas and which the legacy catalog carries. + Catalog string `json:"catalog,omitempty"` + Schema string `json:"schema"` + Name string `json:"name"` + Kind string `json:"kind,omitempty"` + Columns []Column `json:"columns"` +} + +// Column is one of a relation's columns. +type Column struct { + Name string `json:"name"` + Type string `json:"type"` + NotNull bool `json:"not_null,omitempty"` + Array bool `json:"array,omitempty"` + Length int `json:"length,omitempty"` +} + +// Arg is one of a function's parameters. Mode is 'i'n, 'o'ut, 'b'oth, 't'able +// or 'v'ariadic, and defaults to in. +type Arg struct { + Name string `json:"name,omitempty"` + Type string `json:"type"` + Mode string `json:"mode,omitempty"` + HasDefault bool `json:"has_default,omitempty"` +} + +// Dialect returns the catalog option that seeds the dialect described by the +// JSONL files in dir. A dialect that ships extension data — a directory per +// extension under extensions/ — also has CREATE EXTENSION wired up to it. +func Dialect(fsys fs.FS, dir string) core.Option { + return core.WithSeed(func(cat *core.Catalog) error { + sub, err := fs.Sub(fsys, dir) + if err != nil { + return fmt.Errorf("seed: %s: %w", dir, err) + } + settings, err := loadSettings(sub) + if err != nil { + return err + } + if err := apply(cat, sub, settings); err != nil { + return err + } + cat.SetExtensionLoader(func(name string) error { + dir, ok := settings.extensionDir(name) + if !ok { + // An extension sqlc has no data for adds nothing, the way + // the legacy catalog has always treated one. + return nil + } + return applyExtension(cat, sub, dir) + }) + return nil + }) +} + +// ExtensionDir resolves what a schema named — an extension, or a virtual +// table module the dialect's settings map to one — to the extension's +// directory under dir, reporting whether the dialect has data for it. +func ExtensionDir(fsys fs.FS, dir, name string) (string, bool) { + sub, err := fs.Sub(fsys, dir) + if err != nil { + return "", false + } + settings, err := loadSettings(sub) + if err != nil { + return "", false + } + rel, ok := settings.extensionDir(name) + if !ok { + return "", false + } + return path.Join(dir, rel), true +} + +// extensionDir is the directory of the extension a name refers to, +// relative to the dialect, if the dialect ships one. +func (s Settings) extensionDir(name string) (string, bool) { + if ext, ok := s.Modules[strings.ToLower(name)]; ok { + name = ext + } + dir := path.Join(ExtensionsDir, name) + if _, err := fs.Stat(s.fsys, dir); err != nil { + return "", false + } + return dir, true +} + +func apply(cat *core.Catalog, fsys fs.FS, settings Settings) error { + var err error + b := &builder{ + cat: cat, + settings: settings, + oids: map[string]int64{}, + namespaces: map[string]int64{}, + seenCasts: map[[2]int64]bool{}, + } + if b.dialectOID, err = cat.CreateDialect(settings.Dialect); err != nil { + return err + } + + // Types come first: everything else names them. + if err := stream(fsys, TypesFile, b.addType); err != nil { + return err + } + // Every dialect has arrays, whether or not its list names the family, + // and a lookup of one against the cached catalog cannot add it then. + if _, err := b.createType(core.ArrayTypeName, "A", 0); err != nil { + return err + } + if err := b.consts(); err != nil { + return err + } + if err := b.rules(); err != nil { + return err + } + if err := b.categoryOperators(); err != nil { + return err + } + if err := stream(fsys, OperatorsFile, b.addOperator); err != nil { + return err + } + if err := stream(fsys, CastsFile, b.addCast); err != nil { + return err + } + if err := b.categoryCasts(); err != nil { + return err + } + if err := stream(fsys, FunctionsFile, b.addFunction); err != nil { + return err + } + return stream(fsys, RelationsFile, b.addRelation) +} + +func loadSettings(fsys fs.FS) (Settings, error) { + f, err := fsys.Open(SettingsFile) + if err != nil { + return Settings{}, fmt.Errorf("seed: %w", err) + } + defer f.Close() + + dec := json.NewDecoder(bufio.NewReader(f)) + dec.DisallowUnknownFields() + var settings Settings + if err := dec.Decode(&settings); err != nil { + return Settings{}, fmt.Errorf("seed: %s: %w", SettingsFile, err) + } + if settings.Dialect == "" { + return Settings{}, fmt.Errorf("seed: %s: dialect has no name", SettingsFile) + } + settings.fsys = fsys + return settings, nil +} + +// stream decodes name a record at a time, handing each to fn as it is read. A +// file that is not there contributes nothing, so a dialect only writes the +// files it needs. An unknown field is an error rather than something to +// ignore, so that a misspelled key is caught where it is written. +func stream[T any](fsys fs.FS, name string, fn func(T) error) error { + f, err := fsys.Open(name) + if errors.Is(err, fs.ErrNotExist) { + return nil + } + if err != nil { + return fmt.Errorf("seed: %w", err) + } + defer f.Close() + + dec := json.NewDecoder(bufio.NewReader(f)) + dec.DisallowUnknownFields() + for record := 1; ; record++ { + var rec T + if err := dec.Decode(&rec); err != nil { + if errors.Is(err, io.EOF) { + return nil + } + return fmt.Errorf("seed: %s: record %d: %w", name, record, err) + } + if err := fn(rec); err != nil { + return fmt.Errorf("seed: %s: record %d: %w", name, record, err) + } + } +} + +// Functions streams a dialect's functions into the form the engine catalogs +// use. It is how an engine whose standard library lives in functions.jsonl +// hands that library to the rest of sqlc. +func Functions(fsys fs.FS, dir string) ([]*catalog.Function, error) { + sub, err := fs.Sub(fsys, dir) + if err != nil { + return nil, fmt.Errorf("seed: %s: %w", dir, err) + } + var out []*catalog.Function + err = stream(sub, FunctionsFile, func(fn Function) error { + args := make([]*catalog.Argument, 0, len(fn.Args)) + for _, a := range fn.Args { + args = append(args, &catalog.Argument{ + Name: a.Name, + Type: &ast.TypeName{Name: a.Type}, + HasDefault: a.HasDefault, + Mode: argMode(a.Mode), + }) + } + out = append(out, &catalog.Function{ + Name: fn.Name, + Args: args, + ReturnType: &ast.TypeName{Name: fn.Returns}, + ReturnTypeNullable: fn.Nullable, + }) + return nil + }) + if err != nil { + return nil, err + } + return out, nil +} + +// Relations streams the relations a dialect ships with in the named schema +// into the form the engine catalogs use. +func Relations(fsys fs.FS, dir, schema string) ([]*catalog.Table, error) { + sub, err := fs.Sub(fsys, dir) + if err != nil { + return nil, fmt.Errorf("seed: %s: %w", dir, err) + } + var out []*catalog.Table + err = stream(sub, RelationsFile, func(rel Relation) error { + if rel.Schema != schema { + return nil + } + table := &catalog.Table{ + Rel: &ast.TableName{Catalog: rel.Catalog, Schema: rel.Schema, Name: rel.Name}, + Columns: make([]*catalog.Column, 0, len(rel.Columns)), + } + for _, col := range rel.Columns { + // A column's type may carry arguments, as MySQL's varchar(64) + // does; the legacy catalog holds the family and the length + // apart. + t := core.ParseTypeExpr(col.Type) + column := &catalog.Column{ + Name: col.Name, + Type: ast.TypeName{Name: t.Name}, + IsNotNull: col.NotNull, + IsArray: col.Array, + } + if col.Array { + column.ArrayDims = 1 + } + if col.Length > 0 { + length := col.Length + column.Length = &length + } else if len(t.Args) > 0 && t.Args[0].Int != nil { + length := int(*t.Args[0].Int) + column.Length = &length + } + table.Columns = append(table.Columns, column) + } + out = append(out, table) + return nil + }) + if err != nil { + return nil, err + } + return out, nil +} + +// argModes maps the mode a record carries to the one the catalog uses. The +// letters are PostgreSQL's, which is where the generated function lists come +// from. +var argModes = map[string]ast.FuncParamMode{ + "i": ast.FuncParamIn, + "o": ast.FuncParamOut, + "b": ast.FuncParamInOut, + "v": ast.FuncParamVariadic, + "t": ast.FuncParamTable, + "d": ast.FuncParamDefault, +} + +func argMode(mode string) ast.FuncParamMode { + if m, ok := argModes[mode]; ok { + return m + } + return ast.FuncParamIn +} + +// ArgMode is the letter a record carries for a catalog argument mode, the +// inverse of the mapping applied when reading one. +func ArgMode(mode ast.FuncParamMode) string { + for letter, m := range argModes { + if m == mode { + return letter + } + } + return "i" +} + +type builder struct { + cat *core.Catalog + settings Settings + dialectOID int64 + + // oids maps a lowercased type spelling to the row a seed record naming + // it means, and categories records the category each family was seeded + // under, in the order they were read. + oids map[string]int64 + categories []categorized + + // namespaces maps a schema name to its OID, so that a run of relations in + // the same schema resolves it once. + namespaces map[string]int64 + + // seenCasts records the pairs already registered. The alias rules and the + // category rules overlap, and a cast pair is unique in the catalog. + seenCasts map[[2]int64]bool +} + +type categorized struct { + name string + category string +} + +func (b *builder) addType(t Type) error { + var baseOID int64 + if t.Base != "" { + oid, ok := b.oids[strings.ToLower(t.Base)] + if !ok { + return fmt.Errorf("type %q: base %q is not a type listed before it", t.Name, t.Base) + } + baseOID = oid + } + oid, err := b.createType(t.Name, t.Category, baseOID) + if err != nil { + return fmt.Errorf("type %q: %w", t.Name, err) + } + for _, alias := range t.Aliases { + if err := b.addAlias(alias, oid, t.Category); err != nil { + return fmt.Errorf("type %q: alias %q: %w", t.Name, alias, err) + } + } + return nil +} + +// addAlias registers another spelling of a type: a row that points at the +// type as its canonical form, or — for a dialect whose aliases are types of +// their own — as its base. +func (b *builder) addAlias(name string, typeOID int64, category string) error { + key := strings.ToLower(name) + if _, ok := b.oids[key]; ok { + return nil + } + spec := core.TypeSpec{Name: key, Typtype: "b", Category: category, DialectOID: b.dialectOID} + if b.settings.Alias == "base" { + spec.BaseOID = typeOID + } else { + spec.CanonicalOID = typeOID + } + oid, err := b.cat.CreateTypeSpec(spec) + if err != nil { + return err + } + // A record naming the alias means the type it stands for, unless the + // alias is a type of its own. + if b.settings.Alias == "base" { + b.oids[key] = oid + } else { + b.oids[key] = typeOID + } + return nil +} + +func (b *builder) createType(name, category string, baseOID int64) (int64, error) { + key := strings.ToLower(name) + if oid, ok := b.oids[key]; ok { + return oid, nil + } + oid, err := b.cat.CreateTypeSpec(core.TypeSpec{ + Name: key, + Typtype: "b", + Category: category, + BaseOID: baseOID, + DialectOID: b.dialectOID, + }) + if err != nil { + return 0, err + } + b.oids[key] = oid + b.categories = append(b.categories, categorized{name: key, category: category}) + return oid, nil +} + +// constKinds are the kinds of literal a dialect may name a type for. +var constKinds = []string{core.ConstInteger, core.ConstFloat, core.ConstString, core.ConstBool} + +func (b *builder) consts() error { + for kind := range b.settings.Const { + if !slices.Contains(constKinds, kind) { + return fmt.Errorf("seed %s: unknown constant kind %q, want one of %s", + b.settings.Dialect, kind, strings.Join(constKinds, ", ")) + } + } + // Written in a fixed order rather than the map's: a catalog built from the + // same dialect twice has to come out byte for byte the same, so that the + // cache stores one copy of it rather than one per run. + for _, kind := range constKinds { + name, ok := b.settings.Const[kind] + if !ok { + continue + } + if _, ok := b.oids[strings.ToLower(name)]; !ok { + return fmt.Errorf("seed %s: constant %s names unknown type %q", b.settings.Dialect, kind, name) + } + if err := b.cat.SetConstType(b.dialectOID, kind, name); err != nil { + return err + } + } + if b.settings.DefaultSchema != "" { + if err := b.cat.SetDialectFlag(b.dialectOID, core.FlagDefaultSchema, strings.ToLower(b.settings.DefaultSchema)); err != nil { + return err + } + } + for key, name := range map[string]string{ + core.FlagBoolType: b.settings.Bool, + core.FlagLimitType: b.settings.Limit, + core.FlagUntypedType: b.settings.Untyped, + } { + if name == "" { + continue + } + if _, ok := b.oids[strings.ToLower(name)]; !ok { + return fmt.Errorf("seed %s: %s names unknown type %q", b.settings.Dialect, key, name) + } + if err := b.cat.SetDialectFlag(b.dialectOID, key, name); err != nil { + return err + } + } + if b.settings.PropagateNullable { + if err := b.cat.SetDialectFlag(b.dialectOID, core.FlagPropagateNullable, "true"); err != nil { + return err + } + } + if b.settings.QualifyDuplicateColumns { + if err := b.cat.SetDialectFlag(b.dialectOID, core.FlagQualifyDuplicateColumns, "true"); err != nil { + return err + } + } + // A schema declares types the seed knows nothing about — enums, domains, + // arrays, a SQLite column typed whatever the author felt like. Recording + // the comparison operators lets the catalog give those types the same ones. + if len(b.settings.Comparison) > 0 { + if err := b.cat.SetDialectFlag(b.dialectOID, core.FlagComparisonOperators, + strings.Join(b.settings.Comparison, ",")); err != nil { + return err + } + } + // The cast categories are recorded for the same reason: a type an + // extension adds joins its category's casts. + if b.settings.CastCategories != "" { + return b.cat.SetDialectFlag(b.dialectOID, core.FlagCastCategories, b.settings.CastCategories) + } + return nil +} + +// rules records what the dialect does to a type before storing it: its +// rewrites, its identifier words and positions, and its affinity rule. +func (b *builder) rules() error { + s := b.settings + for i, rw := range s.Rewrites { + if rw.From == "" || rw.To == "" { + return fmt.Errorf("seed %s: rewrite %d needs from and to", s.Dialect, i+1) + } + if err := b.cat.AddTypeRewrite(i+1, rw.From, rw.To, rw.Where); err != nil { + return err + } + } + if len(s.Idents) > 0 { + if err := b.cat.SetDialectFlag(b.dialectOID, core.FlagIdents, strings.ToLower(strings.Join(s.Idents, ","))); err != nil { + return err + } + } + if len(s.IdentArgs) > 0 { + families := make([]string, 0, len(s.IdentArgs)) + for family := range s.IdentArgs { + families = append(families, family) + } + // In a fixed order, so the catalog comes out the same every time. + slices.Sort(families) + entries := make([]string, 0, len(families)) + for _, family := range families { + positions := make([]string, 0, len(s.IdentArgs[family])) + for _, p := range s.IdentArgs[family] { + positions = append(positions, strconv.Itoa(p)) + } + entries = append(entries, strings.ToLower(family)+":"+strings.Join(positions, ",")) + } + if err := b.cat.SetDialectFlag(b.dialectOID, core.FlagIdentArgs, strings.Join(entries, ";")); err != nil { + return err + } + } + for i, a := range s.Affinity { + oid, ok := b.oids[strings.ToLower(a.Type)] + if !ok { + return fmt.Errorf("seed %s: affinity names unknown type %q", s.Dialect, a.Type) + } + if err := b.cat.AddTypeAffinity(i+1, a.Contains, oid); err != nil { + return err + } + } + return nil +} + +func (b *builder) categoryOperators() error { + s := b.settings + boolOID, ok := b.oids[strings.ToLower(s.Bool)] + if len(s.Comparison) > 0 && !ok { + return fmt.Errorf("seed %s: comparison operators need a bool type", s.Dialect) + } + for _, t := range b.categories { + if strings.Contains(s.ComparisonCategories, t.category) { + for _, op := range s.Comparison { + if err := b.operator(op, t.name, t.name, s.Bool, boolOID); err != nil { + return err + } + } + } + if strings.Contains(s.ArithmeticCategories, t.category) { + for _, op := range s.Arithmetic { + if err := b.operator(op, t.name, t.name, t.name, b.oids[t.name]); err != nil { + return err + } + } + } + } + return nil +} + +func (b *builder) addOperator(op Operator) error { + return b.operator(op.Name, op.Left, op.Right, op.Result, 0) +} + +func (b *builder) operator(name, left, right, result string, resultOID int64) error { + leftOID, ok := b.oids[strings.ToLower(left)] + if !ok { + return fmt.Errorf("operator %q: unknown left type %q", name, left) + } + rightOID, ok := b.oids[strings.ToLower(right)] + if !ok { + return fmt.Errorf("operator %q: unknown right type %q", name, right) + } + if resultOID == 0 { + resultOID, ok = b.oids[strings.ToLower(result)] + if !ok { + return fmt.Errorf("operator %q: unknown result type %q", name, result) + } + } + _, err := b.cat.CreateOperator(core.OperatorSpec{ + Name: name, + DialectOID: b.dialectOID, + LeftTypeOID: leftOID, + RightTypeOID: rightOID, + ResultTypeOID: resultOID, + }) + return err +} + +// categoryCasts applies the rule that makes the types in a category mutually +// castable, once every type has been read. +func (b *builder) categoryCasts() error { + categories := b.settings.CastCategories + if categories == "" { + return nil + } + anyCategory := categories == "*" + for _, src := range b.categories { + if !anyCategory && !strings.Contains(categories, src.category) { + continue + } + for _, tgt := range b.categories { + if src.name == tgt.name { + continue + } + if !anyCategory && src.category != tgt.category { + continue + } + if err := b.addCast(Cast{Source: src.name, Target: tgt.name, Context: "i"}); err != nil { + return err + } + } + } + return nil +} + +func (b *builder) addCast(c Cast) error { + srcOID, ok := b.oids[strings.ToLower(c.Source)] + if !ok { + return fmt.Errorf("cast: unknown source type %q", c.Source) + } + tgtOID, ok := b.oids[strings.ToLower(c.Target)] + if !ok { + return fmt.Errorf("cast: unknown target type %q", c.Target) + } + if srcOID == tgtOID || b.seenCasts[[2]int64{srcOID, tgtOID}] { + return nil + } + b.seenCasts[[2]int64{srcOID, tgtOID}] = true + context := c.Context + if context == "" { + context = "i" + } + return b.cat.CreateCast(core.CastSpec{ + SourceTypeOID: srcOID, + TargetTypeOID: tgtOID, + Context: context, + DialectOID: b.dialectOID, + }) +} + +func (b *builder) addFunction(fn Function) error { + returns, template := returnTemplate(fn.Returns) + returnOID, err := b.funcType(returns) + if err != nil { + return fmt.Errorf("function %q: %w", fn.Name, err) + } + args := make([]core.ProcArg, 0, len(fn.Args)) + for _, a := range fn.Args { + // An out or table parameter is part of the result, not the call. + switch a.Mode { + case "o", "t": + continue + } + argOID, err := b.funcType(a.Type) + if err != nil { + return fmt.Errorf("function %q: %w", fn.Name, err) + } + args = append(args, core.ProcArg{ + Name: a.Name, + TypeOID: argOID, + Mode: a.Mode, + HasDefault: a.HasDefault, + }) + } + _, err = b.cat.CreateProc(core.ProcSpec{ + Name: fn.Name, + DialectOID: b.dialectOID, + Kind: fn.Kind, + ReturnTypeOID: returnOID, + ReturnNullable: fn.Nullable, + NeverNull: fn.NeverNull, + ReturnTemplate: template, + Args: args, + }) + if err != nil { + return fmt.Errorf("function %q: %w", fn.Name, err) + } + return nil +} + +// returnTemplate splits a function's Returns into the type the catalog +// records and the template it keeps: a result spelled over the arguments, +// as Decimal(18, $2) is, records its family and keeps the whole spelling +// to fill in at each call. A bare $n, the type of that argument, is a +// pseudo-type of its own rather than a template. +func returnTemplate(returns string) (string, string) { + if !strings.Contains(returns, "$") || strings.HasPrefix(returns, "$") { + return returns, "" + } + t := core.ParseTypeExpr(returns) + return t.Name, returns +} + +func (b *builder) addRelation(rel Relation) error { + if rel.Name == "" { + return errors.New("relation has no name") + } + nsOID, err := b.namespace(rel.Schema) + if err != nil { + return err + } + kind := rel.Kind + if kind == "" { + kind = "r" + } + classOID, err := b.cat.CreateClass(nsOID, rel.Name, kind) + if err != nil { + return err + } + for i, col := range rel.Columns { + t := core.ParseTypeExpr(col.Type) + if col.Array { + t = core.Array(t) + } + typeOID, err := b.columnType(t) + if err != nil { + return fmt.Errorf("relation %q column %q: %w", rel.Name, col.Name, err) + } + if err := b.cat.CreateAttributeSpec(core.AttributeSpec{ + ClassOID: classOID, + Name: col.Name, + TypeOID: typeOID, + Num: i + 1, + NotNull: col.NotNull, + DeclType: col.Type, + }); err != nil { + return fmt.Errorf("relation %q column %q: %w", rel.Name, col.Name, err) + } + } + return nil +} + +// namespace resolves the schema a relation belongs to, creating it the first +// time it is named. A relation with no schema belongs to the default one. +func (b *builder) namespace(schema string) (int64, error) { + if schema == "" { + schema = "public" + } + if oid, ok := b.namespaces[schema]; ok { + return oid, nil + } + oid, err := b.cat.NamespaceOID(schema) + if err != nil { + if oid, err = b.cat.CreateNamespace(schema); err != nil { + return 0, err + } + } + b.namespaces[schema] = oid + return oid, nil +} + +// columnType resolves a column's type, which may be an array or carry +// arguments. +func (b *builder) columnType(t *core.TypeExpr) (int64, error) { + key := t.Key() + if oid, ok := b.oids[key]; ok { + return oid, nil + } + oid, err := b.cat.ResolveTypeExpr(t) + if err != nil { + return 0, err + } + b.oids[key] = oid + return oid, nil +} + +// funcType resolves the type a function signature names. Signatures reference +// pseudo types ("any", "record") and types no dialect bothers to list, so an +// unknown name is registered rather than rejected. +func (b *builder) funcType(name string) (int64, error) { + if name == "" { + return 0, nil + } + key := strings.ToLower(name) + if oid, ok := b.oids[key]; ok { + return oid, nil + } + oid, err := b.cat.ResolvePseudoTypeExpr(core.ParseTypeExpr(name)) + if err != nil { + return 0, err + } + b.oids[key] = oid + return oid, nil +} diff --git a/internal/core/sqlc.json b/internal/core/sqlc.json new file mode 100644 index 0000000..3b4763b --- /dev/null +++ b/internal/core/sqlc.json @@ -0,0 +1,16 @@ +{ + "version": "2", + "sql": [ + { + "engine": "sqlite", + "schema": "catalogdef/schema.sql", + "queries": "catalogdef/query.sql", + "gen": { + "go": { + "package": "catalogdb", + "out": "catalogdb" + } + } + } + ] +} diff --git a/internal/core/typeexpr.go b/internal/core/typeexpr.go new file mode 100644 index 0000000..59372bb --- /dev/null +++ b/internal/core/typeexpr.go @@ -0,0 +1,324 @@ +package core + +import ( + "strconv" + "strings" +) + +// TypeExpr is a type written as a call expression: a lowercased name applied +// to arguments that are other types, integers, booleans or strings, each +// with an optional label, and a nullable flag at whatever depth it applies. +// Nothing about a nested type is special-cased, so an array of nullable +// strings is array(string nullable), a map is map(string, uint32) and a +// named tuple is tuple(lat: float64, lon: float64). The catalog resolves the +// names; the expression only records what was declared or inferred. +type TypeExpr struct { + Name string `json:"name"` + Nullable bool `json:"nullable,omitempty"` + Args []TypeArg `json:"args,omitempty"` +} + +// TypeArg is one argument of a TypeExpr: exactly one of Type, Int, Bool, +// String or Ident is set. Ident is a bare word that is not a type — the max +// of nvarchar(max), the function of SimpleAggregateFunction(sum, UInt64), +// the fields of interval day to second. +type TypeArg struct { + Label string `json:"label,omitempty"` + Type *TypeExpr `json:"type,omitempty"` + Int *int64 `json:"int,omitempty"` + Bool *bool `json:"bool,omitempty"` + String *string `json:"string,omitempty"` + Ident *string `json:"ident,omitempty"` +} + +// ArrayTypeName is the family every dialect's array is an instance of: an +// array of integers is array(integer), whatever the dialect spells it. +const ArrayTypeName = "array" + +// Array wraps element in one array dimension. +func Array(element *TypeExpr) *TypeExpr { + return &TypeExpr{Name: ArrayTypeName, Args: []TypeArg{{Type: element}}} +} + +// IsArray reports whether the expression is an array. +func (t *TypeExpr) IsArray() bool { + return t != nil && t.Name == ArrayTypeName && len(t.Args) > 0 && t.Args[0].Type != nil +} + +// Element is an array's element type, or nil for anything else. +func (t *TypeExpr) Element() *TypeExpr { + if !t.IsArray() { + return nil + } + return t.Args[0].Type +} + +// ArrayDims counts the array dimensions wrapped around the expression's +// innermost type, and Innermost is that type: the integer of an array of +// arrays of integers. +func (t *TypeExpr) ArrayDims() int { + dims := 0 + for t.IsArray() { + dims++ + t = t.Element() + } + return dims +} + +func (t *TypeExpr) Innermost() *TypeExpr { + for t.IsArray() { + t = t.Element() + } + return t +} + +// Clone copies the expression, arguments and all, so that a caller can set +// nullability on the copy without touching a cached one. +func (t *TypeExpr) Clone() *TypeExpr { + if t == nil { + return nil + } + out := &TypeExpr{Name: t.Name, Nullable: t.Nullable} + if len(t.Args) > 0 { + out.Args = make([]TypeArg, len(t.Args)) + for i, a := range t.Args { + out.Args[i] = a + out.Args[i].Type = a.Type.Clone() + } + } + return out +} + +// WithNullable returns a copy of the expression with its own nullability set +// as given; the nullability of a nested type is left alone. +func (t *TypeExpr) WithNullable(nullable bool) *TypeExpr { + out := t.Clone() + if out != nil { + out.Nullable = nullable + } + return out +} + +// Key is the expression's canonical spelling, which identifies its row in +// the catalog: the expression's own nullability is not part of it, since a +// row is never nullable, while the nullability of a nested type is. +func (t *TypeExpr) Key() string { + if t == nil { + return "" + } + if !t.Nullable { + return t.String() + } + return t.WithNullable(false).String() +} + +// ParseTypeExpr reads a type spelled the way every dialect spells one, as a +// name optionally applied to a parenthesised, comma-separated argument list +// whose entries may be labelled (`lat Float64` in a tuple, `'a' = 1` in an +// enum). A Nullable(T) wrapper becomes T with Nullable set, and a trailing +// [] becomes an array of the element. +func ParseTypeExpr(s string) *TypeExpr { + s = strings.TrimSpace(s) + if element, ok := strings.CutSuffix(s, ArraySuffix); ok { + return Array(ParseTypeExpr(element)) + } + name, args := splitTypeArgs(s) + name = strings.ToLower(name) + if name == "nullable" && len(args) == 1 { + t := ParseTypeExpr(args[0]) + t.Nullable = true + return t + } + t := &TypeExpr{Name: name} + for _, a := range args { + t.Args = append(t.Args, parseTypeArg(a)) + } + return t +} + +func parseTypeArg(a string) TypeArg { + a = strings.TrimSpace(a) + if strings.HasPrefix(a, "'") { + end := quotedEnd(a) + lit := strings.ReplaceAll(strings.ReplaceAll(a[1:end-1], `\'`, `'`), `''`, `'`) + if rest := strings.TrimSpace(a[end:]); strings.HasPrefix(rest, "=") { + arg := parseTypeArg(rest[1:]) + arg.Label = lit + return arg + } + return TypeArg{String: &lit} + } + if n, err := strconv.ParseInt(a, 10, 64); err == nil { + return TypeArg{Int: &n} + } + switch strings.ToLower(a) { + case "true", "false": + b := strings.EqualFold(a, "true") + return TypeArg{Bool: &b} + } + // A label is a word before a colon, as the canonical form writes it: + // `lat: Float64`. A word before a space is a label too, as ClickHouse + // writes `lat Float64`, but only when what follows is a single word, + // since `timestamp with time zone` is a name and not a label. + head := a + if p := strings.IndexByte(a, '('); p >= 0 { + head = a[:p] + } + if i := strings.IndexByte(head, ':'); i > 0 && !strings.ContainsAny(head[:i], " '\"") { + return TypeArg{Label: strings.TrimSpace(a[:i]), Type: ParseTypeExpr(a[i+1:])} + } + if i := strings.IndexByte(head, ' '); i > 0 && !strings.Contains(strings.TrimSpace(head[i+1:]), " ") { + return TypeArg{Label: a[:i], Type: ParseTypeExpr(a[i+1:])} + } + return TypeArg{Type: ParseTypeExpr(a)} +} + +// quotedEnd returns the index just past the single-quoted literal starting +// at the beginning of s, honouring backslash escapes and doubled quotes. +func quotedEnd(s string) int { + for i := 1; i < len(s); i++ { + switch { + case s[i] == '\\' && i+1 < len(s): + i++ + case s[i] == '\'' && i+1 < len(s) && s[i+1] == '\'': + i++ + case s[i] == '\'': + return i + 1 + } + } + return len(s) +} + +// splitTypeArgs splits `Base(arg, arg)` into its base name and top-level +// arguments, leaving nested parentheses and quoted strings intact. Words +// after the closing parenthesis belong to the name, since MySQL writes +// decimal(10,2) unsigned and PostgreSQL timestamp(3) with time zone. +func splitTypeArgs(t string) (string, []string) { + open := strings.IndexByte(t, '(') + if open < 0 { + return t, nil + } + close := matchingParen(t, open) + if close < 0 { + return t, nil + } + base := strings.TrimSpace(t[:open]) + if rest := strings.TrimSpace(t[close+1:]); rest != "" { + base += " " + rest + } + inner := t[open+1 : close] + var ( + args []string + depth int + quote byte + start int + ) + for i := 0; i < len(inner); i++ { + c := inner[i] + switch { + case quote != 0: + if c == '\\' { + i++ + } else if c == quote { + quote = 0 + } + case c == '\'' || c == '"' || c == '`': + quote = c + case c == '(': + depth++ + case c == ')': + depth-- + case c == ',' && depth == 0: + args = append(args, strings.TrimSpace(inner[start:i])) + start = i + 1 + } + } + if last := strings.TrimSpace(inner[start:]); last != "" || len(args) > 0 { + args = append(args, last) + } + return base, args +} + +// matchingParen finds the parenthesis closing the one at open, skipping +// nested parentheses and quoted strings, or -1 when it is not closed. +func matchingParen(t string, open int) int { + depth := 0 + var quote byte + for i := open; i < len(t); i++ { + c := t[i] + switch { + case quote != 0: + if c == '\\' { + i++ + } else if c == quote { + quote = 0 + } + case c == '\'' || c == '"' || c == '`': + quote = c + case c == '(': + depth++ + case c == ')': + depth-- + if depth == 0 { + return i + } + } + } + return -1 +} + +// HasNullable reports whether the expression marks nullability anywhere, +// which tells whether the spelling it came from said so itself. +func (t *TypeExpr) HasNullable() bool { + if t == nil { + return false + } + if t.Nullable { + return true + } + for _, a := range t.Args { + if a.Type.HasNullable() { + return true + } + } + return false +} + +// String renders the expression in its canonical text form, with a trailing +// "nullable" marking a nullable type. +func (t *TypeExpr) String() string { + if t == nil { + return "" + } + var b strings.Builder + b.WriteString(t.Name) + if len(t.Args) > 0 { + b.WriteByte('(') + for i, a := range t.Args { + if i > 0 { + b.WriteString(", ") + } + if a.Label != "" { + b.WriteString(a.Label) + b.WriteString(": ") + } + switch { + case a.Type != nil: + b.WriteString(a.Type.String()) + case a.Int != nil: + b.WriteString(strconv.FormatInt(*a.Int, 10)) + case a.Bool != nil: + b.WriteString(strconv.FormatBool(*a.Bool)) + case a.String != nil: + b.WriteString("'" + strings.ReplaceAll(*a.String, "'", `\'`) + "'") + case a.Ident != nil: + b.WriteString(*a.Ident) + } + } + b.WriteByte(')') + } + if t.Nullable { + b.WriteString(" nullable") + } + return b.String() +} diff --git a/internal/core/typename.go b/internal/core/typename.go new file mode 100644 index 0000000..4c37a27 --- /dev/null +++ b/internal/core/typename.go @@ -0,0 +1,150 @@ +package core + +import ( + "fmt" + "strings" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +// TypeExprOfTypeName reads the type an AST node names into an expression. +// An engine that renders the whole type as a call expression — DuckDB's +// struct(a: integer, b: varchar) — hands it over in Canonical; one that +// folds it into the spelling the formatter prints back — ClickHouse's +// Array(Nullable(String)), SQLite's VARYING CHARACTER(10) — in Spelling. +// Otherwise the name comes from Name or the qualifying parts of Names, the +// type modifiers become integer or string arguments, and each array bound +// wraps the result in an array. +func TypeExprOfTypeName(tn *ast.TypeName) *TypeExpr { + if tn == nil { + return nil + } + if tn.Canonical != "" { + return ParseTypeExpr(tn.Canonical) + } + if tn.Spelling != "" { + return ParseTypeExpr(tn.Spelling) + } + name := strings.TrimSpace(tn.Name) + if name == "" && tn.Names != nil { + parts := make([]string, 0, len(tn.Names.Items)) + for _, item := range tn.Names.Items { + s, ok := item.(*ast.String) + if !ok || s.Str == "pg_catalog" { + continue + } + parts = append(parts, s.Str) + } + name = strings.Join(parts, ".") + } + name = strings.ToLower(name) + if name == "" { + return nil + } + // An engine that reports the schema apart from the name qualifies it + // the way a dotted name does, so the type resolves in its namespace. + if schema := strings.ToLower(tn.Schema); schema != "" && schema != "pg_catalog" && !strings.Contains(name, ".") { + name = schema + "." + name + } + // A name an engine spelled with its own arguments or array suffix reads + // the same way a spelling does. + t := ParseTypeExpr(name) + for _, item := range listItems(tn.Typmods) { + if arg, ok := typmodArg(item); ok { + t.Args = append(t.Args, arg) + } + } + for range listItems(tn.ArrayBounds) { + t = Array(t) + } + return t +} + +// ColumnTypeExpr reads a column definition's type. Engines report an array +// column either on the type name or on the column itself. +func ColumnTypeExpr(col *ast.ColumnDef) *TypeExpr { + if col == nil { + return nil + } + t := TypeExprOfTypeName(col.TypeName) + if t == nil { + return nil + } + // MySQL reports an unsigned column on the definition, and the + // members of an enum or set apart from the type's name. + if col.IsUnsigned && !strings.Contains(t.Name, " unsigned") { + t.Name += " unsigned" + } + if vals := listItems(col.Vals); len(vals) > 0 && len(t.Args) == 0 { + for _, item := range vals { + if s, ok := item.(*ast.String); ok { + v := s.Str + t.Args = append(t.Args, TypeArg{String: &v}) + } + } + } + if col.TypeName.Canonical != "" || col.TypeName.Spelling != "" || listItems(col.TypeName.ArrayBounds) != nil { + return t + } + dims := col.ArrayDims + if dims == 0 && col.IsArray { + dims = 1 + } + for i := 0; i < dims; i++ { + t = Array(t) + } + return t +} + +// typmodArg reads one type modifier as an argument: an integer, a quoted +// string, or a bare word, which is an identifier such as the max of +// nvarchar(max) or the day to second of an interval. A constant node holds +// a literal; a bare String node holds a word. +func typmodArg(n ast.Node) (TypeArg, bool) { + switch v := n.(type) { + case *ast.A_Const: + switch val := v.Val.(type) { + case *ast.String: + s := val.Str + return TypeArg{String: &s}, true + default: + return typmodArg(v.Val) + } + case *ast.Integer: + i := v.Ival + return TypeArg{Int: &i}, true + case *ast.String: + s := strings.ToLower(v.Str) + return TypeArg{Ident: &s}, true + case *ast.ColumnRef: + parts := make([]string, 0, len(listItems(v.Fields))) + for _, item := range listItems(v.Fields) { + if s, ok := item.(*ast.String); ok { + parts = append(parts, s.Str) + } + } + if len(parts) == 0 { + return TypeArg{}, false + } + ident := strings.ToLower(strings.Join(parts, ".")) + return TypeArg{Ident: &ident}, true + } + return TypeArg{}, false +} + +func listItems(l *ast.List) []ast.Node { + if l == nil { + return nil + } + return l.Items +} + +// ResolveType interns the type an AST node names, registering it when the +// dialect's seed did not: a schema is free to declare types of its own. +func (c *Catalog) ResolveType(tn *ast.TypeName) (int64, error) { + t := TypeExprOfTypeName(tn) + if t == nil { + return 0, fmt.Errorf("missing type name") + } + return c.ResolveTypeExpr(t) +} diff --git a/internal/core/types.go b/internal/core/types.go new file mode 100644 index 0000000..7c482a1 --- /dev/null +++ b/internal/core/types.go @@ -0,0 +1,825 @@ +package core + +import ( + "context" + "database/sql" + "errors" + "fmt" + "slices" + "strings" + "sync" + + "github.com/sqlc-dev/sqlc/internal/core/catalogdb" +) + +// TypeSpec describes a type row. Name is the family's name; Expr is the +// canonical spelling of the whole expression and defaults to the name, which +// is what a family's is. +type TypeSpec struct { + Name string + Expr string + Typtype string + Category string + Preferred bool + NamespaceOID int64 + DialectOID int64 + FamilyOID int64 + ElementOID int64 + BaseOID int64 + CanonicalOID int64 + NotNull bool +} + +// TypeInfo is a type row as the catalog holds it. +type TypeInfo struct { + OID int64 + NamespaceOID int64 + Name string + Expr string + Category string + Typtype string + Preferred bool + FamilyOID int64 + ElementOID int64 + BaseOID int64 + CanonicalOID int64 + NotNull bool +} + +// IsFamily reports whether the row is a family rather than an instance. +func (t TypeInfo) IsFamily() bool { return t.FamilyOID == 0 } + +// typeCache remembers what the catalog holds about a type. A row never +// changes once written, and a restored catalog is read-only, so a cached +// answer is good for the life of the catalog. Analysis runs concurrently on +// a restored catalog, so the cache is locked. +type typeCache struct { + mu sync.RWMutex + infos map[int64]TypeInfo + exprs map[int64]*TypeExpr + namespaces map[int64]string + namespaceOIDs map[string]int64 +} + +func (c *typeCache) namespace(oid int64) (string, bool) { + c.mu.RLock() + defer c.mu.RUnlock() + name, ok := c.namespaces[oid] + return name, ok +} + +func (c *typeCache) namespaceOID(name string) (int64, bool) { + c.mu.RLock() + defer c.mu.RUnlock() + oid, ok := c.namespaceOIDs[name] + return oid, ok +} + +func (c *typeCache) putNamespace(oid int64, name string) { + c.mu.Lock() + defer c.mu.Unlock() + if c.namespaces == nil { + c.namespaces = map[int64]string{} + c.namespaceOIDs = map[string]int64{} + } + c.namespaces[oid] = name + c.namespaceOIDs[name] = oid +} + +func (c *typeCache) info(oid int64) (TypeInfo, bool) { + c.mu.RLock() + defer c.mu.RUnlock() + info, ok := c.infos[oid] + return info, ok +} + +func (c *typeCache) expr(oid int64) (*TypeExpr, bool) { + c.mu.RLock() + defer c.mu.RUnlock() + e, ok := c.exprs[oid] + return e, ok +} + +func (c *typeCache) put(info TypeInfo, expr *TypeExpr) { + c.mu.Lock() + defer c.mu.Unlock() + if c.infos == nil { + c.infos = map[int64]TypeInfo{} + c.exprs = map[int64]*TypeExpr{} + } + c.infos[info.OID] = info + if expr != nil { + c.exprs[info.OID] = expr + } +} + +func (c *Catalog) CreateType(name string) (int64, error) { + return c.CreateTypeSpec(TypeSpec{Name: name, Typtype: "b"}) +} + +// CreateTypeSpec inserts a type row. It is the raw insert: nothing is +// canonicalized and no arguments are written, so it is what the seed and +// ResolveTypeExpr build on rather than what a caller with an expression +// wants. +func (c *Catalog) CreateTypeSpec(t TypeSpec) (int64, error) { + if t.Typtype == "" { + t.Typtype = "b" + } + if t.NamespaceOID == 0 { + oid, err := c.NamespaceOID("public") + if err != nil { + return 0, fmt.Errorf("create type %q: default namespace: %w", t.Name, err) + } + t.NamespaceOID = oid + } + name := strings.ToLower(t.Name) + expr := t.Expr + if expr == "" { + expr = name + } + oid, err := c.q.CreateType(context.Background(), catalogdb.CreateTypeParams{ + Name: name, + Expr: expr, + Typtype: t.Typtype, + Category: nullString(t.Category), + Preferred: boolToInt64(t.Preferred), + NamespaceOid: t.NamespaceOID, + DialectOid: nullInt64(t.DialectOID), + FamilyOid: nullInt64(t.FamilyOID), + ElementOid: nullInt64(t.ElementOID), + BaseOid: nullInt64(t.BaseOID), + CanonicalOid: nullInt64(t.CanonicalOID), + NotNull: boolToInt64(t.NotNull), + }) + if err != nil { + return 0, fmt.Errorf("create type %q: %w", expr, err) + } + return oid, nil +} + +// ArraySuffix is the suffix a schema appends to an element type's spelling +// to name an array of it, which ParseTypeExpr reads as one array dimension. +const ArraySuffix = "[]" + +// CreateUserType registers a type family a schema declared rather than the +// dialect, such as an enum or a name the dialect's seed does not list. The +// type gains the dialect's comparison operators, so a column of it can be +// compared. +func (c *Catalog) CreateUserType(name, category string) (int64, error) { + typtype := "b" + if category == "E" { + typtype = "e" + } + nsOID, bare, err := c.declaredTypeNamespace(strings.ToLower(name)) + if err != nil { + return 0, fmt.Errorf("create type %q: %w", name, err) + } + spec := TypeSpec{ + Name: bare, + NamespaceOID: nsOID, + Typtype: typtype, + Category: category, + DialectOID: c.dialectOID, + } + // A dialect may say what an unknown spelling stands on, as SQLite's + // affinity rule does; the type then resolves through that base and + // needs no operators of its own. + if category == "U" { + baseOID, err := c.userTypeBase(bare) + if err != nil { + return 0, err + } + if baseOID != 0 { + base, err := c.LookupType(baseOID) + if err != nil { + return 0, err + } + spec.BaseOID = baseOID + spec.Category = base.Category + return c.CreateTypeSpec(spec) + } + } + oid, err := c.CreateTypeSpec(spec) + if err != nil { + return 0, err + } + if err := c.createComparisons(oid); err != nil { + return 0, err + } + return oid, nil +} + +// createComparisons gives a type the dialect's comparison operators, which the +// seed registered for the types it knew about up front. +func (c *Catalog) createComparisons(typeOID int64) error { + if c.dialectOID == 0 { + return nil + } + ops, _ := c.DialectFlag(c.dialectOID, FlagComparisonOperators) + boolName, _ := c.DialectFlag(c.dialectOID, "const."+ConstBool) + if ops == "" || boolName == "" { + return nil + } + boolOID, err := c.TypeOID(boolName) + if err != nil { + return nil + } + for _, op := range strings.Split(ops, ",") { + if op == "" { + continue + } + if _, err := c.CreateOperator(OperatorSpec{ + Name: op, + DialectOID: c.dialectOID, + LeftTypeOID: typeOID, + RightTypeOID: typeOID, + ResultTypeOID: boolOID, + }); err != nil { + return err + } + } + return nil +} + +// TypeOIDsInCategory returns the type families the catalog's dialect has in +// the named category, in the order they were created. +func (c *Catalog) TypeOIDsInCategory(category string) ([]int64, error) { + oids, err := c.q.TypeOIDsInCategory(context.Background(), catalogdb.TypeOIDsInCategoryParams{ + DialectOid: nullInt64(c.dialectOID), + Category: nullString(category), + }) + if err != nil { + return nil, fmt.Errorf("types in category %q: %w", category, err) + } + return oids, nil +} + +// TypeOID returns the family a name refers to: an alias spelling resolves to +// the type it names. +func (c *Catalog) TypeOID(name string) (int64, error) { + oid, err := c.familyOIDByName(strings.ToLower(name)) + if err != nil { + return 0, fmt.Errorf("type %q: %w", name, err) + } + return c.canonicalOID(oid) +} + +// familyOIDByName finds the family row a bare name refers to, alias rows +// included, in the default namespaces: the catalog's own, PostgreSQL's +// system catalog and the dialect's default schema, in that order of +// preference. A type in any other namespace is reached by qualifying it, +// as PostgreSQL reaches one off the search path. +func (c *Catalog) familyOIDByName(name string) (int64, error) { + nsOIDs, err := c.defaultNamespaceOIDs() + if err != nil { + return 0, err + } + rows, err := c.q.TypeOIDsByNameInNamespaces(context.Background(), catalogdb.TypeOIDsByNameInNamespacesParams{ + Name: name, + NamespaceOids: nsOIDs, + }) + if err != nil { + return 0, err + } + for _, ns := range nsOIDs { + for _, row := range rows { + if row.NamespaceOid == ns { + return row.Oid, nil + } + } + } + return 0, sql.ErrNoRows +} + +// defaultNamespaceOIDs lists the namespaces a bare type name is looked up +// in, in order of preference, skipping any the catalog does not have yet. +func (c *Catalog) defaultNamespaceOIDs() ([]int64, error) { + names := []string{"pg_catalog", "public"} + if c.dialectOID != 0 { + if name, _ := c.DialectFlag(c.dialectOID, FlagDefaultSchema); name != "" { + names = append(names, name) + } + } + out := make([]int64, 0, len(names)) + for _, name := range names { + oid, err := c.namespaceOIDByName(name) + if err != nil { + continue + } + out = append(out, oid) + } + return out, nil +} + +// namespaceOIDByName is NamespaceOID with the answer remembered, since a +// type lookup asks for the same few namespaces every time. A namespace +// created after the answer was cached is found on the next miss. +func (c *Catalog) namespaceOIDByName(name string) (int64, error) { + if oid, ok := c.types.namespaceOID(name); ok { + return oid, nil + } + oid, err := c.NamespaceOID(name) + if err != nil { + return 0, err + } + c.types.putNamespace(oid, name) + return oid, nil +} + +// familyOIDByQualifiedName is familyOIDByName for a name that may carry its +// namespace, as myschema.mood does: a qualified name is looked up in that +// namespace alone. +func (c *Catalog) familyOIDByQualifiedName(name string) (int64, error) { + ns, bare := splitQualifiedName(name) + if ns == "" { + return c.familyOIDByName(bare) + } + nsOID, err := c.namespaceOIDByName(ns) + if err != nil { + return 0, err + } + return c.q.TypeOIDByNameInNamespace(context.Background(), catalogdb.TypeOIDByNameInNamespaceParams{ + NamespaceOid: nsOID, + Name: bare, + }) +} + +// TypeDeclared reports whether a schema's CREATE TYPE would redeclare a +// type: one of that name in the namespace the name qualifies, or in the +// default namespaces for a bare name. +func (c *Catalog) TypeDeclared(name string) bool { + _, err := c.familyOIDByQualifiedName(strings.ToLower(name)) + return err == nil +} + +// splitQualifiedName splits "myschema.mood" into its namespace and name. A +// name with no dot has no namespace. +func splitQualifiedName(name string) (ns, bare string) { + if i := strings.LastIndexByte(name, '.'); i > 0 { + return name[:i], name[i+1:] + } + return "", name +} + +// declaredTypeNamespace is the namespace a declared type's row goes in: the +// one its name qualifies, created if the schema has not, or the dialect's +// default schema — dbo, main — so that a bare CREATE TYPE and a qualified +// reference to it name one row. +func (c *Catalog) declaredTypeNamespace(name string) (int64, string, error) { + ns, bare := splitQualifiedName(name) + if ns == "" { + if c.dialectOID != 0 { + ns, _ = c.DialectFlag(c.dialectOID, FlagDefaultSchema) + } + if ns == "" { + return 0, bare, nil + } + } + oid, err := c.NamespaceOID(ns) + if err != nil { + if oid, err = c.CreateNamespace(ns); err != nil { + return 0, "", err + } + } + return oid, bare, nil +} + +// CreateTypeWithArgs registers a declared type that has arguments of its own +// — a composite's fields, an enum's labels — as a family row carrying them. +// The arguments' types are interned first. +func (c *Catalog) CreateTypeWithArgs(spec TypeSpec, args []TypeArg) (int64, error) { + nsOID, bare, err := c.declaredTypeNamespace(strings.ToLower(spec.Name)) + if err != nil { + return 0, fmt.Errorf("create type %q: %w", spec.Name, err) + } + spec.Name = bare + if nsOID != 0 { + spec.NamespaceOID = nsOID + } + if spec.DialectOID == 0 { + spec.DialectOID = c.dialectOID + } + argOIDs := make([]int64, len(args)) + for i, a := range args { + if a.Type == nil { + continue + } + oid, _, err := c.internType(a.Type, func(name string) (int64, error) { + return c.CreateUserType(name, "U") + }, true) + if err != nil { + return 0, fmt.Errorf("create type %q: %w", spec.Name, err) + } + argOIDs[i] = oid + } + oid, err := c.CreateTypeSpec(spec) + if err != nil { + return 0, err + } + if err := c.createComparisons(oid); err != nil { + return 0, err + } + return oid, c.insertTypeArgs(oid, spec.Expr, args, argOIDs) +} + +// insertTypeArgs writes a type's argument rows. +func (c *Catalog) insertTypeArgs(oid int64, key string, args []TypeArg, argOIDs []int64) error { + ctx := context.Background() + for i, a := range args { + p := catalogdb.CreateTypeArgParams{TypeOid: oid, Ord: int64(i + 1), Label: a.Label} + switch { + case a.Type != nil: + p.ArgTypeOid = nullInt64(argOIDs[i]) + p.Nullable = boolToInt64(a.Type.Nullable) + case a.Int != nil: + p.IntValue = sql.NullInt64{Int64: *a.Int, Valid: true} + case a.Bool != nil: + p.BoolValue = sql.NullInt64{Int64: boolToInt64(*a.Bool), Valid: true} + case a.String != nil: + p.StringValue = sql.NullString{String: *a.String, Valid: true} + case a.Ident != nil: + p.Ident = sql.NullString{String: *a.Ident, Valid: true} + } + if err := c.q.CreateTypeArg(ctx, p); err != nil { + return fmt.Errorf("type %q: argument %d: %w", key, i+1, err) + } + } + return nil +} + +// canonicalOID follows an alias row to the row it stands for. +func (c *Catalog) canonicalOID(oid int64) (int64, error) { + for i := 0; i < 16; i++ { + info, err := c.LookupType(oid) + if err != nil { + return 0, err + } + if info.CanonicalOID == 0 { + return oid, nil + } + oid = info.CanonicalOID + } + return 0, fmt.Errorf("type oid %d: alias chain does not end", oid) +} + +// ResolutionOID is the row an operator, function or cast over the type is +// looked up on when none is registered on the type itself: an instance's +// family, an alias's canonical type, a domain's or wrapper's base. It +// returns 0 when there is nothing further to fall back to. +func (c *Catalog) ResolutionOID(oid int64) int64 { + info, err := c.LookupType(oid) + if err != nil { + return 0 + } + switch { + case info.CanonicalOID != 0: + return info.CanonicalOID + case info.FamilyOID != 0: + return info.FamilyOID + case info.BaseOID != 0: + return info.BaseOID + } + return 0 +} + +// ResolutionChain lists the type and every row resolution falls back to, in +// order, ending with the family everything about the type is registered on. +func (c *Catalog) ResolutionChain(oid int64) []int64 { + chain := []int64{oid} + for i := 0; i < 16 && oid != 0; i++ { + oid = c.ResolutionOID(oid) + if oid != 0 { + chain = append(chain, oid) + } + } + return chain +} + +// TypeName returns the family name of a type row. +func (c *Catalog) TypeName(oid int64) (string, error) { + info, err := c.LookupType(oid) + if err != nil { + return "", err + } + return info.Name, nil +} + +// LookupType returns what the catalog holds about a type row. +func (c *Catalog) LookupType(oid int64) (TypeInfo, error) { + if info, ok := c.types.info(oid); ok { + return info, nil + } + row, err := c.q.LookupType(context.Background(), oid) + if err != nil { + return TypeInfo{}, fmt.Errorf("lookup type oid %d: %w", oid, err) + } + info := TypeInfo{ + OID: row.Oid, + NamespaceOID: row.NamespaceOid, + Name: row.Name, + Expr: row.Expr, + Category: row.Category.String, + Typtype: row.Typtype, + Preferred: row.Preferred != 0, + FamilyOID: orZero(row.FamilyOid), + ElementOID: orZero(row.ElementOid), + BaseOID: orZero(row.BaseOid), + CanonicalOID: orZero(row.CanonicalOid), + NotNull: row.NotNull != 0, + } + c.types.put(info, nil) + return info, nil +} + +// namespaceName is the name of a namespace row, remembered once read. +func (c *Catalog) namespaceName(oid int64) (string, error) { + if name, ok := c.types.namespace(oid); ok { + return name, nil + } + namespaces, err := c.Namespaces() + if err != nil { + return "", err + } + for _, ns := range namespaces { + c.types.putNamespace(ns.OID, ns.Name) + } + name, _ := c.types.namespace(oid) + return name, nil +} + +// TypeExprOf is the expression a type row stands for, read back from its +// arguments: the family's name for a family, the family applied to its +// arguments for an instance. The result is the caller's to change. +func (c *Catalog) TypeExprOf(oid int64) (*TypeExpr, error) { + if e, ok := c.types.expr(oid); ok { + return e.Clone(), nil + } + info, err := c.LookupType(oid) + if err != nil { + return nil, err + } + expr := &TypeExpr{Name: c.qualifiedName(info)} + if !info.IsFamily() { + rows, err := c.q.TypeArgs(context.Background(), oid) + if err != nil { + return nil, fmt.Errorf("type oid %d: arguments: %w", oid, err) + } + for _, r := range rows { + arg := TypeArg{Label: r.Label} + switch { + case r.ArgTypeOid.Valid: + t, err := c.TypeExprOf(r.ArgTypeOid.Int64) + if err != nil { + return nil, err + } + t.Nullable = r.Nullable != 0 + arg.Type = t + case r.IntValue.Valid: + v := r.IntValue.Int64 + arg.Int = &v + case r.BoolValue.Valid: + v := r.BoolValue.Int64 != 0 + arg.Bool = &v + case r.StringValue.Valid: + v := r.StringValue.String + arg.String = &v + case r.Ident.Valid: + v := r.Ident.String + arg.Ident = &v + } + expr.Args = append(expr.Args, arg) + } + } + c.types.put(info, expr) + return expr.Clone(), nil +} + +// qualifiedName is the name a type row is known by in an expression: its +// name, qualified with its namespace when that is not one of the dialect's +// defaults, as format_type prints a type off the search path. An +// instance's key is built from these, so the array of one schema's mood is +// a row apart from the array of another's. +func (c *Catalog) qualifiedName(info TypeInfo) string { + if ns, err := c.namespaceName(info.NamespaceOID); err == nil && ns != "" && !slices.Contains(c.DefaultNamespaces(), ns) { + return ns + "." + info.Name + } + return info.Name +} + +// ResolveTypeExpr interns the type an expression names and returns its row: +// the family for a bare name, the instance for a family applied to +// arguments, each argument type interned first. Names are canonicalized, so +// integer and int4 intern to one row. A family the dialect did not seed is +// one the schema declared, and is registered as a user type. +func (c *Catalog) ResolveTypeExpr(t *TypeExpr) (int64, error) { + oid, _, err := c.internType(t, func(name string) (int64, error) { + return c.CreateUserType(name, "U") + }, true) + return oid, err +} + +// ResolvePseudoTypeExpr is ResolveTypeExpr for the type a function signature +// names. Signatures reference pseudo-types ("any", "record") and types no +// dialect bothers to list, so an unknown family is registered as an opaque +// type rather than rejected, and gets no operators of its own. +func (c *Catalog) ResolvePseudoTypeExpr(t *TypeExpr) (int64, error) { + oid, _, err := c.internType(t, func(name string) (int64, error) { + return c.CreateTypeSpec(TypeSpec{Name: name, Category: "U", DialectOID: c.dialectOID}) + }, true) + return oid, err +} + +// ResolveTypeName is ResolveTypeExpr for a type spelled as a string. +func (c *Catalog) ResolveTypeName(name string) (int64, error) { + return c.ResolveTypeExpr(ParseTypeExpr(name)) +} + +var errUnknownType = errors.New("unknown type") + +// TypeLookup is what LookupTypeExpr found for an expression. +type TypeLookup struct { + // OID is the instance row when the catalog holds one, otherwise the + // family row. + OID int64 + // FamilyOID is the family, which is OID for a family or an instance the + // catalog does not hold. + FamilyOID int64 + // Expr is the expression canonicalized: the family and every argument + // type spelled as the catalog spells them, whether or not the instance + // is a row. + Expr *TypeExpr +} + +// LookupTypeExpr finds the row an expression names without writing, and +// reports false when the family is not one the catalog holds. +func (c *Catalog) LookupTypeExpr(t *TypeExpr) (TypeLookup, bool) { + refuse := func(string) (int64, error) { return 0, errUnknownType } + oid, canonical, err := c.internType(t, refuse, false) + if errors.Is(err, errUnknownType) && canonical != nil { + // The family is known and the instance is not a row. + familyOID, _, err := c.internType(&TypeExpr{Name: canonical.Name}, refuse, false) + if err != nil { + return TypeLookup{}, false + } + return TypeLookup{OID: familyOID, FamilyOID: familyOID, Expr: canonical}, true + } + if err != nil { + return TypeLookup{}, false + } + info, err := c.LookupType(oid) + if err != nil { + return TypeLookup{}, false + } + familyOID := oid + if !info.IsFamily() { + familyOID = info.FamilyOID + } + return TypeLookup{OID: oid, FamilyOID: familyOID, Expr: canonical}, true +} + +// internType resolves an expression to its row, creating the instance row +// when there is none and write allows it, and calling newFamily for a +// family name the catalog does not hold, which may refuse. Alongside the +// row it returns the expression canonicalized; when the instance is not a +// row and writing is not allowed, the canonical expression still comes +// back with errUnknownType. +func (c *Catalog) internType(t *TypeExpr, newFamily func(name string) (int64, error), write bool) (int64, *TypeExpr, error) { + if t == nil || strings.TrimSpace(t.Name) == "" { + return 0, nil, fmt.Errorf("missing type name") + } + t, err := c.canonicalize(t) + if err != nil { + return 0, nil, err + } + name := strings.ToLower(strings.TrimSpace(t.Name)) + familyOID, err := c.familyOIDByQualifiedName(name) + if err != nil { + if name == ArrayTypeName && write { + // Every dialect has arrays, whether or not its seed lists the + // family; one that does not gets it as an array type rather + // than a user type. + familyOID, err = c.CreateTypeSpec(TypeSpec{Name: name, Category: "A", DialectOID: c.dialectOID}) + } else { + familyOID, err = newFamily(name) + } + if err != nil { + return 0, nil, fmt.Errorf("type %q: %w", name, err) + } + } + if familyOID, err = c.canonicalOID(familyOID); err != nil { + return 0, nil, err + } + family, err := c.LookupType(familyOID) + if err != nil { + return 0, nil, err + } + if len(t.Args) == 0 { + return familyOID, &TypeExpr{Name: c.qualifiedName(family)}, nil + } + + // The instance's canonical spelling is the family applied to its + // arguments as the catalog spells them, so each argument type is + // resolved first and read back. An argument whose own instance is not + // a row, in a lookup that may not write, still has a canonical + // spelling, which the whole expression's is built from. + canonical := &TypeExpr{Name: c.qualifiedName(family), Args: make([]TypeArg, len(t.Args))} + argOIDs := make([]int64, len(t.Args)) + unknown := false + for i, a := range t.Args { + canonical.Args[i] = a + if a.Type == nil { + continue + } + oid, argExpr, err := c.internType(a.Type, newFamily, write) + if err != nil { + if !errors.Is(err, errUnknownType) || argExpr == nil { + return 0, nil, err + } + unknown = true + } + argOIDs[i] = oid + argExpr.Nullable = a.Type.Nullable + canonical.Args[i].Type = argExpr + } + if unknown { + return 0, canonical, errUnknownType + } + key := canonical.Key() + ctx := context.Background() + if oid, err := c.q.TypeOIDByExprInNamespace(ctx, catalogdb.TypeOIDByExprInNamespaceParams{ + NamespaceOid: family.NamespaceOID, + Expr: key, + }); err == nil { + return oid, canonical, nil + } else if !errors.Is(err, sql.ErrNoRows) { + return 0, nil, fmt.Errorf("type %q: %w", key, err) + } + // A lookup that may not write stops here, canonical expression in hand. + if !write { + return 0, canonical, errUnknownType + } + + spec := TypeSpec{ + Name: family.Name, + Expr: key, + Typtype: family.Typtype, + Category: family.Category, + NamespaceOID: family.NamespaceOID, + DialectOID: c.dialectOID, + FamilyOID: familyOID, + } + if family.Name == ArrayTypeName && argOIDs[0] != 0 { + spec.ElementOID = argOIDs[0] + } + oid, err := c.CreateTypeSpec(spec) + if err != nil { + return 0, nil, err + } + if err := c.insertTypeArgs(oid, key, canonical.Args, argOIDs); err != nil { + return 0, nil, err + } + return oid, canonical, nil +} + +func nullableOID(oid int64) any { + if oid == 0 { + return nil + } + return oid +} + +func nullableString(s string) any { + if s == "" { + return nil + } + return s +} + +func boolToInt(b bool) int { + if b { + return 1 + } + return 0 +} + +func nullInt64(oid int64) sql.NullInt64 { + return sql.NullInt64{Int64: oid, Valid: oid != 0} +} + +func nullString(s string) sql.NullString { + return sql.NullString{String: s, Valid: s != ""} +} + +func boolToInt64(b bool) int64 { + if b { + return 1 + } + return 0 +} + +func orZero(n sql.NullInt64) int64 { + if n.Valid { + return n.Int64 + } + return 0 +} diff --git a/internal/core/types.md b/internal/core/types.md new file mode 100644 index 0000000..771b09c --- /dev/null +++ b/internal/core/types.md @@ -0,0 +1,769 @@ +# Types in the analysis core + +How the core catalog, the analyzer and `sqlc analyze` represent a type today, +where that falls short of each engine's type system, how each engine's own +catalog represents one, and the design that closes the gap: every type the +schema or the dialect declares is a row holding its full expression, +canonicalized the way the engine would and denormalized so that a bare name +like `integer` and a structured expression like `numeric(10, 2)` both +resolve to one. + +## What a type is today + +The catalog (`catalogdef/schema.sql`) has one row per *name* in `sql_type`: +a lowercased string, a category letter, a `typtype` that is only ever `b` or +`e`, and an `element_oid` that is written for arrays but never read. A +dialect's `types.jsonl` seeds one row per type and one more per alias, then +joins every spelling of a type to every other with implicit casts. Arrays are +rows named after their element with `[]` appended, created on first use. +Anything else — a type argument, a struct field, an enum label, a domain's +base, a range's subtype — has nowhere to go: `sql_attribute` keeps the +column's verbatim spelling in `decl_type` (only SQLite and ClickHouse set it) +and has `type_length` and `type_scale` columns that no DDL path fills. + +The analyzer (`analyzer/expr.go`) types an expression as `exprType`: a type +OID, or a bare name when the catalog has no row, plus nullability. A type is +therefore a row, and a type that is not a row degrades to whatever row its +spelling's first word finds. + +The output (`TypeExpr` in `typeexpr.go`, printed by `sqlc analyze`) already +has the right shape: a name applied to labelled arguments that are types, +integers, booleans or strings, with `nullable` at any depth. It is complete +only where a source column's `decl_type` spelling exists to be parsed; every +other column and every parameter is rebuilt from the flat row name. + +## What each engine loses + +The table is what `sqlc analyze` reports today for a schema exercising each +engine's type system, against what the engine itself says the type is. + +| Engine | Declared | Reported | The engine says | +|---|---|---|---| +| PostgreSQL | `numeric(10,2)`, `varchar(255)`, `timestamp(3)`, `bit(8)` | `numeric`, `varchar`, `timestamp`, `bit` | typmods are part of the type | +| PostgreSQL | `int[][]` | `array(int4)` | two dimensions | +| PostgreSQL | `CREATE DOMAIN posint AS integer` | `posint`, category U | an integer with a constraint | +| PostgreSQL | `CREATE TYPE point2 AS (x float8, y float8)` | `point2`, category U | two named fields | +| PostgreSQL | `CREATE TYPE mood AS ENUM (...)` | `mood` | the labels | +| PostgreSQL | `CREATE TYPE floatrange AS RANGE (subtype = float8)` | `floatrange`, category U | a range over float8 | +| PostgreSQL | `myschema.mood` | `mood` for a column, `myschema.mood` for a cast: two rows, both in `public` | one type in a namespace | +| PostgreSQL | `interval day to second` | `interval` | fields are a typmod | +| MySQL | `BIGINT UNSIGNED`, `INT UNSIGNED` | `bigint`, `int` | a different value range; codegen picks `int64` over `uint64` | +| MySQL | `TINYINT(1)` | `tinyint` | the display width is how drivers and codegen spot a boolean | +| MySQL | `DECIMAL(10,2) UNSIGNED`, `DATETIME(6)`, `VARCHAR(255)` | `decimal`, `datetime`, `varchar` | precision, fractional seconds, length | +| MySQL | `ENUM('a','b')`, `SET('x','y')` | `enum`, `set` | the members | +| MySQL | `CAST(? AS CHAR(10))` | `var_string` | `char`; the parser's internal name leaks | +| SQLite | `FOO BAR(3)`, `VARCHAR(255)` | `foo bar(3)`, `varchar(255)` | correct spelling, but each is a row of category U that compares with nothing, and the affinity SQLite gives it (NUMERIC, TEXT) is not modelled | +| ClickHouse | every column type | complete | complete, from the spelling | +| ClickHouse | `CAST(x AS Nullable(String))` | `nullable` | `Nullable(String)` | +| ClickHouse | `CAST(x AS Array(UInt8))` | `array` | `Array(UInt8)` | +| ClickHouse | `toDecimal64(x, 4)`, `toDateTime64(x, 3)` | `decimal64`, `datetime64` | `Decimal(18, 4)`, `DateTime64(3)`: the result depends on an argument's value | +| ClickHouse | `SimpleAggregateFunction(sum, UInt64)` | `simpleaggregatefunction(sum, uint64)` | `sum` is a function name, which the expression reads as a type | +| ClickHouse | `n Nested(a UInt8, b String)` | one column `n` | two columns `n.a Array(UInt8)`, `n.b Array(String)` | +| DuckDB | `STRUCT(a INTEGER, b VARCHAR)`, `MAP(VARCHAR, INTEGER)`, `UNION(num INTEGER, str VARCHAR)` | `struct`, `map`, `union` | the fields | +| DuckDB | `INTEGER[]`, `INTEGER[3]`, `INTEGER[][]` | `array(integer)` for all three | LIST, fixed-size ARRAY, nested LIST | +| DuckDB | `DECIMAL(18,3)`, `VARCHAR(10)`, `ENUM('a','b')` | `decimal`, `varchar`, `enum` | arguments and members | +| GoogleSQL | `ARRAY` | a row *named* `array` | an array of int64 | +| GoogleSQL | `STRUCT`, `ARRAY>` | `struct`, `array` | the fields | +| GoogleSQL | `STRING(10)`, `NUMERIC(10,2)`, `[1, 2]`, `STRUCT(1 AS x)` | `string`, `numeric`, untyped, untyped | parameters; a constructed array and struct | +| SQL Server | `NVARCHAR(MAX)`, `VARBINARY(MAX)` | `nvarchar`, `varbinary` | MAX decides the Go type | +| SQL Server | `DECIMAL(10,2)`, `DATETIME2(3)`, `FLOAT(24)`, `VECTOR(3)` | `decimal`, `datetime2`, `float`, `vector` | arguments; `FLOAT(24)` is `real` | +| SQL Server | `CREATE TYPE dbo.PhoneNumber FROM varchar(20) NOT NULL` | `phonenumber`, category U | a `varchar(20)` that is never null, in schema `dbo` | + +Three of these are regressions against the legacy compiler rather than gaps +shared with it: the plugin protocol's `Column` carries `unsigned`, `length` +and `array_dims`, codegen reads all three (`golang/mysql_type.go` turns +`tinyint` with length 1 into `bool` and `unsigned` into `uint64`; +`golang/go_type.go` nests one slice per dimension), and the core bridge in +`compiler/parse_core.go` sets none of them from what the core reports. + +Two are broken outside column declarations only: ClickHouse's columns are +whole because the engine hands the core a spelling and the core keeps it on +the attribute. The same spelling in a cast, a function result or a typed +placeholder has no attribute to live on, so it degrades to its first word. +That is the tell: the expression belongs to the type, not to the column. + +## What each engine's own catalog says + +Each engine was asked, on a live system where one could be had, what it +records about a type, how it spells a column's type back, what it says a +query result's type is, and how it describes a function. PostgreSQL 16, +MySQL 8, SQLite 3.53, ClickHouse 25.8 and DuckDB 1.5 answered directly; SQL +Server and GoogleSQL are from their documented catalogs and the parsers +sqlc uses for them. + +**PostgreSQL** has one `pg_type` row per family, and a second row per array +type (`_int4`, with `typelem` pointing at the element). Arguments are not +part of the type: they are an opaque `int32` typmod on the use site — +`pg_attribute.atttypmod`, a domain's `typtypmod`, a function argument's +type has none — whose encoding is the type's own business and which +`format_type(oid, typmod)` decodes back into a spelling. Dimensions are +likewise on the attribute (`attndims`) and informational: `int[3]` and +`int[][]` are both the type `integer[]`. Declared types are rows with a +`typtype`: `e` with labels and their order in `pg_enum`, `c` with fields as +the attributes of a hidden relation (`typrelid`), `d` with `typbasetype`, +`typtypmod` and `typnotnull`, `r` and `m` with the subtype in `pg_range`; +pseudo-types (`anyarray`, `record`) are rows of `typtype` `p` and category +`P`. What it reports is canonical and not what was written: `int` comes back +as `integer`, `varchar(255)` as `character varying(255)`, `timestamp(3)` as +`timestamp(3) without time zone`, `int[3]` as `integer[]`, and a domain +column as the domain's name. A view keeps its columns' typmods; a prepared +statement's result types (`pg_prepared_statements.result_types`, the +protocol's RowDescription) carry the typmod only for a column read straight +from a table and `-1` for an expression, so `numeric(10,2) + 1` is +`numeric`. `pg_proc` has full signatures over families and pseudo-types, +`pg_operator` likewise, and `pg_cast` the contexts. + +**MySQL** has no catalog of types, functions or operators. What it has is +`information_schema.COLUMNS`, which describes a column twice: `DATA_TYPE` is +the family (`bigint`, `decimal`, `enum`) and `COLUMN_TYPE` is the whole +canonical spelling — `bigint unsigned`, `tinyint(1)`, `decimal(10,2) +unsigned`, `enum('a','b')`, `bigint(20) unsigned zerofill` — beside the +arguments decoded into `NUMERIC_PRECISION`, `NUMERIC_SCALE`, +`CHARACTER_MAXIMUM_LENGTH`, `DATETIME_PRECISION`, `CHARACTER_SET_NAME` and +`COLLATION_NAME`. The spelling is canonical: `BOOLEAN` becomes `tinyint(1)`, +`INTEGER` becomes `int`, `VARCHAR(10) CHARACTER SET binary` becomes +`varbinary(10)`. A view's columns show that the binder computes a full type +for every expression: `decimal(10,2) + 1` is `decimal(11,2)`, `decimal(10,2) +* decimal(10,2)` is `decimal(20,4)`, `int unsigned + 1` is `bigint +unsigned`, `CONCAT(varchar(255), 'x')` is `varchar(256)`, `SUM(int unsigned)` +is `decimal(32,0)`, `AVG(int)` is `decimal(14,4)`, `->>` is `longtext`. User +routines are described the same way in `ROUTINES` and `PARAMETERS` +(`DTD_IDENTIFIER` is `decimal(5,2)`, `bigint unsigned`); built-in functions +are not described at all. A result set on the wire is coarser than the +catalog: a storage type code (`TINY`, `LONG`, `NEWDECIMAL`, `VAR_STRING`), +a length in bytes, a decimals count and flags (`UNSIGNED`, `NOT_NULL`, +`ENUM`, `SET`, `BINARY`), so a `varchar(255)` column and `CAST(x AS +CHAR(10))` are both `VAR_STRING`, an enum is `STRING` with the `ENUM` flag, +and a `tinyint(1)` is `TINY` with length 1. That code is where the parser's +`var_string` comes from. + +**SQLite** has no catalog of types either. `pragma_table_xinfo` returns a +column's declared type verbatim — `VARCHAR(255)`, `FOO BAR(3)`, `my type`, +or nothing — and the type system is affinity: a rule over the spelling's +substrings (INT anywhere is INTEGER; CHAR, CLOB or TEXT is TEXT; BLOB or no +type is BLOB; REAL, FLOA or DOUB is REAL; anything else is NUMERIC) that +decides how a stored value is coerced, so `FOO BAR(3)` holding `'12'` +stores the integer 12. Arguments are decoration: `CAST(x AS DECIMAL(5,2))` +applies NUMERIC affinity and nothing else. A `STRICT` table admits only +`INT`, `INTEGER`, `REAL`, `TEXT`, `BLOB` and `ANY`, and rejects +`VARCHAR(10)`. An expression has no type; a value has a storage class +(`typeof()` is `integer`, `real`, `text`, `blob` or `null`), and a result +column's `sqlite3_column_decltype` is the declared spelling for a column +read from a table and nothing for anything else. `pragma_function_list` +names functions and their arity and nothing more. + +**ClickHouse** models a type as a call expression, which is why the output +shape was chosen. `system.data_type_families` lists 66 families and 73 +aliases (`INT` is an alias of `Int32`); a column's type in `system.columns` +is the whole expression, canonicalized: `Decimal32(4)` is stored as +`Decimal(9, 4)`, `Enum('a', 'b')` as `Enum8('a' = 1, 'b' = 2)`, +`Variant(String, Int64)` with its members sorted, and `Nested(a UInt8, b +String)` as two columns `n.a Array(UInt8)` and `n.b Array(String)`. +`Nullable` and `LowCardinality` are spelled as wrappers and reported as part +of the type, at any depth. Every expression has a full type computed by the +binder, from argument types with promotion — `Int8 + UInt8` is `Int16`, +`Int32 + UInt64` is `Int64`, `Int32 / Int32` is `Float64`, `Decimal(9, 4) * +Decimal(38, 10)` is `Decimal(38, 14)` — from argument values — +`toDecimal64(x, 4)` is `Decimal(18, 4)`, `toDateTime64(x, 3)` is +`DateTime64(3)` — and from literals by value: `1` is `UInt8`, `-1` is +`Int8`, `[1, NULL]` is `Array(Nullable(UInt8))`. Wrappers propagate: +`concat(lc, 'x')` is `LowCardinality(String)`, `ns = 'x'` is +`Nullable(UInt8)`, `NULL` is `Nullable(Nothing)`. A typed placeholder +`{p:Decimal(10, 2)}` is exactly its declared type. `system.functions` has a +name, an aggregate flag, an alias and a description, and no signature. + +**DuckDB** has `duckdb_types()`, one row per spelling with a `logical_type` +naming the family (`int`, `int4` and `integer` are three rows over +`INTEGER`), a category (`NUMERIC`, `STRING`, `DATETIME`, `BOOLEAN`, +`COMPOSITE`, or none for `bit` and `enum`), and `labels` for an enum, which +a `CREATE TYPE ... AS ENUM` adds to as a non-internal row in the user's +schema. `duckdb_columns().data_type` is the whole canonical expression: +`INTEGER[]`, `INTEGER[3]`, `STRUCT(a INTEGER, b VARCHAR)`, `MAP(VARCHAR, +INTEGER)`, `UNION(num INTEGER, str VARCHAR)`, `DECIMAL(18,3)`, with the +precision and scale also decoded into their own columns. Canonicalization +goes further than anywhere else: `TEXT` is `VARCHAR`, `VARCHAR(10)` is +`VARCHAR` (the length is dropped), `NUMERIC` is `DECIMAL(18,3)`, `VARINT` is +`BIGNUM`, `FLOAT4` is `FLOAT`, `JSON` keeps its name over `VARCHAR`'s id, +and a column of the named enum `mood` is reported as `ENUM('sad', 'ok')` +with the name gone. Expressions have full binder-computed types: +`DECIMAL(18,3) * DECIMAL(18,3)` is `DECIMAL(18,6)`, `1.5` is +`DECIMAL(2,1)`, `SUM(INTEGER)` is `HUGEINT`, `SUM(DECIMAL(18,3))` is +`DECIMAL(38,3)`, `INTEGER / 2` is `DOUBLE`, `[1, NULL]` is `INTEGER[]` with +no inner nullability, and `NULL` is a type of its own. `duckdb_functions()` +has signatures over families and generics — `parameter_types` are +`DECIMAL`, `INTEGER[]`, `ANY`, `T`, `K`, `V` and `return_type` a family — +so the arguments of a result are the binder's, not the catalog's. A +prepared statement's parameter types are `UNKNOWN` until bound. + +**SQL Server** describes a column in `sys.columns` as a family plus decoded +arguments: `system_type_id` and `user_type_id`, `max_length` in bytes with +`-1` for `MAX`, `precision`, `scale`, `collation_name`, `is_nullable`, +`is_identity`. `sys.types` has one row per system type — `decimal` and +`numeric` are two — and one per alias type from `CREATE TYPE ... FROM`, with +`is_user_defined`, its own `max_length`, `precision`, `scale` and +`is_nullable`, and its base's `system_type_id`; `sysname` is such a row over +`nvarchar(128)`, and CLR types like `geography` and `hierarchyid` are +assembly types sharing one `system_type_id`. Canonicalization fills in what +was left out and folds one family into another: `varchar` alone is +`varchar(1)` in a declaration and `varchar(30)` in a `CAST`, `decimal` is +`decimal(18,0)`, `datetime2` is `datetime2(7)`, `FLOAT(24)` is stored as +`real` and `FLOAT(25)` and up as `float`. `sys.all_parameters` describes a +function's parameters the same way as a column. The T-SQL parser sqlc uses +(`teesql`) reports a type as a name with a parameter list in which `MAX` is +a literal node of its own. + +**GoogleSQL** has no catalog sqlc can read offline; its two hosts describe a +column as a whole string. BigQuery's `INFORMATION_SCHEMA.COLUMNS.DATA_TYPE` +is `ARRAY>`, `NUMERIC(10, 2)` or `STRING(10)`, +and `COLUMN_FIELD_PATHS` lists every nested struct field with a path and a +`DATA_TYPE` of its own. Spanner's `SPANNER_TYPE` is `STRING(MAX)`, +`ARRAY`, `PROTO` or `ENUM`, and a column +cannot be a struct. The parser sqlc uses (`zetajones`) has a node per type +form — `SimpleType` with a `TypeParameterList`, `ArrayType`, `StructType` +with named fields, `RangeType`, `MapType`, `FunctionType` — and, as in T-SQL, +`MAX` is a literal node in the parameter list. Arrays do not nest. + +What the review settles: + +| | Unit of identity | Where arguments live | Column spelling reported | Result types | Function signatures | +|---|---|---|---|---|---| +| PostgreSQL | family row, plus one row per array type | opaque typmod and dims on the use site | canonical, decoded by `format_type` | family, typmod only for a table column | full, over families and pseudo-types | +| MySQL | none: a spelling | decoded columns beside the spelling | canonical spelling | full, computed by the binder | none for built-ins | +| SQLite | none: the declared text | none: decoration | verbatim | storage class of the value | arity only | +| ClickHouse | family, with aliases | in the spelling | canonical expression | full, computed by the binder | none | +| DuckDB | family, with aliases | in the spelling, plus decoded columns | canonical expression, some arguments dropped | full, computed by the binder | families and generics | +| SQL Server | family row and alias-type row | decoded columns on the use site | canonical, defaults filled in | family and decoded arguments | families and decoded arguments | +| GoogleSQL | none offline: a spelling | in the spelling | canonical spelling | full | none offline | + +Two conclusions follow. First, no engine keeps arguments inside its type +table: PostgreSQL and SQL Server put them on the use site and everything +else puts them in the spelling. A row per expression is nonetheless the +right shape for sqlc, because sqlc's job is to *report* the expression, and +every engine that decodes its use-site arguments decodes them into exactly +the call expression `TypeExpr` already is; PostgreSQL's typmod is a +per-type encoding that only PostgreSQL can read, so sqlc would store the +decoded form either way. Second, every engine with a catalog canonicalizes +on the way in and reports the canonical form, never the declared spelling, +and the same is true of what `goldeneye` checks the analyze cases against. +The design below changes on that point. + +## The design + +### One row per type expression + +`sql_type` keeps one row per distinct type expression. A row is either a +**family** — a name the dialect or the schema declares, such as `numeric`, +`array`, `struct`, `mood` — or an **instance**, a family applied to +arguments, such as `numeric(10, 2)`, `array(int4)` or +`struct(a: int4, b: text)`. The row's `expr` is the expression's canonical +string, which is its interning key; the row's `name` is the family's name, +so the index that turns `integer` into a row keeps working for instances, +and an instance points at its family. + +```sql +CREATE TABLE sql_type ( + oid INTEGER PRIMARY KEY AUTOINCREMENT, + namespace_oid INTEGER NOT NULL REFERENCES sql_namespace(oid), + dialect_oid INTEGER REFERENCES sql_dialect(oid), + name TEXT NOT NULL, -- the family name: 'numeric', 'array', 'mood' + expr TEXT NOT NULL, -- the whole expression, canonical: 'numeric(10, 2)'; equals name for a family + typtype TEXT NOT NULL DEFAULT 'b', -- b base, c composite, d domain, e enum, r range, p pseudo + category TEXT, + preferred INTEGER NOT NULL DEFAULT 0, + family_oid INTEGER REFERENCES sql_type(oid), -- NULL on a family; the family on an instance + element_oid INTEGER REFERENCES sql_type(oid), -- what the type holds: an array's element, a map's value, a range's subtype + base_oid INTEGER REFERENCES sql_type(oid), -- what the type stands on: a domain's or alias type's base, a wrapper's inner type, a SQLite spelling's affinity + canonical_oid INTEGER REFERENCES sql_type(oid), -- the row the engine reports this one as: integer -> int4, float(24) -> real, mood -> enum('sad', 'ok') in DuckDB + not_null INTEGER NOT NULL DEFAULT 0, -- a domain or alias type declared NOT NULL + UNIQUE (namespace_oid, expr) +); +CREATE INDEX idx_sql_type_name ON sql_type(name); + +-- sql_type_arg: the arguments of an instance, or the fields, labels or +-- members of a declared composite, enum or set, in order. Exactly one of +-- arg_type_oid, int_value, bool_value, string_value and ident is set. +CREATE TABLE sql_type_arg ( + type_oid INTEGER NOT NULL REFERENCES sql_type(oid), + ord INTEGER NOT NULL, + label TEXT NOT NULL DEFAULT '', -- a struct field, tuple element or enum label + arg_type_oid INTEGER REFERENCES sql_type(oid), + nullable INTEGER NOT NULL DEFAULT 0, -- the argument type is nullable here: Array(Nullable(String)) + int_value INTEGER, + bool_value INTEGER, + string_value TEXT, + ident TEXT, -- a bare word that is not a type: max, sum, day to second + PRIMARY KEY (type_oid, ord) +); +``` + +`size` goes: nothing reads it. `type_length` and `type_scale` leave +`sql_attribute`: they were one engine's two arguments, and now every +engine's arguments are rows. `decl_type` stays, since the verbatim spelling +is what the formatter prints back and what SQLite reports. + +The four pointer columns are the denormalization. Each is derivable by +walking `sql_type_arg`, and each is what resolution asks for in one +statement: + +- `family_oid` is what operator and function lookup fall back to when there + is no overload on the instance: `numeric(10, 2) + numeric(5, 1)` finds no + operator on either instance and resolves on `numeric`, which is exactly + what `pg_operator` and `duckdb_functions()` hold. +- `element_oid` is what a subscript, `ANY($1)`, `unnest` and a star over a + map yield, and what `IsArray` was; it is PostgreSQL's `typelem` and + `pg_range.rngsubtype`. +- `base_oid` is what a domain, an alias type, `LowCardinality(T)` or a + SQLite spelling resolves through: `posint = 1` finds no operator on + `posint` and resolves on `int4`; `FOO BAR(3) = 1` resolves on `numeric`. + It is `typbasetype`, SQL Server's `system_type_id` behind a + `user_type_id`, and SQLite's affinity rule. +- `canonical_oid` is the row the engine would report this one as. An alias + spelling points at its family (`integer` at `int4`); a declared type + points at what the engine reports instead of its name when it does so + (DuckDB's `mood` at `enum('sad', 'ok')`); an instance points at the + instance canonicalization rewrote it to when the rewrite changes the + family (SQL Server's `float(24)` at `real`). It replaces the n² implicit + casts between spellings of one type. + +A declared type is a family row with arguments of its own. `CREATE TYPE +point2 AS (x float8, y float8)` is a row named `point2`, `typtype` `c`, with +two labelled type arguments, the way PostgreSQL keeps them as the attributes +of `typrelid`; `CREATE TYPE mood AS ENUM ('sad', 'ok')` is a row with +`typtype` `e` and two string arguments in order, which is `pg_enum` and +DuckDB's `labels`; ClickHouse's `Enum8('active' = 1, 'deleted' = 2)` is an +instance of `enum8` with two labelled integer arguments and `base_oid` at +`int8`; `CREATE DOMAIN posint AS integer` and SQL Server's `CREATE TYPE +PhoneNumber FROM varchar(20) NOT NULL` are rows with `typtype` `d`, +`base_oid` at the base instance and `not_null` set. The same table holds +what the schema names and what it constructs anonymously. + +### Canonicalize on the way in; report the canonical form + +Every engine with a catalog rewrites a declared type before storing it and +reports the rewritten form, and `goldeneye` checks the analyze cases against +what the engine reports. So interning canonicalizes, in three steps that +are dialect data or dialect code: + +1. **Aliases**, which `types.jsonl` already lists: `int` and `integer` + resolve to the canonical family. This also settles what the canonical + *name* is: the one the engine reports, which for PostgreSQL is + `format_type`'s (`integer`, `bigint`, `character varying`) rather than + `pg_type`'s (`int4`, `int8`, `varchar`), so PostgreSQL's `types.jsonl` + flips which spelling is the name and which the alias. Codegen accepts + both spellings already. + + `format_type` is a string and the output is an expression, so the + spelling is read into one, and its grammar is slightly wider than + `name(args)`: the typmod may sit inside a multi-word name + (`timestamp(3) without time zone`, `time(4) with time zone`), after + trailing words (`interval day to second(3)`), or before an array suffix + (`numeric(10,2)[]`, `character varying(255)[]`), and one name is quoted + (`"char"`). The family is the words with the parenthesis lifted out, so + `timestamp(3) without time zone` is `{name: "timestamp without time + zone", args: [3]}`, `interval day to second(3)` is `interval` with an + identifier argument and an integer one, and `numeric(10,2)[]` is + `array(numeric(10, 2))`. Two spellings are the same family under + different typmods, `bpchar` and `character(5)`, and canonicalize to + `character`. The PostgreSQL goldens change with this: `bigserial` + becomes `bigint` (a serial is a default, not a type PostgreSQL reports), + `int4` becomes `integer`, `varchar` becomes `character varying`. +2. **Argument defaults and drops**, which are data: SQL Server's `varchar` + is `varchar(1)` and `decimal` is `decimal(18, 0)`; DuckDB's `numeric` is + `decimal(18, 3)` and `varchar(10)` is `varchar`; PostgreSQL's `int[3]` is + `array(int4)`. A family in `types.jsonl` may say `"defaults": [18, 0]` + or `"args": 0`. +3. **Rewrites that change the family by argument**, which are data too: an + ordered list of pattern, template and bound in `dialect.json` — + `Decimal32($1)` to `Decimal(9, $1)`, `float($1)` to `real` where `$1 <= + 24`, `boolean` to `tinyint(1)`, `sysname` to `nvarchar(128)` — that the + seed loads into a table and the catalog applies before interning. What + only a parser can do stays in the engine's converter, which every engine + has anyway: ClickHouse numbers an Enum's members and sorts a Variant's + when it spells the type, and MySQL's parser folds `varchar(n) character + set binary` into `varbinary(n)`. + +The reported type is the canonical row's expression. The declared spelling +is kept on the attribute in `decl_type`, for the formatter and for SQLite, +whose canonical form is the spelling itself. This reverses the earlier +choice of reporting a column as it was declared: the engines do not, and +the check that keeps the analyzer honest compares against the engines. + +### Nullability is not a type + +A row is never nullable. Outer nullability stays where it is: on the +attribute, on the analyzer's `exprType`, on the reported column. Inner +nullability is a flag on the argument position, so `Array(Nullable(String))` +is an instance of `array` whose one argument is `string` with `nullable` +set, and `Nullable(String)` in a cast is `string` with the expression's own +nullability set. This is what `TypeExpr` already says — `nullable` at +whatever depth it applies, never a wrapper — and it keeps `string` and +`string nullable` from being two types that need their own operators. The +review confirms only ClickHouse spells inner nullability at all: DuckDB's +`[1, NULL]` is `INTEGER[]` and PostgreSQL has no such thing. + +### Array dimensions + +PostgreSQL's type for `int[][]` is `integer[]`, with the dimensions on the +attribute and unenforced; DuckDB and ClickHouse nest, `INTEGER[][]` and +`Array(Array(UInt8))`, and DuckDB distinguishes the fixed-size +`INTEGER[3]`. The expression nests one `array` per declared dimension in +every dialect, with a fixed size as a second argument (`array(integer, 3)`), +because codegen renders one slice per dimension and a two-dimensional +PostgreSQL column has to come out `[][]int32` as it does on the legacy path. +PostgreSQL's canonicalization therefore keeps the dimensions its own +catalog drops, and a future PostgreSQL check in `goldeneye` reads `attndims` +to reproduce them. Subscripting follows the dialect: PostgreSQL yields the +innermost element however many subscripts are applied. + +### The catalog interns at schema time; the analyzer looks up at query time + +The cached catalog is opened read-only (`catalog.go` opens it with +`mode=ro&immutable=1`), and `exprType` carries a bare name precisely so that +analysis never has to write. That constraint stands, and it decides which +expressions become rows: + +- **Interned**: what the dialect seeds and what the schema declares. Every + column type, every declared type's fields and base, every function + signature's argument and return type becomes a row on load, through one + entry point, `ResolveTypeExpr(*TypeExpr) (oid, error)`, which + canonicalizes, then walks the expression bottom-up, interning each + argument type first. `ResolveType` and `ResolveTypeName` become callers + of it. +- **Looked up**: what a query writes. A cast, a constructed array or struct, + a typed placeholder and a function result are resolved by + `LookupTypeExpr(*TypeExpr) (oid, familyOID, bool)`, which canonicalizes, + finds the instance row when the schema happened to declare the same + expression and otherwise the family row, and never writes. + +`exprType` becomes the pair: + +```go +type exprType struct { + typeOID int64 // the instance row when the catalog has one, else the family row, else 0 + expr *core.TypeExpr // the whole expression, whenever anything is known about it + nullable bool + ... +} +``` + +Resolution uses `typeOID` and its `family_oid`, `base_oid` and +`canonical_oid` chain; reporting uses `expr`. The `typeName` fallback and +the `[]` suffix convention go away: an array is `array` applied to its +element, in the catalog as in the output, and `TypeNameString` is replaced +by a function that reads an `ast.TypeName` into a `TypeExpr`, folding +`Typmods` into integer arguments, `ArrayBounds` into one `array` per +dimension, `Names` into a namespace and a name, and `Spelling` through +`ParseTypeExpr`. + +### Result types: the family from the catalog, the arguments from the dialect + +MySQL, ClickHouse and DuckDB compute a full type for every expression in the +binder — `decimal(10,2) + 1` is `decimal(11,2)`, `Int8 + UInt8` is `Int16`, +`SUM(INTEGER)` is `HUGEINT` — and none of them keeps those rules in a +catalog; PostgreSQL's catalog says `numeric + numeric` is `numeric` and its +results drop the typmod. The catalog can only ever answer at the family +level, and that is the baseline every dialect gets: an operator or function +result is the family the overload names, with the arguments of an `$n` +result carried over from the argument it stands for. A result that depends +on an argument's value is a template in the seed — `"returns": "Decimal(18, +$2)"` for `toDecimal64(x, s)` — that the analyzer fills in from the call's +literals. ClickHouse needs it, since its check compares whole expressions; +MySQL's check reads the wire type, which is the family with its flags, so +the baseline passes it. Arithmetic promotion — `Int8 + UInt8` is `Int16` — +is not expressed yet. + +### What each engine hands the core + +The contract with an engine is that its `ast.TypeName` reads into a +`TypeExpr` that says everything the engine's own catalog would. Where an +engine already folds its type into a spelling, `ParseTypeExpr` reads it; +where it does not, the converter has a small change to make. + +| Engine | Form | Expression | +|---|---|---| +| PostgreSQL | `numeric(10,2)`, `varchar(255)`, `timestamp(3) with time zone` | `numeric(10, 2)`, `character varying(255)`, `timestamp with time zone(3)`: typmods become integer arguments on the canonical family, named as `format_type` names it | +| PostgreSQL | `int[]`, `int[][]`, `int[3]` | `array(integer)`, `array(array(integer))`, `array(integer)`: one per array bound, the bound itself dropped as PostgreSQL drops it | +| PostgreSQL | `interval day to second` | `interval('day to second')`: the fields are one identifier argument, as `format_type` prints them | +| PostgreSQL | domain, composite, enum, range | declared rows, as above; `CreateDomainStmt`, `CompositeTypeStmt` and `CreateRangeStmt` gain `schema.Apply` cases | +| PostgreSQL | `myschema.mood` | a row in namespace `myschema`; `Names` resolves to a namespace rather than a dotted name | +| MySQL | `BIGINT UNSIGNED`, `DECIMAL(10,2) UNSIGNED` | `bigint unsigned`, `decimal unsigned(10, 2)`: unsigned is a family of its own, as `COLUMN_TYPE` and the wire flag report it, rather than the alias of the signed type `types.jsonl` lists today; the converter puts it in the name instead of on `ColumnDef.IsUnsigned`, which the core ignores | +| MySQL | `TINYINT(1)`, `DATETIME(6)`, `VARCHAR(255)`, `BOOLEAN` | `tinyint(1)`, `datetime(6)`, `varchar(255)`, `tinyint(1)`: the converter's `Typmods` are read, and `boolean` canonicalizes as MySQL does | +| MySQL | `ENUM('a','b')`, `SET('x','y')` | `enum('a', 'b')`, `set('x', 'y')`: the converter renders `Vals` into the spelling | +| MySQL | `CAST(x AS CHAR(10))` | `char(10)`: the cast converter names the SQL type, not the wire code `var_string` | +| MySQL | `VARCHAR(10) CHARACTER SET binary` | `varbinary(10)`, as the parser folds it; collation is not part of the type | +| SQLite | any spelling | the spelling as an instance, `varchar(255)`, `foo bar(3)`, verbatim as `pragma_table_xinfo` reports it, with `base_oid` set by the affinity rule applied when the dialect resolves an unknown name; `types.jsonl`'s alias lists become the rule | +| SQLite | `STRICT` tables, `ANY` | the family rows; a strict table's column names one of them or fails, as SQLite does | +| SQLite | an expression | its storage class, `integer`, `real`, `text` or `blob`, which is what `typeof()` and the check report | +| ClickHouse | every parametric type | the spelling, read as today, now also for casts, `{p:T}` placeholders and results | +| ClickHouse | `Nullable(T)`, `LowCardinality(T)` | `T` with `nullable`; `lowcardinality(T)` with `base_oid` at `T` | +| ClickHouse | `Decimal32(4)`, `Enum('a', 'b')`, `Variant(String, Int64)`, `INT` | `decimal(9, 4)` by a rewrite, `enum8(a: 1, b: 2)` and `variant(int64, string)` by the converter, `int32` by an alias | +| ClickHouse | `SimpleAggregateFunction(sum, UInt64)` | `simpleaggregatefunction(sum, uint64)` with `sum` an identifier argument | +| ClickHouse | `toDecimal64(x, s)` | `decimal(18, s)`, by the seed's return template | +| ClickHouse | `Nested(a UInt8, b String)` | a relation-shape rule, not a type: the column becomes `n.a array(uint8)` and `n.b array(string)` on load, as `system.columns` has them | +| DuckDB | `STRUCT(a INTEGER, b VARCHAR)`, `MAP(K, V)`, `UNION(...)` | `struct(a: integer, b: varchar)`, `map(varchar, integer)`, `union(num: integer, str: varchar)`: the converter renders the darkwing type expression it already has instead of keeping its name | +| DuckDB | `INTEGER[]`, `INTEGER[3]` | `array(integer)` and `array(integer, 3)`: a list is the cross-dialect array, a fixed size is its second argument | +| DuckDB | `TEXT`, `VARCHAR(10)`, `NUMERIC`, `mood` | `varchar`, `varchar`, `decimal(18, 3)`, `enum('sad', 'ok')`, by aliases, argument rules and `canonical_oid` on the declared enum | +| GoogleSQL | `ARRAY`, `STRUCT`, `RANGE` | `array(int64)`, `struct(a: int64, b: string)`, `range(date)`: the converter renders the zetajones type node in call form, or `ParseTypeExpr` accepts `<...>` | +| GoogleSQL | `STRING(10)`, `STRING(MAX)`, `NUMERIC(10,2)`, `[1, 2]`, `STRUCT(1 AS x)` | the typmods are read, with `max` an identifier argument; the array and struct constructors are typed from their elements | +| SQL Server | `NVARCHAR(MAX)`, `VARCHAR`, `DECIMAL` | `nvarchar(max)` with `max` an identifier argument; `varchar(1)` and `decimal(18, 0)` by the defaults `sys.types` applies | +| SQL Server | `FLOAT(24)` | `real`, by a rewrite | +| SQL Server | `dbo.PhoneNumber`, `sysname` | a row in namespace `dbo`, `typtype` `d`, `base_oid` at `varchar(20)`, `not_null` set; `sysname` seeded the same way over `nvarchar(128)` | + +The `ident` argument is the one addition to `TypeExpr` and to +`goldeneye/analysis.TypeExpr`, which mirrors it. Without it `max`, `sum` and +`day to second` read as types, and today they do: `SimpleAggregateFunction` +reports `sum` as a type. Both parsers that have `MAX` model it as a literal +node, and the converters hand it over as an identifier; `ParseTypeExpr` +writes a bare word that is not a known family as an identifier only when a +dialect says so, since a struct field's type is also a bare word. + +### What the analyzer reports + +`Column` and `Parameter` in `analysis.go` keep `Type` as the expression and +`TypeOID` as the row, instance or family. `DataType` and `IsArray` stay as +the flat view for the legacy compiler bridge, and that bridge derives what +codegen reads from the expression rather than dropping it: `ArrayDims` is +the depth of `array` nesting, `Length` is the first integer argument, +`Unsigned` is a family name ending in ` unsigned`. `sqlc analyze` prints the +expression as it does today, with `ident` as a fifth argument kind. + +`TypeNameString`, `ArraySuffix`, `CreateArrayType`, `TypeLength` and +`TypeScale` are the API that goes; `ResolveTypeExpr`, `LookupTypeExpr` and +`TypeExprOf(oid)` — the expression a row stands for, read back from +`sql_type_arg` — are the API that replaces it. + +### What the seed files gain + +`types.jsonl` is unchanged for a family beyond the optional argument +defaults; an alias becomes a row with `canonical_oid` instead of a mesh of +casts. A function's argument and return types may be expressions, and the +return type may reference an argument's value as well as its type. The +category rules in `dialect.json` apply to families; an instance inherits +its family's category, which is how `numeric(10, 2)` joins the numeric +casts without being seeded. `dialect.json` also carries the dialect's +rewrites, its identifier words and positions, and its affinity rule, so +that nothing about a dialect is code. + +`goldeneye` checks the analyze cases against what each database reports, and +its answer shape is the same `TypeExpr`. ClickHouse and DuckDB report whole +expressions already. MySQL's driver reports the family, unsigned and +nullability but not precision or length, and `ColumnType.DecimalSize` and +`ColumnType.Length` can add them, with the length divided by the charset's +bytes per character since the wire reports bytes. SQLite reports a declared +spelling for a table column and a storage class for an expression, which +are an instance row and a family row respectively. A PostgreSQL check reads +`format_type(atttypid, atttypmod)` and `attndims`. Every check keeps passing +on the way, since a family with no arguments prints as it does now. + +## A worked example: an array of arrays of integers + +```sql +CREATE TABLE grids ( + id bigint PRIMARY KEY, + cells int[][] NOT NULL +); + +-- name: GetGrid :one +SELECT id, cells, cells[1][2] AS cell FROM grids WHERE cells = $1; +``` + +The PostgreSQL parser hands over `pg_catalog.int4` with two array bounds, +which reads into `array(array(int4))`; canonicalization makes it +`array(array(integer))`. Interning walks it bottom-up, so the inner array +gets its row before the outer one. With illustrative OIDs, `sql_type` +holds the seeded families and the two rows the schema added: + +| oid | name | expr | typtype | category | family_oid | element_oid | canonical_oid | +|---|---|---|---|---|---|---|---| +| 23 | integer | integer | b | N | | | | +| 24 | int4 | int4 | b | N | | | 23 | +| 20 | bigint | bigint | b | N | | | | +| 100 | array | array | b | A | | | | +| 1001 | array | array(integer) | b | A | 100 | 23 | | +| 1002 | array | array(array(integer)) | b | A | 100 | 1001 | | + +Row 1001 is what PostgreSQL calls `_int4`; row 1002 is the one PostgreSQL +does not have, since its own type collapses the dimensions onto `attndims`. +An instance takes its family's namespace. `sql_type_arg` has one row per +argument position: + +| type_oid | ord | label | arg_type_oid | nullable | +|---|---|---|---|---| +| 1001 | 1 | | 23 | 0 | +| 1002 | 1 | | 1001 | 0 | + +and `sql_attribute` points `grids.cells` at row 1002, `not_null` set, with +`int[][]` in `decl_type`. + +Analysis resolves `cells` to that attribute, so its `exprType` is +`{typeOID: 1002, expr: array(array(integer)), nullable: false}`, and the +parameter compared with it takes the same type. `cells[1][2]` follows the +dialect's subscript rule — PostgreSQL yields the innermost element however +many subscripts are applied — which is a walk down `element_oid` from 1002 +to 1001 to 23, nullable because a subscript can miss. `sqlc analyze` prints: + +```json +[ + { + "name": "GetGrid", + "cmd": ":one", + "columns": [ + { "name": "id", "type": { "name": "bigint" }, "table": "grids" }, + { + "name": "cells", + "type": { + "name": "array", + "args": [ + { "type": { "name": "array", "args": [ { "type": { "name": "integer" } } ] } } + ] + }, + "table": "grids" + }, + { "name": "cell", "type": { "name": "integer", "nullable": true } } + ], + "params": [ + { + "number": 1, + "column": { + "name": "cells", + "type": { + "name": "array", + "args": [ + { "type": { "name": "array", "args": [ { "type": { "name": "integer" } } ] } } + ] + }, + "table": "grids" + } + } + ] + } +] +``` + +Its string form is `array(array(integer))`; today the same column prints +`array(int4)`, one level, with `type_oid` pointing at a row named `int4[]`. +The legacy bridge derives `DataType` `integer` and `ArrayDims` 2 from the +nesting, so Go codegen renders `[][]int32` as the legacy path does. +DuckDB's `INTEGER[][]` and ClickHouse's `Array(Array(Int32))` produce the +same rows and output, with `int32` in ClickHouse's case. + +## As implemented + +The design above is implemented, engine by engine, with these departures +and details settled on the way: + +- What the note called hooks is data, so that an engine adds a dialect by + writing files and never by registering Go code. `dialect.json` carries + `rewrites`, an ordered list of pattern, template and optional bound — + `float($1)` to `real` where `$1 <= 24`, `decimal` to `decimal(18, 0)`, + `Decimal32($1)` to `Decimal(9, $1)`, `sysname` to `nvarchar(128)` — which + the seed loads into `sql_type_rewrite` and the catalog applies before + interning, first match winning, tried once with the name as spelled and + once with its alias resolved so that `dec` meets a rule on `decimal`; + `idents` and `ident_args`, the words and + argument positions that are identifiers rather than types, kept as dialect + flags; and `affinity`, SQLite's ordered rule for a family the seed does + not list, loaded into `sql_type_affinity` and asked when a schema + declares one. A result that depends on an argument's value is a template + in `functions.jsonl` — `"returns": "Decimal(18, $2)"` — kept on + `sql_proc.return_template` and filled in from the call's literals. What + is genuinely about parsing stays in the engine's converter: ClickHouse + numbers an Enum's members and sorts a Variant's in the canonical + rendering it hands the core, while the spelling the formatter prints stays + the author's. +- A bare type name resolves in the default namespaces only — the catalog's + own, `pg_catalog` and the dialect's default schema — and `CREATE TYPE` + deduplicates within the namespace it names, so `foo.mood` and `mood` are + two types and a bare `mood` never binds to `foo.mood`. A bare `CREATE + TYPE` lands in the dialect's default schema when it has one, so SQL + Server's `PhoneNumber` and `dbo.PhoneNumber` are one row. A type outside + the default namespaces is spelled with its namespace wherever the catalog + spells it, including inside an instance's key, so `array(foo.mood)` and + `array(mood)` are two rows. +- A lookup that may not write — the analyzer's, against the cached catalog + — still canonicalizes an expression whose instance is not a row, however + deep the missing instance sits, so `$1::varchar(10)[]` reports + `array(character varying(10))` against the `array` family. The seed + gives every dialect the `array` family for that reason, whether or not + its `types.jsonl` lists it. +- A family in `types.jsonl` may name a `base` listed before it, which is + how MySQL's unsigned families stand on their signed ones: `bigint + unsigned` is a type of its own, and resolves as a `bigint` where nothing + takes it as itself. +- SQLite's `dialect.json` says `"alias": "base"`, which makes each alias in + its `types.jsonl` a type of its own standing on the type it aliases, + rather than another spelling of it. +- An engine hands the core one of three things: a canonical rendering + (`TypeName.Canonical`, a call expression with fields labelled `a: integer`, + which DuckDB, GoogleSQL and ClickHouse write and the formatter never + prints), the author's spelling (`TypeName.Spelling`, which the formatter + prints back and SQLite hands over as its type), or a name with `Typmods` + and `ArrayBounds`, where an integer constant is an integer argument, a + bare `ast.String` is an identifier and a quoted constant a string. + `ParseTypeExpr` reads a label before a colon, a label before a space only + when a single word follows, and words after a closing parenthesis as part + of the name, as in `decimal(10,2) unsigned`. `ColumnDef.IsUnsigned` and `ColumnDef.Vals` add MySQL's unsigned + and enum members. `ParamRef.Name` carries the name a `{name:Type}` + placeholder gives itself. +- A cast is NULL when its operand is, or when its type says so, as + `Nullable(String)` does; a cast of a placeholder types the placeholder + and takes its name and source from what it is compared with. A cast to + `interval day to second` decodes the field mask the parser reports the + way a column definition does. +- ClickHouse's `LowCardinality(Nullable(T))`, the only order it accepts, + is a nullable column, and the converter and `goldeneye` both read it as + `lowcardinality(T)` with the nullability on the outside, where the + column's nullability lives. +- MySQL types `CAST(x AS CHAR(10))` as `varchar(10)` and `CAST(x AS + BINARY(8))` as `varbinary(8)`, which is what its metadata and a view over + the cast both report, rather than the `char(10)` the table above + proposed. `goldeneye` reads a table column's type from `COLUMN_TYPE`, in + the relations seed and in the analyze check, and compares an expression + by family alone, since the wire carries no arguments. +- SQLite reports a cast to a spelling that is not a storage class, such as + `DECIMAL(5,2)`, as that spelling, while the value's storage class is what + a run would show; the check's cases keep to storage classes. +- DuckDB's `JSON` is grouped under `varchar` by `duckdb_types()`'s logical + type, so a JSON column reports `varchar`; a named enum reports its name, + not its labels, since the canonicalizer cannot see the catalog. A + GoogleSQL array or struct constructor in a select list is still untyped. +- PostgreSQL's `relations.jsonl` spells an array column as its element with + the array flag, which `goldeneye` now writes from `typelem` for the + `_`-prefixed array types alone; `int2vector` and `oidvector` share the + array category but stay types of their own. MySQL's keeps the case of an + enum's members, which are values. + +## Order of work + +1. The tables and the interning entry point: `sql_type.expr`, `family_oid`, + `element_oid`, `base_oid`, `canonical_oid`, `not_null`, `sql_type_arg`, + `ResolveTypeExpr`, `LookupTypeExpr`, `TypeExprOf`, with the alias step + of canonicalization. Arrays become instances of `array`; the `[]` + convention goes. Every existing golden holds, since a bare name prints + the same. +2. The analyzer: `exprType` carries the expression; casts, constructors, + placeholders and function results report it; resolution falls back + through the pointer chain. This is where ClickHouse's casts and + parameters come right. +3. The engines, one at a time, each with an `analyze_types/` case + alongside ClickHouse's and each with its rewrites: PostgreSQL + typmods, dimensions, declared types and `format_type` names; MySQL + unsigned, typmods, members and `boolean`, plus the `var_string` leak; + DuckDB's nested types and dropped arguments; GoogleSQL's angle brackets; + SQL Server's `max`, defaults and alias types; SQLite's affinity rule. +4. The legacy bridge: `parse_core.go` derives `Unsigned`, `Length` and + `ArrayDims` from the expression, and the `experiment_coreanalyzer` cases + grow MySQL unsigned and boolean columns and a PostgreSQL two-dimensional + array, so the core path generates what the legacy path does. +5. Return templates for value-dependent results, ClickHouse first; then + MySQL's precision arithmetic once its check reads precision from the + wire. + +## Open questions + +- How far a return template goes. ClickHouse's arithmetic promotion and + `toDecimal64(x, 4)` are finite rules; `arrayMap(f, arr)` returns an array + of the lambda's result, which needs the lambda typed first. +- Whether DuckDB's dropped `VARCHAR(10)` length and reported anonymous enum + should be canonicalized away as DuckDB does, or kept because a user + declared them. The check decides for the former. diff --git a/internal/dbmanager/client.go b/internal/dbmanager/client.go new file mode 100644 index 0000000..2c49433 --- /dev/null +++ b/internal/dbmanager/client.go @@ -0,0 +1,150 @@ +package dbmanager + +import ( + "context" + "fmt" + "hash/fnv" + "io" + "net/url" + "strings" + + "github.com/jackc/pgx/v5" + "golang.org/x/sync/singleflight" + + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/pgx/poolcache" + "github.com/sqlc-dev/sqlc/internal/shfmt" +) + +type CreateDatabaseRequest struct { + Engine string + Migrations []string + Prefix string +} + +type CreateDatabaseResponse struct { + Uri string +} + +type Client interface { + CreateDatabase(context.Context, *CreateDatabaseRequest) (*CreateDatabaseResponse, error) + Close(context.Context) +} + +var flight singleflight.Group + +type ManagedClient struct { + cache *poolcache.Cache + replacer *shfmt.Replacer + servers []config.Server +} + +func dbid(migrations []string) string { + h := fnv.New64() + for _, query := range migrations { + io.WriteString(h, query) + } + return fmt.Sprintf("%x", h.Sum(nil)) +} + +func (m *ManagedClient) CreateDatabase(ctx context.Context, req *CreateDatabaseRequest) (*CreateDatabaseResponse, error) { + hash := dbid(req.Migrations) + prefix := req.Prefix + if prefix == "" { + prefix = "sqlc_managed" + } + name := fmt.Sprintf("%s_%s", prefix, hash) + + engine := config.Engine(req.Engine) + switch engine { + case config.EngineMySQL: + // pass + case config.EnginePostgreSQL: + // pass + default: + return nil, fmt.Errorf("unsupported engine: %s", engine) + } + + var base string + for _, server := range m.servers { + if server.Engine == engine { + base = server.URI + break + } + } + + if strings.TrimSpace(base) == "" { + return nil, fmt.Errorf("no PostgreSQL database server found") + } + + serverUri := m.replacer.Replace(base) + pool, err := m.cache.Open(ctx, serverUri) + if err != nil { + return nil, err + } + + uri, err := url.Parse(serverUri) + if err != nil { + return nil, err + } + uri.Path = "/" + name + + key := uri.String() + _, err, _ = flight.Do(key, func() (any, error) { + // TODO: Use a parameterized query + row := pool.QueryRow(ctx, + fmt.Sprintf(`SELECT datname FROM pg_database WHERE datname = '%s'`, name)) + + var datname string + if err := row.Scan(&datname); err == nil { + return nil, nil + } + + if _, err := pool.Exec(ctx, fmt.Sprintf(`CREATE DATABASE "%s"`, name)); err != nil { + return nil, err + } + + conn, err := pgx.Connect(ctx, uri.String()) + if err != nil { + pool.Exec(ctx, fmt.Sprintf(`DROP DATABASE IF EXISTS "%s" WITH (FORCE)`, name)) + return nil, fmt.Errorf("connect %s: %s", name, err) + } + defer conn.Close(ctx) + + var migrationErr error + for _, q := range req.Migrations { + if len(strings.TrimSpace(q)) == 0 { + continue + } + if _, err := conn.Exec(ctx, q); err != nil { + migrationErr = fmt.Errorf("%s: %s", q, err) + break + } + } + + if migrationErr != nil { + pool.Exec(ctx, fmt.Sprintf(`DROP DATABASE IF EXISTS "%s" WITH (FORCE)`, name)) + return nil, migrationErr + } + + return nil, nil + }) + + if err != nil { + return nil, err + } + + return &CreateDatabaseResponse{Uri: key}, err +} + +func (m *ManagedClient) Close(ctx context.Context) { + m.cache.Close() +} + +func NewClient(servers []config.Server) *ManagedClient { + return &ManagedClient{ + cache: poolcache.New(), + servers: servers, + replacer: shfmt.NewReplacer(nil), + } +} diff --git a/internal/debug/dump.go b/internal/debug/dump.go new file mode 100644 index 0000000..ac5eb73 --- /dev/null +++ b/internal/debug/dump.go @@ -0,0 +1,28 @@ +package debug + +import ( + "encoding/json" + "fmt" + + "github.com/davecgh/go-spew/spew" + + "github.com/sqlc-dev/sqlc/internal/sqlcdebug" +) + +// Active reports whether SQLCDEBUG had any value set at startup. It +// remains a global so unrelated debug-spew sites that don't tie to a +// specific setting can gate their output on "is debug mode on at all". +var Active = sqlcdebug.Any() + +func Dump(n ...any) { + if Active { + spew.Dump(n) + } +} + +func DumpAsJSON(a any) { + if Active { + out, _ := json.MarshalIndent(a, "", " ") + fmt.Printf("%s\n", out) + } +} diff --git a/internal/docs/lint.go b/internal/docs/lint.go new file mode 100644 index 0000000..58edb91 --- /dev/null +++ b/internal/docs/lint.go @@ -0,0 +1,381 @@ +// Package docs validates the documentation content contract for docs/. +// +// The docs/ directory is plain CommonMark + GitHub-flavored Markdown with no +// rendering toolchain in this repository; a separate repository consumes it +// and builds the documentation site. This package enforces the contract that +// consumer relies on: +// +// - every page parses as Markdown and starts with exactly one level-1 +// heading (the page title) +// - every relative link and image resolves to a file inside docs/, and +// anchor fragments resolve to a heading in the target page +// - every page appears exactly once in toc.yaml, either in a section or in +// the unlisted set, and every toc.yaml entry names a real page +// - no raw HTML or JSX except HTML comments +// - no MyST/Sphinx directives left over from the old toolchain +package docs + +import ( + "bytes" + "fmt" + "os" + "path" + "path/filepath" + "sort" + "strings" + "unicode" + + "github.com/yuin/goldmark" + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/extension" + "github.com/yuin/goldmark/text" + "gopkg.in/yaml.v3" +) + +// A Problem is a single contract violation, located by file (relative to the +// docs root) and 1-based line number. +type Problem struct { + File string + Line int + Message string +} + +func (p Problem) String() string { + return fmt.Sprintf("%s:%d: %s", p.File, p.Line, p.Message) +} + +type tocFile struct { + Index string `yaml:"index"` + Sections []struct { + Title string `yaml:"title"` + Pages []string `yaml:"pages"` + } `yaml:"sections"` + Unlisted []string `yaml:"unlisted"` +} + +type page struct { + src []byte + doc ast.Node + anchors map[string]bool +} + +// Lint validates every Markdown file under root against the content +// contract and cross-checks the set of files against root/toc.yaml. +func Lint(root string) ([]Problem, error) { + var problems []Problem + + files, err := markdownFiles(root) + if err != nil { + return nil, err + } + + md := goldmark.New(goldmark.WithExtensions(extension.GFM)) + + // First pass: parse everything and collect heading anchors, so link + // fragments can be validated against any page. + pages := make(map[string]*page, len(files)) + for _, rel := range files { + src, err := os.ReadFile(filepath.Join(root, filepath.FromSlash(rel))) + if err != nil { + return nil, err + } + doc := md.Parser().Parse(text.NewReader(src)) + pages[rel] = &page{src: src, doc: doc, anchors: headingAnchors(doc, src)} + } + + for _, rel := range files { + problems = append(problems, lintPage(rel, pages)...) + } + + problems = append(problems, lintTOC(root, files)...) + + sort.Slice(problems, func(i, j int) bool { + if problems[i].File != problems[j].File { + return problems[i].File < problems[j].File + } + return problems[i].Line < problems[j].Line + }) + return problems, nil +} + +// markdownFiles returns the slash-separated paths of all .md files under +// root, relative to root. +func markdownFiles(root string) ([]string, error) { + var files []string + err := filepath.WalkDir(root, func(p string, d os.DirEntry, err error) error { + if err != nil { + return err + } + if !d.IsDir() && strings.HasSuffix(d.Name(), ".md") { + rel, err := filepath.Rel(root, p) + if err != nil { + return err + } + files = append(files, filepath.ToSlash(rel)) + } + return nil + }) + if err != nil { + return nil, err + } + sort.Strings(files) + return files, nil +} + +func lintPage(rel string, pages map[string]*page) []Problem { + var problems []Problem + p := pages[rel] + report := func(n ast.Node, format string, args ...any) { + problems = append(problems, Problem{ + File: rel, + Line: nodeLine(n, p.src), + Message: fmt.Sprintf(format, args...), + }) + } + + var h1s int + firstBlock := true + ast.Walk(p.doc, func(n ast.Node, entering bool) (ast.WalkStatus, error) { + if !entering { + return ast.WalkContinue, nil + } + if n.Type() == ast.TypeBlock && n.Parent() == p.doc { + if firstBlock { + firstBlock = false + if h, ok := n.(*ast.Heading); !ok || h.Level != 1 { + report(n, "page must start with a level-1 heading (its title)") + } + } + } + switch n := n.(type) { + case *ast.Heading: + if n.Level == 1 { + h1s++ + if h1s == 2 { + report(n, "page has more than one level-1 heading") + } + } + case *ast.Link: + problems = append(problems, checkLink(rel, string(n.Destination), false, n, pages)...) + case *ast.Image: + problems = append(problems, checkLink(rel, string(n.Destination), true, n, pages)...) + case *ast.HTMLBlock, *ast.RawHTML: + if raw := rawHTMLText(n, p.src); !isHTMLComment(raw) { + report(n, "raw HTML is not allowed: %s", firstLine(raw)) + } + case *ast.Paragraph: + if t := nodeText(n, p.src); strings.HasPrefix(t, ":::") { + report(n, "MyST directive syntax is not allowed; use GitHub alerts (> [!NOTE]) instead") + } + case *ast.FencedCodeBlock: + if info := fenceInfo(n, p.src); strings.HasPrefix(info, "{") { + report(n, "MyST fenced directive %q is not allowed; use GitHub alerts (> [!NOTE]) instead", info) + } + } + return ast.WalkContinue, nil + }) + return problems +} + +func checkLink(rel, dest string, isImage bool, n ast.Node, pages map[string]*page) []Problem { + p := pages[rel] + problem := func(format string, args ...any) []Problem { + return []Problem{{ + File: rel, + Line: nodeLine(n, p.src), + Message: fmt.Sprintf(format, args...), + }} + } + + switch { + case dest == "": + return problem("empty link destination") + case strings.HasPrefix(dest, "http://"), strings.HasPrefix(dest, "https://"), strings.HasPrefix(dest, "mailto:"): + return nil + case strings.HasPrefix(dest, "#"): + if !p.anchors[strings.TrimPrefix(dest, "#")] { + return problem("anchor %s not found in this page", dest) + } + return nil + case strings.HasPrefix(dest, "/"): + return problem("absolute link %q; use a path relative to this file", dest) + case strings.Contains(dest, "://"): + return problem("unsupported link scheme in %q", dest) + } + + pathPart, frag, _ := strings.Cut(dest, "#") + target := path.Join(path.Dir(rel), pathPart) + if target == ".." || strings.HasPrefix(target, "../") { + return problem("link %q points outside docs/", dest) + } + + tp, ok := pages[target] + if !ok { + if isImage || !strings.HasSuffix(target, ".md") { + // Non-page assets (images, other files) just need to exist on + // disk; they were not parsed in the first pass. + return problem("link target %q does not exist", target) + } + return problem("link target %q does not exist", target) + } + if frag != "" && !tp.anchors[frag] { + return problem("anchor #%s not found in %s", frag, target) + } + return nil +} + +func lintTOC(root string, files []string) []Problem { + const tocName = "toc.yaml" + problem := func(format string, args ...any) Problem { + return Problem{File: tocName, Line: 1, Message: fmt.Sprintf(format, args...)} + } + + data, err := os.ReadFile(filepath.Join(root, tocName)) + if err != nil { + return []Problem{problem("%v", err)} + } + dec := yaml.NewDecoder(bytes.NewReader(data)) + dec.KnownFields(true) + var toc tocFile + if err := dec.Decode(&toc); err != nil { + return []Problem{problem("%v", err)} + } + + var problems []Problem + listed := make(map[string]int) + add := func(entry string) { + listed[entry]++ + } + add(toc.Index) + for _, s := range toc.Sections { + for _, pg := range s.Pages { + add(pg) + } + } + for _, pg := range toc.Unlisted { + add(pg) + } + + onDisk := make(map[string]bool, len(files)) + for _, f := range files { + onDisk[f] = true + } + for entry, count := range listed { + if count > 1 { + problems = append(problems, problem("%s is listed %d times", entry, count)) + } + if !onDisk[entry] { + problems = append(problems, problem("%s is listed but does not exist", entry)) + } + } + for _, f := range files { + if listed[f] == 0 { + problems = append(problems, problem("%s is not listed; add it to a section or to unlisted", f)) + } + } + return problems +} + +// headingAnchors returns the set of GitHub-style anchor slugs for the +// headings in doc, applying GitHub's -1, -2 suffixes for duplicates. +func headingAnchors(doc ast.Node, src []byte) map[string]bool { + anchors := make(map[string]bool) + seen := make(map[string]int) + ast.Walk(doc, func(n ast.Node, entering bool) (ast.WalkStatus, error) { + if h, ok := n.(*ast.Heading); ok && entering { + slug := slugify(nodeText(h, src)) + if c := seen[slug]; c > 0 { + anchors[fmt.Sprintf("%s-%d", slug, c)] = true + } else { + anchors[slug] = true + } + seen[slug]++ + } + return ast.WalkContinue, nil + }) + return anchors +} + +// slugify converts heading text to a GitHub-style anchor: lowercase, spaces +// become hyphens, and everything except letters, digits, hyphens and +// underscores is dropped. +func slugify(s string) string { + var b strings.Builder + for _, r := range strings.ToLower(s) { + switch { + case unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' || r == '-': + b.WriteRune(r) + case r == ' ': + b.WriteByte('-') + } + } + return b.String() +} + +func nodeText(n ast.Node, src []byte) string { + var b strings.Builder + ast.Walk(n, func(c ast.Node, entering bool) (ast.WalkStatus, error) { + if entering { + switch c := c.(type) { + case *ast.Text: + b.Write(c.Segment.Value(src)) + case *ast.String: + b.Write(c.Value) + } + } + return ast.WalkContinue, nil + }) + return b.String() +} + +func rawHTMLText(n ast.Node, src []byte) string { + var b strings.Builder + switch n := n.(type) { + case *ast.HTMLBlock: + for i := 0; i < n.Lines().Len(); i++ { + seg := n.Lines().At(i) + b.Write(seg.Value(src)) + } + if n.HasClosure() { + b.Write(n.ClosureLine.Value(src)) + } + case *ast.RawHTML: + for i := 0; i < n.Segments.Len(); i++ { + seg := n.Segments.At(i) + b.Write(seg.Value(src)) + } + } + return strings.TrimSpace(b.String()) +} + +func isHTMLComment(raw string) bool { + return strings.HasPrefix(raw, "") +} + +func fenceInfo(n *ast.FencedCodeBlock, src []byte) string { + if n.Info == nil { + return "" + } + return strings.TrimSpace(string(n.Info.Segment.Value(src))) +} + +func firstLine(s string) string { + if i := strings.IndexByte(s, '\n'); i >= 0 { + return s[:i] + } + return s +} + +// nodeLine returns the 1-based line number of n, using the nearest +// enclosing block that carries source positions. +func nodeLine(n ast.Node, src []byte) int { + if rh, ok := n.(*ast.RawHTML); ok && rh.Segments.Len() > 0 { + return 1 + bytes.Count(src[:rh.Segments.At(0).Start], []byte("\n")) + } + for cur := n; cur != nil; cur = cur.Parent() { + if cur.Type() == ast.TypeBlock && cur.Lines().Len() > 0 { + return 1 + bytes.Count(src[:cur.Lines().At(0).Start], []byte("\n")) + } + } + return 1 +} diff --git a/internal/docs/lint_test.go b/internal/docs/lint_test.go new file mode 100644 index 0000000..dbfa9a5 --- /dev/null +++ b/internal/docs/lint_test.go @@ -0,0 +1,116 @@ +package docs + +import ( + "os" + "path/filepath" + "runtime" + "strings" + "testing" +) + +// TestDocs validates the repository's docs/ directory against the content +// contract. This is a unit test rather than an endtoend case because the +// contract is a property of the documentation source tree, not of anything +// the sqlc CLI does: there is no command whose output could pin it down. +func TestDocs(t *testing.T) { + _, thisFile, _, ok := runtime.Caller(0) + if !ok { + t.Fatal("could not locate source file") + } + root := filepath.Join(filepath.Dir(thisFile), "..", "..", "docs") + + problems, err := Lint(root) + if err != nil { + t.Fatal(err) + } + for _, p := range problems { + t.Errorf("%s", p) + } +} + +// TestLintViolations pins down what the linter rejects, using a synthetic +// docs tree that violates each rule of the contract once. +func TestLintViolations(t *testing.T) { + root := t.TempDir() + write := func(name, content string) { + t.Helper() + p := filepath.Join(root, filepath.FromSlash(name)) + if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(p, []byte(content), 0o644); err != nil { + t.Fatal(err) + } + } + + write("toc.yaml", ` +index: index.md +sections: + - title: Guides + pages: + - sub/page.md + - sub/page.md + - ghost.md +`) + write("index.md", `# Index + +A [broken link](missing.md) and a [bad anchor](sub/page.md#nope) and +a [bad self anchor](#nowhere) and an [absolute link](/sub/page.md) and +an [escaping link](../outside.md). + +
raw html
+ + + +:::{note} +myst directive +::: + +`+"```{warning}"+` +myst fence +`+"```"+` + +# Second title +`) + write("sub/page.md", "Not a heading first.\n\n# Title\n") + write("orphan.md", "# Orphan\n") + + problems, err := Lint(root) + if err != nil { + t.Fatal(err) + } + want := []string{ + `index.md:3: link target "missing.md" does not exist`, + "index.md:3: anchor #nope not found in sub/page.md", + "index.md:3: anchor #nowhere not found in this page", + `index.md:3: absolute link "/sub/page.md"`, + `index.md:3: link "../outside.md" points outside docs/`, + "index.md:7: raw HTML is not allowed:
raw html
", + "index.md:11: MyST directive syntax is not allowed", + `index.md:16: MyST fenced directive "{warning}" is not allowed`, + "index.md:19: page has more than one level-1 heading", + "sub/page.md:1: page must start with a level-1 heading", + "toc.yaml:1: sub/page.md is listed 2 times", + "toc.yaml:1: ghost.md is listed but does not exist", + "toc.yaml:1: orphan.md is not listed", + } + var got []string + for _, p := range problems { + got = append(got, p.String()) + } + for _, w := range want { + found := false + for _, g := range got { + if strings.Contains(g, w) { + found = true + break + } + } + if !found { + t.Errorf("expected a problem containing %q, got:\n %s", w, strings.Join(got, "\n ")) + } + } + if len(got) != len(want) { + t.Errorf("got %d problems, want %d:\n %s", len(got), len(want), strings.Join(got, "\n ")) + } +} diff --git a/internal/endtoend/CLAUDE.md b/internal/endtoend/CLAUDE.md new file mode 100644 index 0000000..b9c995c --- /dev/null +++ b/internal/endtoend/CLAUDE.md @@ -0,0 +1,117 @@ +# End-to-End Tests - Native Database Setup + +This document describes how to set up MySQL and PostgreSQL for running end-to-end tests in environments without Docker, particularly when using an HTTP proxy. + +## Overview + +The end-to-end tests support three methods for connecting to databases: + +1. **Environment Variables**: Set `POSTGRESQL_SERVER_URI` and `MYSQL_SERVER_URI` directly +2. **Docker**: Automatically starts containers via the docker package +3. **Native Installation**: Starts existing database services on Linux + +## Installing Databases with HTTP Proxy + +In environments where DNS doesn't work directly but an HTTP proxy is available (e.g., some CI environments), you need to configure apt to use the proxy before installing packages. + +### Configure apt Proxy + +```bash +# Check if HTTP_PROXY is set +echo $HTTP_PROXY + +# Configure apt to use the proxy +sudo tee /etc/apt/apt.conf.d/99proxy << EOF +Acquire::http::Proxy "$HTTP_PROXY"; +Acquire::https::Proxy "$HTTPS_PROXY"; +EOF + +# Update package lists +sudo apt-get update -qq +``` + +### Install PostgreSQL + +```bash +# Install PostgreSQL +sudo DEBIAN_FRONTEND=noninteractive apt-get install -y postgresql postgresql-contrib + +# Start the service +sudo service postgresql start + +# Set password for postgres user +sudo -u postgres psql -c "ALTER USER postgres PASSWORD 'postgres';" + +# Configure pg_hba.conf for password authentication +# Find the hba_file location: +sudo -u postgres psql -t -c "SHOW hba_file;" + +# Add md5 authentication for localhost (add to the beginning of pg_hba.conf): +# host all all 127.0.0.1/32 md5 + +# Reload PostgreSQL +sudo service postgresql reload +``` + +### Install MySQL + +```bash +# Pre-configure MySQL root password +echo "mysql-server mysql-server/root_password password mysecretpassword" | sudo debconf-set-selections +echo "mysql-server mysql-server/root_password_again password mysecretpassword" | sudo debconf-set-selections + +# Install MySQL +sudo DEBIAN_FRONTEND=noninteractive apt-get install -y mysql-server + +# Start the service +sudo service mysql start + +# Verify connection +mysql -uroot -pmysecretpassword -e "SELECT 1;" +``` + +## Expected Database Credentials + +The native database support expects the following credentials: + +### PostgreSQL +- **URI**: `postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable` +- **User**: `postgres` +- **Password**: `postgres` +- **Port**: `5432` + +### MySQL +- **URI**: `root:mysecretpassword@tcp(localhost:3306)/mysql?multiStatements=true&parseTime=true` +- **User**: `root` +- **Password**: `mysecretpassword` +- **Port**: `3306` + +## Running Tests + +```bash +# Run end-to-end tests +go test -v -run TestReplay -timeout 20m ./internal/endtoend/... + +# With verbose logging +go test -v -run TestReplay -timeout 20m ./internal/endtoend/... 2>&1 | tee test.log +``` + +## Troubleshooting + +### apt-get times out or fails +- Ensure HTTP proxy is configured in `/etc/apt/apt.conf.d/99proxy` +- Check that the proxy URL is correct: `echo $HTTP_PROXY` +- Try running `sudo apt-get update` first to verify connectivity + +### MySQL connection refused +- Check if MySQL is running: `sudo service mysql status` +- Verify the password: `mysql -uroot -pmysecretpassword -e "SELECT 1;"` +- Check if MySQL is listening on TCP: `netstat -tlnp | grep 3306` + +### PostgreSQL authentication failed +- Verify pg_hba.conf has md5 authentication for localhost +- Check password: `PGPASSWORD=postgres psql -h localhost -U postgres -c "SELECT 1;"` +- Reload PostgreSQL after config changes: `sudo service postgresql reload` + +### DNS resolution fails +This is expected in some environments. Configure apt proxy as shown above. diff --git a/internal/endtoend/case_test.go b/internal/endtoend/case_test.go new file mode 100644 index 0000000..3579183 --- /dev/null +++ b/internal/endtoend/case_test.go @@ -0,0 +1,143 @@ +package main + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + "runtime" + "strings" + "testing" +) + +type Testcase struct { + Name string + Path string + ConfigName string + Stderr []byte + Stdout []byte + Exec *Exec +} + +type ExecMeta struct { + InvalidSchema bool `json:"invalid_schema"` +} + +type Exec struct { + Command string `json:"command"` + Args []string `json:"args"` + Contexts []string `json:"contexts"` + Process string `json:"process"` + OS []string `json:"os"` + Env map[string]string `json:"env"` + Meta ExecMeta `json:"meta"` +} + +func parseStderr(t *testing.T, dir, testctx string) []byte { + t.Helper() + paths := []string{ + filepath.Join(dir, "stderr", fmt.Sprintf("%s.txt", testctx)), + filepath.Join(dir, fmt.Sprintf("stderr_%s.txt", runtime.GOOS)), + filepath.Join(dir, "stderr.txt"), + } + for _, path := range paths { + if _, err := os.Stat(path); !os.IsNotExist(err) { + blob, err := os.ReadFile(path) + if err != nil { + t.Fatal(err) + } + return blob + } + } + return nil +} + +// parseStdout reads the command's expected output: stdout.json for a +// command that prints JSON, so editors highlight it, otherwise stdout.txt. +func parseStdout(t *testing.T, dir string) []byte { + t.Helper() + for _, name := range []string{"stdout.json", "stdout.txt"} { + path := filepath.Join(dir, name) + if _, err := os.Stat(path); os.IsNotExist(err) { + continue + } + blob, err := os.ReadFile(path) + if err != nil { + t.Fatal(err) + } + return blob + } + return nil +} + +// hasSQLCConfig reports whether dir contains an sqlc configuration file. +func hasSQLCConfig(dir string) bool { + for _, name := range []string{"sqlc.json", "sqlc.yaml", "sqlc.yml"} { + if _, err := os.Stat(filepath.Join(dir, name)); err == nil { + return true + } + } + return false +} + +func parseExec(t *testing.T, dir string) *Exec { + t.Helper() + path := filepath.Join(dir, "exec.json") + if _, err := os.Stat(path); os.IsNotExist(err) { + return nil + } + var e Exec + blob, err := os.ReadFile(path) + if err != nil { + t.Fatalf("%s: %s", path, err) + } + if err := json.Unmarshal(blob, &e); err != nil { + t.Fatalf("%s: %s", path, err) + } + if e.Command == "" { + e.Command = "generate" + } + return &e +} + +func FindTests(t *testing.T, root, testctx string) []*Testcase { + var tcs []*Testcase + err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + name := info.Name() + if name == "sqlc.json" || name == "sqlc.yaml" || name == "sqlc.yml" { + dir := filepath.Dir(path) + tcs = append(tcs, &Testcase{ + Path: dir, + Name: strings.TrimPrefix(dir, root+string(filepath.Separator)), + ConfigName: name, + Stderr: parseStderr(t, dir, testctx), + Stdout: parseStdout(t, dir), + Exec: parseExec(t, dir), + }) + return filepath.SkipDir + } + // Config-less command tests (e.g. parse, analyze) are discovered by + // their exec.json when no sqlc config is present in the directory. + if name == "exec.json" { + dir := filepath.Dir(path) + if !hasSQLCConfig(dir) { + tcs = append(tcs, &Testcase{ + Path: dir, + Name: strings.TrimPrefix(dir, root+string(filepath.Separator)), + Stderr: parseStderr(t, dir, testctx), + Stdout: parseStdout(t, dir), + Exec: parseExec(t, dir), + }) + return filepath.SkipDir + } + } + return nil + }) + if err != nil { + t.Fatal(err) + } + return tcs +} diff --git a/internal/endtoend/ddl_test.go b/internal/endtoend/ddl_test.go new file mode 100644 index 0000000..3cd66a6 --- /dev/null +++ b/internal/endtoend/ddl_test.go @@ -0,0 +1,64 @@ +package main + +import ( + "fmt" + "os" + "path/filepath" + "testing" + + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/sqltest/local" +) + +func TestValidSchema(t *testing.T) { + for _, replay := range FindTests(t, "testdata", "base") { + + if replay.Exec != nil { + if replay.Exec.Meta.InvalidSchema { + continue + } + } + + // Config-less command tests (parse, analyze) have no schema to validate. + if replay.ConfigName == "" { + continue + } + + file := filepath.Join(replay.Path, replay.ConfigName) + rd, err := os.Open(file) + if err != nil { + t.Fatal(err) + } + + conf, err := config.ParseConfig(rd) + if err != nil { + t.Fatal(err) + } + + for j, pkg := range conf.SQL { + switch pkg.Engine { + case config.EnginePostgreSQL: + // pass + case config.EngineMySQL: + // pass + default: + continue + } + t.Run(fmt.Sprintf("endtoend-%s-%d", file, j), func(t *testing.T) { + t.Parallel() + + var schema []string + for _, path := range pkg.Schema { + schema = append(schema, filepath.Join(filepath.Dir(file), path)) + } + + switch pkg.Engine { + case config.EnginePostgreSQL: + local.PostgreSQL(t, schema) + case config.EngineMySQL: + local.MySQL(t, schema) + } + }) + } + } +} diff --git a/internal/endtoend/endtoend_test.go b/internal/endtoend/endtoend_test.go new file mode 100644 index 0000000..1196ea7 --- /dev/null +++ b/internal/endtoend/endtoend_test.go @@ -0,0 +1,456 @@ +package main + +import ( + "bytes" + "context" + "fmt" + "os" + osexec "os/exec" + "path/filepath" + "runtime" + "slices" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + + "github.com/sqlc-dev/sqlc/internal/cmd" + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/opts" + "github.com/sqlc-dev/sqlc/internal/sqlcdebug" + "github.com/sqlc-dev/sqlc/internal/sqltest/docker" + "github.com/sqlc-dev/sqlc/internal/sqltest/native" +) + +// withSQLCDEBUG installs the given SQLCDEBUG-formatted string for the +// duration of the test and restores the empty default afterwards. +// +// Callers in TestReplay are sequential, so this does not need a mutex: +// Go's test scheduler does not run TestReplay concurrently with the +// parallel top-level tests in this package. +func withSQLCDEBUG(t *testing.T, raw string) func() { + t.Helper() + if raw == "" { + return func() {} + } + sqlcdebug.Update(raw) + return func() { sqlcdebug.Update("") } +} + +func lineEndings() cmp.Option { + return cmp.Transformer("LineEndings", func(in string) string { + // Replace Windows new lines with Unix newlines + return strings.Replace(in, "\r\n", "\n", -1) + }) +} + +func stderrTransformer() cmp.Option { + return cmp.Transformer("Stderr", func(in string) string { + s := strings.Replace(in, "\r", "", -1) + return strings.Replace(s, "\\", "/", -1) + }) +} + +func TestExamples(t *testing.T) { + t.Parallel() + ctx := context.Background() + + examples, err := filepath.Abs(filepath.Join("..", "..", "examples")) + if err != nil { + t.Fatal(err) + } + + files, err := os.ReadDir(examples) + if err != nil { + t.Fatal(err) + } + + for _, replay := range files { + if !replay.IsDir() { + continue + } + tc := replay.Name() + t.Run(tc, func(t *testing.T) { + t.Parallel() + path := filepath.Join(examples, tc) + var stderr bytes.Buffer + opts := &cmd.Options{ + Env: cmd.Env{}, + Stderr: &stderr, + } + output, err := cmd.Generate(ctx, path, "", opts) + if err != nil { + t.Fatalf("sqlc generate failed: %s", stderr.String()) + } + cmpDirectory(t, path, output) + }) + } +} + +func BenchmarkExamples(b *testing.B) { + ctx := context.Background() + examples, err := filepath.Abs(filepath.Join("..", "..", "examples")) + if err != nil { + b.Fatal(err) + } + files, err := os.ReadDir(examples) + if err != nil { + b.Fatal(err) + } + for _, replay := range files { + if !replay.IsDir() { + continue + } + tc := replay.Name() + b.Run(tc, func(b *testing.B) { + path := filepath.Join(examples, tc) + for i := 0; i < b.N; i++ { + var stderr bytes.Buffer + opts := &cmd.Options{ + Env: cmd.Env{}, + Stderr: &stderr, + } + cmd.Generate(ctx, path, "", opts) + } + }) + } +} + +type textContext struct { + Mutate func(*testing.T, string) func(*config.Config) + Enabled func() bool + // Experiments names the experiments every case in this context runs + // with. A case's own SQLCEXPERIMENT is appended to these, so a case can + // still turn one back off with the "no" prefix. + Experiments func() []string +} + +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 mysqlURI, postgresURI string + + // First, check environment variables + if uri := os.Getenv("POSTGRESQL_SERVER_URI"); uri != "" { + postgresURI = uri + } + if uri := os.Getenv("MYSQL_SERVER_URI"); uri != "" { + mysqlURI = uri + } + + // Try Docker for any missing databases + if postgresURI == "" || mysqlURI == "" { + if err := docker.Installed(); err == nil { + if postgresURI == "" { + host, err := docker.StartPostgreSQLServer(ctx) + if err != nil { + t.Logf("docker postgresql startup failed: %s", err) + } else { + postgresURI = host + } + } + if mysqlURI == "" { + host, err := docker.StartMySQLServer(ctx) + if err != nil { + t.Logf("docker mysql startup failed: %s", err) + } else { + mysqlURI = host + } + } + } + } + + // Try native installation for any missing databases (Linux only) + if postgresURI == "" || mysqlURI == "" { + if err := native.Supported(); err == nil { + if postgresURI == "" { + host, err := native.StartPostgreSQLServer(ctx) + if err != nil { + t.Logf("native postgresql startup failed: %s", err) + } else { + postgresURI = host + } + } + if mysqlURI == "" { + host, err := native.StartMySQLServer(ctx) + if err != nil { + t.Logf("native mysql startup failed: %s", err) + } else { + mysqlURI = host + } + } + } + } + + // Log which databases are available + t.Logf("PostgreSQL available: %v (URI: %s)", postgresURI != "", postgresURI) + t.Logf("MySQL available: %v (URI: %s)", mysqlURI != "", mysqlURI) + + contexts := map[string]textContext{ + "base": { + Mutate: func(t *testing.T, path string) func(*config.Config) { return func(c *config.Config) {} }, + Enabled: func() bool { return true }, + }, + "managed-db": { + Mutate: func(t *testing.T, path string) func(*config.Config) { + return func(c *config.Config) { + // Add all servers - tests will fail if database isn't available + c.Servers = []config.Server{ + { + Name: "postgres", + Engine: config.EnginePostgreSQL, + URI: postgresURI, + }, + { + Name: "mysql", + Engine: config.EngineMySQL, + URI: mysqlURI, + }, + } + + for i := range c.SQL { + switch c.SQL[i].Engine { + case config.EnginePostgreSQL: + c.SQL[i].Database = &config.Database{ + Managed: true, + } + case config.EngineMySQL: + c.SQL[i].Database = &config.Database{ + Managed: true, + } + case config.EngineSQLite: + c.SQL[i].Database = &config.Database{ + Managed: true, + } + default: + // pass + } + } + } + }, + Enabled: func() bool { + // Enabled if at least one database URI is available + return postgresURI != "" || mysqlURI != "" + }, + }, + "core": { + Mutate: func(t *testing.T, path string) func(*config.Config) { return func(c *config.Config) {} }, + Experiments: func() []string { return []string{"coreanalyzer"} }, + Enabled: func() bool { + // Running the whole corpus through the analysis core is opt-in + // while the two paths still disagree. The core needs no + // database, so nothing else gates this. + return os.Getenv("SQLC_TEST_CORE") != "" + }, + }, + } + + for name, testctx := range contexts { + + if !testctx.Enabled() { + continue + } + + for _, replay := range FindTests(t, "testdata", name) { + tc := replay + t.Run(filepath.Join(name, tc.Name), func(t *testing.T) { + var stderr bytes.Buffer + var output map[string]string + var err error + + path, _ := filepath.Abs(tc.Path) + args := tc.Exec + if args == nil { + args = &Exec{Command: "generate"} + } + expected := string(tc.Stderr) + + if args.Process != "" { + _, err := osexec.LookPath(args.Process) + if err != nil { + t.Skipf("executable not found: %s %s", args.Process, err) + } + } + + if len(args.Contexts) > 0 { + if !slices.Contains(args.Contexts, name) { + t.Skipf("unsupported context: %s", name) + } + } + + if len(args.OS) > 0 { + if !slices.Contains(args.OS, runtime.GOOS) { + t.Skipf("unsupported os: %s", runtime.GOOS) + } + } + + experiments := args.Env["SQLCEXPERIMENT"] + if testctx.Experiments != nil { + experiments = strings.Join(append(testctx.Experiments(), experiments), ",") + } + + opts := cmd.Options{ + Env: cmd.Env{ + Experiment: opts.ExperimentFromString(experiments), + }, + Stderr: &stderr, + MutateConfig: testctx.Mutate(t, path), + } + + release := withSQLCDEBUG(t, args.Env["SQLCDEBUG"]) + defer release() + + switch args.Command { + case "diff": + err = cmd.Diff(ctx, path, "", &opts) + case "generate": + output, err = cmd.Generate(ctx, path, "", &opts) + if err == nil { + cmpDirectory(t, path, output) + } + case "vet": + err = cmd.Vet(ctx, path, "", &opts) + case "parse", "analyze", "fmt": + // These commands are flag-driven (fmt cases pass --diff so + // nothing is rewritten). Run them through the real CLI + // entry point from inside the test directory so file + // arguments resolve and the output stays independent of + // the absolute path. + var stdout bytes.Buffer + wd, werr := os.Getwd() + if werr != nil { + t.Fatal(werr) + } + if cerr := os.Chdir(path); cerr != nil { + t.Fatal(cerr) + } + code := cmd.Do(append([]string{args.Command}, args.Args...), nil, &stdout, &stderr) + if cerr := os.Chdir(wd); cerr != nil { + t.Fatal(cerr) + } + if code != 0 { + err = fmt.Errorf("%s exited with code %d", args.Command, code) + } else if diff := cmp.Diff(strings.TrimSpace(string(tc.Stdout)), strings.TrimSpace(stdout.String()), lineEndings()); diff != "" { + t.Errorf("stdout differed (-want +got):\n%s", diff) + } + default: + t.Fatalf("unknown command") + } + + if len(expected) == 0 && err != nil { + t.Fatalf("sqlc %s failed: %s", args.Command, stderr.String()) + } + + diff := cmp.Diff( + strings.TrimSpace(expected), + strings.TrimSpace(stderr.String()), + stderrTransformer(), + ) + if diff != "" { + t.Fatalf("stderr differed (-want +got):\n%s", diff) + } + }) + } + } +} + +func cmpDirectory(t *testing.T, dir string, actual map[string]string) { + expected := map[string]string{} + var ff = func(path string, file os.FileInfo, err error) error { + if err != nil { + return err + } + if file.IsDir() { + return nil + } + if !strings.HasSuffix(path, ".go") && !strings.HasSuffix(path, ".kt") && !strings.HasSuffix(path, ".py") && !strings.HasSuffix(path, ".json") && !strings.HasSuffix(path, ".txt") { + return nil + } + // TODO: Figure out a better way to ignore certain files + if strings.HasSuffix(path, ".txt") && filepath.Base(path) != "hello.txt" { + return nil + } + if filepath.Base(path) == "sqlc.json" { + return nil + } + if filepath.Base(path) == "exec.json" { + return nil + } + if strings.Contains(path, "/kotlin/build") { + return nil + } + if strings.HasSuffix(path, "_test.go") || strings.Contains(path, "src/test/") { + return nil + } + if strings.Contains(path, "/python/.venv") || strings.Contains(path, "/python/src/tests/") || + strings.HasSuffix(path, "__init__.py") || strings.Contains(path, "/python/src/dbtest/") || + strings.Contains(path, "/python/.mypy_cache") { + return nil + } + blob, err := os.ReadFile(path) + if err != nil { + return err + } + expected[path] = string(blob) + return nil + } + if err := filepath.Walk(dir, ff); err != nil { + t.Fatal(err) + } + + opts := []cmp.Option{ + cmpopts.EquateEmpty(), + lineEndings(), + } + + if !cmp.Equal(expected, actual, opts...) { + t.Errorf("%s contents differ", dir) + for name, contents := range expected { + if actual[name] == "" { + t.Errorf("%s is empty", name) + return + } + if diff := cmp.Diff(contents, actual[name], opts...); diff != "" { + t.Errorf("%s differed (-want +got):\n%s", name, diff) + } + } + } +} + +func BenchmarkReplay(b *testing.B) { + ctx := context.Background() + var dirs []string + err := filepath.Walk("testdata", func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.Name() == "sqlc.json" || info.Name() == "sqlc.yaml" || info.Name() == "sqlc.yml" { + dirs = append(dirs, filepath.Dir(path)) + return filepath.SkipDir + } + return nil + }) + if err != nil { + b.Fatal(err) + } + for _, replay := range dirs { + tc := replay + b.Run(tc, func(b *testing.B) { + path, _ := filepath.Abs(tc) + for i := 0; i < b.N; i++ { + var stderr bytes.Buffer + opts := &cmd.Options{ + Env: cmd.Env{}, + Stderr: &stderr, + } + cmd.Generate(ctx, path, "", opts) + } + }) + } +} diff --git a/internal/endtoend/fmt_test.go b/internal/endtoend/fmt_test.go new file mode 100644 index 0000000..3420a8d --- /dev/null +++ b/internal/endtoend/fmt_test.go @@ -0,0 +1,194 @@ +package main + +import ( + "bytes" + "fmt" + "io" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/debug" + "github.com/sqlc-dev/sqlc/internal/engine/dolphin" + "github.com/sqlc-dev/sqlc/internal/engine/postgresql" + "github.com/sqlc-dev/sqlc/internal/engine/sqlite" + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/format" +) + +// sqlParser is an interface for SQL parsers +type sqlParser interface { + Parse(r io.Reader) ([]ast.Statement, error) +} + +// sqlFormatter is an interface for formatters +type sqlFormatter interface { + format.Dialect +} + +func TestFormat(t *testing.T) { + t.Parallel() + for _, tc := range FindTests(t, "testdata", "base") { + // Config-less command tests (parse, analyze) have no config to format. + if tc.ConfigName == "" { + continue + } + t.Run(tc.Name, func(t *testing.T) { + // Parse the config file to determine the engine + configPath := filepath.Join(tc.Path, tc.ConfigName) + configFile, err := os.Open(configPath) + if err != nil { + t.Fatal(err) + } + conf, err := config.ParseConfig(configFile) + configFile.Close() + if err != nil { + t.Fatal(err) + } + + // Skip if there are no SQL packages configured + if len(conf.SQL) == 0 { + return + } + + engine := conf.SQL[0].Engine + + // Select the appropriate parser and fingerprint function based on engine + var parse sqlParser + var formatter sqlFormatter + var fingerprint func(string) (string, error) + + switch engine { + case config.EnginePostgreSQL: + pgParser := postgresql.NewParser() + parse = pgParser + formatter = pgParser + fingerprint = postgresql.Fingerprint + case config.EngineMySQL: + mysqlParser := dolphin.NewParser() + parse = mysqlParser + formatter = mysqlParser + // For MySQL, we use a "round-trip" fingerprint: parse the SQL, format it, + // and return the formatted string. This tests that our formatting produces + // valid SQL that parses to the same AST structure. + fingerprint = func(sql string) (string, error) { + stmts, err := mysqlParser.Parse(strings.NewReader(sql)) + if err != nil { + return "", err + } + if len(stmts) == 0 { + return "", nil + } + return ast.Format(stmts[0].Raw, mysqlParser), nil + } + case config.EngineSQLite: + sqliteParser := sqlite.NewParser() + parse = sqliteParser + formatter = sqliteParser + // For SQLite, we use the same "round-trip" fingerprint strategy as MySQL: + // parse the SQL, format it, and return the formatted string. + fingerprint = func(sql string) (string, error) { + stmts, err := sqliteParser.Parse(strings.NewReader(sql)) + if err != nil { + return "", err + } + if len(stmts) == 0 { + return "", nil + } + return strings.ToLower(ast.Format(stmts[0].Raw, sqliteParser)), nil + } + default: + // Skip unsupported engines + return + } + + // Find query files from config + var queryFiles []string + for _, sql := range conf.SQL { + for _, q := range sql.Queries { + queryPath := filepath.Join(tc.Path, q) + info, err := os.Stat(queryPath) + if err != nil { + continue + } + if info.IsDir() { + // If it's a directory, glob for .sql files + matches, err := filepath.Glob(filepath.Join(queryPath, "*.sql")) + if err != nil { + continue + } + queryFiles = append(queryFiles, matches...) + } else { + queryFiles = append(queryFiles, queryPath) + } + } + } + + if len(queryFiles) == 0 { + return + } + + for _, queryFile := range queryFiles { + if _, err := os.Stat(queryFile); os.IsNotExist(err) { + continue + } + + contents, err := os.ReadFile(queryFile) + if err != nil { + t.Fatal(err) + } + + // Parse the entire file to get proper statement boundaries + stmts, err := parse.Parse(bytes.NewReader(contents)) + if err != nil { + // Skip files with parse errors (e.g., syntax_errors test cases) + return + } + + for i, stmt := range stmts { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + // Extract the original query text using statement location and length + start := stmt.Raw.StmtLocation + length := stmt.Raw.StmtLen + if length == 0 { + // If StmtLen is 0, it means the statement goes to the end of the input + length = len(contents) - start + } + query := strings.TrimSpace(string(contents[start : start+length])) + + expected, err := fingerprint(query) + if err != nil { + t.Fatal(err) + } + + if false { + r, err := postgresql.Parse(query) + debug.Dump(r, err) + } + + out := ast.Format(stmt.Raw, formatter) + // An empty rendering is the formatter's signal that + // the statement carries syntax the AST does not + // model; sqlc fmt keeps such statements as written. + if strings.TrimSpace(strings.TrimSuffix(strings.TrimSpace(out), ";")) == "" { + t.Skip("statement has no faithful rendering") + } + actual, err := fingerprint(out) + if err != nil { + t.Error(err) + } + if expected != actual { + debug.Dump(stmt.Raw) + t.Errorf("- %s", expected) + t.Errorf("- %s", query) + t.Errorf("+ %s", actual) + t.Errorf("+ %s", out) + } + }) + } + } + }) + } +} diff --git a/internal/endtoend/json_schema_test.go b/internal/endtoend/json_schema_test.go new file mode 100644 index 0000000..64893e2 --- /dev/null +++ b/internal/endtoend/json_schema_test.go @@ -0,0 +1,82 @@ +package main + +import ( + "encoding/json" + "io/fs" + "os" + "path/filepath" + "testing" + + "github.com/xeipuuv/gojsonschema" +) + +type conf struct { + Version string `json:"version"` +} + +func loadSchema(t *testing.T, path string) *gojsonschema.Schema { + t.Helper() + + schemaBytes, err := os.ReadFile(path) + if err != nil { + t.Fatal(err) + } + + loader := gojsonschema.NewStringLoader(string(schemaBytes)) + schema, err := gojsonschema.NewSchema(loader) + if err != nil { + t.Fatalf("invalid schema: %s", err) + } + return schema +} + +func TestJsonSchema(t *testing.T) { + t.Parallel() + + schemaOne := loadSchema(t, filepath.Join("..", "config", "v_one.json")) + schemaTwo := loadSchema(t, filepath.Join("..", "config", "v_two.json")) + + srcs := []string{ + filepath.Join("..", "..", "examples"), + filepath.Join("testdata"), + } + + for _, dir := range srcs { + err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if filepath.Base(path) != "sqlc.json" { + return nil + } + t.Run(path, func(t *testing.T) { + t.Parallel() + contents, err := os.ReadFile(path) + if err != nil { + t.Fatal(err) + } + var c conf + if err := json.Unmarshal(contents, &c); err != nil { + t.Fatal(err) + } + l := gojsonschema.NewStringLoader(string(contents)) + switch c.Version { + case "1": + if _, err := schemaOne.Validate(l); err != nil { + t.Fatal(err) + } + case "2": + if _, err := schemaTwo.Validate(l); err != nil { + t.Fatal(err) + } + default: + t.Fatalf("unknown schema version: %s", c.Version) + } + }) + return nil + }) + if err != nil { + t.Error(err) + } + } +} diff --git a/internal/endtoend/testdata/alias/mysql/go/db.go b/internal/endtoend/testdata/alias/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/alias/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/alias/mysql/go/models.go b/internal/endtoend/testdata/alias/mysql/go/models.go new file mode 100644 index 0000000..9ac222a --- /dev/null +++ b/internal/endtoend/testdata/alias/mysql/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID uint64 +} diff --git a/internal/endtoend/testdata/alias/mysql/go/query.sql.go b/internal/endtoend/testdata/alias/mysql/go/query.sql.go new file mode 100644 index 0000000..281c3f5 --- /dev/null +++ b/internal/endtoend/testdata/alias/mysql/go/query.sql.go @@ -0,0 +1,20 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const aliasBar = `-- name: AliasBar :exec +DELETE FROM bar b +WHERE b.id = ? +` + +func (q *Queries) AliasBar(ctx context.Context, id uint64) error { + _, err := q.db.ExecContext(ctx, aliasBar, id) + return err +} diff --git a/internal/endtoend/testdata/alias/mysql/query.sql b/internal/endtoend/testdata/alias/mysql/query.sql new file mode 100644 index 0000000..d762623 --- /dev/null +++ b/internal/endtoend/testdata/alias/mysql/query.sql @@ -0,0 +1,3 @@ +-- name: AliasBar :exec +DELETE FROM bar b +WHERE b.id = ?; diff --git a/internal/endtoend/testdata/alias/mysql/schema.sql b/internal/endtoend/testdata/alias/mysql/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/alias/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/alias/mysql/sqlc.json b/internal/endtoend/testdata/alias/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/alias/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/alias/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/alias/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/alias/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/alias/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/alias/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/alias/postgresql/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/alias/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/alias/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..93fa0ab --- /dev/null +++ b/internal/endtoend/testdata/alias/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,20 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const aliasBar = `-- name: AliasBar :exec +DELETE FROM bar b +WHERE b.id = $1 +` + +func (q *Queries) AliasBar(ctx context.Context, id int32) error { + _, err := q.db.Exec(ctx, aliasBar, id) + return err +} diff --git a/internal/endtoend/testdata/alias/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/alias/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..69c610c --- /dev/null +++ b/internal/endtoend/testdata/alias/postgresql/pgx/v4/query.sql @@ -0,0 +1,3 @@ +-- name: AliasBar :exec +DELETE FROM bar b +WHERE b.id = $1; diff --git a/internal/endtoend/testdata/alias/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/alias/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/alias/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/alias/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/alias/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/alias/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/alias/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/alias/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/alias/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/alias/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/alias/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/alias/postgresql/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/alias/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/alias/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..93fa0ab --- /dev/null +++ b/internal/endtoend/testdata/alias/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,20 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const aliasBar = `-- name: AliasBar :exec +DELETE FROM bar b +WHERE b.id = $1 +` + +func (q *Queries) AliasBar(ctx context.Context, id int32) error { + _, err := q.db.Exec(ctx, aliasBar, id) + return err +} diff --git a/internal/endtoend/testdata/alias/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/alias/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..69c610c --- /dev/null +++ b/internal/endtoend/testdata/alias/postgresql/pgx/v5/query.sql @@ -0,0 +1,3 @@ +-- name: AliasBar :exec +DELETE FROM bar b +WHERE b.id = $1; diff --git a/internal/endtoend/testdata/alias/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/alias/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/alias/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/alias/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/alias/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/alias/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/alias/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/alias/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/alias/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/alias/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/alias/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/alias/postgresql/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/alias/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/alias/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..2f81fed --- /dev/null +++ b/internal/endtoend/testdata/alias/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,20 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const aliasBar = `-- name: AliasBar :exec +DELETE FROM bar b +WHERE b.id = $1 +` + +func (q *Queries) AliasBar(ctx context.Context, id int32) error { + _, err := q.db.ExecContext(ctx, aliasBar, id) + return err +} diff --git a/internal/endtoend/testdata/alias/postgresql/stdlib/query.sql b/internal/endtoend/testdata/alias/postgresql/stdlib/query.sql new file mode 100644 index 0000000..69c610c --- /dev/null +++ b/internal/endtoend/testdata/alias/postgresql/stdlib/query.sql @@ -0,0 +1,3 @@ +-- name: AliasBar :exec +DELETE FROM bar b +WHERE b.id = $1; diff --git a/internal/endtoend/testdata/alias/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/alias/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..b7ee888 --- /dev/null +++ b/internal/endtoend/testdata/alias/postgresql/stdlib/schema.sql @@ -0,0 +1 @@ +CREATE TABLE bar (id serial not null); \ No newline at end of file diff --git a/internal/endtoend/testdata/alias/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/alias/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/alias/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/alias/sqlite/go/db.go b/internal/endtoend/testdata/alias/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/alias/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/alias/sqlite/go/models.go b/internal/endtoend/testdata/alias/sqlite/go/models.go new file mode 100644 index 0000000..bc354e0 --- /dev/null +++ b/internal/endtoend/testdata/alias/sqlite/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int64 +} diff --git a/internal/endtoend/testdata/alias/sqlite/go/query.sql.go b/internal/endtoend/testdata/alias/sqlite/go/query.sql.go new file mode 100644 index 0000000..5e00770 --- /dev/null +++ b/internal/endtoend/testdata/alias/sqlite/go/query.sql.go @@ -0,0 +1,20 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const aliasBar = `-- name: AliasBar :exec +DELETE FROM bar AS b +WHERE b.id = ? +` + +func (q *Queries) AliasBar(ctx context.Context, id int64) error { + _, err := q.db.ExecContext(ctx, aliasBar, id) + return err +} diff --git a/internal/endtoend/testdata/alias/sqlite/query.sql b/internal/endtoend/testdata/alias/sqlite/query.sql new file mode 100644 index 0000000..05df804 --- /dev/null +++ b/internal/endtoend/testdata/alias/sqlite/query.sql @@ -0,0 +1,3 @@ +-- name: AliasBar :exec +DELETE FROM bar AS b +WHERE b.id = ?; diff --git a/internal/endtoend/testdata/alias/sqlite/schema.sql b/internal/endtoend/testdata/alias/sqlite/schema.sql new file mode 100644 index 0000000..89b739c --- /dev/null +++ b/internal/endtoend/testdata/alias/sqlite/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id integer NOT NULL PRIMARY KEY AUTOINCREMENT); + diff --git a/internal/endtoend/testdata/alias/sqlite/sqlc.json b/internal/endtoend/testdata/alias/sqlite/sqlc.json new file mode 100644 index 0000000..d4963e7 --- /dev/null +++ b/internal/endtoend/testdata/alias/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/analyze_ast/postgresql/exec.json b/internal/endtoend/testdata/analyze_ast/postgresql/exec.json new file mode 100644 index 0000000..7d04ef8 --- /dev/null +++ b/internal/endtoend/testdata/analyze_ast/postgresql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "postgresql", "--schema", "schema.sql", "--ast", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_ast/postgresql/query.sql b/internal/endtoend/testdata/analyze_ast/postgresql/query.sql new file mode 100644 index 0000000..17af794 --- /dev/null +++ b/internal/endtoend/testdata/analyze_ast/postgresql/query.sql @@ -0,0 +1,2 @@ +-- name: GetAuthorName :one +SELECT name FROM authors WHERE id = $1; diff --git a/internal/endtoend/testdata/analyze_ast/postgresql/schema.sql b/internal/endtoend/testdata/analyze_ast/postgresql/schema.sql new file mode 100644 index 0000000..69b607d --- /dev/null +++ b/internal/endtoend/testdata/analyze_ast/postgresql/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/analyze_ast/postgresql/stdout.json b/internal/endtoend/testdata/analyze_ast/postgresql/stdout.json new file mode 100644 index 0000000..0ab1d7e --- /dev/null +++ b/internal/endtoend/testdata/analyze_ast/postgresql/stdout.json @@ -0,0 +1,136 @@ +[ + { + "name": "GetAuthorName", + "cmd": ":one", + "columns": [ + { + "name": "name", + "type": { + "name": "text" + }, + "table": "authors" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "authors" + } + } + ], + "ast": { + "tag": "RawStmt", + "stmt": { + "tag": "SelectStmt", + "distinct_clause": { + "tag": "List" + }, + "target_list": { + "tag": "List", + "items": [ + { + "tag": "ResTarget", + "indirection": { + "tag": "List" + }, + "val": { + "tag": "ColumnRef", + "name": "", + "fields": { + "tag": "List", + "items": [ + { + "tag": "String", + "str": "name" + } + ] + }, + "location": 35 + }, + "location": 35 + } + ] + }, + "from_clause": { + "tag": "List", + "items": [ + { + "tag": "RangeVar", + "relname": "authors", + "inh": true, + "relpersistence": 112, + "location": 45 + } + ] + }, + "where_clause": { + "tag": "A_Expr", + "kind": 1, + "name": { + "tag": "List", + "items": [ + { + "tag": "String", + "str": "=" + } + ] + }, + "lexpr": { + "tag": "ColumnRef", + "name": "", + "fields": { + "tag": "List", + "items": [ + { + "tag": "String", + "str": "id" + } + ] + }, + "location": 59 + }, + "rexpr": { + "tag": "ParamRef", + "number": 1, + "location": 64, + "dollar": true + }, + "location": 62 + }, + "group_clause": { + "tag": "List" + }, + "having_clause": { + "tag": "TODO" + }, + "window_clause": { + "tag": "List" + }, + "values_lists": { + "tag": "List" + }, + "sort_clause": { + "tag": "List" + }, + "limit_offset": { + "tag": "TODO" + }, + "limit_count": { + "tag": "TODO" + }, + "locking_clause": { + "tag": "List" + }, + "op": 0, + "all": false + }, + "stmt_location": 0, + "stmt_len": 66 + } + } +] diff --git a/internal/endtoend/testdata/analyze_basic/clickhouse/exec.json b/internal/endtoend/testdata/analyze_basic/clickhouse/exec.json new file mode 100644 index 0000000..c92bfa3 --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/clickhouse/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "clickhouse", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_basic/clickhouse/fixture.sql b/internal/endtoend/testdata/analyze_basic/clickhouse/fixture.sql new file mode 100644 index 0000000..88c3087 --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/clickhouse/fixture.sql @@ -0,0 +1 @@ +INSERT INTO events (id, name, tag, amount, created) VALUES (1, 'signup', NULL, 9.5, '2024-01-01 00:00:00'); diff --git a/internal/endtoend/testdata/analyze_basic/clickhouse/query.sql b/internal/endtoend/testdata/analyze_basic/clickhouse/query.sql new file mode 100644 index 0000000..4c756ec --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/clickhouse/query.sql @@ -0,0 +1,2 @@ +-- name: ListEvents :many +SELECT id, name, tag, amount, created FROM events; diff --git a/internal/endtoend/testdata/analyze_basic/clickhouse/schema.sql b/internal/endtoend/testdata/analyze_basic/clickhouse/schema.sql new file mode 100644 index 0000000..29960ee --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/clickhouse/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE events ( + id UInt64, + name String, + tag Nullable(String), + amount Float64, + created DateTime +) ENGINE = MergeTree ORDER BY id; diff --git a/internal/endtoend/testdata/analyze_basic/clickhouse/stdout.json b/internal/endtoend/testdata/analyze_basic/clickhouse/stdout.json new file mode 100644 index 0000000..ad9963d --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/clickhouse/stdout.json @@ -0,0 +1,45 @@ +[ + { + "name": "ListEvents", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "uint64" + }, + "table": "events" + }, + { + "name": "name", + "type": { + "name": "string" + }, + "table": "events" + }, + { + "name": "tag", + "type": { + "name": "string", + "nullable": true + }, + "table": "events" + }, + { + "name": "amount", + "type": { + "name": "float64" + }, + "table": "events" + }, + { + "name": "created", + "type": { + "name": "datetime" + }, + "table": "events" + } + ], + "params": [] + } +] diff --git a/internal/endtoend/testdata/analyze_basic/duckdb/exec.json b/internal/endtoend/testdata/analyze_basic/duckdb/exec.json new file mode 100644 index 0000000..56cb4b3 --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/duckdb/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "duckdb", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_basic/duckdb/query.sql b/internal/endtoend/testdata/analyze_basic/duckdb/query.sql new file mode 100644 index 0000000..b694368 --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/duckdb/query.sql @@ -0,0 +1,2 @@ +-- name: ListAuthors :many +SELECT id, name, bio, royalties, created FROM authors; diff --git a/internal/endtoend/testdata/analyze_basic/duckdb/schema.sql b/internal/endtoend/testdata/analyze_basic/duckdb/schema.sql new file mode 100644 index 0000000..dda49e8 --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/duckdb/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE authors ( + id BIGINT PRIMARY KEY, + name TEXT NOT NULL, + bio TEXT, + royalties DECIMAL(10,2) NOT NULL, + created TIMESTAMP NOT NULL +); diff --git a/internal/endtoend/testdata/analyze_basic/duckdb/stdout.json b/internal/endtoend/testdata/analyze_basic/duckdb/stdout.json new file mode 100644 index 0000000..6459e87 --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/duckdb/stdout.json @@ -0,0 +1,53 @@ +[ + { + "name": "ListAuthors", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "authors" + }, + { + "name": "name", + "type": { + "name": "varchar" + }, + "table": "authors" + }, + { + "name": "bio", + "type": { + "name": "varchar", + "nullable": true + }, + "table": "authors" + }, + { + "name": "royalties", + "type": { + "name": "decimal", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "authors" + }, + { + "name": "created", + "type": { + "name": "timestamp" + }, + "table": "authors" + } + ], + "params": [] + } +] diff --git a/internal/endtoend/testdata/analyze_basic/googlesql/exec.json b/internal/endtoend/testdata/analyze_basic/googlesql/exec.json new file mode 100644 index 0000000..a53dddd --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/googlesql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "googlesql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_basic/googlesql/query.sql b/internal/endtoend/testdata/analyze_basic/googlesql/query.sql new file mode 100644 index 0000000..e3aba1c --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/googlesql/query.sql @@ -0,0 +1,2 @@ +-- name: GetUser :one +SELECT id, name FROM users WHERE id = @id; diff --git a/internal/endtoend/testdata/analyze_basic/googlesql/schema.sql b/internal/endtoend/testdata/analyze_basic/googlesql/schema.sql new file mode 100644 index 0000000..ff91a9a --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/googlesql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE users ( + id INT64 NOT NULL, + name STRING(MAX) NOT NULL, + bio STRING(MAX), +) PRIMARY KEY (id); diff --git a/internal/endtoend/testdata/analyze_basic/googlesql/stdout.json b/internal/endtoend/testdata/analyze_basic/googlesql/stdout.json new file mode 100644 index 0000000..bcc6377 --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/googlesql/stdout.json @@ -0,0 +1,39 @@ +[ + { + "name": "GetUser", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "int64" + }, + "table": "users" + }, + { + "name": "name", + "type": { + "name": "string", + "args": [ + { + "ident": "max" + } + ] + }, + "table": "users" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "int64" + }, + "table": "users" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_basic/mssql/exec.json b/internal/endtoend/testdata/analyze_basic/mssql/exec.json new file mode 100644 index 0000000..253b05a --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/mssql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "mssql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_basic/mssql/query.sql b/internal/endtoend/testdata/analyze_basic/mssql/query.sql new file mode 100644 index 0000000..b694368 --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/mssql/query.sql @@ -0,0 +1,2 @@ +-- name: ListAuthors :many +SELECT id, name, bio, royalties, created FROM authors; diff --git a/internal/endtoend/testdata/analyze_basic/mssql/schema.sql b/internal/endtoend/testdata/analyze_basic/mssql/schema.sql new file mode 100644 index 0000000..3629635 --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/mssql/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE authors ( + id BIGINT IDENTITY(1,1) PRIMARY KEY, + name NVARCHAR(100) NOT NULL, + bio NVARCHAR(MAX), + royalties DECIMAL(10,2) NOT NULL, + created DATETIME2 NOT NULL +); diff --git a/internal/endtoend/testdata/analyze_basic/mssql/stdout.json b/internal/endtoend/testdata/analyze_basic/mssql/stdout.json new file mode 100644 index 0000000..818c4c2 --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/mssql/stdout.json @@ -0,0 +1,68 @@ +[ + { + "name": "ListAuthors", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "authors" + }, + { + "name": "name", + "type": { + "name": "nvarchar", + "args": [ + { + "int": 100 + } + ] + }, + "table": "authors" + }, + { + "name": "bio", + "type": { + "name": "nvarchar", + "nullable": true, + "args": [ + { + "ident": "max" + } + ] + }, + "table": "authors" + }, + { + "name": "royalties", + "type": { + "name": "decimal", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "authors" + }, + { + "name": "created", + "type": { + "name": "datetime2", + "args": [ + { + "int": 7 + } + ] + }, + "table": "authors" + } + ], + "params": [] + } +] diff --git a/internal/endtoend/testdata/analyze_basic/mysql/exec.json b/internal/endtoend/testdata/analyze_basic/mysql/exec.json new file mode 100644 index 0000000..a5b24d3 --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/mysql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "mysql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_basic/mysql/query.sql b/internal/endtoend/testdata/analyze_basic/mysql/query.sql new file mode 100644 index 0000000..137c1d1 --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: GetUser :one +SELECT id, name FROM users WHERE id = ?; diff --git a/internal/endtoend/testdata/analyze_basic/mysql/schema.sql b/internal/endtoend/testdata/analyze_basic/mysql/schema.sql new file mode 100644 index 0000000..52f9948 --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/mysql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE users ( + id BIGINT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + bio TEXT +); diff --git a/internal/endtoend/testdata/analyze_basic/mysql/stdout.json b/internal/endtoend/testdata/analyze_basic/mysql/stdout.json new file mode 100644 index 0000000..56ae272 --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/mysql/stdout.json @@ -0,0 +1,39 @@ +[ + { + "name": "GetUser", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + }, + { + "name": "name", + "type": { + "name": "varchar", + "args": [ + { + "int": 255 + } + ] + }, + "table": "users" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_basic/postgresql/exec.json b/internal/endtoend/testdata/analyze_basic/postgresql/exec.json new file mode 100644 index 0000000..b102755 --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/postgresql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "postgresql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_basic/postgresql/query.sql b/internal/endtoend/testdata/analyze_basic/postgresql/query.sql new file mode 100644 index 0000000..55ef1fa --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/postgresql/query.sql @@ -0,0 +1,2 @@ +-- name: GetAuthor :one +SELECT * FROM authors WHERE id = $1; diff --git a/internal/endtoend/testdata/analyze_basic/postgresql/schema.sql b/internal/endtoend/testdata/analyze_basic/postgresql/schema.sql new file mode 100644 index 0000000..69b607d --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/postgresql/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/analyze_basic/postgresql/stdout.json b/internal/endtoend/testdata/analyze_basic/postgresql/stdout.json new file mode 100644 index 0000000..faa4c1a --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/postgresql/stdout.json @@ -0,0 +1,42 @@ +[ + { + "name": "GetAuthor", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "authors" + }, + { + "name": "name", + "type": { + "name": "text" + }, + "table": "authors" + }, + { + "name": "bio", + "type": { + "name": "text", + "nullable": true + }, + "table": "authors" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "authors" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_basic/sqlite/exec.json b/internal/endtoend/testdata/analyze_basic/sqlite/exec.json new file mode 100644 index 0000000..aa77909 --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/sqlite/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "sqlite", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_basic/sqlite/query.sql b/internal/endtoend/testdata/analyze_basic/sqlite/query.sql new file mode 100644 index 0000000..137c1d1 --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: GetUser :one +SELECT id, name FROM users WHERE id = ?; diff --git a/internal/endtoend/testdata/analyze_basic/sqlite/schema.sql b/internal/endtoend/testdata/analyze_basic/sqlite/schema.sql new file mode 100644 index 0000000..884e5c9 --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/sqlite/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE users ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL, + age INTEGER +); diff --git a/internal/endtoend/testdata/analyze_basic/sqlite/stdout.json b/internal/endtoend/testdata/analyze_basic/sqlite/stdout.json new file mode 100644 index 0000000..8799d17 --- /dev/null +++ b/internal/endtoend/testdata/analyze_basic/sqlite/stdout.json @@ -0,0 +1,34 @@ +[ + { + "name": "GetUser", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "integer" + }, + "table": "users" + }, + { + "name": "name", + "type": { + "name": "text" + }, + "table": "users" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "integer" + }, + "table": "users" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_dml/duckdb/exec.json b/internal/endtoend/testdata/analyze_dml/duckdb/exec.json new file mode 100644 index 0000000..56cb4b3 --- /dev/null +++ b/internal/endtoend/testdata/analyze_dml/duckdb/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "duckdb", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_dml/duckdb/query.sql b/internal/endtoend/testdata/analyze_dml/duckdb/query.sql new file mode 100644 index 0000000..cf01653 --- /dev/null +++ b/internal/endtoend/testdata/analyze_dml/duckdb/query.sql @@ -0,0 +1,13 @@ +-- name: CreateAuthor :one +INSERT INTO authors (id, name, bio) VALUES ($1, $2, $3) RETURNING id; + +-- name: UpdateAuthor :exec +UPDATE authors SET name = $name, bio = $bio WHERE id = $id; + +-- name: DeleteBooksByAuthor :exec +DELETE FROM books USING authors a WHERE books.author_id = a.id AND a.name = $1; + +-- name: TitlesFromBooks :many +INSERT INTO books (id, author_id, title) +SELECT id + 1000, author_id, upper(title) FROM books WHERE price > $min_price +RETURNING id, title; diff --git a/internal/endtoend/testdata/analyze_dml/duckdb/schema.sql b/internal/endtoend/testdata/analyze_dml/duckdb/schema.sql new file mode 100644 index 0000000..7c41b6c --- /dev/null +++ b/internal/endtoend/testdata/analyze_dml/duckdb/schema.sql @@ -0,0 +1,12 @@ +CREATE TABLE authors ( + id BIGINT PRIMARY KEY, + name TEXT NOT NULL, + bio TEXT +); + +CREATE TABLE books ( + id BIGINT PRIMARY KEY, + author_id BIGINT NOT NULL, + title TEXT NOT NULL, + price DECIMAL(10,2) +); diff --git a/internal/endtoend/testdata/analyze_dml/duckdb/stdout.json b/internal/endtoend/testdata/analyze_dml/duckdb/stdout.json new file mode 100644 index 0000000..621fdfd --- /dev/null +++ b/internal/endtoend/testdata/analyze_dml/duckdb/stdout.json @@ -0,0 +1,144 @@ +[ + { + "name": "CreateAuthor", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "authors" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "authors" + } + }, + { + "number": 2, + "column": { + "name": "name", + "type": { + "name": "varchar" + }, + "table": "authors" + } + }, + { + "number": 3, + "column": { + "name": "bio", + "type": { + "name": "varchar", + "nullable": true + }, + "table": "authors" + } + } + ] + }, + { + "name": "UpdateAuthor", + "cmd": ":exec", + "columns": [], + "params": [ + { + "number": 1, + "column": { + "name": "name", + "type": { + "name": "varchar" + }, + "table": "authors" + } + }, + { + "number": 2, + "column": { + "name": "bio", + "type": { + "name": "varchar", + "nullable": true + }, + "table": "authors" + } + }, + { + "number": 3, + "column": { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "authors" + } + } + ] + }, + { + "name": "DeleteBooksByAuthor", + "cmd": ":exec", + "columns": [], + "params": [ + { + "number": 1, + "column": { + "name": "name", + "type": { + "name": "varchar" + }, + "table": "authors" + } + } + ] + }, + { + "name": "TitlesFromBooks", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "books" + }, + { + "name": "title", + "type": { + "name": "varchar" + }, + "table": "books" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "price", + "type": { + "name": "decimal", + "nullable": true, + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "books" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_dml/googlesql/exec.json b/internal/endtoend/testdata/analyze_dml/googlesql/exec.json new file mode 100644 index 0000000..a53dddd --- /dev/null +++ b/internal/endtoend/testdata/analyze_dml/googlesql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "googlesql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_dml/googlesql/query.sql b/internal/endtoend/testdata/analyze_dml/googlesql/query.sql new file mode 100644 index 0000000..e35c5f5 --- /dev/null +++ b/internal/endtoend/testdata/analyze_dml/googlesql/query.sql @@ -0,0 +1,17 @@ +-- name: CreateUser :exec +INSERT INTO users (id, name, bio) VALUES (@id, @name, @bio); + +-- name: CreateUserReturning :one +INSERT INTO users (id, name) VALUES (@id, @name) THEN RETURN id, name; + +-- name: UpdateBio :exec +UPDATE users SET bio = @bio WHERE id = @id; + +-- name: UpdateNameReturning :one +UPDATE users SET name = @name WHERE id = @id THEN RETURN id, name; + +-- name: DeleteUser :exec +DELETE FROM users WHERE id = @id; + +-- name: DeleteUserReturning :one +DELETE FROM users WHERE id = @id THEN RETURN id; diff --git a/internal/endtoend/testdata/analyze_dml/googlesql/schema.sql b/internal/endtoend/testdata/analyze_dml/googlesql/schema.sql new file mode 100644 index 0000000..ff91a9a --- /dev/null +++ b/internal/endtoend/testdata/analyze_dml/googlesql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE users ( + id INT64 NOT NULL, + name STRING(MAX) NOT NULL, + bio STRING(MAX), +) PRIMARY KEY (id); diff --git a/internal/endtoend/testdata/analyze_dml/googlesql/stdout.json b/internal/endtoend/testdata/analyze_dml/googlesql/stdout.json new file mode 100644 index 0000000..f2ee81d --- /dev/null +++ b/internal/endtoend/testdata/analyze_dml/googlesql/stdout.json @@ -0,0 +1,229 @@ +[ + { + "name": "CreateUser", + "cmd": ":exec", + "columns": [], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "int64" + }, + "table": "users" + } + }, + { + "number": 2, + "column": { + "name": "name", + "type": { + "name": "string", + "args": [ + { + "ident": "max" + } + ] + }, + "table": "users" + } + }, + { + "number": 3, + "column": { + "name": "bio", + "type": { + "name": "string", + "nullable": true, + "args": [ + { + "ident": "max" + } + ] + }, + "table": "users" + } + } + ] + }, + { + "name": "CreateUserReturning", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "int64" + }, + "table": "users" + }, + { + "name": "name", + "type": { + "name": "string", + "args": [ + { + "ident": "max" + } + ] + }, + "table": "users" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "int64" + }, + "table": "users" + } + }, + { + "number": 2, + "column": { + "name": "name", + "type": { + "name": "string", + "args": [ + { + "ident": "max" + } + ] + }, + "table": "users" + } + } + ] + }, + { + "name": "UpdateBio", + "cmd": ":exec", + "columns": [], + "params": [ + { + "number": 1, + "column": { + "name": "bio", + "type": { + "name": "string", + "nullable": true, + "args": [ + { + "ident": "max" + } + ] + }, + "table": "users" + } + }, + { + "number": 2, + "column": { + "name": "id", + "type": { + "name": "int64" + }, + "table": "users" + } + } + ] + }, + { + "name": "UpdateNameReturning", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "int64" + }, + "table": "users" + }, + { + "name": "name", + "type": { + "name": "string", + "args": [ + { + "ident": "max" + } + ] + }, + "table": "users" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "name", + "type": { + "name": "string", + "args": [ + { + "ident": "max" + } + ] + }, + "table": "users" + } + }, + { + "number": 2, + "column": { + "name": "id", + "type": { + "name": "int64" + }, + "table": "users" + } + } + ] + }, + { + "name": "DeleteUser", + "cmd": ":exec", + "columns": [], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "int64" + }, + "table": "users" + } + } + ] + }, + { + "name": "DeleteUserReturning", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "int64" + }, + "table": "users" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "int64" + }, + "table": "users" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_dml/mssql/exec.json b/internal/endtoend/testdata/analyze_dml/mssql/exec.json new file mode 100644 index 0000000..253b05a --- /dev/null +++ b/internal/endtoend/testdata/analyze_dml/mssql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "mssql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_dml/mssql/query.sql b/internal/endtoend/testdata/analyze_dml/mssql/query.sql new file mode 100644 index 0000000..cdf7d9f --- /dev/null +++ b/internal/endtoend/testdata/analyze_dml/mssql/query.sql @@ -0,0 +1,11 @@ +-- name: CreateAuthor :one +INSERT INTO authors (name, bio) OUTPUT INSERTED.id VALUES (@name, @bio); + +-- name: UpdateAuthorAlias :exec +UPDATE a SET name = @name FROM authors a WHERE a.id = @id; + +-- name: UpdateBookPrices :exec +UPDATE b SET price = @price FROM books b JOIN authors a ON b.author_id = a.id WHERE a.name = @author; + +-- name: DeleteBooksByAuthor :exec +DELETE b FROM books b INNER JOIN authors a ON b.author_id = a.id WHERE a.name = @name; diff --git a/internal/endtoend/testdata/analyze_dml/mssql/schema.sql b/internal/endtoend/testdata/analyze_dml/mssql/schema.sql new file mode 100644 index 0000000..5a53ca7 --- /dev/null +++ b/internal/endtoend/testdata/analyze_dml/mssql/schema.sql @@ -0,0 +1,12 @@ +CREATE TABLE authors ( + id BIGINT IDENTITY(1,1) PRIMARY KEY, + name NVARCHAR(100) NOT NULL, + bio NVARCHAR(MAX) +); + +CREATE TABLE books ( + id BIGINT IDENTITY(1,1) PRIMARY KEY, + author_id BIGINT NOT NULL, + title NVARCHAR(200) NOT NULL, + price DECIMAL(10,2) +); diff --git a/internal/endtoend/testdata/analyze_dml/mssql/stdout.json b/internal/endtoend/testdata/analyze_dml/mssql/stdout.json new file mode 100644 index 0000000..74f6850 --- /dev/null +++ b/internal/endtoend/testdata/analyze_dml/mssql/stdout.json @@ -0,0 +1,143 @@ +[ + { + "name": "CreateAuthor", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "authors" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "name", + "type": { + "name": "nvarchar", + "args": [ + { + "int": 100 + } + ] + }, + "table": "authors" + } + }, + { + "number": 2, + "column": { + "name": "bio", + "type": { + "name": "nvarchar", + "nullable": true, + "args": [ + { + "ident": "max" + } + ] + }, + "table": "authors" + } + } + ] + }, + { + "name": "UpdateAuthorAlias", + "cmd": ":exec", + "columns": [], + "params": [ + { + "number": 1, + "column": { + "name": "name", + "type": { + "name": "nvarchar", + "args": [ + { + "int": 100 + } + ] + }, + "table": "authors" + } + }, + { + "number": 2, + "column": { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "authors" + } + } + ] + }, + { + "name": "UpdateBookPrices", + "cmd": ":exec", + "columns": [], + "params": [ + { + "number": 1, + "column": { + "name": "price", + "type": { + "name": "decimal", + "nullable": true, + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "books" + } + }, + { + "number": 2, + "column": { + "name": "name", + "type": { + "name": "nvarchar", + "args": [ + { + "int": 100 + } + ] + }, + "table": "authors" + } + } + ] + }, + { + "name": "DeleteBooksByAuthor", + "cmd": ":exec", + "columns": [], + "params": [ + { + "number": 1, + "column": { + "name": "name", + "type": { + "name": "nvarchar", + "args": [ + { + "int": 100 + } + ] + }, + "table": "authors" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_dml/mysql/exec.json b/internal/endtoend/testdata/analyze_dml/mysql/exec.json new file mode 100644 index 0000000..a5b24d3 --- /dev/null +++ b/internal/endtoend/testdata/analyze_dml/mysql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "mysql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_dml/mysql/query.sql b/internal/endtoend/testdata/analyze_dml/mysql/query.sql new file mode 100644 index 0000000..6adfb02 --- /dev/null +++ b/internal/endtoend/testdata/analyze_dml/mysql/query.sql @@ -0,0 +1,11 @@ +-- name: CreateUser :exec +INSERT INTO users (id, name, bio) VALUES (?, ?, ?); + +-- name: UpdateBio :exec +UPDATE users SET bio = ? WHERE id = ?; + +-- name: DeleteUser :exec +DELETE FROM users WHERE id = ?; + +-- name: DeleteUserPosts :exec +DELETE p FROM posts p JOIN users u ON u.id = p.user_id WHERE u.name = ?; diff --git a/internal/endtoend/testdata/analyze_dml/mysql/schema.sql b/internal/endtoend/testdata/analyze_dml/mysql/schema.sql new file mode 100644 index 0000000..ad0d0c1 --- /dev/null +++ b/internal/endtoend/testdata/analyze_dml/mysql/schema.sql @@ -0,0 +1,12 @@ +CREATE TABLE users ( + id BIGINT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + bio TEXT +); + +CREATE TABLE posts ( + id BIGINT PRIMARY KEY, + user_id BIGINT NOT NULL, + title VARCHAR(255), + created DATETIME NOT NULL +); diff --git a/internal/endtoend/testdata/analyze_dml/mysql/stdout.json b/internal/endtoend/testdata/analyze_dml/mysql/stdout.json new file mode 100644 index 0000000..1d5d37e --- /dev/null +++ b/internal/endtoend/testdata/analyze_dml/mysql/stdout.json @@ -0,0 +1,112 @@ +[ + { + "name": "CreateUser", + "cmd": ":exec", + "columns": [], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + } + }, + { + "number": 2, + "column": { + "name": "name", + "type": { + "name": "varchar", + "args": [ + { + "int": 255 + } + ] + }, + "table": "users" + } + }, + { + "number": 3, + "column": { + "name": "bio", + "type": { + "name": "text", + "nullable": true + }, + "table": "users" + } + } + ] + }, + { + "name": "UpdateBio", + "cmd": ":exec", + "columns": [], + "params": [ + { + "number": 1, + "column": { + "name": "bio", + "type": { + "name": "text", + "nullable": true + }, + "table": "users" + } + }, + { + "number": 2, + "column": { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + } + } + ] + }, + { + "name": "DeleteUser", + "cmd": ":exec", + "columns": [], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + } + } + ] + }, + { + "name": "DeleteUserPosts", + "cmd": ":exec", + "columns": [], + "params": [ + { + "number": 1, + "column": { + "name": "name", + "type": { + "name": "varchar", + "args": [ + { + "int": 255 + } + ] + }, + "table": "users" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_dml/postgresql/exec.json b/internal/endtoend/testdata/analyze_dml/postgresql/exec.json new file mode 100644 index 0000000..b102755 --- /dev/null +++ b/internal/endtoend/testdata/analyze_dml/postgresql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "postgresql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_dml/postgresql/query.sql b/internal/endtoend/testdata/analyze_dml/postgresql/query.sql new file mode 100644 index 0000000..7039b17 --- /dev/null +++ b/internal/endtoend/testdata/analyze_dml/postgresql/query.sql @@ -0,0 +1,14 @@ +-- name: CreateUser :one +INSERT INTO users (name, bio) VALUES ($1, $2) RETURNING *; + +-- name: UpdateBio :exec +UPDATE users SET bio = $1 WHERE id = $2; + +-- name: UpdateNameReturning :one +UPDATE users SET name = $1 WHERE id = $2 RETURNING id, name; + +-- name: DeleteUser :exec +DELETE FROM users WHERE id = $1; + +-- name: DeleteUserReturning :one +DELETE FROM users WHERE id = $1 RETURNING id; diff --git a/internal/endtoend/testdata/analyze_dml/postgresql/schema.sql b/internal/endtoend/testdata/analyze_dml/postgresql/schema.sql new file mode 100644 index 0000000..897da6c --- /dev/null +++ b/internal/endtoend/testdata/analyze_dml/postgresql/schema.sql @@ -0,0 +1,12 @@ +CREATE TABLE users ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); + +CREATE TABLE posts ( + id BIGSERIAL PRIMARY KEY, + user_id bigint NOT NULL, + title varchar(255), + created timestamptz NOT NULL +); diff --git a/internal/endtoend/testdata/analyze_dml/postgresql/stdout.json b/internal/endtoend/testdata/analyze_dml/postgresql/stdout.json new file mode 100644 index 0000000..e9f777c --- /dev/null +++ b/internal/endtoend/testdata/analyze_dml/postgresql/stdout.json @@ -0,0 +1,165 @@ +[ + { + "name": "CreateUser", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + }, + { + "name": "name", + "type": { + "name": "text" + }, + "table": "users" + }, + { + "name": "bio", + "type": { + "name": "text", + "nullable": true + }, + "table": "users" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "name", + "type": { + "name": "text" + }, + "table": "users" + } + }, + { + "number": 2, + "column": { + "name": "bio", + "type": { + "name": "text", + "nullable": true + }, + "table": "users" + } + } + ] + }, + { + "name": "UpdateBio", + "cmd": ":exec", + "columns": [], + "params": [ + { + "number": 1, + "column": { + "name": "bio", + "type": { + "name": "text", + "nullable": true + }, + "table": "users" + } + }, + { + "number": 2, + "column": { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + } + } + ] + }, + { + "name": "UpdateNameReturning", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + }, + { + "name": "name", + "type": { + "name": "text" + }, + "table": "users" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "name", + "type": { + "name": "text" + }, + "table": "users" + } + }, + { + "number": 2, + "column": { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + } + } + ] + }, + { + "name": "DeleteUser", + "cmd": ":exec", + "columns": [], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + } + } + ] + }, + { + "name": "DeleteUserReturning", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_dml/sqlite/exec.json b/internal/endtoend/testdata/analyze_dml/sqlite/exec.json new file mode 100644 index 0000000..aa77909 --- /dev/null +++ b/internal/endtoend/testdata/analyze_dml/sqlite/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "sqlite", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_dml/sqlite/query.sql b/internal/endtoend/testdata/analyze_dml/sqlite/query.sql new file mode 100644 index 0000000..43e84ac --- /dev/null +++ b/internal/endtoend/testdata/analyze_dml/sqlite/query.sql @@ -0,0 +1,8 @@ +-- name: CreateUser :one +INSERT INTO users (name, bio) VALUES (?, ?) RETURNING *; + +-- name: UpdateBio :exec +UPDATE users SET bio = ? WHERE id = ?; + +-- name: DeleteUser :exec +DELETE FROM users WHERE id = ?; diff --git a/internal/endtoend/testdata/analyze_dml/sqlite/schema.sql b/internal/endtoend/testdata/analyze_dml/sqlite/schema.sql new file mode 100644 index 0000000..7fc8892 --- /dev/null +++ b/internal/endtoend/testdata/analyze_dml/sqlite/schema.sql @@ -0,0 +1,12 @@ +CREATE TABLE users ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL, + bio TEXT +); + +CREATE TABLE posts ( + id INTEGER PRIMARY KEY, + user_id INTEGER NOT NULL, + title TEXT, + created TEXT NOT NULL +); diff --git a/internal/endtoend/testdata/analyze_dml/sqlite/stdout.json b/internal/endtoend/testdata/analyze_dml/sqlite/stdout.json new file mode 100644 index 0000000..0686336 --- /dev/null +++ b/internal/endtoend/testdata/analyze_dml/sqlite/stdout.json @@ -0,0 +1,98 @@ +[ + { + "name": "CreateUser", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "integer" + }, + "table": "users" + }, + { + "name": "name", + "type": { + "name": "text" + }, + "table": "users" + }, + { + "name": "bio", + "type": { + "name": "text", + "nullable": true + }, + "table": "users" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "name", + "type": { + "name": "text" + }, + "table": "users" + } + }, + { + "number": 2, + "column": { + "name": "bio", + "type": { + "name": "text", + "nullable": true + }, + "table": "users" + } + } + ] + }, + { + "name": "UpdateBio", + "cmd": ":exec", + "columns": [], + "params": [ + { + "number": 1, + "column": { + "name": "bio", + "type": { + "name": "text", + "nullable": true + }, + "table": "users" + } + }, + { + "number": 2, + "column": { + "name": "id", + "type": { + "name": "integer" + }, + "table": "users" + } + } + ] + }, + { + "name": "DeleteUser", + "cmd": ":exec", + "columns": [], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "integer" + }, + "table": "users" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_exec/clickhouse/exec.json b/internal/endtoend/testdata/analyze_exec/clickhouse/exec.json new file mode 100644 index 0000000..c92bfa3 --- /dev/null +++ b/internal/endtoend/testdata/analyze_exec/clickhouse/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "clickhouse", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_exec/clickhouse/fixture.sql b/internal/endtoend/testdata/analyze_exec/clickhouse/fixture.sql new file mode 100644 index 0000000..9adc5fa --- /dev/null +++ b/internal/endtoend/testdata/analyze_exec/clickhouse/fixture.sql @@ -0,0 +1,2 @@ +INSERT INTO events VALUES (1, 'signup', NULL, 9.5), (2, 'login', 'web', 0.5); +INSERT INTO users VALUES (1, 'a@example.com'); diff --git a/internal/endtoend/testdata/analyze_exec/clickhouse/query.sql b/internal/endtoend/testdata/analyze_exec/clickhouse/query.sql new file mode 100644 index 0000000..a27579e --- /dev/null +++ b/internal/endtoend/testdata/analyze_exec/clickhouse/query.sql @@ -0,0 +1,11 @@ +-- name: CreateUser :exec +INSERT INTO users (id, email) VALUES (?, ?); + +-- name: CreateEvent :exec +INSERT INTO events VALUES (?, ?, ?, ?); + +-- name: CreateEvents :exec +INSERT INTO events (id, name) VALUES (?, ?), (?, ?); + +-- name: DropUsers :exec +TRUNCATE TABLE users; diff --git a/internal/endtoend/testdata/analyze_exec/clickhouse/schema.sql b/internal/endtoend/testdata/analyze_exec/clickhouse/schema.sql new file mode 100644 index 0000000..9c04e10 --- /dev/null +++ b/internal/endtoend/testdata/analyze_exec/clickhouse/schema.sql @@ -0,0 +1,11 @@ +CREATE TABLE events ( + id UInt64, + name String, + tag Nullable(String), + amount Float64 +) ENGINE = MergeTree ORDER BY id; + +CREATE TABLE users ( + id UInt64, + email String +) ENGINE = MergeTree ORDER BY id; diff --git a/internal/endtoend/testdata/analyze_exec/clickhouse/stdout.json b/internal/endtoend/testdata/analyze_exec/clickhouse/stdout.json new file mode 100644 index 0000000..3709c49 --- /dev/null +++ b/internal/endtoend/testdata/analyze_exec/clickhouse/stdout.json @@ -0,0 +1,130 @@ +[ + { + "name": "CreateUser", + "cmd": ":exec", + "columns": [], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "uint64" + }, + "table": "users" + } + }, + { + "number": 2, + "column": { + "name": "email", + "type": { + "name": "string" + }, + "table": "users" + } + } + ] + }, + { + "name": "CreateEvent", + "cmd": ":exec", + "columns": [], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "uint64" + }, + "table": "events" + } + }, + { + "number": 2, + "column": { + "name": "name", + "type": { + "name": "string" + }, + "table": "events" + } + }, + { + "number": 3, + "column": { + "name": "tag", + "type": { + "name": "string", + "nullable": true + }, + "table": "events" + } + }, + { + "number": 4, + "column": { + "name": "amount", + "type": { + "name": "float64" + }, + "table": "events" + } + } + ] + }, + { + "name": "CreateEvents", + "cmd": ":exec", + "columns": [], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "uint64" + }, + "table": "events" + } + }, + { + "number": 2, + "column": { + "name": "name", + "type": { + "name": "string" + }, + "table": "events" + } + }, + { + "number": 3, + "column": { + "name": "id", + "type": { + "name": "uint64" + }, + "table": "events" + } + }, + { + "number": 4, + "column": { + "name": "name", + "type": { + "name": "string" + }, + "table": "events" + } + } + ] + }, + { + "name": "DropUsers", + "cmd": ":exec", + "columns": [], + "params": [] + } +] diff --git a/internal/endtoend/testdata/analyze_expressions/clickhouse/exec.json b/internal/endtoend/testdata/analyze_expressions/clickhouse/exec.json new file mode 100644 index 0000000..c92bfa3 --- /dev/null +++ b/internal/endtoend/testdata/analyze_expressions/clickhouse/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "clickhouse", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_expressions/clickhouse/fixture.sql b/internal/endtoend/testdata/analyze_expressions/clickhouse/fixture.sql new file mode 100644 index 0000000..9adc5fa --- /dev/null +++ b/internal/endtoend/testdata/analyze_expressions/clickhouse/fixture.sql @@ -0,0 +1,2 @@ +INSERT INTO events VALUES (1, 'signup', NULL, 9.5), (2, 'login', 'web', 0.5); +INSERT INTO users VALUES (1, 'a@example.com'); diff --git a/internal/endtoend/testdata/analyze_expressions/clickhouse/query.sql b/internal/endtoend/testdata/analyze_expressions/clickhouse/query.sql new file mode 100644 index 0000000..dd5604e --- /dev/null +++ b/internal/endtoend/testdata/analyze_expressions/clickhouse/query.sql @@ -0,0 +1,29 @@ +-- name: Aggregates :one +SELECT count() AS n, max(amount) AS top, sum(amount), min(tag) AS first_tag, uniq(name) +FROM events; + +-- name: Expressions :many +SELECT id + 1 AS next_id, nullIf(name, '') AS maybe, coalesce(tag, 'none') AS tag_or_none, + lower(name), toDate(now()) AS today, id > 1 AS big, if(id = 1, 'one', NULL) AS word +FROM events; + +-- name: LeftJoinDefaults :many +SELECT e.id, e.name, u.email +FROM events e +LEFT JOIN users u ON u.id = e.id; + +-- name: Positional :many +SELECT id, name FROM events WHERE name = ? AND amount > ? AND tag = ?; + +-- name: Named :many +SELECT id, name FROM events +WHERE name = sqlc.arg(name) AND tag = sqlc.narg(tag) AND (amount > sqlc.arg(amount) OR amount < sqlc.arg(amount)); + +-- name: Functions :many +SELECT id FROM events WHERE lower(name) = ? AND id IN (?) AND toDate(now()) > ?; + +-- name: Paging :many +SELECT id FROM events ORDER BY id LIMIT ? OFFSET ?; + +-- name: Projected :one +SELECT ? AS echo, 'literal' AS lit; diff --git a/internal/endtoend/testdata/analyze_expressions/clickhouse/schema.sql b/internal/endtoend/testdata/analyze_expressions/clickhouse/schema.sql new file mode 100644 index 0000000..9c04e10 --- /dev/null +++ b/internal/endtoend/testdata/analyze_expressions/clickhouse/schema.sql @@ -0,0 +1,11 @@ +CREATE TABLE events ( + id UInt64, + name String, + tag Nullable(String), + amount Float64 +) ENGINE = MergeTree ORDER BY id; + +CREATE TABLE users ( + id UInt64, + email String +) ENGINE = MergeTree ORDER BY id; diff --git a/internal/endtoend/testdata/analyze_expressions/clickhouse/stdout.json b/internal/endtoend/testdata/analyze_expressions/clickhouse/stdout.json new file mode 100644 index 0000000..e3e4716 --- /dev/null +++ b/internal/endtoend/testdata/analyze_expressions/clickhouse/stdout.json @@ -0,0 +1,342 @@ +[ + { + "name": "Aggregates", + "cmd": ":one", + "columns": [ + { + "name": "n", + "type": { + "name": "uint64" + } + }, + { + "name": "top", + "type": { + "name": "float64" + } + }, + { + "name": "sum(amount)", + "type": { + "name": "float64" + } + }, + { + "name": "first_tag", + "type": { + "name": "string", + "nullable": true + } + }, + { + "name": "uniq(name)", + "type": { + "name": "uint64" + } + } + ], + "params": [] + }, + { + "name": "Expressions", + "cmd": ":many", + "columns": [ + { + "name": "next_id", + "type": { + "name": "uint64" + } + }, + { + "name": "maybe", + "type": { + "name": "string", + "nullable": true + } + }, + { + "name": "tag_or_none", + "type": { + "name": "string" + } + }, + { + "name": "lower(name)", + "type": { + "name": "string" + } + }, + { + "name": "today", + "type": { + "name": "date" + } + }, + { + "name": "big", + "type": { + "name": "uint8" + } + }, + { + "name": "word", + "type": { + "name": "string", + "nullable": true + } + } + ], + "params": [] + }, + { + "name": "LeftJoinDefaults", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "uint64" + }, + "table": "events" + }, + { + "name": "name", + "type": { + "name": "string" + }, + "table": "events" + }, + { + "name": "email", + "type": { + "name": "string" + }, + "table": "users" + } + ], + "params": [] + }, + { + "name": "Positional", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "uint64" + }, + "table": "events" + }, + { + "name": "name", + "type": { + "name": "string" + }, + "table": "events" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "name", + "type": { + "name": "string" + }, + "table": "events" + } + }, + { + "number": 2, + "column": { + "name": "amount", + "type": { + "name": "float64" + }, + "table": "events" + } + }, + { + "number": 3, + "column": { + "name": "tag", + "type": { + "name": "string", + "nullable": true + }, + "table": "events" + } + } + ] + }, + { + "name": "Named", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "uint64" + }, + "table": "events" + }, + { + "name": "name", + "type": { + "name": "string" + }, + "table": "events" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "name", + "type": { + "name": "string" + }, + "table": "events" + } + }, + { + "number": 2, + "column": { + "name": "tag", + "type": { + "name": "string", + "nullable": true + }, + "table": "events" + } + }, + { + "number": 3, + "column": { + "name": "amount", + "type": { + "name": "float64" + }, + "table": "events" + } + }, + { + "number": 4, + "column": { + "name": "amount", + "type": { + "name": "float64" + }, + "table": "events" + } + } + ] + }, + { + "name": "Functions", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "uint64" + }, + "table": "events" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "lower", + "type": { + "name": "string" + } + } + }, + { + "number": 2, + "column": { + "name": "id", + "type": { + "name": "uint64" + }, + "table": "events" + } + }, + { + "number": 3, + "column": { + "name": "toDate", + "type": { + "name": "date" + } + } + } + ] + }, + { + "name": "Paging", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "uint64" + }, + "table": "events" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "", + "type": { + "name": "uint64" + } + } + }, + { + "number": 2, + "column": { + "name": "", + "type": { + "name": "uint64" + } + } + } + ] + }, + { + "name": "Projected", + "cmd": ":one", + "columns": [ + { + "name": "echo", + "type": { + "name": "nothing", + "nullable": true + } + }, + { + "name": "lit", + "type": { + "name": "string" + } + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "echo", + "type": { + "name": "nothing", + "nullable": true + } + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_expressions/sqlite/exec.json b/internal/endtoend/testdata/analyze_expressions/sqlite/exec.json new file mode 100644 index 0000000..aa77909 --- /dev/null +++ b/internal/endtoend/testdata/analyze_expressions/sqlite/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "sqlite", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_expressions/sqlite/fixture.sql b/internal/endtoend/testdata/analyze_expressions/sqlite/fixture.sql new file mode 100644 index 0000000..cda60b0 --- /dev/null +++ b/internal/endtoend/testdata/analyze_expressions/sqlite/fixture.sql @@ -0,0 +1,4 @@ +INSERT INTO users (id, name, bio, score) VALUES (1, 'ann', NULL, 1.5); +INSERT INTO users (id, name, bio, score) VALUES (2, 'bob', 'hello', 2.5); +INSERT INTO posts (id, user_id, title, created) VALUES (1, 1, 'first', '2024-01-01'); +INSERT INTO posts (id, user_id, title, created) VALUES (2, 1, NULL, '2024-01-02'); diff --git a/internal/endtoend/testdata/analyze_expressions/sqlite/query.sql b/internal/endtoend/testdata/analyze_expressions/sqlite/query.sql new file mode 100644 index 0000000..04fdc2f --- /dev/null +++ b/internal/endtoend/testdata/analyze_expressions/sqlite/query.sql @@ -0,0 +1,23 @@ +-- name: PostStats :one +SELECT count(*) AS total, max(id) AS latest, min(created) AS first +FROM posts WHERE user_id = ?; + +-- name: UserScores :one +SELECT avg(score) AS mean, sum(score) AS sum, sum(id) AS ids, group_concat(name) AS names +FROM users; + +-- name: ListUsers :many +SELECT id, lower(name) AS lname, id + 1 AS next +FROM users WHERE id IN (?, ?); + +-- name: ListPosts :many +SELECT id, title FROM posts ORDER BY created LIMIT ? OFFSET ?; + +-- name: UserPosts :many +SELECT u.name, p.title, p.created +FROM users u LEFT JOIN posts p ON p.user_id = u.id +WHERE u.name LIKE ? || '%'; + +-- name: CreatePost :one +INSERT INTO posts (user_id, title, created) VALUES (?, ?, datetime('now')) +RETURNING id, created; diff --git a/internal/endtoend/testdata/analyze_expressions/sqlite/schema.sql b/internal/endtoend/testdata/analyze_expressions/sqlite/schema.sql new file mode 100644 index 0000000..72c6a57 --- /dev/null +++ b/internal/endtoend/testdata/analyze_expressions/sqlite/schema.sql @@ -0,0 +1,15 @@ +CREATE TABLE users ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL, + bio TEXT, + score REAL NOT NULL DEFAULT 0 +); + +CREATE TABLE posts ( + id INTEGER PRIMARY KEY, + user_id INTEGER NOT NULL REFERENCES users(id), + title TEXT, + created TEXT NOT NULL +); + +CREATE INDEX posts_user ON posts(user_id); diff --git a/internal/endtoend/testdata/analyze_expressions/sqlite/stdout.json b/internal/endtoend/testdata/analyze_expressions/sqlite/stdout.json new file mode 100644 index 0000000..2432693 --- /dev/null +++ b/internal/endtoend/testdata/analyze_expressions/sqlite/stdout.json @@ -0,0 +1,245 @@ +[ + { + "name": "PostStats", + "cmd": ":one", + "columns": [ + { + "name": "total", + "type": { + "name": "integer" + } + }, + { + "name": "latest", + "type": { + "name": "integer", + "nullable": true + } + }, + { + "name": "first", + "type": { + "name": "text", + "nullable": true + } + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "user_id", + "type": { + "name": "integer" + }, + "table": "posts" + } + } + ] + }, + { + "name": "UserScores", + "cmd": ":one", + "columns": [ + { + "name": "mean", + "type": { + "name": "real", + "nullable": true + } + }, + { + "name": "sum", + "type": { + "name": "real", + "nullable": true + } + }, + { + "name": "ids", + "type": { + "name": "integer", + "nullable": true + } + }, + { + "name": "names", + "type": { + "name": "text", + "nullable": true + } + } + ], + "params": [] + }, + { + "name": "ListUsers", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "integer" + }, + "table": "users" + }, + { + "name": "lname", + "type": { + "name": "text" + } + }, + { + "name": "next", + "type": { + "name": "integer" + } + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "integer" + }, + "table": "users" + } + }, + { + "number": 2, + "column": { + "name": "id", + "type": { + "name": "integer" + }, + "table": "users" + } + } + ] + }, + { + "name": "ListPosts", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "integer" + }, + "table": "posts" + }, + { + "name": "title", + "type": { + "name": "text", + "nullable": true + }, + "table": "posts" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "", + "type": { + "name": "integer" + } + } + }, + { + "number": 2, + "column": { + "name": "", + "type": { + "name": "integer" + } + } + } + ] + }, + { + "name": "UserPosts", + "cmd": ":many", + "columns": [ + { + "name": "name", + "type": { + "name": "text" + }, + "table": "users" + }, + { + "name": "title", + "type": { + "name": "text", + "nullable": true + }, + "table": "posts" + }, + { + "name": "created", + "type": { + "name": "text" + }, + "table": "posts" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "", + "type": { + "name": "text" + } + } + } + ] + }, + { + "name": "CreatePost", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "integer" + }, + "table": "posts" + }, + { + "name": "created", + "type": { + "name": "text" + }, + "table": "posts" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "user_id", + "type": { + "name": "integer" + }, + "table": "posts" + } + }, + { + "number": 2, + "column": { + "name": "title", + "type": { + "name": "text", + "nullable": true + }, + "table": "posts" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_extension/postgresql/exec.json b/internal/endtoend/testdata/analyze_extension/postgresql/exec.json new file mode 100644 index 0000000..b102755 --- /dev/null +++ b/internal/endtoend/testdata/analyze_extension/postgresql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "postgresql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_extension/postgresql/query.sql b/internal/endtoend/testdata/analyze_extension/postgresql/query.sql new file mode 100644 index 0000000..1138718 --- /dev/null +++ b/internal/endtoend/testdata/analyze_extension/postgresql/query.sql @@ -0,0 +1,8 @@ +-- name: GetUserByEmail :one +SELECT id, email FROM users WHERE email = $1; + +-- name: MatchingEmails :many +SELECT id FROM users WHERE email = name; + +-- name: RankUsers :many +SELECT id, similarity(name, $1) AS score FROM users; diff --git a/internal/endtoend/testdata/analyze_extension/postgresql/schema.sql b/internal/endtoend/testdata/analyze_extension/postgresql/schema.sql new file mode 100644 index 0000000..acaea17 --- /dev/null +++ b/internal/endtoend/testdata/analyze_extension/postgresql/schema.sql @@ -0,0 +1,8 @@ +CREATE EXTENSION citext; +CREATE EXTENSION pg_trgm; + +CREATE TABLE users ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + email citext NOT NULL +); diff --git a/internal/endtoend/testdata/analyze_extension/postgresql/stdout.json b/internal/endtoend/testdata/analyze_extension/postgresql/stdout.json new file mode 100644 index 0000000..dd4477e --- /dev/null +++ b/internal/endtoend/testdata/analyze_extension/postgresql/stdout.json @@ -0,0 +1,78 @@ +[ + { + "name": "GetUserByEmail", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + }, + { + "name": "email", + "type": { + "name": "citext" + }, + "table": "users" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "email", + "type": { + "name": "citext" + }, + "table": "users" + } + } + ] + }, + { + "name": "MatchingEmails", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + } + ], + "params": [] + }, + { + "name": "RankUsers", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + }, + { + "name": "score", + "type": { + "name": "real" + } + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "", + "type": { + "name": "text" + } + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_params/clickhouse/exec.json b/internal/endtoend/testdata/analyze_params/clickhouse/exec.json new file mode 100644 index 0000000..c92bfa3 --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/clickhouse/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "clickhouse", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_params/clickhouse/fixture.sql b/internal/endtoend/testdata/analyze_params/clickhouse/fixture.sql new file mode 100644 index 0000000..f13ad59 --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/clickhouse/fixture.sql @@ -0,0 +1,2 @@ +INSERT INTO events (id, name, tag, amount, created) VALUES (1, 'signup', NULL, 9.5, '2024-01-01 00:00:00'); +INSERT INTO events (id, name, tag, amount, created) VALUES (2, 'login', 'web', 0.5, '2024-01-02 00:00:00'); diff --git a/internal/endtoend/testdata/analyze_params/clickhouse/query.sql b/internal/endtoend/testdata/analyze_params/clickhouse/query.sql new file mode 100644 index 0000000..5405a5b --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/clickhouse/query.sql @@ -0,0 +1,5 @@ +-- name: GetEvent :one +SELECT id, name FROM events WHERE id = ?; + +-- name: FilterEvents :many +SELECT id, name FROM events WHERE name = ? AND amount > ?; diff --git a/internal/endtoend/testdata/analyze_params/clickhouse/schema.sql b/internal/endtoend/testdata/analyze_params/clickhouse/schema.sql new file mode 100644 index 0000000..29960ee --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/clickhouse/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE events ( + id UInt64, + name String, + tag Nullable(String), + amount Float64, + created DateTime +) ENGINE = MergeTree ORDER BY id; diff --git a/internal/endtoend/testdata/analyze_params/clickhouse/stdout.json b/internal/endtoend/testdata/analyze_params/clickhouse/stdout.json new file mode 100644 index 0000000..548bb8b --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/clickhouse/stdout.json @@ -0,0 +1,76 @@ +[ + { + "name": "GetEvent", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "uint64" + }, + "table": "events" + }, + { + "name": "name", + "type": { + "name": "string" + }, + "table": "events" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "uint64" + }, + "table": "events" + } + } + ] + }, + { + "name": "FilterEvents", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "uint64" + }, + "table": "events" + }, + { + "name": "name", + "type": { + "name": "string" + }, + "table": "events" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "name", + "type": { + "name": "string" + }, + "table": "events" + } + }, + { + "number": 2, + "column": { + "name": "amount", + "type": { + "name": "float64" + }, + "table": "events" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_params/duckdb/exec.json b/internal/endtoend/testdata/analyze_params/duckdb/exec.json new file mode 100644 index 0000000..56cb4b3 --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/duckdb/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "duckdb", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_params/duckdb/query.sql b/internal/endtoend/testdata/analyze_params/duckdb/query.sql new file mode 100644 index 0000000..ed26e54 --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/duckdb/query.sql @@ -0,0 +1,8 @@ +-- name: GetAuthor :one +SELECT id, name, bio FROM authors WHERE id = $1; + +-- name: FilterAuthors :many +SELECT id, name FROM authors WHERE name = $name AND royalties > $royalties; + +-- name: SearchAuthors :many +SELECT id FROM authors WHERE name LIKE ? AND bio IS NOT NULL; diff --git a/internal/endtoend/testdata/analyze_params/duckdb/schema.sql b/internal/endtoend/testdata/analyze_params/duckdb/schema.sql new file mode 100644 index 0000000..48e8522 --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/duckdb/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE authors ( + id BIGINT PRIMARY KEY, + name TEXT NOT NULL, + bio TEXT, + royalties DECIMAL(10,2) NOT NULL +); diff --git a/internal/endtoend/testdata/analyze_params/duckdb/stdout.json b/internal/endtoend/testdata/analyze_params/duckdb/stdout.json new file mode 100644 index 0000000..40037c2 --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/duckdb/stdout.json @@ -0,0 +1,117 @@ +[ + { + "name": "GetAuthor", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "authors" + }, + { + "name": "name", + "type": { + "name": "varchar" + }, + "table": "authors" + }, + { + "name": "bio", + "type": { + "name": "varchar", + "nullable": true + }, + "table": "authors" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "authors" + } + } + ] + }, + { + "name": "FilterAuthors", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "authors" + }, + { + "name": "name", + "type": { + "name": "varchar" + }, + "table": "authors" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "name", + "type": { + "name": "varchar" + }, + "table": "authors" + } + }, + { + "number": 2, + "column": { + "name": "royalties", + "type": { + "name": "decimal", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "authors" + } + } + ] + }, + { + "name": "SearchAuthors", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "authors" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "name", + "type": { + "name": "varchar" + }, + "table": "authors" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_params/mssql/exec.json b/internal/endtoend/testdata/analyze_params/mssql/exec.json new file mode 100644 index 0000000..253b05a --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/mssql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "mssql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_params/mssql/query.sql b/internal/endtoend/testdata/analyze_params/mssql/query.sql new file mode 100644 index 0000000..c410ec5 --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/mssql/query.sql @@ -0,0 +1,5 @@ +-- name: GetAuthor :one +SELECT id, name, bio FROM authors WHERE id = @id; + +-- name: FilterAuthors :many +SELECT id, name FROM authors WHERE name = @name AND royalties > @royalties; diff --git a/internal/endtoend/testdata/analyze_params/mssql/schema.sql b/internal/endtoend/testdata/analyze_params/mssql/schema.sql new file mode 100644 index 0000000..3629635 --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/mssql/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE authors ( + id BIGINT IDENTITY(1,1) PRIMARY KEY, + name NVARCHAR(100) NOT NULL, + bio NVARCHAR(MAX), + royalties DECIMAL(10,2) NOT NULL, + created DATETIME2 NOT NULL +); diff --git a/internal/endtoend/testdata/analyze_params/mssql/stdout.json b/internal/endtoend/testdata/analyze_params/mssql/stdout.json new file mode 100644 index 0000000..ab55aa9 --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/mssql/stdout.json @@ -0,0 +1,112 @@ +[ + { + "name": "GetAuthor", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "authors" + }, + { + "name": "name", + "type": { + "name": "nvarchar", + "args": [ + { + "int": 100 + } + ] + }, + "table": "authors" + }, + { + "name": "bio", + "type": { + "name": "nvarchar", + "nullable": true, + "args": [ + { + "ident": "max" + } + ] + }, + "table": "authors" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "authors" + } + } + ] + }, + { + "name": "FilterAuthors", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "authors" + }, + { + "name": "name", + "type": { + "name": "nvarchar", + "args": [ + { + "int": 100 + } + ] + }, + "table": "authors" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "name", + "type": { + "name": "nvarchar", + "args": [ + { + "int": 100 + } + ] + }, + "table": "authors" + } + }, + { + "number": 2, + "column": { + "name": "royalties", + "type": { + "name": "decimal", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "authors" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_params/mysql/exec.json b/internal/endtoend/testdata/analyze_params/mysql/exec.json new file mode 100644 index 0000000..a5b24d3 --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/mysql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "mysql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_params/mysql/query.sql b/internal/endtoend/testdata/analyze_params/mysql/query.sql new file mode 100644 index 0000000..83088a7 --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/mysql/query.sql @@ -0,0 +1,8 @@ +-- name: GetUser :one +SELECT id, name FROM users WHERE id = ?; + +-- name: FilterUsers :many +SELECT id, name FROM users WHERE name = sqlc.arg(name) AND bio = sqlc.narg(bio); + +-- name: UsersByID :many +SELECT id, name FROM users WHERE id IN (sqlc.slice(ids)); diff --git a/internal/endtoend/testdata/analyze_params/mysql/schema.sql b/internal/endtoend/testdata/analyze_params/mysql/schema.sql new file mode 100644 index 0000000..ad0d0c1 --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/mysql/schema.sql @@ -0,0 +1,12 @@ +CREATE TABLE users ( + id BIGINT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + bio TEXT +); + +CREATE TABLE posts ( + id BIGINT PRIMARY KEY, + user_id BIGINT NOT NULL, + title VARCHAR(255), + created DATETIME NOT NULL +); diff --git a/internal/endtoend/testdata/analyze_params/mysql/stdout.json b/internal/endtoend/testdata/analyze_params/mysql/stdout.json new file mode 100644 index 0000000..6232a4d --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/mysql/stdout.json @@ -0,0 +1,129 @@ +[ + { + "name": "GetUser", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + }, + { + "name": "name", + "type": { + "name": "varchar", + "args": [ + { + "int": 255 + } + ] + }, + "table": "users" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + } + } + ] + }, + { + "name": "FilterUsers", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + }, + { + "name": "name", + "type": { + "name": "varchar", + "args": [ + { + "int": 255 + } + ] + }, + "table": "users" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "name", + "type": { + "name": "varchar", + "args": [ + { + "int": 255 + } + ] + }, + "table": "users" + } + }, + { + "number": 2, + "column": { + "name": "bio", + "type": { + "name": "text", + "nullable": true + }, + "table": "users" + } + } + ] + }, + { + "name": "UsersByID", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + }, + { + "name": "name", + "type": { + "name": "varchar", + "args": [ + { + "int": 255 + } + ] + }, + "table": "users" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "ids", + "type": { + "name": "bigint" + }, + "table": "users" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_params/postgresql/exec.json b/internal/endtoend/testdata/analyze_params/postgresql/exec.json new file mode 100644 index 0000000..b102755 --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/postgresql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "postgresql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_params/postgresql/query.sql b/internal/endtoend/testdata/analyze_params/postgresql/query.sql new file mode 100644 index 0000000..7dd9d17 --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/postgresql/query.sql @@ -0,0 +1,11 @@ +-- name: GetUser :one +SELECT id, name FROM users WHERE id = $1; + +-- name: FilterUsers :many +SELECT id, name FROM users WHERE name = sqlc.arg(name) AND bio = sqlc.narg(bio); + +-- name: UsersByID :many +SELECT id, name FROM users WHERE id = ANY(sqlc.slice(ids)); + +-- name: PostsBetween :many +SELECT id, title FROM posts WHERE created BETWEEN $1 AND $2; diff --git a/internal/endtoend/testdata/analyze_params/postgresql/schema.sql b/internal/endtoend/testdata/analyze_params/postgresql/schema.sql new file mode 100644 index 0000000..897da6c --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/postgresql/schema.sql @@ -0,0 +1,12 @@ +CREATE TABLE users ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); + +CREATE TABLE posts ( + id BIGSERIAL PRIMARY KEY, + user_id bigint NOT NULL, + title varchar(255), + created timestamptz NOT NULL +); diff --git a/internal/endtoend/testdata/analyze_params/postgresql/stdout.json b/internal/endtoend/testdata/analyze_params/postgresql/stdout.json new file mode 100644 index 0000000..fd46e40 --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/postgresql/stdout.json @@ -0,0 +1,157 @@ +[ + { + "name": "GetUser", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + }, + { + "name": "name", + "type": { + "name": "text" + }, + "table": "users" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + } + } + ] + }, + { + "name": "FilterUsers", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + }, + { + "name": "name", + "type": { + "name": "text" + }, + "table": "users" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "name", + "type": { + "name": "text" + }, + "table": "users" + } + }, + { + "number": 2, + "column": { + "name": "bio", + "type": { + "name": "text", + "nullable": true + }, + "table": "users" + } + } + ] + }, + { + "name": "UsersByID", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + }, + { + "name": "name", + "type": { + "name": "text" + }, + "table": "users" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "ids", + "type": { + "name": "bigint" + }, + "table": "users" + } + } + ] + }, + { + "name": "PostsBetween", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "posts" + }, + { + "name": "title", + "type": { + "name": "character varying", + "nullable": true, + "args": [ + { + "int": 255 + } + ] + }, + "table": "posts" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "created", + "type": { + "name": "timestamp with time zone" + }, + "table": "posts" + } + }, + { + "number": 2, + "column": { + "name": "created", + "type": { + "name": "timestamp with time zone" + }, + "table": "posts" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_params/sqlite/exec.json b/internal/endtoend/testdata/analyze_params/sqlite/exec.json new file mode 100644 index 0000000..aa77909 --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/sqlite/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "sqlite", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_params/sqlite/query.sql b/internal/endtoend/testdata/analyze_params/sqlite/query.sql new file mode 100644 index 0000000..782c3fb --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/sqlite/query.sql @@ -0,0 +1,8 @@ +-- name: GetUser :one +SELECT id, name FROM users WHERE id = ?; + +-- name: FilterUsers :many +SELECT id, name FROM users WHERE name = sqlc.arg(name) AND bio = sqlc.narg(bio); + +-- name: CountPosts :one +SELECT count(*) AS total FROM posts WHERE user_id = ?; diff --git a/internal/endtoend/testdata/analyze_params/sqlite/schema.sql b/internal/endtoend/testdata/analyze_params/sqlite/schema.sql new file mode 100644 index 0000000..7fc8892 --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/sqlite/schema.sql @@ -0,0 +1,12 @@ +CREATE TABLE users ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL, + bio TEXT +); + +CREATE TABLE posts ( + id INTEGER PRIMARY KEY, + user_id INTEGER NOT NULL, + title TEXT, + created TEXT NOT NULL +); diff --git a/internal/endtoend/testdata/analyze_params/sqlite/stdout.json b/internal/endtoend/testdata/analyze_params/sqlite/stdout.json new file mode 100644 index 0000000..fd0e721 --- /dev/null +++ b/internal/endtoend/testdata/analyze_params/sqlite/stdout.json @@ -0,0 +1,101 @@ +[ + { + "name": "GetUser", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "integer" + }, + "table": "users" + }, + { + "name": "name", + "type": { + "name": "text" + }, + "table": "users" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "id", + "type": { + "name": "integer" + }, + "table": "users" + } + } + ] + }, + { + "name": "FilterUsers", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "integer" + }, + "table": "users" + }, + { + "name": "name", + "type": { + "name": "text" + }, + "table": "users" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "name", + "type": { + "name": "text" + }, + "table": "users" + } + }, + { + "number": 2, + "column": { + "name": "bio", + "type": { + "name": "text", + "nullable": true + }, + "table": "users" + } + } + ] + }, + { + "name": "CountPosts", + "cmd": ":one", + "columns": [ + { + "name": "total", + "type": { + "name": "integer" + } + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "user_id", + "type": { + "name": "integer" + }, + "table": "posts" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_select/duckdb/exec.json b/internal/endtoend/testdata/analyze_select/duckdb/exec.json new file mode 100644 index 0000000..56cb4b3 --- /dev/null +++ b/internal/endtoend/testdata/analyze_select/duckdb/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "duckdb", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_select/duckdb/query.sql b/internal/endtoend/testdata/analyze_select/duckdb/query.sql new file mode 100644 index 0000000..794d153 --- /dev/null +++ b/internal/endtoend/testdata/analyze_select/duckdb/query.sql @@ -0,0 +1,16 @@ +-- name: ListUsers :many +SELECT * FROM users; + +-- name: CountUsers :one +SELECT count(*) AS total FROM users; + +-- name: ListUserPosts :many +SELECT u.name, p.* FROM users u JOIN posts p ON p.user_id = u.id WHERE u.name = $1; + +-- name: TopUsers :many +WITH counts AS ( + SELECT user_id, count(*) AS n FROM posts GROUP BY user_id +) +SELECT u.name, c.n FROM users u JOIN counts c ON c.user_id = u.id +ORDER BY c.n DESC +LIMIT 5; diff --git a/internal/endtoend/testdata/analyze_select/duckdb/schema.sql b/internal/endtoend/testdata/analyze_select/duckdb/schema.sql new file mode 100644 index 0000000..b69cc33 --- /dev/null +++ b/internal/endtoend/testdata/analyze_select/duckdb/schema.sql @@ -0,0 +1,12 @@ +CREATE TABLE users ( + id BIGINT NOT NULL, + name TEXT NOT NULL, + age INTEGER +); + +CREATE TABLE posts ( + id BIGINT NOT NULL, + user_id BIGINT NOT NULL, + title TEXT NOT NULL, + body TEXT +); diff --git a/internal/endtoend/testdata/analyze_select/duckdb/stdout.json b/internal/endtoend/testdata/analyze_select/duckdb/stdout.json new file mode 100644 index 0000000..e0744b9 --- /dev/null +++ b/internal/endtoend/testdata/analyze_select/duckdb/stdout.json @@ -0,0 +1,118 @@ +[ + { + "name": "ListUsers", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + }, + { + "name": "name", + "type": { + "name": "varchar" + }, + "table": "users" + }, + { + "name": "age", + "type": { + "name": "integer", + "nullable": true + }, + "table": "users" + } + ], + "params": [] + }, + { + "name": "CountUsers", + "cmd": ":one", + "columns": [ + { + "name": "total", + "type": { + "name": "bigint" + } + } + ], + "params": [] + }, + { + "name": "ListUserPosts", + "cmd": ":many", + "columns": [ + { + "name": "name", + "type": { + "name": "varchar" + }, + "table": "users" + }, + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "posts" + }, + { + "name": "user_id", + "type": { + "name": "bigint" + }, + "table": "posts" + }, + { + "name": "title", + "type": { + "name": "varchar" + }, + "table": "posts" + }, + { + "name": "body", + "type": { + "name": "varchar", + "nullable": true + }, + "table": "posts" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "name", + "type": { + "name": "varchar" + }, + "table": "users" + } + } + ] + }, + { + "name": "TopUsers", + "cmd": ":many", + "columns": [ + { + "name": "name", + "type": { + "name": "varchar" + }, + "table": "users" + }, + { + "name": "n", + "type": { + "name": "bigint" + } + } + ], + "params": [] + } +] diff --git a/internal/endtoend/testdata/analyze_select/googlesql/exec.json b/internal/endtoend/testdata/analyze_select/googlesql/exec.json new file mode 100644 index 0000000..a53dddd --- /dev/null +++ b/internal/endtoend/testdata/analyze_select/googlesql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "googlesql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_select/googlesql/query.sql b/internal/endtoend/testdata/analyze_select/googlesql/query.sql new file mode 100644 index 0000000..b4e7756 --- /dev/null +++ b/internal/endtoend/testdata/analyze_select/googlesql/query.sql @@ -0,0 +1,8 @@ +-- name: ListUsers :many +SELECT * FROM users; + +-- name: CountUsers :one +SELECT COUNT(*) AS total FROM users; + +-- name: ListUserPosts :many +SELECT u.name, p.* FROM users u JOIN posts p ON p.user_id = u.id WHERE u.name = @name; diff --git a/internal/endtoend/testdata/analyze_select/googlesql/schema.sql b/internal/endtoend/testdata/analyze_select/googlesql/schema.sql new file mode 100644 index 0000000..0c5bc52 --- /dev/null +++ b/internal/endtoend/testdata/analyze_select/googlesql/schema.sql @@ -0,0 +1,12 @@ +CREATE TABLE users ( + id INT64 NOT NULL, + name STRING(MAX) NOT NULL, + bio STRING(MAX), +) PRIMARY KEY (id); + +CREATE TABLE posts ( + id INT64 NOT NULL, + user_id INT64 NOT NULL, + title STRING(255), + created TIMESTAMP NOT NULL, +) PRIMARY KEY (id); diff --git a/internal/endtoend/testdata/analyze_select/googlesql/stdout.json b/internal/endtoend/testdata/analyze_select/googlesql/stdout.json new file mode 100644 index 0000000..919d313 --- /dev/null +++ b/internal/endtoend/testdata/analyze_select/googlesql/stdout.json @@ -0,0 +1,123 @@ +[ + { + "name": "ListUsers", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "int64" + }, + "table": "users" + }, + { + "name": "name", + "type": { + "name": "string", + "args": [ + { + "ident": "max" + } + ] + }, + "table": "users" + }, + { + "name": "bio", + "type": { + "name": "string", + "nullable": true, + "args": [ + { + "ident": "max" + } + ] + }, + "table": "users" + } + ], + "params": [] + }, + { + "name": "CountUsers", + "cmd": ":one", + "columns": [ + { + "name": "total", + "type": { + "name": "int64" + } + } + ], + "params": [] + }, + { + "name": "ListUserPosts", + "cmd": ":many", + "columns": [ + { + "name": "name", + "type": { + "name": "string", + "args": [ + { + "ident": "max" + } + ] + }, + "table": "users" + }, + { + "name": "id", + "type": { + "name": "int64" + }, + "table": "posts" + }, + { + "name": "user_id", + "type": { + "name": "int64" + }, + "table": "posts" + }, + { + "name": "title", + "type": { + "name": "string", + "nullable": true, + "args": [ + { + "int": 255 + } + ] + }, + "table": "posts" + }, + { + "name": "created", + "type": { + "name": "timestamp" + }, + "table": "posts" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "name", + "type": { + "name": "string", + "args": [ + { + "ident": "max" + } + ] + }, + "table": "users" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_select/mysql/exec.json b/internal/endtoend/testdata/analyze_select/mysql/exec.json new file mode 100644 index 0000000..a5b24d3 --- /dev/null +++ b/internal/endtoend/testdata/analyze_select/mysql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "mysql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_select/mysql/query.sql b/internal/endtoend/testdata/analyze_select/mysql/query.sql new file mode 100644 index 0000000..ff6b716 --- /dev/null +++ b/internal/endtoend/testdata/analyze_select/mysql/query.sql @@ -0,0 +1,17 @@ +-- name: ListUsers :many +SELECT * FROM users; + +-- name: CountUsers :one +SELECT count(*) AS total FROM users; + +-- name: ListUserPosts :many +SELECT u.name, p.* FROM users u JOIN posts p ON p.user_id = u.id WHERE u.name = ?; + +-- name: SearchPosts :many +SELECT id, title FROM posts WHERE title LIKE ? AND created > ?; + +-- name: LatestPostPerUser :many +WITH latest AS ( + SELECT user_id, max(created) AS created FROM posts GROUP BY user_id +) +SELECT u.name, latest.created FROM users u JOIN latest ON latest.user_id = u.id; diff --git a/internal/endtoend/testdata/analyze_select/mysql/schema.sql b/internal/endtoend/testdata/analyze_select/mysql/schema.sql new file mode 100644 index 0000000..ad0d0c1 --- /dev/null +++ b/internal/endtoend/testdata/analyze_select/mysql/schema.sql @@ -0,0 +1,12 @@ +CREATE TABLE users ( + id BIGINT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + bio TEXT +); + +CREATE TABLE posts ( + id BIGINT PRIMARY KEY, + user_id BIGINT NOT NULL, + title VARCHAR(255), + created DATETIME NOT NULL +); diff --git a/internal/endtoend/testdata/analyze_select/mysql/stdout.json b/internal/endtoend/testdata/analyze_select/mysql/stdout.json new file mode 100644 index 0000000..3e679fd --- /dev/null +++ b/internal/endtoend/testdata/analyze_select/mysql/stdout.json @@ -0,0 +1,198 @@ +[ + { + "name": "ListUsers", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + }, + { + "name": "name", + "type": { + "name": "varchar", + "args": [ + { + "int": 255 + } + ] + }, + "table": "users" + }, + { + "name": "bio", + "type": { + "name": "text", + "nullable": true + }, + "table": "users" + } + ], + "params": [] + }, + { + "name": "CountUsers", + "cmd": ":one", + "columns": [ + { + "name": "total", + "type": { + "name": "bigint" + } + } + ], + "params": [] + }, + { + "name": "ListUserPosts", + "cmd": ":many", + "columns": [ + { + "name": "name", + "type": { + "name": "varchar", + "args": [ + { + "int": 255 + } + ] + }, + "table": "users" + }, + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "posts" + }, + { + "name": "user_id", + "type": { + "name": "bigint" + }, + "table": "posts" + }, + { + "name": "title", + "type": { + "name": "varchar", + "nullable": true, + "args": [ + { + "int": 255 + } + ] + }, + "table": "posts" + }, + { + "name": "created", + "type": { + "name": "datetime" + }, + "table": "posts" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "name", + "type": { + "name": "varchar", + "args": [ + { + "int": 255 + } + ] + }, + "table": "users" + } + } + ] + }, + { + "name": "SearchPosts", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "posts" + }, + { + "name": "title", + "type": { + "name": "varchar", + "nullable": true, + "args": [ + { + "int": 255 + } + ] + }, + "table": "posts" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "title", + "type": { + "name": "varchar", + "nullable": true, + "args": [ + { + "int": 255 + } + ] + }, + "table": "posts" + } + }, + { + "number": 2, + "column": { + "name": "created", + "type": { + "name": "datetime" + }, + "table": "posts" + } + } + ] + }, + { + "name": "LatestPostPerUser", + "cmd": ":many", + "columns": [ + { + "name": "name", + "type": { + "name": "varchar", + "args": [ + { + "int": 255 + } + ] + }, + "table": "users" + }, + { + "name": "created", + "type": { + "name": "datetime", + "nullable": true + } + } + ], + "params": [] + } +] diff --git a/internal/endtoend/testdata/analyze_select/postgresql/exec.json b/internal/endtoend/testdata/analyze_select/postgresql/exec.json new file mode 100644 index 0000000..b102755 --- /dev/null +++ b/internal/endtoend/testdata/analyze_select/postgresql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "postgresql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_select/postgresql/query.sql b/internal/endtoend/testdata/analyze_select/postgresql/query.sql new file mode 100644 index 0000000..d11618b --- /dev/null +++ b/internal/endtoend/testdata/analyze_select/postgresql/query.sql @@ -0,0 +1,17 @@ +-- name: ListUsers :many +SELECT * FROM users; + +-- name: CountUsers :one +SELECT count(*) AS total FROM users; + +-- name: ListUserPosts :many +SELECT u.name, p.* FROM users u JOIN posts p ON p.user_id = u.id WHERE u.name = $1; + +-- name: SearchPosts :many +SELECT id, title FROM posts WHERE title LIKE $1 AND created > $2; + +-- name: LatestPostPerUser :many +WITH latest AS ( + SELECT user_id, max(created) AS created FROM posts GROUP BY user_id +) +SELECT u.name, latest.created FROM users u JOIN latest ON latest.user_id = u.id; diff --git a/internal/endtoend/testdata/analyze_select/postgresql/schema.sql b/internal/endtoend/testdata/analyze_select/postgresql/schema.sql new file mode 100644 index 0000000..897da6c --- /dev/null +++ b/internal/endtoend/testdata/analyze_select/postgresql/schema.sql @@ -0,0 +1,12 @@ +CREATE TABLE users ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); + +CREATE TABLE posts ( + id BIGSERIAL PRIMARY KEY, + user_id bigint NOT NULL, + title varchar(255), + created timestamptz NOT NULL +); diff --git a/internal/endtoend/testdata/analyze_select/postgresql/stdout.json b/internal/endtoend/testdata/analyze_select/postgresql/stdout.json new file mode 100644 index 0000000..95f2d69 --- /dev/null +++ b/internal/endtoend/testdata/analyze_select/postgresql/stdout.json @@ -0,0 +1,177 @@ +[ + { + "name": "ListUsers", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "users" + }, + { + "name": "name", + "type": { + "name": "text" + }, + "table": "users" + }, + { + "name": "bio", + "type": { + "name": "text", + "nullable": true + }, + "table": "users" + } + ], + "params": [] + }, + { + "name": "CountUsers", + "cmd": ":one", + "columns": [ + { + "name": "total", + "type": { + "name": "bigint" + } + } + ], + "params": [] + }, + { + "name": "ListUserPosts", + "cmd": ":many", + "columns": [ + { + "name": "name", + "type": { + "name": "text" + }, + "table": "users" + }, + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "posts" + }, + { + "name": "user_id", + "type": { + "name": "bigint" + }, + "table": "posts" + }, + { + "name": "title", + "type": { + "name": "character varying", + "nullable": true, + "args": [ + { + "int": 255 + } + ] + }, + "table": "posts" + }, + { + "name": "created", + "type": { + "name": "timestamp with time zone" + }, + "table": "posts" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "name", + "type": { + "name": "text" + }, + "table": "users" + } + } + ] + }, + { + "name": "SearchPosts", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "posts" + }, + { + "name": "title", + "type": { + "name": "character varying", + "nullable": true, + "args": [ + { + "int": 255 + } + ] + }, + "table": "posts" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "title", + "type": { + "name": "character varying", + "nullable": true, + "args": [ + { + "int": 255 + } + ] + }, + "table": "posts" + } + }, + { + "number": 2, + "column": { + "name": "created", + "type": { + "name": "timestamp with time zone" + }, + "table": "posts" + } + } + ] + }, + { + "name": "LatestPostPerUser", + "cmd": ":many", + "columns": [ + { + "name": "name", + "type": { + "name": "text" + }, + "table": "users" + }, + { + "name": "created", + "type": { + "name": "timestamp with time zone" + } + } + ], + "params": [] + } +] diff --git a/internal/endtoend/testdata/analyze_select/sqlite/exec.json b/internal/endtoend/testdata/analyze_select/sqlite/exec.json new file mode 100644 index 0000000..aa77909 --- /dev/null +++ b/internal/endtoend/testdata/analyze_select/sqlite/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "sqlite", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_select/sqlite/query.sql b/internal/endtoend/testdata/analyze_select/sqlite/query.sql new file mode 100644 index 0000000..985fc6d --- /dev/null +++ b/internal/endtoend/testdata/analyze_select/sqlite/query.sql @@ -0,0 +1,11 @@ +-- name: ListUsers :many +SELECT * FROM users; + +-- name: CountUsers :one +SELECT count(*) AS total FROM users; + +-- name: ListUserPosts :many +SELECT u.name, p.* FROM users u JOIN posts p ON p.user_id = u.id WHERE u.name = ?; + +-- name: SearchPosts :many +SELECT id, title FROM posts WHERE title LIKE ? AND created > ?; diff --git a/internal/endtoend/testdata/analyze_select/sqlite/schema.sql b/internal/endtoend/testdata/analyze_select/sqlite/schema.sql new file mode 100644 index 0000000..7fc8892 --- /dev/null +++ b/internal/endtoend/testdata/analyze_select/sqlite/schema.sql @@ -0,0 +1,12 @@ +CREATE TABLE users ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL, + bio TEXT +); + +CREATE TABLE posts ( + id INTEGER PRIMARY KEY, + user_id INTEGER NOT NULL, + title TEXT, + created TEXT NOT NULL +); diff --git a/internal/endtoend/testdata/analyze_select/sqlite/stdout.json b/internal/endtoend/testdata/analyze_select/sqlite/stdout.json new file mode 100644 index 0000000..032d947 --- /dev/null +++ b/internal/endtoend/testdata/analyze_select/sqlite/stdout.json @@ -0,0 +1,142 @@ +[ + { + "name": "ListUsers", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "integer" + }, + "table": "users" + }, + { + "name": "name", + "type": { + "name": "text" + }, + "table": "users" + }, + { + "name": "bio", + "type": { + "name": "text", + "nullable": true + }, + "table": "users" + } + ], + "params": [] + }, + { + "name": "CountUsers", + "cmd": ":one", + "columns": [ + { + "name": "total", + "type": { + "name": "integer" + } + } + ], + "params": [] + }, + { + "name": "ListUserPosts", + "cmd": ":many", + "columns": [ + { + "name": "name", + "type": { + "name": "text" + }, + "table": "users" + }, + { + "name": "id", + "type": { + "name": "integer" + }, + "table": "posts" + }, + { + "name": "user_id", + "type": { + "name": "integer" + }, + "table": "posts" + }, + { + "name": "title", + "type": { + "name": "text", + "nullable": true + }, + "table": "posts" + }, + { + "name": "created", + "type": { + "name": "text" + }, + "table": "posts" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "name", + "type": { + "name": "text" + }, + "table": "users" + } + } + ] + }, + { + "name": "SearchPosts", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "integer" + }, + "table": "posts" + }, + { + "name": "title", + "type": { + "name": "text", + "nullable": true + }, + "table": "posts" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "title", + "type": { + "name": "text", + "nullable": true + }, + "table": "posts" + } + }, + { + "number": 2, + "column": { + "name": "created", + "type": { + "name": "text" + }, + "table": "posts" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_subqueries/clickhouse/exec.json b/internal/endtoend/testdata/analyze_subqueries/clickhouse/exec.json new file mode 100644 index 0000000..c92bfa3 --- /dev/null +++ b/internal/endtoend/testdata/analyze_subqueries/clickhouse/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "clickhouse", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_subqueries/clickhouse/fixture.sql b/internal/endtoend/testdata/analyze_subqueries/clickhouse/fixture.sql new file mode 100644 index 0000000..9adc5fa --- /dev/null +++ b/internal/endtoend/testdata/analyze_subqueries/clickhouse/fixture.sql @@ -0,0 +1,2 @@ +INSERT INTO events VALUES (1, 'signup', NULL, 9.5), (2, 'login', 'web', 0.5); +INSERT INTO users VALUES (1, 'a@example.com'); diff --git a/internal/endtoend/testdata/analyze_subqueries/clickhouse/query.sql b/internal/endtoend/testdata/analyze_subqueries/clickhouse/query.sql new file mode 100644 index 0000000..601ba8e --- /dev/null +++ b/internal/endtoend/testdata/analyze_subqueries/clickhouse/query.sql @@ -0,0 +1,27 @@ +-- name: Aliased :many +SELECT s.x, s.total, s.email +FROM ( + SELECT e.id AS x, sum(e.amount) AS total, any(u.email) AS email + FROM events e JOIN users u ON u.id = e.id + GROUP BY e.id +) s; + +-- name: Union :many +SELECT id, name FROM events +UNION ALL +SELECT id, email FROM users; + +-- name: ScalarSubquery :many +SELECT id, (SELECT count() FROM users) AS user_count +FROM events +WHERE id IN (SELECT id FROM users WHERE email = ?); + + +-- name: Cte :many +WITH t AS (SELECT id, tag FROM events) +SELECT t.id, t.tag, s.cnt +FROM t +JOIN (SELECT id, count() AS cnt FROM events GROUP BY id) s ON s.id = t.id; + +-- name: Star :many +SELECT * FROM users u JOIN events e ON e.id = u.id; diff --git a/internal/endtoend/testdata/analyze_subqueries/clickhouse/schema.sql b/internal/endtoend/testdata/analyze_subqueries/clickhouse/schema.sql new file mode 100644 index 0000000..9c04e10 --- /dev/null +++ b/internal/endtoend/testdata/analyze_subqueries/clickhouse/schema.sql @@ -0,0 +1,11 @@ +CREATE TABLE events ( + id UInt64, + name String, + tag Nullable(String), + amount Float64 +) ENGINE = MergeTree ORDER BY id; + +CREATE TABLE users ( + id UInt64, + email String +) ENGINE = MergeTree ORDER BY id; diff --git a/internal/endtoend/testdata/analyze_subqueries/clickhouse/stdout.json b/internal/endtoend/testdata/analyze_subqueries/clickhouse/stdout.json new file mode 100644 index 0000000..bc4f0ec --- /dev/null +++ b/internal/endtoend/testdata/analyze_subqueries/clickhouse/stdout.json @@ -0,0 +1,159 @@ +[ + { + "name": "Aliased", + "cmd": ":many", + "columns": [ + { + "name": "x", + "type": { + "name": "uint64" + }, + "table": "events" + }, + { + "name": "total", + "type": { + "name": "float64" + } + }, + { + "name": "email", + "type": { + "name": "string" + } + } + ], + "params": [] + }, + { + "name": "Union", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "uint64" + }, + "table": "events" + }, + { + "name": "name", + "type": { + "name": "string" + }, + "table": "events" + } + ], + "params": [] + }, + { + "name": "ScalarSubquery", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "uint64" + }, + "table": "events" + }, + { + "name": "user_count", + "type": { + "name": "uint64", + "nullable": true + } + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "email", + "type": { + "name": "string" + }, + "table": "users" + } + } + ] + }, + { + "name": "Cte", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "uint64" + }, + "table": "events" + }, + { + "name": "tag", + "type": { + "name": "string", + "nullable": true + }, + "table": "events" + }, + { + "name": "cnt", + "type": { + "name": "uint64" + } + } + ], + "params": [] + }, + { + "name": "Star", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "uint64" + }, + "table": "users" + }, + { + "name": "email", + "type": { + "name": "string" + }, + "table": "users" + }, + { + "name": "e.id", + "type": { + "name": "uint64" + }, + "table": "events" + }, + { + "name": "name", + "type": { + "name": "string" + }, + "table": "events" + }, + { + "name": "tag", + "type": { + "name": "string", + "nullable": true + }, + "table": "events" + }, + { + "name": "amount", + "type": { + "name": "float64" + }, + "table": "events" + } + ], + "params": [] + } +] diff --git a/internal/endtoend/testdata/analyze_system_catalog/mysql/exec.json b/internal/endtoend/testdata/analyze_system_catalog/mysql/exec.json new file mode 100644 index 0000000..a5b24d3 --- /dev/null +++ b/internal/endtoend/testdata/analyze_system_catalog/mysql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "mysql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_system_catalog/mysql/query.sql b/internal/endtoend/testdata/analyze_system_catalog/mysql/query.sql new file mode 100644 index 0000000..9dd9fd3 --- /dev/null +++ b/internal/endtoend/testdata/analyze_system_catalog/mysql/query.sql @@ -0,0 +1,7 @@ +-- name: ListColumns :many +SELECT table_name, column_name, data_type +FROM information_schema.columns +WHERE table_schema = ?; + +-- name: CountTables :one +SELECT count(*) AS total FROM information_schema.tables WHERE table_type = ?; diff --git a/internal/endtoend/testdata/analyze_system_catalog/mysql/schema.sql b/internal/endtoend/testdata/analyze_system_catalog/mysql/schema.sql new file mode 100644 index 0000000..8ef7dad --- /dev/null +++ b/internal/endtoend/testdata/analyze_system_catalog/mysql/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE authors ( + id BIGINT PRIMARY KEY, + name VARCHAR(255) NOT NULL +); diff --git a/internal/endtoend/testdata/analyze_system_catalog/mysql/stdout.json b/internal/endtoend/testdata/analyze_system_catalog/mysql/stdout.json new file mode 100644 index 0000000..134b5b1 --- /dev/null +++ b/internal/endtoend/testdata/analyze_system_catalog/mysql/stdout.json @@ -0,0 +1,93 @@ +[ + { + "name": "ListColumns", + "cmd": ":many", + "columns": [ + { + "name": "table_name", + "type": { + "name": "varchar", + "args": [ + { + "int": 64 + } + ] + }, + "table": "columns" + }, + { + "name": "column_name", + "type": { + "name": "varchar", + "nullable": true, + "args": [ + { + "int": 64 + } + ] + }, + "table": "columns" + }, + { + "name": "data_type", + "type": { + "name": "longtext", + "nullable": true + }, + "table": "columns" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "table_schema", + "type": { + "name": "varchar", + "args": [ + { + "int": 64 + } + ] + }, + "table": "columns" + } + } + ] + }, + { + "name": "CountTables", + "cmd": ":one", + "columns": [ + { + "name": "total", + "type": { + "name": "bigint" + } + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "table_type", + "type": { + "name": "enum", + "args": [ + { + "string": "BASE TABLE" + }, + { + "string": "VIEW" + }, + { + "string": "SYSTEM VIEW" + } + ] + }, + "table": "tables" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_system_catalog/postgresql/exec.json b/internal/endtoend/testdata/analyze_system_catalog/postgresql/exec.json new file mode 100644 index 0000000..b102755 --- /dev/null +++ b/internal/endtoend/testdata/analyze_system_catalog/postgresql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "postgresql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_system_catalog/postgresql/query.sql b/internal/endtoend/testdata/analyze_system_catalog/postgresql/query.sql new file mode 100644 index 0000000..19822f9 --- /dev/null +++ b/internal/endtoend/testdata/analyze_system_catalog/postgresql/query.sql @@ -0,0 +1,7 @@ +-- name: ListColumns :many +SELECT table_name, column_name, data_type +FROM information_schema.columns +WHERE table_schema = $1; + +-- name: CountRelations :one +SELECT count(*) AS total FROM pg_catalog.pg_class WHERE relkind = $1; diff --git a/internal/endtoend/testdata/analyze_system_catalog/postgresql/schema.sql b/internal/endtoend/testdata/analyze_system_catalog/postgresql/schema.sql new file mode 100644 index 0000000..f05417f --- /dev/null +++ b/internal/endtoend/testdata/analyze_system_catalog/postgresql/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL +); diff --git a/internal/endtoend/testdata/analyze_system_catalog/postgresql/stdout.json b/internal/endtoend/testdata/analyze_system_catalog/postgresql/stdout.json new file mode 100644 index 0000000..dc48b00 --- /dev/null +++ b/internal/endtoend/testdata/analyze_system_catalog/postgresql/stdout.json @@ -0,0 +1,69 @@ +[ + { + "name": "ListColumns", + "cmd": ":many", + "columns": [ + { + "name": "table_name", + "type": { + "name": "sql_identifier", + "nullable": true + }, + "table": "columns" + }, + { + "name": "column_name", + "type": { + "name": "sql_identifier", + "nullable": true + }, + "table": "columns" + }, + { + "name": "data_type", + "type": { + "name": "character_data", + "nullable": true + }, + "table": "columns" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "table_schema", + "type": { + "name": "sql_identifier", + "nullable": true + }, + "table": "columns" + } + } + ] + }, + { + "name": "CountRelations", + "cmd": ":one", + "columns": [ + { + "name": "total", + "type": { + "name": "bigint" + } + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "relkind", + "type": { + "name": "character" + }, + "table": "pg_class" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_types/bigquery/exec.json b/internal/endtoend/testdata/analyze_types/bigquery/exec.json new file mode 100644 index 0000000..a53dddd --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/bigquery/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "googlesql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_types/bigquery/query.sql b/internal/endtoend/testdata/analyze_types/bigquery/query.sql new file mode 100644 index 0000000..c798e56 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/bigquery/query.sql @@ -0,0 +1,16 @@ +-- name: AllTypes :many +SELECT * FROM things; + +-- name: Casts :one +SELECT + CAST(@a AS NUMERIC(5,2)) AS a, + CAST(@b AS ARRAY) AS b, + CAST(@c AS STRUCT) AS c, + CAST(@d AS STRING(5)) AS d, + SAFE_CAST(@e AS BIGNUMERIC) AS e, + [1, 2] AS f +FROM things; + +-- name: Params :one +SELECT id FROM things +WHERE s = @s AND ai = @ai AND n = @n AND st = @st AND smax = @smax; diff --git a/internal/endtoend/testdata/analyze_types/bigquery/schema.sql b/internal/endtoend/testdata/analyze_types/bigquery/schema.sql new file mode 100644 index 0000000..feb8468 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/bigquery/schema.sql @@ -0,0 +1,21 @@ +CREATE TABLE things ( + id INT64 NOT NULL, + s STRING(10), + smax STRING(MAX), + n NUMERIC(10,2), + bn BIGNUMERIC, + byt BYTES(MAX), + ai ARRAY, + as2 ARRAY, + st STRUCT
, + ast ARRAY>, + ts TIMESTAMP, + d DATE, + j JSON, + g GEOGRAPHY, + iv INTERVAL, + b BOOL, + f FLOAT64, + f32 FLOAT32, + tl TOKENLIST +) PRIMARY KEY (id); diff --git a/internal/endtoend/testdata/analyze_types/bigquery/stdout.json b/internal/endtoend/testdata/analyze_types/bigquery/stdout.json new file mode 100644 index 0000000..bae5a90 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/bigquery/stdout.json @@ -0,0 +1,482 @@ +[ + { + "name": "AllTypes", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "int64" + }, + "table": "things" + }, + { + "name": "s", + "type": { + "name": "string", + "nullable": true, + "args": [ + { + "int": 10 + } + ] + }, + "table": "things" + }, + { + "name": "smax", + "type": { + "name": "string", + "nullable": true, + "args": [ + { + "ident": "max" + } + ] + }, + "table": "things" + }, + { + "name": "n", + "type": { + "name": "numeric", + "nullable": true, + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "things" + }, + { + "name": "bn", + "type": { + "name": "bignumeric", + "nullable": true + }, + "table": "things" + }, + { + "name": "byt", + "type": { + "name": "bytes", + "nullable": true, + "args": [ + { + "ident": "max" + } + ] + }, + "table": "things" + }, + { + "name": "ai", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "int64" + } + } + ] + }, + "table": "things" + }, + { + "name": "as2", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "string", + "args": [ + { + "ident": "max" + } + ] + } + } + ] + }, + "table": "things" + }, + { + "name": "st", + "type": { + "name": "struct", + "nullable": true, + "args": [ + { + "label": "a", + "type": { + "name": "int64" + } + }, + { + "label": "b", + "type": { + "name": "string" + } + } + ] + }, + "table": "things" + }, + { + "name": "ast", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "struct", + "args": [ + { + "label": "x", + "type": { + "name": "int64" + } + } + ] + } + } + ] + }, + "table": "things" + }, + { + "name": "ts", + "type": { + "name": "timestamp", + "nullable": true + }, + "table": "things" + }, + { + "name": "d", + "type": { + "name": "date", + "nullable": true + }, + "table": "things" + }, + { + "name": "j", + "type": { + "name": "json", + "nullable": true + }, + "table": "things" + }, + { + "name": "g", + "type": { + "name": "geography", + "nullable": true + }, + "table": "things" + }, + { + "name": "iv", + "type": { + "name": "interval", + "nullable": true + }, + "table": "things" + }, + { + "name": "b", + "type": { + "name": "bool", + "nullable": true + }, + "table": "things" + }, + { + "name": "f", + "type": { + "name": "float64", + "nullable": true + }, + "table": "things" + }, + { + "name": "f32", + "type": { + "name": "float32", + "nullable": true + }, + "table": "things" + }, + { + "name": "tl", + "type": { + "name": "tokenlist", + "nullable": true + }, + "table": "things" + } + ], + "params": [] + }, + { + "name": "Casts", + "cmd": ":one", + "columns": [ + { + "name": "a", + "type": { + "name": "numeric", + "args": [ + { + "int": 5 + }, + { + "int": 2 + } + ] + } + }, + { + "name": "b", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "int64" + } + } + ] + } + }, + { + "name": "c", + "type": { + "name": "struct", + "args": [ + { + "label": "x", + "type": { + "name": "int64" + } + } + ] + } + }, + { + "name": "d", + "type": { + "name": "string", + "args": [ + { + "int": 5 + } + ] + } + }, + { + "name": "e", + "type": { + "name": "bignumeric" + } + }, + { + "name": "f" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "", + "type": { + "name": "numeric", + "args": [ + { + "int": 5 + }, + { + "int": 2 + } + ] + } + } + }, + { + "number": 2, + "column": { + "name": "", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "int64" + } + } + ] + } + } + }, + { + "number": 3, + "column": { + "name": "", + "type": { + "name": "struct", + "args": [ + { + "label": "x", + "type": { + "name": "int64" + } + } + ] + } + } + }, + { + "number": 4, + "column": { + "name": "", + "type": { + "name": "string", + "args": [ + { + "int": 5 + } + ] + } + } + }, + { + "number": 5, + "column": { + "name": "", + "type": { + "name": "bignumeric" + } + } + } + ] + }, + { + "name": "Params", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "int64" + }, + "table": "things" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "s", + "type": { + "name": "string", + "nullable": true, + "args": [ + { + "int": 10 + } + ] + }, + "table": "things" + } + }, + { + "number": 2, + "column": { + "name": "ai", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "int64" + } + } + ] + }, + "table": "things" + } + }, + { + "number": 3, + "column": { + "name": "n", + "type": { + "name": "numeric", + "nullable": true, + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "things" + } + }, + { + "number": 4, + "column": { + "name": "st", + "type": { + "name": "struct", + "nullable": true, + "args": [ + { + "label": "a", + "type": { + "name": "int64" + } + }, + { + "label": "b", + "type": { + "name": "string" + } + } + ] + }, + "table": "things" + } + }, + { + "number": 5, + "column": { + "name": "smax", + "type": { + "name": "string", + "nullable": true, + "args": [ + { + "ident": "max" + } + ] + }, + "table": "things" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_types/clickhouse/exec.json b/internal/endtoend/testdata/analyze_types/clickhouse/exec.json new file mode 100644 index 0000000..c92bfa3 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/clickhouse/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "clickhouse", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_types/clickhouse/fixture.sql b/internal/endtoend/testdata/analyze_types/clickhouse/fixture.sql new file mode 100644 index 0000000..d4353b2 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/clickhouse/fixture.sql @@ -0,0 +1 @@ +INSERT INTO things VALUES (1, 'a', NULL, 1.5, ['x'], [NULL, 'y'], [[1, 2]], 'k', '2024-01-01 00:00:00', '2024-01-01 00:00:00.123', 1.25, 'active', {'k': 1}, (1.0, 2.0), (51.5, -0.1), {'a': NULL}, '127.0.0.1', '00000000-0000-0000-0000-000000000000', 'abcd', true, 1.5, 'x', 'v', [1], ['s'], 3, 7); diff --git a/internal/endtoend/testdata/analyze_types/clickhouse/query.sql b/internal/endtoend/testdata/analyze_types/clickhouse/query.sql new file mode 100644 index 0000000..8a4ff3e --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/clickhouse/query.sql @@ -0,0 +1,19 @@ +-- name: AllTypes :many +SELECT * FROM things; + +-- name: StarColumns :many +SELECT id, name, tag, amount, tags, labels, matrix, kind, created, updated, price, status, attrs, pos, geo, scores, ip, uid, fixed, flag, small, plain, either, n.a, n.b, total, whole FROM things; + +-- name: Casts :one +SELECT + CAST(id AS String) AS a, + toDecimal64(id, 4) AS b, + CAST(name AS Nullable(String)) AS c, + toDateTime64(created, 3) AS d, + CAST(tags AS Array(String)) AS e, + CAST(tag AS Nullable(String)) AS f +FROM things; + +-- name: Placeholders :many +SELECT id FROM things +WHERE id = {p1:UInt64} AND name = {p2:String} AND amount > {p3:Float64} AND tag = {p4:Nullable(String)} AND price = {p5:Decimal(10, 2)}; diff --git a/internal/endtoend/testdata/analyze_types/clickhouse/schema.sql b/internal/endtoend/testdata/analyze_types/clickhouse/schema.sql new file mode 100644 index 0000000..1dddddd --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/clickhouse/schema.sql @@ -0,0 +1,28 @@ +CREATE TABLE things ( + id UInt64, + name String, + tag Nullable(String), + amount Float64, + tags Array(String), + labels Array(Nullable(String)), + matrix Array(Array(UInt8)), + kind LowCardinality(Nullable(String)), + created DateTime, + updated DateTime64(3, 'UTC'), + price Decimal(10, 2), + status Enum8('active' = 1, 'deleted' = 2), + attrs Map(String, UInt32), + pos Tuple(Float64, Float64), + geo Tuple(lat Float64, lon Float64), + scores Map(String, Nullable(UInt8)), + ip IPv4, + uid UUID, + fixed FixedString(4), + flag Bool, + small Decimal32(4), + plain Enum('x', 'y'), + either Variant(String, Int64), + n Nested(a UInt8, b String), + total SimpleAggregateFunction(sum, UInt64), + whole INT +) ENGINE = MergeTree ORDER BY id; diff --git a/internal/endtoend/testdata/analyze_types/clickhouse/stdout.json b/internal/endtoend/testdata/analyze_types/clickhouse/stdout.json new file mode 100644 index 0000000..9c597de --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/clickhouse/stdout.json @@ -0,0 +1,881 @@ +[ + { + "name": "AllTypes", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "uint64" + }, + "table": "things" + }, + { + "name": "name", + "type": { + "name": "string" + }, + "table": "things" + }, + { + "name": "tag", + "type": { + "name": "string", + "nullable": true + }, + "table": "things" + }, + { + "name": "amount", + "type": { + "name": "float64" + }, + "table": "things" + }, + { + "name": "tags", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "string" + } + } + ] + }, + "table": "things" + }, + { + "name": "labels", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "string", + "nullable": true + } + } + ] + }, + "table": "things" + }, + { + "name": "matrix", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "uint8" + } + } + ] + } + } + ] + }, + "table": "things" + }, + { + "name": "kind", + "type": { + "name": "lowcardinality", + "nullable": true, + "args": [ + { + "type": { + "name": "string" + } + } + ] + }, + "table": "things" + }, + { + "name": "created", + "type": { + "name": "datetime" + }, + "table": "things" + }, + { + "name": "updated", + "type": { + "name": "datetime64", + "args": [ + { + "int": 3 + }, + { + "string": "UTC" + } + ] + }, + "table": "things" + }, + { + "name": "price", + "type": { + "name": "decimal", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "things" + }, + { + "name": "status", + "type": { + "name": "enum8", + "args": [ + { + "label": "active", + "int": 1 + }, + { + "label": "deleted", + "int": 2 + } + ] + }, + "table": "things" + }, + { + "name": "attrs", + "type": { + "name": "map", + "args": [ + { + "type": { + "name": "string" + } + }, + { + "type": { + "name": "uint32" + } + } + ] + }, + "table": "things" + }, + { + "name": "pos", + "type": { + "name": "tuple", + "args": [ + { + "type": { + "name": "float64" + } + }, + { + "type": { + "name": "float64" + } + } + ] + }, + "table": "things" + }, + { + "name": "geo", + "type": { + "name": "tuple", + "args": [ + { + "label": "lat", + "type": { + "name": "float64" + } + }, + { + "label": "lon", + "type": { + "name": "float64" + } + } + ] + }, + "table": "things" + }, + { + "name": "scores", + "type": { + "name": "map", + "args": [ + { + "type": { + "name": "string" + } + }, + { + "type": { + "name": "uint8", + "nullable": true + } + } + ] + }, + "table": "things" + }, + { + "name": "ip", + "type": { + "name": "ipv4" + }, + "table": "things" + }, + { + "name": "uid", + "type": { + "name": "uuid" + }, + "table": "things" + }, + { + "name": "fixed", + "type": { + "name": "fixedstring", + "args": [ + { + "int": 4 + } + ] + }, + "table": "things" + }, + { + "name": "flag", + "type": { + "name": "bool" + }, + "table": "things" + }, + { + "name": "small", + "type": { + "name": "decimal", + "args": [ + { + "int": 9 + }, + { + "int": 4 + } + ] + }, + "table": "things" + }, + { + "name": "plain", + "type": { + "name": "enum8", + "args": [ + { + "label": "x", + "int": 1 + }, + { + "label": "y", + "int": 2 + } + ] + }, + "table": "things" + }, + { + "name": "either", + "type": { + "name": "variant", + "args": [ + { + "type": { + "name": "int64" + } + }, + { + "type": { + "name": "string" + } + } + ] + }, + "table": "things" + }, + { + "name": "n.a", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "uint8" + } + } + ] + }, + "table": "things" + }, + { + "name": "n.b", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "string" + } + } + ] + }, + "table": "things" + }, + { + "name": "total", + "type": { + "name": "simpleaggregatefunction", + "args": [ + { + "ident": "sum" + }, + { + "type": { + "name": "uint64" + } + } + ] + }, + "table": "things" + }, + { + "name": "whole", + "type": { + "name": "int32" + }, + "table": "things" + } + ], + "params": [] + }, + { + "name": "StarColumns", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "uint64" + }, + "table": "things" + }, + { + "name": "name", + "type": { + "name": "string" + }, + "table": "things" + }, + { + "name": "tag", + "type": { + "name": "string", + "nullable": true + }, + "table": "things" + }, + { + "name": "amount", + "type": { + "name": "float64" + }, + "table": "things" + }, + { + "name": "tags", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "string" + } + } + ] + }, + "table": "things" + }, + { + "name": "labels", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "string", + "nullable": true + } + } + ] + }, + "table": "things" + }, + { + "name": "matrix", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "uint8" + } + } + ] + } + } + ] + }, + "table": "things" + }, + { + "name": "kind", + "type": { + "name": "lowcardinality", + "nullable": true, + "args": [ + { + "type": { + "name": "string" + } + } + ] + }, + "table": "things" + }, + { + "name": "created", + "type": { + "name": "datetime" + }, + "table": "things" + }, + { + "name": "updated", + "type": { + "name": "datetime64", + "args": [ + { + "int": 3 + }, + { + "string": "UTC" + } + ] + }, + "table": "things" + }, + { + "name": "price", + "type": { + "name": "decimal", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "things" + }, + { + "name": "status", + "type": { + "name": "enum8", + "args": [ + { + "label": "active", + "int": 1 + }, + { + "label": "deleted", + "int": 2 + } + ] + }, + "table": "things" + }, + { + "name": "attrs", + "type": { + "name": "map", + "args": [ + { + "type": { + "name": "string" + } + }, + { + "type": { + "name": "uint32" + } + } + ] + }, + "table": "things" + }, + { + "name": "pos", + "type": { + "name": "tuple", + "args": [ + { + "type": { + "name": "float64" + } + }, + { + "type": { + "name": "float64" + } + } + ] + }, + "table": "things" + }, + { + "name": "geo", + "type": { + "name": "tuple", + "args": [ + { + "label": "lat", + "type": { + "name": "float64" + } + }, + { + "label": "lon", + "type": { + "name": "float64" + } + } + ] + }, + "table": "things" + }, + { + "name": "scores", + "type": { + "name": "map", + "args": [ + { + "type": { + "name": "string" + } + }, + { + "type": { + "name": "uint8", + "nullable": true + } + } + ] + }, + "table": "things" + }, + { + "name": "ip", + "type": { + "name": "ipv4" + }, + "table": "things" + }, + { + "name": "uid", + "type": { + "name": "uuid" + }, + "table": "things" + }, + { + "name": "fixed", + "type": { + "name": "fixedstring", + "args": [ + { + "int": 4 + } + ] + }, + "table": "things" + }, + { + "name": "flag", + "type": { + "name": "bool" + }, + "table": "things" + }, + { + "name": "small", + "type": { + "name": "decimal", + "args": [ + { + "int": 9 + }, + { + "int": 4 + } + ] + }, + "table": "things" + }, + { + "name": "plain", + "type": { + "name": "enum8", + "args": [ + { + "label": "x", + "int": 1 + }, + { + "label": "y", + "int": 2 + } + ] + }, + "table": "things" + }, + { + "name": "either", + "type": { + "name": "variant", + "args": [ + { + "type": { + "name": "int64" + } + }, + { + "type": { + "name": "string" + } + } + ] + }, + "table": "things" + }, + { + "name": "n.a", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "uint8" + } + } + ] + }, + "table": "things" + }, + { + "name": "n.b", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "string" + } + } + ] + }, + "table": "things" + }, + { + "name": "total", + "type": { + "name": "simpleaggregatefunction", + "args": [ + { + "ident": "sum" + }, + { + "type": { + "name": "uint64" + } + } + ] + }, + "table": "things" + }, + { + "name": "whole", + "type": { + "name": "int32" + }, + "table": "things" + } + ], + "params": [] + }, + { + "name": "Casts", + "cmd": ":one", + "columns": [ + { + "name": "a", + "type": { + "name": "string" + } + }, + { + "name": "b", + "type": { + "name": "decimal", + "args": [ + { + "int": 18 + }, + { + "int": 4 + } + ] + } + }, + { + "name": "c", + "type": { + "name": "string", + "nullable": true + } + }, + { + "name": "d", + "type": { + "name": "datetime64", + "args": [ + { + "int": 3 + } + ] + } + }, + { + "name": "e", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "string" + } + } + ] + } + }, + { + "name": "f", + "type": { + "name": "string", + "nullable": true + } + } + ], + "params": [] + }, + { + "name": "Placeholders", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "uint64" + }, + "table": "things" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "p1", + "type": { + "name": "uint64" + }, + "table": "things" + } + }, + { + "number": 2, + "column": { + "name": "p2", + "type": { + "name": "string" + }, + "table": "things" + } + }, + { + "number": 3, + "column": { + "name": "p3", + "type": { + "name": "float64" + }, + "table": "things" + } + }, + { + "number": 4, + "column": { + "name": "p4", + "type": { + "name": "string", + "nullable": true + }, + "table": "things" + } + }, + { + "number": 5, + "column": { + "name": "p5", + "type": { + "name": "decimal", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "things" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_types/duckdb/exec.json b/internal/endtoend/testdata/analyze_types/duckdb/exec.json new file mode 100644 index 0000000..56cb4b3 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/duckdb/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "duckdb", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_types/duckdb/query.sql b/internal/endtoend/testdata/analyze_types/duckdb/query.sql new file mode 100644 index 0000000..3e232d2 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/duckdb/query.sql @@ -0,0 +1,18 @@ +-- name: AllTypes :many +SELECT * FROM things; + +-- name: Casts :one +SELECT + $1::DECIMAL(5,2) AS a, + $2::INTEGER[] AS b, + $3::STRUCT(a INTEGER) AS c, + $4::mood AS d, + CAST($5 AS VARCHAR(5)) AS e, + $6::MAP(VARCHAR, INTEGER) AS f, + $7::INTEGER[3] AS g, + $8::main.mood AS h +FROM things; + +-- name: Params :one +SELECT id FROM things +WHERE ints = $1 AND point = $2 AND price = $3 AND m = $4 AND either = $5 AND grid = $6; diff --git a/internal/endtoend/testdata/analyze_types/duckdb/schema.sql b/internal/endtoend/testdata/analyze_types/duckdb/schema.sql new file mode 100644 index 0000000..0a8a1b4 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/duckdb/schema.sql @@ -0,0 +1,31 @@ +CREATE TYPE mood AS ENUM ('sad', 'ok'); + +CREATE TABLE things ( + id INTEGER PRIMARY KEY, + ints INTEGER[], + fixed INTEGER[3], + point STRUCT(a INTEGER, b VARCHAR), + attrs MAP(VARCHAR, INTEGER), + either UNION(num INTEGER, str VARCHAR), + price DECIMAL(18,3), + title VARCHAR(10), + kind ENUM('a','b'), + m mood, + mm main.mood, + big HUGEINT, + ubig UHUGEINT, + data BLOB, + bits BIT, + uid UUID, + tstz TIMESTAMP WITH TIME ZONE, + tsns TIMESTAMP_NS, + iv INTERVAL, + doc JSON, + grid INTEGER[][], + vi VARINT, + f4 FLOAT4, + points STRUCT(a INTEGER)[], + lists MAP(VARCHAR, INTEGER[]), + body TEXT, + n NUMERIC +); diff --git a/internal/endtoend/testdata/analyze_types/duckdb/stdout.json b/internal/endtoend/testdata/analyze_types/duckdb/stdout.json new file mode 100644 index 0000000..fff8ac0 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/duckdb/stdout.json @@ -0,0 +1,709 @@ +[ + { + "name": "AllTypes", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "integer" + }, + "table": "things" + }, + { + "name": "ints", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "integer" + } + } + ] + }, + "table": "things" + }, + { + "name": "fixed", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "integer" + } + }, + { + "int": 3 + } + ] + }, + "table": "things" + }, + { + "name": "point", + "type": { + "name": "struct", + "nullable": true, + "args": [ + { + "label": "a", + "type": { + "name": "integer" + } + }, + { + "label": "b", + "type": { + "name": "varchar" + } + } + ] + }, + "table": "things" + }, + { + "name": "attrs", + "type": { + "name": "map", + "nullable": true, + "args": [ + { + "type": { + "name": "varchar" + } + }, + { + "type": { + "name": "integer" + } + } + ] + }, + "table": "things" + }, + { + "name": "either", + "type": { + "name": "union", + "nullable": true, + "args": [ + { + "label": "num", + "type": { + "name": "integer" + } + }, + { + "label": "str", + "type": { + "name": "varchar" + } + } + ] + }, + "table": "things" + }, + { + "name": "price", + "type": { + "name": "decimal", + "nullable": true, + "args": [ + { + "int": 18 + }, + { + "int": 3 + } + ] + }, + "table": "things" + }, + { + "name": "title", + "type": { + "name": "varchar", + "nullable": true + }, + "table": "things" + }, + { + "name": "kind", + "type": { + "name": "enum", + "nullable": true, + "args": [ + { + "string": "a" + }, + { + "string": "b" + } + ] + }, + "table": "things" + }, + { + "name": "m", + "type": { + "name": "mood", + "nullable": true + }, + "table": "things" + }, + { + "name": "mm", + "type": { + "name": "mood", + "nullable": true + }, + "table": "things" + }, + { + "name": "big", + "type": { + "name": "hugeint", + "nullable": true + }, + "table": "things" + }, + { + "name": "ubig", + "type": { + "name": "uhugeint", + "nullable": true + }, + "table": "things" + }, + { + "name": "data", + "type": { + "name": "blob", + "nullable": true + }, + "table": "things" + }, + { + "name": "bits", + "type": { + "name": "bit", + "nullable": true + }, + "table": "things" + }, + { + "name": "uid", + "type": { + "name": "uuid", + "nullable": true + }, + "table": "things" + }, + { + "name": "tstz", + "type": { + "name": "timestamp with time zone", + "nullable": true + }, + "table": "things" + }, + { + "name": "tsns", + "type": { + "name": "timestamp_ns", + "nullable": true + }, + "table": "things" + }, + { + "name": "iv", + "type": { + "name": "interval", + "nullable": true + }, + "table": "things" + }, + { + "name": "doc", + "type": { + "name": "varchar", + "nullable": true + }, + "table": "things" + }, + { + "name": "grid", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + } + ] + } + } + ] + }, + "table": "things" + }, + { + "name": "vi", + "type": { + "name": "bignum", + "nullable": true + }, + "table": "things" + }, + { + "name": "f4", + "type": { + "name": "float", + "nullable": true + }, + "table": "things" + }, + { + "name": "points", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "struct", + "args": [ + { + "label": "a", + "type": { + "name": "integer" + } + } + ] + } + } + ] + }, + "table": "things" + }, + { + "name": "lists", + "type": { + "name": "map", + "nullable": true, + "args": [ + { + "type": { + "name": "varchar" + } + }, + { + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + } + ] + } + } + ] + }, + "table": "things" + }, + { + "name": "body", + "type": { + "name": "varchar", + "nullable": true + }, + "table": "things" + }, + { + "name": "n", + "type": { + "name": "decimal", + "nullable": true, + "args": [ + { + "int": 18 + }, + { + "int": 3 + } + ] + }, + "table": "things" + } + ], + "params": [] + }, + { + "name": "Casts", + "cmd": ":one", + "columns": [ + { + "name": "a", + "type": { + "name": "decimal", + "args": [ + { + "int": 5 + }, + { + "int": 2 + } + ] + } + }, + { + "name": "b", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + } + ] + } + }, + { + "name": "c", + "type": { + "name": "struct", + "args": [ + { + "label": "a", + "type": { + "name": "integer" + } + } + ] + } + }, + { + "name": "d", + "type": { + "name": "mood" + } + }, + { + "name": "e", + "type": { + "name": "varchar" + } + }, + { + "name": "f", + "type": { + "name": "map", + "args": [ + { + "type": { + "name": "varchar" + } + }, + { + "type": { + "name": "integer" + } + } + ] + } + }, + { + "name": "g", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + }, + { + "int": 3 + } + ] + } + }, + { + "name": "h", + "type": { + "name": "mood" + } + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "", + "type": { + "name": "decimal", + "args": [ + { + "int": 5 + }, + { + "int": 2 + } + ] + } + } + }, + { + "number": 2, + "column": { + "name": "", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + } + ] + } + } + }, + { + "number": 3, + "column": { + "name": "", + "type": { + "name": "struct", + "args": [ + { + "label": "a", + "type": { + "name": "integer" + } + } + ] + } + } + }, + { + "number": 4, + "column": { + "name": "", + "type": { + "name": "mood" + } + } + }, + { + "number": 5, + "column": { + "name": "", + "type": { + "name": "varchar" + } + } + }, + { + "number": 6, + "column": { + "name": "", + "type": { + "name": "map", + "args": [ + { + "type": { + "name": "varchar" + } + }, + { + "type": { + "name": "integer" + } + } + ] + } + } + }, + { + "number": 7, + "column": { + "name": "", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + }, + { + "int": 3 + } + ] + } + } + }, + { + "number": 8, + "column": { + "name": "", + "type": { + "name": "mood" + } + } + } + ] + }, + { + "name": "Params", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "integer" + }, + "table": "things" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "ints", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "integer" + } + } + ] + }, + "table": "things" + } + }, + { + "number": 2, + "column": { + "name": "point", + "type": { + "name": "struct", + "nullable": true, + "args": [ + { + "label": "a", + "type": { + "name": "integer" + } + }, + { + "label": "b", + "type": { + "name": "varchar" + } + } + ] + }, + "table": "things" + } + }, + { + "number": 3, + "column": { + "name": "price", + "type": { + "name": "decimal", + "nullable": true, + "args": [ + { + "int": 18 + }, + { + "int": 3 + } + ] + }, + "table": "things" + } + }, + { + "number": 4, + "column": { + "name": "m", + "type": { + "name": "mood", + "nullable": true + }, + "table": "things" + } + }, + { + "number": 5, + "column": { + "name": "either", + "type": { + "name": "union", + "nullable": true, + "args": [ + { + "label": "num", + "type": { + "name": "integer" + } + }, + { + "label": "str", + "type": { + "name": "varchar" + } + } + ] + }, + "table": "things" + } + }, + { + "number": 6, + "column": { + "name": "grid", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + } + ] + } + } + ] + }, + "table": "things" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_types/googlesql/exec.json b/internal/endtoend/testdata/analyze_types/googlesql/exec.json new file mode 100644 index 0000000..a53dddd --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/googlesql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "googlesql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_types/googlesql/query.sql b/internal/endtoend/testdata/analyze_types/googlesql/query.sql new file mode 100644 index 0000000..06cca17 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/googlesql/query.sql @@ -0,0 +1,14 @@ +-- name: AllTypes :many +SELECT * FROM things; + +-- name: Casts :one +SELECT + CAST(@a AS NUMERIC) AS a, + CAST(@b AS ARRAY) AS b, + CAST(@d AS STRING) AS d, + SAFE_CAST(@e AS FLOAT64) AS e +FROM things; + +-- name: Params :one +SELECT id FROM things +WHERE s = @s AND n = @n AND smax = @smax AND f32 = @f32; diff --git a/internal/endtoend/testdata/analyze_types/googlesql/schema.sql b/internal/endtoend/testdata/analyze_types/googlesql/schema.sql new file mode 100644 index 0000000..176f055 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/googlesql/schema.sql @@ -0,0 +1,16 @@ +CREATE TABLE things ( + id INT64 NOT NULL, + s STRING(10), + smax STRING(MAX), + n NUMERIC, + byt BYTES(MAX), + ai ARRAY, + as2 ARRAY, + ts TIMESTAMP, + d DATE, + j JSON, + b BOOL, + f FLOAT64, + f32 FLOAT32, + u UUID +) PRIMARY KEY (id); diff --git a/internal/endtoend/testdata/analyze_types/googlesql/stdout.json b/internal/endtoend/testdata/analyze_types/googlesql/stdout.json new file mode 100644 index 0000000..2871cba --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/googlesql/stdout.json @@ -0,0 +1,305 @@ +[ + { + "name": "AllTypes", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "int64" + }, + "table": "things" + }, + { + "name": "s", + "type": { + "name": "string", + "nullable": true, + "args": [ + { + "int": 10 + } + ] + }, + "table": "things" + }, + { + "name": "smax", + "type": { + "name": "string", + "nullable": true, + "args": [ + { + "ident": "max" + } + ] + }, + "table": "things" + }, + { + "name": "n", + "type": { + "name": "numeric", + "nullable": true + }, + "table": "things" + }, + { + "name": "byt", + "type": { + "name": "bytes", + "nullable": true, + "args": [ + { + "ident": "max" + } + ] + }, + "table": "things" + }, + { + "name": "ai", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "int64" + } + } + ] + }, + "table": "things" + }, + { + "name": "as2", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "string", + "args": [ + { + "ident": "max" + } + ] + } + } + ] + }, + "table": "things" + }, + { + "name": "ts", + "type": { + "name": "timestamp", + "nullable": true + }, + "table": "things" + }, + { + "name": "d", + "type": { + "name": "date", + "nullable": true + }, + "table": "things" + }, + { + "name": "j", + "type": { + "name": "json", + "nullable": true + }, + "table": "things" + }, + { + "name": "b", + "type": { + "name": "bool", + "nullable": true + }, + "table": "things" + }, + { + "name": "f", + "type": { + "name": "float64", + "nullable": true + }, + "table": "things" + }, + { + "name": "f32", + "type": { + "name": "float32", + "nullable": true + }, + "table": "things" + }, + { + "name": "u", + "type": { + "name": "uuid", + "nullable": true + }, + "table": "things" + } + ], + "params": [] + }, + { + "name": "Casts", + "cmd": ":one", + "columns": [ + { + "name": "a", + "type": { + "name": "numeric" + } + }, + { + "name": "b", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "int64" + } + } + ] + } + }, + { + "name": "d", + "type": { + "name": "string" + } + }, + { + "name": "e", + "type": { + "name": "float64" + } + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "", + "type": { + "name": "numeric" + } + } + }, + { + "number": 2, + "column": { + "name": "", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "int64" + } + } + ] + } + } + }, + { + "number": 3, + "column": { + "name": "", + "type": { + "name": "string" + } + } + }, + { + "number": 4, + "column": { + "name": "", + "type": { + "name": "float64" + } + } + } + ] + }, + { + "name": "Params", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "int64" + }, + "table": "things" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "s", + "type": { + "name": "string", + "nullable": true, + "args": [ + { + "int": 10 + } + ] + }, + "table": "things" + } + }, + { + "number": 2, + "column": { + "name": "n", + "type": { + "name": "numeric", + "nullable": true + }, + "table": "things" + } + }, + { + "number": 3, + "column": { + "name": "smax", + "type": { + "name": "string", + "nullable": true, + "args": [ + { + "ident": "max" + } + ] + }, + "table": "things" + } + }, + { + "number": 4, + "column": { + "name": "f32", + "type": { + "name": "float32", + "nullable": true + }, + "table": "things" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_types/mssql/exec.json b/internal/endtoend/testdata/analyze_types/mssql/exec.json new file mode 100644 index 0000000..253b05a --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/mssql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "mssql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_types/mssql/query.sql b/internal/endtoend/testdata/analyze_types/mssql/query.sql new file mode 100644 index 0000000..e2075d7 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/mssql/query.sql @@ -0,0 +1,24 @@ +-- name: AllTypes :many +SELECT * FROM things; + +-- name: Casts :one +SELECT + CAST(amount AS DECIMAL(5,2)) AS a, + CAST(title AS NVARCHAR(MAX)) AS b, + CAST(body AS VARCHAR(10)) AS c, + CONVERT(DATETIME2(3), updated) AS d, + CAST(amount AS MONEY) AS e, + CAST(f53 AS FLOAT(24)) AS f, + CAST(code AS CHAR(3)) AS g +FROM things +WHERE CAST(@a AS DECIMAL(5,2)) > 0 + AND CAST(@b AS NVARCHAR(MAX)) <> N'' + AND CAST(@c AS VARCHAR(10)) <> '' + AND CONVERT(DATETIME2(3), @d) > '2000-01-01' + AND CAST(@e AS MONEY) > 0 + AND TRY_CAST(@f AS FLOAT(24)) > 0 + AND CAST(@g AS CHAR(3)) <> ''; + +-- name: Params :one +SELECT id FROM things +WHERE price = @price AND body = @body AND phone = @phone AND offset_at = @offset_at; diff --git a/internal/endtoend/testdata/analyze_types/mssql/schema.sql b/internal/endtoend/testdata/analyze_types/mssql/schema.sql new file mode 100644 index 0000000..1e65802 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/mssql/schema.sql @@ -0,0 +1,37 @@ +CREATE TYPE dbo.PhoneNumber FROM varchar(20) NOT NULL; +CREATE TYPE Code FROM char(3); + +CREATE TABLE things ( + id BIGINT IDENTITY(1,1) PRIMARY KEY, + price DECIMAL(10,2) NOT NULL, + amount NUMERIC(18,4), + plain DECIMAL, + body NVARCHAR(MAX), + title VARCHAR(50), + code CHAR(10), + ncode NCHAR(5), + blob VARBINARY(MAX), + key16 BINARY(16), + created DATETIME2(3), + updated DATETIME2, + offset_at DATETIMEOFFSET(7), + tm TIME(4), + f FLOAT(24), + f53 FLOAT, + r REAL, + m MONEY, + b BIT, + u UNIQUEIDENTIFIER, + x XML, + j JSON, + sv SQL_VARIANT, + rv ROWVERSION, + g GEOGRAPHY, + h HIERARCHYID, + vec VECTOR(3), + sn sysname, + phone dbo.PhoneNumber, + code2 dbo.Code, + code3 Code, + bare VARCHAR +); diff --git a/internal/endtoend/testdata/analyze_types/mssql/stdout.json b/internal/endtoend/testdata/analyze_types/mssql/stdout.json new file mode 100644 index 0000000..e52bc1c --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/mssql/stdout.json @@ -0,0 +1,600 @@ +[ + { + "name": "AllTypes", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "things" + }, + { + "name": "price", + "type": { + "name": "decimal", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "things" + }, + { + "name": "amount", + "type": { + "name": "decimal", + "nullable": true, + "args": [ + { + "int": 18 + }, + { + "int": 4 + } + ] + }, + "table": "things" + }, + { + "name": "plain", + "type": { + "name": "decimal", + "nullable": true, + "args": [ + { + "int": 18 + }, + { + "int": 0 + } + ] + }, + "table": "things" + }, + { + "name": "body", + "type": { + "name": "nvarchar", + "nullable": true, + "args": [ + { + "ident": "max" + } + ] + }, + "table": "things" + }, + { + "name": "title", + "type": { + "name": "varchar", + "nullable": true, + "args": [ + { + "int": 50 + } + ] + }, + "table": "things" + }, + { + "name": "code", + "type": { + "name": "char", + "nullable": true, + "args": [ + { + "int": 10 + } + ] + }, + "table": "things" + }, + { + "name": "ncode", + "type": { + "name": "nchar", + "nullable": true, + "args": [ + { + "int": 5 + } + ] + }, + "table": "things" + }, + { + "name": "blob", + "type": { + "name": "varbinary", + "nullable": true, + "args": [ + { + "ident": "max" + } + ] + }, + "table": "things" + }, + { + "name": "key16", + "type": { + "name": "binary", + "nullable": true, + "args": [ + { + "int": 16 + } + ] + }, + "table": "things" + }, + { + "name": "created", + "type": { + "name": "datetime2", + "nullable": true, + "args": [ + { + "int": 3 + } + ] + }, + "table": "things" + }, + { + "name": "updated", + "type": { + "name": "datetime2", + "nullable": true, + "args": [ + { + "int": 7 + } + ] + }, + "table": "things" + }, + { + "name": "offset_at", + "type": { + "name": "datetimeoffset", + "nullable": true, + "args": [ + { + "int": 7 + } + ] + }, + "table": "things" + }, + { + "name": "tm", + "type": { + "name": "time", + "nullable": true, + "args": [ + { + "int": 4 + } + ] + }, + "table": "things" + }, + { + "name": "f", + "type": { + "name": "real", + "nullable": true + }, + "table": "things" + }, + { + "name": "f53", + "type": { + "name": "float", + "nullable": true + }, + "table": "things" + }, + { + "name": "r", + "type": { + "name": "real", + "nullable": true + }, + "table": "things" + }, + { + "name": "m", + "type": { + "name": "money", + "nullable": true + }, + "table": "things" + }, + { + "name": "b", + "type": { + "name": "bit", + "nullable": true + }, + "table": "things" + }, + { + "name": "u", + "type": { + "name": "uniqueidentifier", + "nullable": true + }, + "table": "things" + }, + { + "name": "x", + "type": { + "name": "xml", + "nullable": true + }, + "table": "things" + }, + { + "name": "j", + "type": { + "name": "json", + "nullable": true + }, + "table": "things" + }, + { + "name": "sv", + "type": { + "name": "sql_variant", + "nullable": true + }, + "table": "things" + }, + { + "name": "rv", + "type": { + "name": "rowversion" + }, + "table": "things" + }, + { + "name": "g", + "type": { + "name": "geography", + "nullable": true + }, + "table": "things" + }, + { + "name": "h", + "type": { + "name": "hierarchyid", + "nullable": true + }, + "table": "things" + }, + { + "name": "vec", + "type": { + "name": "vector", + "nullable": true, + "args": [ + { + "int": 3 + } + ] + }, + "table": "things" + }, + { + "name": "sn", + "type": { + "name": "nvarchar", + "args": [ + { + "int": 128 + } + ] + }, + "table": "things" + }, + { + "name": "phone", + "type": { + "name": "phonenumber" + }, + "table": "things" + }, + { + "name": "code2", + "type": { + "name": "code", + "nullable": true + }, + "table": "things" + }, + { + "name": "code3", + "type": { + "name": "code", + "nullable": true + }, + "table": "things" + }, + { + "name": "bare", + "type": { + "name": "varchar", + "nullable": true, + "args": [ + { + "int": 1 + } + ] + }, + "table": "things" + } + ], + "params": [] + }, + { + "name": "Casts", + "cmd": ":one", + "columns": [ + { + "name": "a", + "type": { + "name": "decimal", + "nullable": true, + "args": [ + { + "int": 5 + }, + { + "int": 2 + } + ] + } + }, + { + "name": "b", + "type": { + "name": "nvarchar", + "nullable": true, + "args": [ + { + "ident": "max" + } + ] + } + }, + { + "name": "c", + "type": { + "name": "varchar", + "nullable": true, + "args": [ + { + "int": 10 + } + ] + } + }, + { + "name": "d", + "type": { + "name": "datetime2", + "nullable": true, + "args": [ + { + "int": 3 + } + ] + } + }, + { + "name": "e", + "type": { + "name": "money", + "nullable": true + } + }, + { + "name": "f", + "type": { + "name": "real", + "nullable": true + } + }, + { + "name": "g", + "type": { + "name": "char", + "nullable": true, + "args": [ + { + "int": 3 + } + ] + } + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "", + "type": { + "name": "decimal", + "args": [ + { + "int": 5 + }, + { + "int": 2 + } + ] + } + } + }, + { + "number": 2, + "column": { + "name": "", + "type": { + "name": "nvarchar", + "args": [ + { + "ident": "max" + } + ] + } + } + }, + { + "number": 3, + "column": { + "name": "", + "type": { + "name": "varchar", + "args": [ + { + "int": 10 + } + ] + } + } + }, + { + "number": 4, + "column": { + "name": "", + "type": { + "name": "datetime2", + "args": [ + { + "int": 3 + } + ] + } + } + }, + { + "number": 5, + "column": { + "name": "", + "type": { + "name": "money" + } + } + }, + { + "number": 6, + "column": { + "name": "", + "type": { + "name": "real" + } + } + }, + { + "number": 7, + "column": { + "name": "", + "type": { + "name": "char", + "args": [ + { + "int": 3 + } + ] + } + } + } + ] + }, + { + "name": "Params", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "things" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "price", + "type": { + "name": "decimal", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "things" + } + }, + { + "number": 2, + "column": { + "name": "body", + "type": { + "name": "nvarchar", + "nullable": true, + "args": [ + { + "ident": "max" + } + ] + }, + "table": "things" + } + }, + { + "number": 3, + "column": { + "name": "phone", + "type": { + "name": "phonenumber" + }, + "table": "things" + } + }, + { + "number": 4, + "column": { + "name": "offset_at", + "type": { + "name": "datetimeoffset", + "nullable": true, + "args": [ + { + "int": 7 + } + ] + }, + "table": "things" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_types/mysql/exec.json b/internal/endtoend/testdata/analyze_types/mysql/exec.json new file mode 100644 index 0000000..a5b24d3 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/mysql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "mysql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_types/mysql/query.sql b/internal/endtoend/testdata/analyze_types/mysql/query.sql new file mode 100644 index 0000000..3b3c2a4 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/mysql/query.sql @@ -0,0 +1,22 @@ +-- name: AllTypes :many +SELECT * FROM things; + +-- name: Casts :one +SELECT + CAST(count AS UNSIGNED) AS a, + CAST(price AS DECIMAL(5,2)) AS b, + CAST(title AS CHAR(10)) AS c, + CAST(count AS SIGNED) AS d, + CAST(doc AS JSON) AS e, + CAST(created AS DATETIME(3)) AS f, + CAST(price AS DECIMAL) AS g, + CAST(key16 AS BINARY(8)) AS h, + CAST(d AS DOUBLE) AS i, + CAST(f AS FLOAT) AS j, + CAST(price AS DEC(6,1)) AS k, + CAST(price AS DECIMAL(5)) AS l +FROM things; + +-- name: Params :one +SELECT id FROM things +WHERE count = ? AND price = ? AND kind = ? AND flags = ? AND title = ? AND uprice = ? AND flag = ? AND created = ?; diff --git a/internal/endtoend/testdata/analyze_types/mysql/schema.sql b/internal/endtoend/testdata/analyze_types/mysql/schema.sql new file mode 100644 index 0000000..880de33 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/mysql/schema.sql @@ -0,0 +1,29 @@ +CREATE TABLE things ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + flag TINYINT(1), + count INT UNSIGNED NOT NULL, + price DECIMAL(10,2) NOT NULL, + uprice DECIMAL(10,2) UNSIGNED, + plain DECIMAL, + dd DEC(7,2), + ratio FLOAT(7,4), + f FLOAT, + title VARCHAR(255), + code CHAR(3), + kind ENUM('a','b'), + flags SET('x','y'), + doc JSON, + key16 BINARY(16), + blob255 VARBINARY(255), + created DATETIME(6), + updated TIMESTAMP(3), + y YEAR, + bits BIT(8), + body TEXT, + bin VARCHAR(10) CHARACTER SET binary, + geo GEOMETRY, + ok BOOLEAN, + d DOUBLE, + small MEDIUMINT UNSIGNED, + i INT +); diff --git a/internal/endtoend/testdata/analyze_types/mysql/stdout.json b/internal/endtoend/testdata/analyze_types/mysql/stdout.json new file mode 100644 index 0000000..1e031b3 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/mysql/stdout.json @@ -0,0 +1,608 @@ +[ + { + "name": "AllTypes", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint unsigned" + }, + "table": "things" + }, + { + "name": "flag", + "type": { + "name": "tinyint", + "nullable": true, + "args": [ + { + "int": 1 + } + ] + }, + "table": "things" + }, + { + "name": "count", + "type": { + "name": "int unsigned" + }, + "table": "things" + }, + { + "name": "price", + "type": { + "name": "decimal", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "things" + }, + { + "name": "uprice", + "type": { + "name": "decimal unsigned", + "nullable": true, + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "things" + }, + { + "name": "plain", + "type": { + "name": "decimal", + "nullable": true, + "args": [ + { + "int": 10 + }, + { + "int": 0 + } + ] + }, + "table": "things" + }, + { + "name": "dd", + "type": { + "name": "decimal", + "nullable": true, + "args": [ + { + "int": 7 + }, + { + "int": 2 + } + ] + }, + "table": "things" + }, + { + "name": "ratio", + "type": { + "name": "float", + "nullable": true, + "args": [ + { + "int": 7 + }, + { + "int": 4 + } + ] + }, + "table": "things" + }, + { + "name": "f", + "type": { + "name": "float", + "nullable": true + }, + "table": "things" + }, + { + "name": "title", + "type": { + "name": "varchar", + "nullable": true, + "args": [ + { + "int": 255 + } + ] + }, + "table": "things" + }, + { + "name": "code", + "type": { + "name": "char", + "nullable": true, + "args": [ + { + "int": 3 + } + ] + }, + "table": "things" + }, + { + "name": "kind", + "type": { + "name": "enum", + "nullable": true, + "args": [ + { + "string": "a" + }, + { + "string": "b" + } + ] + }, + "table": "things" + }, + { + "name": "flags", + "type": { + "name": "set", + "nullable": true, + "args": [ + { + "string": "x" + }, + { + "string": "y" + } + ] + }, + "table": "things" + }, + { + "name": "doc", + "type": { + "name": "json", + "nullable": true + }, + "table": "things" + }, + { + "name": "key16", + "type": { + "name": "binary", + "nullable": true, + "args": [ + { + "int": 16 + } + ] + }, + "table": "things" + }, + { + "name": "blob255", + "type": { + "name": "varbinary", + "nullable": true, + "args": [ + { + "int": 255 + } + ] + }, + "table": "things" + }, + { + "name": "created", + "type": { + "name": "datetime", + "nullable": true, + "args": [ + { + "int": 6 + } + ] + }, + "table": "things" + }, + { + "name": "updated", + "type": { + "name": "timestamp", + "nullable": true, + "args": [ + { + "int": 3 + } + ] + }, + "table": "things" + }, + { + "name": "y", + "type": { + "name": "year", + "nullable": true + }, + "table": "things" + }, + { + "name": "bits", + "type": { + "name": "bit", + "nullable": true, + "args": [ + { + "int": 8 + } + ] + }, + "table": "things" + }, + { + "name": "body", + "type": { + "name": "text", + "nullable": true + }, + "table": "things" + }, + { + "name": "bin", + "type": { + "name": "varbinary", + "nullable": true, + "args": [ + { + "int": 10 + } + ] + }, + "table": "things" + }, + { + "name": "geo", + "type": { + "name": "geometry", + "nullable": true + }, + "table": "things" + }, + { + "name": "ok", + "type": { + "name": "tinyint", + "nullable": true, + "args": [ + { + "int": 1 + } + ] + }, + "table": "things" + }, + { + "name": "d", + "type": { + "name": "double", + "nullable": true + }, + "table": "things" + }, + { + "name": "small", + "type": { + "name": "mediumint unsigned", + "nullable": true + }, + "table": "things" + }, + { + "name": "i", + "type": { + "name": "int", + "nullable": true + }, + "table": "things" + } + ], + "params": [] + }, + { + "name": "Casts", + "cmd": ":one", + "columns": [ + { + "name": "a", + "type": { + "name": "bigint unsigned" + } + }, + { + "name": "b", + "type": { + "name": "decimal", + "args": [ + { + "int": 5 + }, + { + "int": 2 + } + ] + } + }, + { + "name": "c", + "type": { + "name": "varchar", + "nullable": true, + "args": [ + { + "int": 10 + } + ] + } + }, + { + "name": "d", + "type": { + "name": "bigint" + } + }, + { + "name": "e", + "type": { + "name": "json", + "nullable": true + } + }, + { + "name": "f", + "type": { + "name": "datetime", + "nullable": true, + "args": [ + { + "int": 3 + } + ] + } + }, + { + "name": "g", + "type": { + "name": "decimal", + "args": [ + { + "int": 10 + }, + { + "int": 0 + } + ] + } + }, + { + "name": "h", + "type": { + "name": "varbinary", + "nullable": true, + "args": [ + { + "int": 8 + } + ] + } + }, + { + "name": "i", + "type": { + "name": "double", + "nullable": true + } + }, + { + "name": "j", + "type": { + "name": "float", + "nullable": true + } + }, + { + "name": "k", + "type": { + "name": "decimal", + "args": [ + { + "int": 6 + }, + { + "int": 1 + } + ] + } + }, + { + "name": "l", + "type": { + "name": "decimal", + "args": [ + { + "int": 5 + }, + { + "int": 0 + } + ] + } + } + ], + "params": [] + }, + { + "name": "Params", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint unsigned" + }, + "table": "things" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "count", + "type": { + "name": "int unsigned" + }, + "table": "things" + } + }, + { + "number": 2, + "column": { + "name": "price", + "type": { + "name": "decimal", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "things" + } + }, + { + "number": 3, + "column": { + "name": "kind", + "type": { + "name": "enum", + "nullable": true, + "args": [ + { + "string": "a" + }, + { + "string": "b" + } + ] + }, + "table": "things" + } + }, + { + "number": 4, + "column": { + "name": "flags", + "type": { + "name": "set", + "nullable": true, + "args": [ + { + "string": "x" + }, + { + "string": "y" + } + ] + }, + "table": "things" + } + }, + { + "number": 5, + "column": { + "name": "title", + "type": { + "name": "varchar", + "nullable": true, + "args": [ + { + "int": 255 + } + ] + }, + "table": "things" + } + }, + { + "number": 6, + "column": { + "name": "uprice", + "type": { + "name": "decimal unsigned", + "nullable": true, + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "things" + } + }, + { + "number": 7, + "column": { + "name": "flag", + "type": { + "name": "tinyint", + "nullable": true, + "args": [ + { + "int": 1 + } + ] + }, + "table": "things" + } + }, + { + "number": 8, + "column": { + "name": "created", + "type": { + "name": "datetime", + "nullable": true, + "args": [ + { + "int": 6 + } + ] + }, + "table": "things" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_types/postgresql/exec.json b/internal/endtoend/testdata/analyze_types/postgresql/exec.json new file mode 100644 index 0000000..b102755 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/postgresql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "postgresql", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_types/postgresql/query.sql b/internal/endtoend/testdata/analyze_types/postgresql/query.sql new file mode 100644 index 0000000..ad7746e --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/postgresql/query.sql @@ -0,0 +1,25 @@ +-- name: AllTypes :many +SELECT * FROM things; + +-- name: Casts :one +SELECT + $1::numeric(10,2) AS a, + $2::int[] AS b, + price::text AS c, + $3::mood AS d, + $4::varchar(20) AS e, + $5::posint AS f, + 1::int8 AS g, + $6::int4[][] AS h, + $7::numeric(5,1) AS i, + ARRAY[1, 2] AS j, + $8::myschema.mood AS k, + $9::varchar(10)[] AS l, + $10::interval day to second AS m, + $11::myschema.mood[] AS n, + $12::mood[] AS o +FROM things; + +-- name: Params :one +SELECT id FROM things +WHERE price = $1 AND ints = $2 AND m = $3 AND p = $4 AND title = $5 AND grid = $6 AND sn = $7 AND fr = $8 AND ivd = $9; diff --git a/internal/endtoend/testdata/analyze_types/postgresql/schema.sql b/internal/endtoend/testdata/analyze_types/postgresql/schema.sql new file mode 100644 index 0000000..0db7266 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/postgresql/schema.sql @@ -0,0 +1,47 @@ +CREATE EXTENSION hstore; +CREATE SCHEMA myschema; +CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy'); +CREATE TYPE myschema.mood AS ENUM ('x', 'y'); +CREATE DOMAIN posint AS integer CHECK (VALUE > 0); +CREATE DOMAIN shortname AS varchar(20) NOT NULL; +CREATE TYPE point2 AS (x float8, y float8); +CREATE TYPE floatrange AS RANGE (subtype = float8); + +CREATE TABLE things ( + id bigserial PRIMARY KEY, + price numeric(10,2) NOT NULL, + amount numeric, + title varchar(255), + code character varying(10), + tag char(5), + raw bpchar, + count pg_catalog.int4, + ints int[], + grid int[][], + bounded int[3], + words text[] NOT NULL, + prices numeric(10,2)[], + ts timestamp(3), + tstz timestamptz NOT NULL, + ttz time with time zone, + iv interval, + ivd interval day to second, + iv3 interval(3), + m mood, + mm myschema.mood, + mms myschema.mood[], + p posint, + sn shortname, + pt point2, + pts point2[], + fr floatrange, + ir int4range, + b bit(8), + vb varbit(16), + js jsonb, + u uuid, + h hstore, + moods mood[], + dp double precision, + ts2 timestamp without time zone +); diff --git a/internal/endtoend/testdata/analyze_types/postgresql/stdout.json b/internal/endtoend/testdata/analyze_types/postgresql/stdout.json new file mode 100644 index 0000000..6091af1 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/postgresql/stdout.json @@ -0,0 +1,921 @@ +[ + { + "name": "AllTypes", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "things" + }, + { + "name": "price", + "type": { + "name": "numeric", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "things" + }, + { + "name": "amount", + "type": { + "name": "numeric", + "nullable": true + }, + "table": "things" + }, + { + "name": "title", + "type": { + "name": "character varying", + "nullable": true, + "args": [ + { + "int": 255 + } + ] + }, + "table": "things" + }, + { + "name": "code", + "type": { + "name": "character varying", + "nullable": true, + "args": [ + { + "int": 10 + } + ] + }, + "table": "things" + }, + { + "name": "tag", + "type": { + "name": "character", + "nullable": true, + "args": [ + { + "int": 5 + } + ] + }, + "table": "things" + }, + { + "name": "raw", + "type": { + "name": "character", + "nullable": true + }, + "table": "things" + }, + { + "name": "count", + "type": { + "name": "integer", + "nullable": true + }, + "table": "things" + }, + { + "name": "ints", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "integer" + } + } + ] + }, + "table": "things" + }, + { + "name": "grid", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + } + ] + } + } + ] + }, + "table": "things" + }, + { + "name": "bounded", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "integer" + } + } + ] + }, + "table": "things" + }, + { + "name": "words", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "text" + } + } + ] + }, + "table": "things" + }, + { + "name": "prices", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "numeric", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + } + } + ] + }, + "table": "things" + }, + { + "name": "ts", + "type": { + "name": "timestamp without time zone", + "nullable": true, + "args": [ + { + "int": 3 + } + ] + }, + "table": "things" + }, + { + "name": "tstz", + "type": { + "name": "timestamp with time zone" + }, + "table": "things" + }, + { + "name": "ttz", + "type": { + "name": "time with time zone", + "nullable": true + }, + "table": "things" + }, + { + "name": "iv", + "type": { + "name": "interval", + "nullable": true + }, + "table": "things" + }, + { + "name": "ivd", + "type": { + "name": "interval", + "nullable": true, + "args": [ + { + "ident": "day to second" + } + ] + }, + "table": "things" + }, + { + "name": "iv3", + "type": { + "name": "interval", + "nullable": true, + "args": [ + { + "int": 3 + } + ] + }, + "table": "things" + }, + { + "name": "m", + "type": { + "name": "mood", + "nullable": true + }, + "table": "things" + }, + { + "name": "mm", + "type": { + "name": "myschema.mood", + "nullable": true + }, + "table": "things" + }, + { + "name": "mms", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "myschema.mood" + } + } + ] + }, + "table": "things" + }, + { + "name": "p", + "type": { + "name": "posint", + "nullable": true + }, + "table": "things" + }, + { + "name": "sn", + "type": { + "name": "shortname" + }, + "table": "things" + }, + { + "name": "pt", + "type": { + "name": "point2", + "nullable": true + }, + "table": "things" + }, + { + "name": "pts", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "point2" + } + } + ] + }, + "table": "things" + }, + { + "name": "fr", + "type": { + "name": "floatrange", + "nullable": true + }, + "table": "things" + }, + { + "name": "ir", + "type": { + "name": "int4range", + "nullable": true + }, + "table": "things" + }, + { + "name": "b", + "type": { + "name": "bit", + "nullable": true, + "args": [ + { + "int": 8 + } + ] + }, + "table": "things" + }, + { + "name": "vb", + "type": { + "name": "bit varying", + "nullable": true, + "args": [ + { + "int": 16 + } + ] + }, + "table": "things" + }, + { + "name": "js", + "type": { + "name": "jsonb", + "nullable": true + }, + "table": "things" + }, + { + "name": "u", + "type": { + "name": "uuid", + "nullable": true + }, + "table": "things" + }, + { + "name": "h", + "type": { + "name": "hstore", + "nullable": true + }, + "table": "things" + }, + { + "name": "moods", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "mood" + } + } + ] + }, + "table": "things" + }, + { + "name": "dp", + "type": { + "name": "double precision", + "nullable": true + }, + "table": "things" + }, + { + "name": "ts2", + "type": { + "name": "timestamp without time zone", + "nullable": true + }, + "table": "things" + } + ], + "params": [] + }, + { + "name": "Casts", + "cmd": ":one", + "columns": [ + { + "name": "a", + "type": { + "name": "numeric", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + } + }, + { + "name": "b", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + } + ] + } + }, + { + "name": "c", + "type": { + "name": "text" + } + }, + { + "name": "d", + "type": { + "name": "mood" + } + }, + { + "name": "e", + "type": { + "name": "character varying", + "args": [ + { + "int": 20 + } + ] + } + }, + { + "name": "f", + "type": { + "name": "posint" + } + }, + { + "name": "g", + "type": { + "name": "bigint" + } + }, + { + "name": "h", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + } + ] + } + } + ] + } + }, + { + "name": "i", + "type": { + "name": "numeric", + "args": [ + { + "int": 5 + }, + { + "int": 1 + } + ] + } + }, + { + "name": "j", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + } + ] + } + }, + { + "name": "k", + "type": { + "name": "myschema.mood" + } + }, + { + "name": "l", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "character varying", + "args": [ + { + "int": 10 + } + ] + } + } + ] + } + }, + { + "name": "m", + "type": { + "name": "interval", + "args": [ + { + "ident": "day to second" + } + ] + } + }, + { + "name": "n", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "myschema.mood" + } + } + ] + } + }, + { + "name": "o", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "mood" + } + } + ] + } + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "", + "type": { + "name": "numeric", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + } + } + }, + { + "number": 2, + "column": { + "name": "", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + } + ] + } + } + }, + { + "number": 3, + "column": { + "name": "", + "type": { + "name": "mood" + } + } + }, + { + "number": 4, + "column": { + "name": "", + "type": { + "name": "character varying", + "args": [ + { + "int": 20 + } + ] + } + } + }, + { + "number": 5, + "column": { + "name": "", + "type": { + "name": "posint" + } + } + }, + { + "number": 6, + "column": { + "name": "", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + } + ] + } + } + ] + } + } + }, + { + "number": 7, + "column": { + "name": "", + "type": { + "name": "numeric", + "args": [ + { + "int": 5 + }, + { + "int": 1 + } + ] + } + } + }, + { + "number": 8, + "column": { + "name": "", + "type": { + "name": "myschema.mood" + } + } + }, + { + "number": 9, + "column": { + "name": "", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "character varying", + "args": [ + { + "int": 10 + } + ] + } + } + ] + } + } + }, + { + "number": 10, + "column": { + "name": "", + "type": { + "name": "interval", + "args": [ + { + "ident": "day to second" + } + ] + } + } + }, + { + "number": 11, + "column": { + "name": "", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "myschema.mood" + } + } + ] + } + } + }, + { + "number": 12, + "column": { + "name": "", + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "mood" + } + } + ] + } + } + } + ] + }, + { + "name": "Params", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "bigint" + }, + "table": "things" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "price", + "type": { + "name": "numeric", + "args": [ + { + "int": 10 + }, + { + "int": 2 + } + ] + }, + "table": "things" + } + }, + { + "number": 2, + "column": { + "name": "ints", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "integer" + } + } + ] + }, + "table": "things" + } + }, + { + "number": 3, + "column": { + "name": "m", + "type": { + "name": "mood", + "nullable": true + }, + "table": "things" + } + }, + { + "number": 4, + "column": { + "name": "p", + "type": { + "name": "posint", + "nullable": true + }, + "table": "things" + } + }, + { + "number": 5, + "column": { + "name": "title", + "type": { + "name": "character varying", + "nullable": true, + "args": [ + { + "int": 255 + } + ] + }, + "table": "things" + } + }, + { + "number": 6, + "column": { + "name": "grid", + "type": { + "name": "array", + "nullable": true, + "args": [ + { + "type": { + "name": "array", + "args": [ + { + "type": { + "name": "integer" + } + } + ] + } + } + ] + }, + "table": "things" + } + }, + { + "number": 7, + "column": { + "name": "sn", + "type": { + "name": "shortname" + }, + "table": "things" + } + }, + { + "number": 8, + "column": { + "name": "fr", + "type": { + "name": "floatrange", + "nullable": true + }, + "table": "things" + } + }, + { + "number": 9, + "column": { + "name": "ivd", + "type": { + "name": "interval", + "nullable": true, + "args": [ + { + "ident": "day to second" + } + ] + }, + "table": "things" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/analyze_types/sqlite/exec.json b/internal/endtoend/testdata/analyze_types/sqlite/exec.json new file mode 100644 index 0000000..aa77909 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/sqlite/exec.json @@ -0,0 +1,5 @@ +{ + "command": "analyze", + "args": ["--dialect", "sqlite", "--schema", "schema.sql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/analyze_types/sqlite/fixture.sql b/internal/endtoend/testdata/analyze_types/sqlite/fixture.sql new file mode 100644 index 0000000..122acdd --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/sqlite/fixture.sql @@ -0,0 +1,4 @@ +INSERT INTO things (id, title, code, price, flag, big, data, untyped, ratio, weird, created, n, label) +VALUES (1, 'abc', 'xy', 1.5, 1, 9000000000, x'00ff', 7, 2.5, '12', '2024-01-01 00:00:00', 3, 'ab'); +INSERT INTO strict_things (id, anything, body, amount, raw, n) VALUES (1, 'x', 'b', 1.5, x'00', 2); +INSERT INTO things (id, n) VALUES (2, 0); diff --git a/internal/endtoend/testdata/analyze_types/sqlite/query.sql b/internal/endtoend/testdata/analyze_types/sqlite/query.sql new file mode 100644 index 0000000..3153311 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/sqlite/query.sql @@ -0,0 +1,18 @@ +-- name: AllTypes :many +SELECT * FROM things; + +-- name: StrictTypes :many +SELECT * FROM strict_things; + +-- name: Casts :one +SELECT + CAST(title AS INTEGER) AS a, + CAST(n AS TEXT) AS b, + CAST(title AS REAL) AS d, + weird + 1 AS e, + title || 'x' AS f +FROM things; + +-- name: Params :one +SELECT id FROM things +WHERE title = ? AND price = ? AND untyped = ? AND weird = ? AND big = ? AND n = ?; diff --git a/internal/endtoend/testdata/analyze_types/sqlite/schema.sql b/internal/endtoend/testdata/analyze_types/sqlite/schema.sql new file mode 100644 index 0000000..675a8d6 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/sqlite/schema.sql @@ -0,0 +1,24 @@ +CREATE TABLE things ( + id INTEGER PRIMARY KEY, + title VARCHAR(255), + code VARYING CHARACTER(10), + price DECIMAL(10,5), + flag BOOLEAN, + big UNSIGNED BIG INT, + data BLOB, + untyped, + ratio DOUBLE PRECISION, + weird FOO BAR(3), + created DATETIME, + n INT NOT NULL, + label NCHAR(5) +); + +CREATE TABLE strict_things ( + id INTEGER, + anything ANY, + body TEXT, + amount REAL, + raw BLOB, + n INT +) STRICT; diff --git a/internal/endtoend/testdata/analyze_types/sqlite/stdout.json b/internal/endtoend/testdata/analyze_types/sqlite/stdout.json new file mode 100644 index 0000000..7d992f9 --- /dev/null +++ b/internal/endtoend/testdata/analyze_types/sqlite/stdout.json @@ -0,0 +1,333 @@ +[ + { + "name": "AllTypes", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "integer" + }, + "table": "things" + }, + { + "name": "title", + "type": { + "name": "varchar", + "nullable": true, + "args": [ + { + "int": 255 + } + ] + }, + "table": "things" + }, + { + "name": "code", + "type": { + "name": "varying character", + "nullable": true, + "args": [ + { + "int": 10 + } + ] + }, + "table": "things" + }, + { + "name": "price", + "type": { + "name": "decimal", + "nullable": true, + "args": [ + { + "int": 10 + }, + { + "int": 5 + } + ] + }, + "table": "things" + }, + { + "name": "flag", + "type": { + "name": "boolean", + "nullable": true + }, + "table": "things" + }, + { + "name": "big", + "type": { + "name": "unsigned big int", + "nullable": true + }, + "table": "things" + }, + { + "name": "data", + "type": { + "name": "blob", + "nullable": true + }, + "table": "things" + }, + { + "name": "untyped", + "type": { + "name": "any", + "nullable": true + }, + "table": "things" + }, + { + "name": "ratio", + "type": { + "name": "double precision", + "nullable": true + }, + "table": "things" + }, + { + "name": "weird", + "type": { + "name": "foo bar", + "nullable": true, + "args": [ + { + "int": 3 + } + ] + }, + "table": "things" + }, + { + "name": "created", + "type": { + "name": "datetime", + "nullable": true + }, + "table": "things" + }, + { + "name": "n", + "type": { + "name": "int" + }, + "table": "things" + }, + { + "name": "label", + "type": { + "name": "nchar", + "nullable": true, + "args": [ + { + "int": 5 + } + ] + }, + "table": "things" + } + ], + "params": [] + }, + { + "name": "StrictTypes", + "cmd": ":many", + "columns": [ + { + "name": "id", + "type": { + "name": "integer", + "nullable": true + }, + "table": "strict_things" + }, + { + "name": "anything", + "type": { + "name": "any", + "nullable": true + }, + "table": "strict_things" + }, + { + "name": "body", + "type": { + "name": "text", + "nullable": true + }, + "table": "strict_things" + }, + { + "name": "amount", + "type": { + "name": "real", + "nullable": true + }, + "table": "strict_things" + }, + { + "name": "raw", + "type": { + "name": "blob", + "nullable": true + }, + "table": "strict_things" + }, + { + "name": "n", + "type": { + "name": "int", + "nullable": true + }, + "table": "strict_things" + } + ], + "params": [] + }, + { + "name": "Casts", + "cmd": ":one", + "columns": [ + { + "name": "a", + "type": { + "name": "integer", + "nullable": true + } + }, + { + "name": "b", + "type": { + "name": "text" + } + }, + { + "name": "d", + "type": { + "name": "real", + "nullable": true + } + }, + { + "name": "e", + "type": { + "name": "integer", + "nullable": true + } + }, + { + "name": "f", + "type": { + "name": "text", + "nullable": true + } + } + ], + "params": [] + }, + { + "name": "Params", + "cmd": ":one", + "columns": [ + { + "name": "id", + "type": { + "name": "integer" + }, + "table": "things" + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "title", + "type": { + "name": "varchar", + "nullable": true, + "args": [ + { + "int": 255 + } + ] + }, + "table": "things" + } + }, + { + "number": 2, + "column": { + "name": "price", + "type": { + "name": "decimal", + "nullable": true, + "args": [ + { + "int": 10 + }, + { + "int": 5 + } + ] + }, + "table": "things" + } + }, + { + "number": 3, + "column": { + "name": "untyped", + "type": { + "name": "any", + "nullable": true + }, + "table": "things" + } + }, + { + "number": 4, + "column": { + "name": "weird", + "type": { + "name": "foo bar", + "nullable": true, + "args": [ + { + "int": 3 + } + ] + }, + "table": "things" + } + }, + { + "number": 5, + "column": { + "name": "big", + "type": { + "name": "unsigned big int", + "nullable": true + }, + "table": "things" + } + }, + { + "number": 6, + "column": { + "name": "n", + "type": { + "name": "int" + }, + "table": "things" + } + } + ] + } +] diff --git a/internal/endtoend/testdata/any/pgx/v4/go/db.go b/internal/endtoend/testdata/any/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/any/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/any/pgx/v4/go/models.go b/internal/endtoend/testdata/any/pgx/v4/go/models.go new file mode 100644 index 0000000..bc354e0 --- /dev/null +++ b/internal/endtoend/testdata/any/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int64 +} diff --git a/internal/endtoend/testdata/any/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/any/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..1bb2829 --- /dev/null +++ b/internal/endtoend/testdata/any/pgx/v4/go/query.sql.go @@ -0,0 +1,36 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const any_ = `-- name: Any :many +SELECT id +FROM bar +WHERE id = ANY($1::bigint[]) +` + +func (q *Queries) Any(ctx context.Context, dollar_1 []int64) ([]int64, error) { + rows, err := q.db.Query(ctx, any_, dollar_1) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var id int64 + 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 +} diff --git a/internal/endtoend/testdata/any/pgx/v4/query.sql b/internal/endtoend/testdata/any/pgx/v4/query.sql new file mode 100644 index 0000000..82f863a --- /dev/null +++ b/internal/endtoend/testdata/any/pgx/v4/query.sql @@ -0,0 +1,4 @@ +-- name: Any :many +SELECT id +FROM bar +WHERE id = ANY($1::bigint[]); diff --git a/internal/endtoend/testdata/any/pgx/v4/schema.sql b/internal/endtoend/testdata/any/pgx/v4/schema.sql new file mode 100644 index 0000000..88127d9 --- /dev/null +++ b/internal/endtoend/testdata/any/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id bigserial not null); + diff --git a/internal/endtoend/testdata/any/pgx/v4/sqlc.json b/internal/endtoend/testdata/any/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/any/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/any/pgx/v5/go/db.go b/internal/endtoend/testdata/any/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/any/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/any/pgx/v5/go/models.go b/internal/endtoend/testdata/any/pgx/v5/go/models.go new file mode 100644 index 0000000..bc354e0 --- /dev/null +++ b/internal/endtoend/testdata/any/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int64 +} diff --git a/internal/endtoend/testdata/any/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/any/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..1bb2829 --- /dev/null +++ b/internal/endtoend/testdata/any/pgx/v5/go/query.sql.go @@ -0,0 +1,36 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const any_ = `-- name: Any :many +SELECT id +FROM bar +WHERE id = ANY($1::bigint[]) +` + +func (q *Queries) Any(ctx context.Context, dollar_1 []int64) ([]int64, error) { + rows, err := q.db.Query(ctx, any_, dollar_1) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var id int64 + 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 +} diff --git a/internal/endtoend/testdata/any/pgx/v5/query.sql b/internal/endtoend/testdata/any/pgx/v5/query.sql new file mode 100644 index 0000000..82f863a --- /dev/null +++ b/internal/endtoend/testdata/any/pgx/v5/query.sql @@ -0,0 +1,4 @@ +-- name: Any :many +SELECT id +FROM bar +WHERE id = ANY($1::bigint[]); diff --git a/internal/endtoend/testdata/any/pgx/v5/schema.sql b/internal/endtoend/testdata/any/pgx/v5/schema.sql new file mode 100644 index 0000000..88127d9 --- /dev/null +++ b/internal/endtoend/testdata/any/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id bigserial not null); + diff --git a/internal/endtoend/testdata/any/pgx/v5/sqlc.json b/internal/endtoend/testdata/any/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/any/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/any/stdlib/go/db.go b/internal/endtoend/testdata/any/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/any/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/any/stdlib/go/models.go b/internal/endtoend/testdata/any/stdlib/go/models.go new file mode 100644 index 0000000..bc354e0 --- /dev/null +++ b/internal/endtoend/testdata/any/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int64 +} diff --git a/internal/endtoend/testdata/any/stdlib/go/query.sql.go b/internal/endtoend/testdata/any/stdlib/go/query.sql.go new file mode 100644 index 0000000..240bb91 --- /dev/null +++ b/internal/endtoend/testdata/any/stdlib/go/query.sql.go @@ -0,0 +1,41 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/lib/pq" +) + +const any_ = `-- name: Any :many +SELECT id +FROM bar +WHERE id = ANY($1::bigint[]) +` + +func (q *Queries) Any(ctx context.Context, dollar_1 []int64) ([]int64, error) { + rows, err := q.db.QueryContext(ctx, any_, pq.Array(dollar_1)) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var id int64 + 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 +} diff --git a/internal/endtoend/testdata/any/stdlib/query.sql b/internal/endtoend/testdata/any/stdlib/query.sql new file mode 100644 index 0000000..82f863a --- /dev/null +++ b/internal/endtoend/testdata/any/stdlib/query.sql @@ -0,0 +1,4 @@ +-- name: Any :many +SELECT id +FROM bar +WHERE id = ANY($1::bigint[]); diff --git a/internal/endtoend/testdata/any/stdlib/schema.sql b/internal/endtoend/testdata/any/stdlib/schema.sql new file mode 100644 index 0000000..88127d9 --- /dev/null +++ b/internal/endtoend/testdata/any/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id bigserial not null); + diff --git a/internal/endtoend/testdata/any/stdlib/sqlc.json b/internal/endtoend/testdata/any/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/any/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/array_in/pgx/v4/go/db.go b/internal/endtoend/testdata/array_in/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/array_in/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/array_in/pgx/v4/go/models.go b/internal/endtoend/testdata/array_in/pgx/v4/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/array_in/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/array_in/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/array_in/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..0886f96 --- /dev/null +++ b/internal/endtoend/testdata/array_in/pgx/v4/go/query.sql.go @@ -0,0 +1,41 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const in = `-- name: In :many +SELECT id +FROM bar +WHERE id IN ($1, $2) +` + +type InParams struct { + ID int32 + ID_2 int32 +} + +func (q *Queries) In(ctx context.Context, arg InParams) ([]int32, error) { + rows, err := q.db.Query(ctx, in, arg.ID, arg.ID_2) + 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 +} diff --git a/internal/endtoend/testdata/array_in/pgx/v4/query.sql b/internal/endtoend/testdata/array_in/pgx/v4/query.sql new file mode 100644 index 0000000..d412b55 --- /dev/null +++ b/internal/endtoend/testdata/array_in/pgx/v4/query.sql @@ -0,0 +1,4 @@ +-- name: In :many +SELECT * +FROM bar +WHERE id IN ($1, $2); diff --git a/internal/endtoend/testdata/array_in/pgx/v4/schema.sql b/internal/endtoend/testdata/array_in/pgx/v4/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/array_in/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/array_in/pgx/v4/sqlc.json b/internal/endtoend/testdata/array_in/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/array_in/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/array_in/pgx/v5/go/db.go b/internal/endtoend/testdata/array_in/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/array_in/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/array_in/pgx/v5/go/models.go b/internal/endtoend/testdata/array_in/pgx/v5/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/array_in/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/array_in/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/array_in/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..0886f96 --- /dev/null +++ b/internal/endtoend/testdata/array_in/pgx/v5/go/query.sql.go @@ -0,0 +1,41 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const in = `-- name: In :many +SELECT id +FROM bar +WHERE id IN ($1, $2) +` + +type InParams struct { + ID int32 + ID_2 int32 +} + +func (q *Queries) In(ctx context.Context, arg InParams) ([]int32, error) { + rows, err := q.db.Query(ctx, in, arg.ID, arg.ID_2) + 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 +} diff --git a/internal/endtoend/testdata/array_in/pgx/v5/query.sql b/internal/endtoend/testdata/array_in/pgx/v5/query.sql new file mode 100644 index 0000000..d412b55 --- /dev/null +++ b/internal/endtoend/testdata/array_in/pgx/v5/query.sql @@ -0,0 +1,4 @@ +-- name: In :many +SELECT * +FROM bar +WHERE id IN ($1, $2); diff --git a/internal/endtoend/testdata/array_in/pgx/v5/schema.sql b/internal/endtoend/testdata/array_in/pgx/v5/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/array_in/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/array_in/pgx/v5/sqlc.json b/internal/endtoend/testdata/array_in/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/array_in/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/array_in/stdlib/go/db.go b/internal/endtoend/testdata/array_in/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/array_in/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/array_in/stdlib/go/models.go b/internal/endtoend/testdata/array_in/stdlib/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/array_in/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/array_in/stdlib/go/query.sql.go b/internal/endtoend/testdata/array_in/stdlib/go/query.sql.go new file mode 100644 index 0000000..f2355cf --- /dev/null +++ b/internal/endtoend/testdata/array_in/stdlib/go/query.sql.go @@ -0,0 +1,44 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const in = `-- name: In :many +SELECT id +FROM bar +WHERE id IN ($1, $2) +` + +type InParams struct { + ID int32 + ID_2 int32 +} + +func (q *Queries) In(ctx context.Context, arg InParams) ([]int32, error) { + rows, err := q.db.QueryContext(ctx, in, arg.ID, arg.ID_2) + 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 +} diff --git a/internal/endtoend/testdata/array_in/stdlib/query.sql b/internal/endtoend/testdata/array_in/stdlib/query.sql new file mode 100644 index 0000000..d412b55 --- /dev/null +++ b/internal/endtoend/testdata/array_in/stdlib/query.sql @@ -0,0 +1,4 @@ +-- name: In :many +SELECT * +FROM bar +WHERE id IN ($1, $2); diff --git a/internal/endtoend/testdata/array_in/stdlib/schema.sql b/internal/endtoend/testdata/array_in/stdlib/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/array_in/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/array_in/stdlib/sqlc.json b/internal/endtoend/testdata/array_in/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/array_in/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/array_text/pgx/v4/go/db.go b/internal/endtoend/testdata/array_text/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/array_text/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/array_text/pgx/v4/go/models.go b/internal/endtoend/testdata/array_text/pgx/v4/go/models.go new file mode 100644 index 0000000..ac93cc0 --- /dev/null +++ b/internal/endtoend/testdata/array_text/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + Tags []string +} diff --git a/internal/endtoend/testdata/array_text/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/array_text/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..72b8523 --- /dev/null +++ b/internal/endtoend/testdata/array_text/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const textArray = `-- name: TextArray :many +SELECT tags FROM bar +` + +func (q *Queries) TextArray(ctx context.Context) ([][]string, error) { + rows, err := q.db.Query(ctx, textArray) + if err != nil { + return nil, err + } + defer rows.Close() + var items [][]string + for rows.Next() { + var tags []string + if err := rows.Scan(&tags); err != nil { + return nil, err + } + items = append(items, tags) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/array_text/pgx/v4/query.sql b/internal/endtoend/testdata/array_text/pgx/v4/query.sql new file mode 100644 index 0000000..4c6b353 --- /dev/null +++ b/internal/endtoend/testdata/array_text/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: TextArray :many +SELECT * FROM bar; diff --git a/internal/endtoend/testdata/array_text/pgx/v4/schema.sql b/internal/endtoend/testdata/array_text/pgx/v4/schema.sql new file mode 100644 index 0000000..9d6d66b --- /dev/null +++ b/internal/endtoend/testdata/array_text/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (tags text[] not null); + diff --git a/internal/endtoend/testdata/array_text/pgx/v4/sqlc.json b/internal/endtoend/testdata/array_text/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/array_text/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/array_text/pgx/v5/go/db.go b/internal/endtoend/testdata/array_text/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/array_text/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/array_text/pgx/v5/go/models.go b/internal/endtoend/testdata/array_text/pgx/v5/go/models.go new file mode 100644 index 0000000..ac93cc0 --- /dev/null +++ b/internal/endtoend/testdata/array_text/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + Tags []string +} diff --git a/internal/endtoend/testdata/array_text/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/array_text/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..72b8523 --- /dev/null +++ b/internal/endtoend/testdata/array_text/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const textArray = `-- name: TextArray :many +SELECT tags FROM bar +` + +func (q *Queries) TextArray(ctx context.Context) ([][]string, error) { + rows, err := q.db.Query(ctx, textArray) + if err != nil { + return nil, err + } + defer rows.Close() + var items [][]string + for rows.Next() { + var tags []string + if err := rows.Scan(&tags); err != nil { + return nil, err + } + items = append(items, tags) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/array_text/pgx/v5/query.sql b/internal/endtoend/testdata/array_text/pgx/v5/query.sql new file mode 100644 index 0000000..4c6b353 --- /dev/null +++ b/internal/endtoend/testdata/array_text/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: TextArray :many +SELECT * FROM bar; diff --git a/internal/endtoend/testdata/array_text/pgx/v5/schema.sql b/internal/endtoend/testdata/array_text/pgx/v5/schema.sql new file mode 100644 index 0000000..9d6d66b --- /dev/null +++ b/internal/endtoend/testdata/array_text/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (tags text[] not null); + diff --git a/internal/endtoend/testdata/array_text/pgx/v5/sqlc.json b/internal/endtoend/testdata/array_text/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/array_text/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/array_text/stdlib/go/db.go b/internal/endtoend/testdata/array_text/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/array_text/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/array_text/stdlib/go/models.go b/internal/endtoend/testdata/array_text/stdlib/go/models.go new file mode 100644 index 0000000..ac93cc0 --- /dev/null +++ b/internal/endtoend/testdata/array_text/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + Tags []string +} diff --git a/internal/endtoend/testdata/array_text/stdlib/go/query.sql.go b/internal/endtoend/testdata/array_text/stdlib/go/query.sql.go new file mode 100644 index 0000000..ee4a2d1 --- /dev/null +++ b/internal/endtoend/testdata/array_text/stdlib/go/query.sql.go @@ -0,0 +1,39 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/lib/pq" +) + +const textArray = `-- name: TextArray :many +SELECT tags FROM bar +` + +func (q *Queries) TextArray(ctx context.Context) ([][]string, error) { + rows, err := q.db.QueryContext(ctx, textArray) + if err != nil { + return nil, err + } + defer rows.Close() + var items [][]string + for rows.Next() { + var tags []string + if err := rows.Scan(pq.Array(&tags)); err != nil { + return nil, err + } + items = append(items, tags) + } + 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/array_text/stdlib/query.sql b/internal/endtoend/testdata/array_text/stdlib/query.sql new file mode 100644 index 0000000..4c6b353 --- /dev/null +++ b/internal/endtoend/testdata/array_text/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: TextArray :many +SELECT * FROM bar; diff --git a/internal/endtoend/testdata/array_text/stdlib/schema.sql b/internal/endtoend/testdata/array_text/stdlib/schema.sql new file mode 100644 index 0000000..9d6d66b --- /dev/null +++ b/internal/endtoend/testdata/array_text/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (tags text[] not null); + diff --git a/internal/endtoend/testdata/array_text/stdlib/sqlc.json b/internal/endtoend/testdata/array_text/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/array_text/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/array_text_join/pgx/v4/go/db.go b/internal/endtoend/testdata/array_text_join/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/array_text_join/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/array_text_join/pgx/v4/go/models.go b/internal/endtoend/testdata/array_text_join/pgx/v4/go/models.go new file mode 100644 index 0000000..73d590b --- /dev/null +++ b/internal/endtoend/testdata/array_text_join/pgx/v4/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID string + Info []string +} + +type Foo struct { + ID string + Bar string +} diff --git a/internal/endtoend/testdata/array_text_join/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/array_text_join/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..0bc4579 --- /dev/null +++ b/internal/endtoend/testdata/array_text_join/pgx/v4/go/query.sql.go @@ -0,0 +1,36 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const joinTextArray = `-- name: JoinTextArray :many +SELECT bar.info +FROM foo +JOIN bar ON foo.bar = bar.id +` + +func (q *Queries) JoinTextArray(ctx context.Context) ([][]string, error) { + rows, err := q.db.Query(ctx, joinTextArray) + if err != nil { + return nil, err + } + defer rows.Close() + var items [][]string + for rows.Next() { + var info []string + if err := rows.Scan(&info); err != nil { + return nil, err + } + items = append(items, info) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/array_text_join/pgx/v4/query.sql b/internal/endtoend/testdata/array_text_join/pgx/v4/query.sql new file mode 100644 index 0000000..68135c6 --- /dev/null +++ b/internal/endtoend/testdata/array_text_join/pgx/v4/query.sql @@ -0,0 +1,4 @@ +-- name: JoinTextArray :many +SELECT bar.info +FROM foo +JOIN bar ON foo.bar = bar.id; diff --git a/internal/endtoend/testdata/array_text_join/pgx/v4/schema.sql b/internal/endtoend/testdata/array_text_join/pgx/v4/schema.sql new file mode 100644 index 0000000..a8ba18e --- /dev/null +++ b/internal/endtoend/testdata/array_text_join/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (id text not null, bar text not null); +CREATE TABLE bar (id text not null, info text[] not null); + diff --git a/internal/endtoend/testdata/array_text_join/pgx/v4/sqlc.json b/internal/endtoend/testdata/array_text_join/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/array_text_join/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/array_text_join/pgx/v5/go/db.go b/internal/endtoend/testdata/array_text_join/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/array_text_join/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/array_text_join/pgx/v5/go/models.go b/internal/endtoend/testdata/array_text_join/pgx/v5/go/models.go new file mode 100644 index 0000000..73d590b --- /dev/null +++ b/internal/endtoend/testdata/array_text_join/pgx/v5/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID string + Info []string +} + +type Foo struct { + ID string + Bar string +} diff --git a/internal/endtoend/testdata/array_text_join/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/array_text_join/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..0bc4579 --- /dev/null +++ b/internal/endtoend/testdata/array_text_join/pgx/v5/go/query.sql.go @@ -0,0 +1,36 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const joinTextArray = `-- name: JoinTextArray :many +SELECT bar.info +FROM foo +JOIN bar ON foo.bar = bar.id +` + +func (q *Queries) JoinTextArray(ctx context.Context) ([][]string, error) { + rows, err := q.db.Query(ctx, joinTextArray) + if err != nil { + return nil, err + } + defer rows.Close() + var items [][]string + for rows.Next() { + var info []string + if err := rows.Scan(&info); err != nil { + return nil, err + } + items = append(items, info) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/array_text_join/pgx/v5/query.sql b/internal/endtoend/testdata/array_text_join/pgx/v5/query.sql new file mode 100644 index 0000000..68135c6 --- /dev/null +++ b/internal/endtoend/testdata/array_text_join/pgx/v5/query.sql @@ -0,0 +1,4 @@ +-- name: JoinTextArray :many +SELECT bar.info +FROM foo +JOIN bar ON foo.bar = bar.id; diff --git a/internal/endtoend/testdata/array_text_join/pgx/v5/schema.sql b/internal/endtoend/testdata/array_text_join/pgx/v5/schema.sql new file mode 100644 index 0000000..a8ba18e --- /dev/null +++ b/internal/endtoend/testdata/array_text_join/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (id text not null, bar text not null); +CREATE TABLE bar (id text not null, info text[] not null); + diff --git a/internal/endtoend/testdata/array_text_join/pgx/v5/sqlc.json b/internal/endtoend/testdata/array_text_join/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/array_text_join/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/array_text_join/stdlib/go/db.go b/internal/endtoend/testdata/array_text_join/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/array_text_join/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/array_text_join/stdlib/go/models.go b/internal/endtoend/testdata/array_text_join/stdlib/go/models.go new file mode 100644 index 0000000..73d590b --- /dev/null +++ b/internal/endtoend/testdata/array_text_join/stdlib/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID string + Info []string +} + +type Foo struct { + ID string + Bar string +} diff --git a/internal/endtoend/testdata/array_text_join/stdlib/go/query.sql.go b/internal/endtoend/testdata/array_text_join/stdlib/go/query.sql.go new file mode 100644 index 0000000..ba11aa1 --- /dev/null +++ b/internal/endtoend/testdata/array_text_join/stdlib/go/query.sql.go @@ -0,0 +1,41 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/lib/pq" +) + +const joinTextArray = `-- name: JoinTextArray :many +SELECT bar.info +FROM foo +JOIN bar ON foo.bar = bar.id +` + +func (q *Queries) JoinTextArray(ctx context.Context) ([][]string, error) { + rows, err := q.db.QueryContext(ctx, joinTextArray) + if err != nil { + return nil, err + } + defer rows.Close() + var items [][]string + for rows.Next() { + var info []string + if err := rows.Scan(pq.Array(&info)); err != nil { + return nil, err + } + items = append(items, info) + } + 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/array_text_join/stdlib/query.sql b/internal/endtoend/testdata/array_text_join/stdlib/query.sql new file mode 100644 index 0000000..68135c6 --- /dev/null +++ b/internal/endtoend/testdata/array_text_join/stdlib/query.sql @@ -0,0 +1,4 @@ +-- name: JoinTextArray :many +SELECT bar.info +FROM foo +JOIN bar ON foo.bar = bar.id; diff --git a/internal/endtoend/testdata/array_text_join/stdlib/schema.sql b/internal/endtoend/testdata/array_text_join/stdlib/schema.sql new file mode 100644 index 0000000..a8ba18e --- /dev/null +++ b/internal/endtoend/testdata/array_text_join/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (id text not null, bar text not null); +CREATE TABLE bar (id text not null, info text[] not null); + diff --git a/internal/endtoend/testdata/array_text_join/stdlib/sqlc.json b/internal/endtoend/testdata/array_text_join/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/array_text_join/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/bad_config/engine/query.sql b/internal/endtoend/testdata/bad_config/engine/query.sql new file mode 100644 index 0000000..18b0c0d --- /dev/null +++ b/internal/endtoend/testdata/bad_config/engine/query.sql @@ -0,0 +1,2 @@ +-- name: Test :exec +SELECT 1; \ No newline at end of file diff --git a/internal/endtoend/testdata/bad_config/engine/sqlc.yaml b/internal/endtoend/testdata/bad_config/engine/sqlc.yaml new file mode 100644 index 0000000..8f20b4e --- /dev/null +++ b/internal/endtoend/testdata/bad_config/engine/sqlc.yaml @@ -0,0 +1,8 @@ +version: 2 +sql: +- queries: query.sql + schema: query.sql + engine: "bad_engine" + gen: + go: + out: "db" \ No newline at end of file diff --git a/internal/endtoend/testdata/bad_config/engine/stderr.txt b/internal/endtoend/testdata/bad_config/engine/stderr.txt new file mode 100644 index 0000000..9797244 --- /dev/null +++ b/internal/endtoend/testdata/bad_config/engine/stderr.txt @@ -0,0 +1 @@ +error creating compiler: unknown engine: bad_engine \ No newline at end of file diff --git a/internal/endtoend/testdata/batch/postgresql/pgx/v4/go/batch.go b/internal/endtoend/testdata/batch/postgresql/pgx/v4/go/batch.go new file mode 100644 index 0000000..9ff7203 --- /dev/null +++ b/internal/endtoend/testdata/batch/postgresql/pgx/v4/go/batch.go @@ -0,0 +1,180 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: batch.go + +package querytest + +import ( + "context" + "database/sql" + "errors" + + "github.com/jackc/pgx/v4" +) + +var ( + ErrBatchAlreadyClosed = errors.New("batch already closed") +) + +const getValues = `-- name: GetValues :batchmany +SELECT a, b +FROM myschema.foo +WHERE b = $1 +` + +type GetValuesBatchResults struct { + br pgx.BatchResults + tot int + closed bool +} + +func (q *Queries) GetValues(ctx context.Context, b []sql.NullInt32) *GetValuesBatchResults { + batch := &pgx.Batch{} + for _, a := range b { + vals := []any{ + a, + } + batch.Queue(getValues, vals...) + } + br := q.db.SendBatch(ctx, batch) + return &GetValuesBatchResults{br, len(b), false} +} + +func (b *GetValuesBatchResults) Query(f func(int, []MyschemaFoo, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + var items []MyschemaFoo + if b.closed { + if f != nil { + f(t, items, ErrBatchAlreadyClosed) + } + continue + } + err := func() error { + rows, err := b.br.Query() + if err != nil { + return err + } + defer rows.Close() + for rows.Next() { + var i MyschemaFoo + if err := rows.Scan(&i.A, &i.B); err != nil { + return err + } + items = append(items, i) + } + return rows.Err() + }() + if f != nil { + f(t, items, err) + } + } +} + +func (b *GetValuesBatchResults) Close() error { + b.closed = true + return b.br.Close() +} + +const insertValues = `-- name: InsertValues :batchone +INSERT INTO myschema.foo (a, b) +VALUES ($1, $2) +RETURNING a +` + +type InsertValuesBatchResults struct { + br pgx.BatchResults + tot int + closed bool +} + +type InsertValuesParams struct { + A sql.NullString + B sql.NullInt32 +} + +func (q *Queries) InsertValues(ctx context.Context, arg []InsertValuesParams) *InsertValuesBatchResults { + batch := &pgx.Batch{} + for _, a := range arg { + vals := []any{ + a.A, + a.B, + } + batch.Queue(insertValues, vals...) + } + br := q.db.SendBatch(ctx, batch) + return &InsertValuesBatchResults{br, len(arg), false} +} + +func (b *InsertValuesBatchResults) QueryRow(f func(int, sql.NullString, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + var a sql.NullString + if b.closed { + if f != nil { + f(t, a, ErrBatchAlreadyClosed) + } + continue + } + row := b.br.QueryRow() + err := row.Scan(&a) + if f != nil { + f(t, a, err) + } + } +} + +func (b *InsertValuesBatchResults) Close() error { + b.closed = true + return b.br.Close() +} + +const updateValues = `-- name: UpdateValues :batchexec +UPDATE myschema.foo SET a = $1, b = $2 +` + +type UpdateValuesBatchResults struct { + br pgx.BatchResults + tot int + closed bool +} + +type UpdateValuesParams struct { + A sql.NullString + B sql.NullInt32 +} + +func (q *Queries) UpdateValues(ctx context.Context, arg []UpdateValuesParams) *UpdateValuesBatchResults { + batch := &pgx.Batch{} + for _, a := range arg { + vals := []any{ + a.A, + a.B, + } + batch.Queue(updateValues, vals...) + } + br := q.db.SendBatch(ctx, batch) + return &UpdateValuesBatchResults{br, len(arg), false} +} + +func (b *UpdateValuesBatchResults) Exec(f func(int, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + if b.closed { + if f != nil { + f(t, ErrBatchAlreadyClosed) + } + continue + } + _, err := b.br.Exec() + if f != nil { + f(t, err) + } + } +} + +func (b *UpdateValuesBatchResults) Close() error { + b.closed = true + return b.br.Close() +} diff --git a/internal/endtoend/testdata/batch/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/batch/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..49b7e30 --- /dev/null +++ b/internal/endtoend/testdata/batch/postgresql/pgx/v4/go/db.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row + SendBatch(context.Context, *pgx.Batch) pgx.BatchResults +} + +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/batch/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/batch/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..fa0d297 --- /dev/null +++ b/internal/endtoend/testdata/batch/postgresql/pgx/v4/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type MyschemaFoo struct { + A sql.NullString + B sql.NullInt32 +} diff --git a/internal/endtoend/testdata/batch/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/batch/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..aa95052 --- /dev/null +++ b/internal/endtoend/testdata/batch/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,6 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest diff --git a/internal/endtoend/testdata/batch/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/batch/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..c8e2570 --- /dev/null +++ b/internal/endtoend/testdata/batch/postgresql/pgx/v4/query.sql @@ -0,0 +1,12 @@ +-- name: InsertValues :batchone +INSERT INTO myschema.foo (a, b) +VALUES ($1, $2) +RETURNING a; + +-- name: GetValues :batchmany +SELECT * +FROM myschema.foo +WHERE b = $1; + +-- name: UpdateValues :batchexec +UPDATE myschema.foo SET a = $1, b = $2; diff --git a/internal/endtoend/testdata/batch/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/batch/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..e53abe5 --- /dev/null +++ b/internal/endtoend/testdata/batch/postgresql/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA myschema; +CREATE TABLE myschema.foo (a text, b integer); + diff --git a/internal/endtoend/testdata/batch/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/batch/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/batch/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/batch/postgresql/pgx/v5/go/batch.go b/internal/endtoend/testdata/batch/postgresql/pgx/v5/go/batch.go new file mode 100644 index 0000000..390c85c --- /dev/null +++ b/internal/endtoend/testdata/batch/postgresql/pgx/v5/go/batch.go @@ -0,0 +1,180 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: batch.go + +package querytest + +import ( + "context" + "errors" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgtype" +) + +var ( + ErrBatchAlreadyClosed = errors.New("batch already closed") +) + +const getValues = `-- name: GetValues :batchmany +SELECT a, b +FROM myschema.foo +WHERE b = $1 +` + +type GetValuesBatchResults struct { + br pgx.BatchResults + tot int + closed bool +} + +func (q *Queries) GetValues(ctx context.Context, b []pgtype.Int4) *GetValuesBatchResults { + batch := &pgx.Batch{} + for _, a := range b { + vals := []any{ + a, + } + batch.Queue(getValues, vals...) + } + br := q.db.SendBatch(ctx, batch) + return &GetValuesBatchResults{br, len(b), false} +} + +func (b *GetValuesBatchResults) Query(f func(int, []MyschemaFoo, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + var items []MyschemaFoo + if b.closed { + if f != nil { + f(t, items, ErrBatchAlreadyClosed) + } + continue + } + err := func() error { + rows, err := b.br.Query() + if err != nil { + return err + } + defer rows.Close() + for rows.Next() { + var i MyschemaFoo + if err := rows.Scan(&i.A, &i.B); err != nil { + return err + } + items = append(items, i) + } + return rows.Err() + }() + if f != nil { + f(t, items, err) + } + } +} + +func (b *GetValuesBatchResults) Close() error { + b.closed = true + return b.br.Close() +} + +const insertValues = `-- name: InsertValues :batchone +INSERT INTO myschema.foo (a, b) +VALUES ($1, $2) +RETURNING a +` + +type InsertValuesBatchResults struct { + br pgx.BatchResults + tot int + closed bool +} + +type InsertValuesParams struct { + A pgtype.Text + B pgtype.Int4 +} + +func (q *Queries) InsertValues(ctx context.Context, arg []InsertValuesParams) *InsertValuesBatchResults { + batch := &pgx.Batch{} + for _, a := range arg { + vals := []any{ + a.A, + a.B, + } + batch.Queue(insertValues, vals...) + } + br := q.db.SendBatch(ctx, batch) + return &InsertValuesBatchResults{br, len(arg), false} +} + +func (b *InsertValuesBatchResults) QueryRow(f func(int, pgtype.Text, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + var a pgtype.Text + if b.closed { + if f != nil { + f(t, a, ErrBatchAlreadyClosed) + } + continue + } + row := b.br.QueryRow() + err := row.Scan(&a) + if f != nil { + f(t, a, err) + } + } +} + +func (b *InsertValuesBatchResults) Close() error { + b.closed = true + return b.br.Close() +} + +const updateValues = `-- name: UpdateValues :batchexec +UPDATE myschema.foo SET a = $1, b = $2 +` + +type UpdateValuesBatchResults struct { + br pgx.BatchResults + tot int + closed bool +} + +type UpdateValuesParams struct { + A pgtype.Text + B pgtype.Int4 +} + +func (q *Queries) UpdateValues(ctx context.Context, arg []UpdateValuesParams) *UpdateValuesBatchResults { + batch := &pgx.Batch{} + for _, a := range arg { + vals := []any{ + a.A, + a.B, + } + batch.Queue(updateValues, vals...) + } + br := q.db.SendBatch(ctx, batch) + return &UpdateValuesBatchResults{br, len(arg), false} +} + +func (b *UpdateValuesBatchResults) Exec(f func(int, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + if b.closed { + if f != nil { + f(t, ErrBatchAlreadyClosed) + } + continue + } + _, err := b.br.Exec() + if f != nil { + f(t, err) + } + } +} + +func (b *UpdateValuesBatchResults) Close() error { + b.closed = true + return b.br.Close() +} diff --git a/internal/endtoend/testdata/batch/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/batch/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..1f79ce6 --- /dev/null +++ b/internal/endtoend/testdata/batch/postgresql/pgx/v5/go/db.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row + SendBatch(context.Context, *pgx.Batch) pgx.BatchResults +} + +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/batch/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/batch/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..80e1ef5 --- /dev/null +++ b/internal/endtoend/testdata/batch/postgresql/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type MyschemaFoo struct { + A pgtype.Text + B pgtype.Int4 +} diff --git a/internal/endtoend/testdata/batch/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/batch/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..aa95052 --- /dev/null +++ b/internal/endtoend/testdata/batch/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,6 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest diff --git a/internal/endtoend/testdata/batch/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/batch/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..c8e2570 --- /dev/null +++ b/internal/endtoend/testdata/batch/postgresql/pgx/v5/query.sql @@ -0,0 +1,12 @@ +-- name: InsertValues :batchone +INSERT INTO myschema.foo (a, b) +VALUES ($1, $2) +RETURNING a; + +-- name: GetValues :batchmany +SELECT * +FROM myschema.foo +WHERE b = $1; + +-- name: UpdateValues :batchexec +UPDATE myschema.foo SET a = $1, b = $2; diff --git a/internal/endtoend/testdata/batch/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/batch/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..e53abe5 --- /dev/null +++ b/internal/endtoend/testdata/batch/postgresql/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA myschema; +CREATE TABLE myschema.foo (a text, b integer); + diff --git a/internal/endtoend/testdata/batch/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/batch/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/batch/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/go/batch.go b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/go/batch.go new file mode 100644 index 0000000..224d287 --- /dev/null +++ b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/go/batch.go @@ -0,0 +1,131 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: batch.go + +package querytest + +import ( + "context" + "database/sql" + "errors" + + "github.com/jackc/pgx/v4" +) + +var ( + ErrBatchAlreadyClosed = errors.New("batch already closed") +) + +const getValues = `-- name: GetValues :batchmany +SELECT a, b +FROM myschema.foo +WHERE b = $1 +` + +type GetValuesBatchResults struct { + br pgx.BatchResults + tot int + closed bool +} + +func (q *Queries) GetValues(ctx context.Context, b []sql.NullInt32) *GetValuesBatchResults { + batch := &pgx.Batch{} + for _, a := range b { + vals := []any{ + a, + } + batch.Queue(getValues, vals...) + } + br := q.db.SendBatch(ctx, batch) + return &GetValuesBatchResults{br, len(b), false} +} + +func (b *GetValuesBatchResults) Query(f func(int, []MyschemaFoo, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + var items []MyschemaFoo + if b.closed { + if f != nil { + f(t, items, ErrBatchAlreadyClosed) + } + continue + } + err := func() error { + rows, err := b.br.Query() + if err != nil { + return err + } + defer rows.Close() + for rows.Next() { + var i MyschemaFoo + if err := rows.Scan(&i.A, &i.B); err != nil { + return err + } + items = append(items, i) + } + return rows.Err() + }() + if f != nil { + f(t, items, err) + } + } +} + +func (b *GetValuesBatchResults) Close() error { + b.closed = true + return b.br.Close() +} + +const insertValues = `-- name: InsertValues :batchone +INSERT INTO myschema.foo (a, b) +VALUES ($1, $2) +RETURNING a +` + +type InsertValuesBatchResults struct { + br pgx.BatchResults + tot int + closed bool +} + +type InsertValuesParams struct { + A sql.NullString + B sql.NullInt32 +} + +func (q *Queries) InsertValues(ctx context.Context, arg []InsertValuesParams) *InsertValuesBatchResults { + batch := &pgx.Batch{} + for _, a := range arg { + vals := []any{ + a.A, + a.B, + } + batch.Queue(insertValues, vals...) + } + br := q.db.SendBatch(ctx, batch) + return &InsertValuesBatchResults{br, len(arg), false} +} + +func (b *InsertValuesBatchResults) QueryRow(f func(int, sql.NullString, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + var a sql.NullString + if b.closed { + if f != nil { + f(t, a, ErrBatchAlreadyClosed) + } + continue + } + row := b.br.QueryRow() + err := row.Scan(&a) + if f != nil { + f(t, a, err) + } + } +} + +func (b *InsertValuesBatchResults) Close() error { + b.closed = true + return b.br.Close() +} diff --git a/internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..49b7e30 --- /dev/null +++ b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/go/db.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row + SendBatch(context.Context, *pgx.Batch) pgx.BatchResults +} + +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/batch_imports/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..fa0d297 --- /dev/null +++ b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type MyschemaFoo struct { + A sql.NullString + B sql.NullInt32 +} diff --git a/internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..865697d --- /dev/null +++ b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const updateValues = `-- name: UpdateValues :exec +UPDATE myschema.foo SET a = $1, b = $2 +` + +type UpdateValuesParams struct { + A sql.NullString + B sql.NullInt32 +} + +func (q *Queries) UpdateValues(ctx context.Context, arg UpdateValuesParams) error { + _, err := q.db.Exec(ctx, updateValues, arg.A, arg.B) + return err +} diff --git a/internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..def00fb --- /dev/null +++ b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/query.sql @@ -0,0 +1,12 @@ +-- name: InsertValues :batchone +INSERT INTO myschema.foo (a, b) +VALUES ($1, $2) +RETURNING a; + +-- name: GetValues :batchmany +SELECT * +FROM myschema.foo +WHERE b = $1; + +-- name: UpdateValues :exec +UPDATE myschema.foo SET a = $1, b = $2; diff --git a/internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..e53abe5 --- /dev/null +++ b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA myschema; +CREATE TABLE myschema.foo (a text, b integer); + diff --git a/internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/go/batch.go b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/go/batch.go new file mode 100644 index 0000000..65bb113 --- /dev/null +++ b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/go/batch.go @@ -0,0 +1,131 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: batch.go + +package querytest + +import ( + "context" + "errors" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgtype" +) + +var ( + ErrBatchAlreadyClosed = errors.New("batch already closed") +) + +const getValues = `-- name: GetValues :batchmany +SELECT a, b +FROM myschema.foo +WHERE b = $1 +` + +type GetValuesBatchResults struct { + br pgx.BatchResults + tot int + closed bool +} + +func (q *Queries) GetValues(ctx context.Context, b []pgtype.Int4) *GetValuesBatchResults { + batch := &pgx.Batch{} + for _, a := range b { + vals := []any{ + a, + } + batch.Queue(getValues, vals...) + } + br := q.db.SendBatch(ctx, batch) + return &GetValuesBatchResults{br, len(b), false} +} + +func (b *GetValuesBatchResults) Query(f func(int, []MyschemaFoo, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + var items []MyschemaFoo + if b.closed { + if f != nil { + f(t, items, ErrBatchAlreadyClosed) + } + continue + } + err := func() error { + rows, err := b.br.Query() + if err != nil { + return err + } + defer rows.Close() + for rows.Next() { + var i MyschemaFoo + if err := rows.Scan(&i.A, &i.B); err != nil { + return err + } + items = append(items, i) + } + return rows.Err() + }() + if f != nil { + f(t, items, err) + } + } +} + +func (b *GetValuesBatchResults) Close() error { + b.closed = true + return b.br.Close() +} + +const insertValues = `-- name: InsertValues :batchone +INSERT INTO myschema.foo (a, b) +VALUES ($1, $2) +RETURNING a +` + +type InsertValuesBatchResults struct { + br pgx.BatchResults + tot int + closed bool +} + +type InsertValuesParams struct { + A pgtype.Text + B pgtype.Int4 +} + +func (q *Queries) InsertValues(ctx context.Context, arg []InsertValuesParams) *InsertValuesBatchResults { + batch := &pgx.Batch{} + for _, a := range arg { + vals := []any{ + a.A, + a.B, + } + batch.Queue(insertValues, vals...) + } + br := q.db.SendBatch(ctx, batch) + return &InsertValuesBatchResults{br, len(arg), false} +} + +func (b *InsertValuesBatchResults) QueryRow(f func(int, pgtype.Text, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + var a pgtype.Text + if b.closed { + if f != nil { + f(t, a, ErrBatchAlreadyClosed) + } + continue + } + row := b.br.QueryRow() + err := row.Scan(&a) + if f != nil { + f(t, a, err) + } + } +} + +func (b *InsertValuesBatchResults) Close() error { + b.closed = true + return b.br.Close() +} diff --git a/internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..1f79ce6 --- /dev/null +++ b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/go/db.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row + SendBatch(context.Context, *pgx.Batch) pgx.BatchResults +} + +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/batch_imports/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..80e1ef5 --- /dev/null +++ b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type MyschemaFoo struct { + A pgtype.Text + B pgtype.Int4 +} diff --git a/internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..11c950c --- /dev/null +++ b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,26 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const updateValues = `-- name: UpdateValues :exec +UPDATE myschema.foo SET a = $1, b = $2 +` + +type UpdateValuesParams struct { + A pgtype.Text + B pgtype.Int4 +} + +func (q *Queries) UpdateValues(ctx context.Context, arg UpdateValuesParams) error { + _, err := q.db.Exec(ctx, updateValues, arg.A, arg.B) + return err +} diff --git a/internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..def00fb --- /dev/null +++ b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/query.sql @@ -0,0 +1,12 @@ +-- name: InsertValues :batchone +INSERT INTO myschema.foo (a, b) +VALUES ($1, $2) +RETURNING a; + +-- name: GetValues :batchmany +SELECT * +FROM myschema.foo +WHERE b = $1; + +-- name: UpdateValues :exec +UPDATE myschema.foo SET a = $1, b = $2; diff --git a/internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..e53abe5 --- /dev/null +++ b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA myschema; +CREATE TABLE myschema.foo (a text, b integer); + diff --git a/internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/batch_imports/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/batch_parameter_limit/issue.md b/internal/endtoend/testdata/batch_parameter_limit/issue.md new file mode 100644 index 0000000..e0d6146 --- /dev/null +++ b/internal/endtoend/testdata/batch_parameter_limit/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/3185 diff --git a/internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/go/batch.go b/internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/go/batch.go new file mode 100644 index 0000000..6d66b12 --- /dev/null +++ b/internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/go/batch.go @@ -0,0 +1,71 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: batch.go + +package querytest + +import ( + "context" + "errors" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgtype" +) + +var ( + ErrBatchAlreadyClosed = errors.New("batch already closed") +) + +const createAuthors = `-- name: CreateAuthors :batchexec +INSERT INTO authors ( + name, bio +) VALUES ( + $1, $2 +) +` + +type CreateAuthorsBatchResults struct { + br pgx.BatchResults + tot int + closed bool +} + +type CreateAuthorsParams struct { + Name string + Bio pgtype.Text +} + +func (q *Queries) CreateAuthors(ctx context.Context, arg []CreateAuthorsParams) *CreateAuthorsBatchResults { + batch := &pgx.Batch{} + for _, a := range arg { + vals := []any{ + a.Name, + a.Bio, + } + batch.Queue(createAuthors, vals...) + } + br := q.db.SendBatch(ctx, batch) + return &CreateAuthorsBatchResults{br, len(arg), false} +} + +func (b *CreateAuthorsBatchResults) Exec(f func(int, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + if b.closed { + if f != nil { + f(t, ErrBatchAlreadyClosed) + } + continue + } + _, err := b.br.Exec() + if f != nil { + f(t, err) + } + } +} + +func (b *CreateAuthorsBatchResults) Close() error { + b.closed = true + return b.br.Close() +} diff --git a/internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/go/db.go b/internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/go/db.go new file mode 100644 index 0000000..1f79ce6 --- /dev/null +++ b/internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/go/db.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row + SendBatch(context.Context, *pgx.Batch) pgx.BatchResults +} + +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/batch_parameter_limit/postgresql/pgx/go/models.go b/internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/go/models.go new file mode 100644 index 0000000..4e97f66 --- /dev/null +++ b/internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Author struct { + ID int64 + Name string + Bio pgtype.Text +} diff --git a/internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..aa95052 --- /dev/null +++ b/internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/go/query.sql.go @@ -0,0 +1,6 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest diff --git a/internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/query.sql b/internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/query.sql new file mode 100644 index 0000000..3c25c93 --- /dev/null +++ b/internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/query.sql @@ -0,0 +1,6 @@ +-- name: CreateAuthors :batchexec +INSERT INTO authors ( + name, bio +) VALUES ( + $1, $2 +); diff --git a/internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/schema.sql b/internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/schema.sql new file mode 100644 index 0000000..69b607d --- /dev/null +++ b/internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/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/batch_parameter_limit/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..e5eb77f --- /dev/null +++ b/internal/endtoend/testdata/batch_parameter_limit/postgresql/pgx/sqlc.yaml @@ -0,0 +1,11 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" + query_parameter_limit: 2 diff --git a/internal/endtoend/testdata/batch_parameter_type/issue.md b/internal/endtoend/testdata/batch_parameter_type/issue.md new file mode 100644 index 0000000..13bb3e6 --- /dev/null +++ b/internal/endtoend/testdata/batch_parameter_type/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/2152 diff --git a/internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/exec.json b/internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/go/batch.go b/internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/go/batch.go new file mode 100644 index 0000000..706e0bf --- /dev/null +++ b/internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/go/batch.go @@ -0,0 +1,101 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: batch.go + +package querytest + +import ( + "context" + "errors" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgtype" +) + +var ( + ErrBatchAlreadyClosed = errors.New("batch already closed") +) + +const insertMappping = `-- name: InsertMappping :batchexec +WITH + table1 + AS ( + SELECT + version + FROM + solar_commcard_mapping + WHERE + "deviceId" = $1 + ORDER BY + "updatedAt" DESC + LIMIT + 1 + ) +INSERT +INTO + solar_commcard_mapping + ("deviceId", version, sn, "updatedAt") +SELECT + $1, $2::text, $3, $4 +WHERE + NOT + EXISTS( + SELECT + version + FROM + table1 + WHERE + table1.version = $2::text + ) + OR NOT EXISTS(SELECT version FROM table1) +` + +type InsertMapppingBatchResults struct { + br pgx.BatchResults + tot int + closed bool +} + +type InsertMapppingParams struct { + DeviceId int64 + Version string + Sn string + UpdatedAt pgtype.Timestamptz +} + +func (q *Queries) InsertMappping(ctx context.Context, arg []InsertMapppingParams) *InsertMapppingBatchResults { + batch := &pgx.Batch{} + for _, a := range arg { + vals := []any{ + a.DeviceId, + a.Version, + a.Sn, + a.UpdatedAt, + } + batch.Queue(insertMappping, vals...) + } + br := q.db.SendBatch(ctx, batch) + return &InsertMapppingBatchResults{br, len(arg), false} +} + +func (b *InsertMapppingBatchResults) Exec(f func(int, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + if b.closed { + if f != nil { + f(t, ErrBatchAlreadyClosed) + } + continue + } + _, err := b.br.Exec() + if f != nil { + f(t, err) + } + } +} + +func (b *InsertMapppingBatchResults) Close() error { + b.closed = true + return b.br.Close() +} diff --git a/internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/go/db.go b/internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/go/db.go new file mode 100644 index 0000000..1f79ce6 --- /dev/null +++ b/internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/go/db.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row + SendBatch(context.Context, *pgx.Batch) pgx.BatchResults +} + +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/batch_parameter_type/postgresql/pgx/go/models.go b/internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/go/models.go new file mode 100644 index 0000000..b9991d5 --- /dev/null +++ b/internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type SolarCommcardMapping struct { + ID int64 + DeviceId int64 + Version string + Sn string + CreatedAt pgtype.Timestamptz + UpdatedAt pgtype.Timestamptz +} diff --git a/internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..aa95052 --- /dev/null +++ b/internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/go/query.sql.go @@ -0,0 +1,6 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest diff --git a/internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/query.sql b/internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/query.sql new file mode 100644 index 0000000..326b9f2 --- /dev/null +++ b/internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/query.sql @@ -0,0 +1,32 @@ +-- name: InsertMappping :batchexec +WITH + table1 + AS ( + SELECT + version + FROM + solar_commcard_mapping + WHERE + "deviceId" = $1 + ORDER BY + "updatedAt" DESC + LIMIT + 1 + ) +INSERT +INTO + solar_commcard_mapping + ("deviceId", version, sn, "updatedAt") +SELECT + $1, @version::text, $3, $4 +WHERE + NOT + EXISTS( + SELECT + * + FROM + table1 + WHERE + table1.version = @version::text + ) + OR NOT EXISTS(SELECT * FROM table1); diff --git a/internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/schema.sql b/internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/schema.sql new file mode 100644 index 0000000..3aaa4db --- /dev/null +++ b/internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/schema.sql @@ -0,0 +1,14 @@ +CREATE TABLE public.solar_commcard_mapping ( + id + INT8 NOT NULL, + "deviceId" + INT8 NOT NULL, + version + VARCHAR(32) DEFAULT ''::VARCHAR NOT NULL, + sn + VARCHAR(32) DEFAULT ''::VARCHAR NOT NULL, + "createdAt" + TIMESTAMPTZ DEFAULT now(), + "updatedAt" + TIMESTAMPTZ DEFAULT now() +); diff --git a/internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/batch_parameter_type/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/between_args/mysql/go/db.go b/internal/endtoend/testdata/between_args/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/between_args/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/between_args/mysql/go/models.go b/internal/endtoend/testdata/between_args/mysql/go/models.go new file mode 100644 index 0000000..cab0799 --- /dev/null +++ b/internal/endtoend/testdata/between_args/mysql/go/models.go @@ -0,0 +1,11 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Product struct { + ID int64 + Name string + Price int32 +} diff --git a/internal/endtoend/testdata/between_args/mysql/go/query.sql.go b/internal/endtoend/testdata/between_args/mysql/go/query.sql.go new file mode 100644 index 0000000..4b357c7 --- /dev/null +++ b/internal/endtoend/testdata/between_args/mysql/go/query.sql.go @@ -0,0 +1,146 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getBetweenPrices = `-- name: GetBetweenPrices :many +SELECT id, name, price +FROM products +WHERE price BETWEEN ? AND ? +` + +type GetBetweenPricesParams struct { + FromPrice int32 + ToPrice int32 +} + +func (q *Queries) GetBetweenPrices(ctx context.Context, arg GetBetweenPricesParams) ([]Product, error) { + rows, err := q.db.QueryContext(ctx, getBetweenPrices, arg.FromPrice, arg.ToPrice) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Product + for rows.Next() { + var i Product + if err := rows.Scan(&i.ID, &i.Name, &i.Price); 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 getBetweenPricesNamed = `-- name: GetBetweenPricesNamed :many +SELECT id, name, price +FROM products +WHERE price BETWEEN ? AND ? +` + +type GetBetweenPricesNamedParams struct { + MinPrice int32 + MaxPrice int32 +} + +func (q *Queries) GetBetweenPricesNamed(ctx context.Context, arg GetBetweenPricesNamedParams) ([]Product, error) { + rows, err := q.db.QueryContext(ctx, getBetweenPricesNamed, arg.MinPrice, arg.MaxPrice) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Product + for rows.Next() { + var i Product + if err := rows.Scan(&i.ID, &i.Name, &i.Price); 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 getBetweenPricesTable = `-- name: GetBetweenPricesTable :many +SELECT id, name, price +FROM products +WHERE products.price BETWEEN ? AND ? +` + +type GetBetweenPricesTableParams struct { + FromPrice int32 + ToPrice int32 +} + +func (q *Queries) GetBetweenPricesTable(ctx context.Context, arg GetBetweenPricesTableParams) ([]Product, error) { + rows, err := q.db.QueryContext(ctx, getBetweenPricesTable, arg.FromPrice, arg.ToPrice) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Product + for rows.Next() { + var i Product + if err := rows.Scan(&i.ID, &i.Name, &i.Price); 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 getBetweenPricesTableAlias = `-- name: GetBetweenPricesTableAlias :many +SELECT id, name, price +FROM products as p +WHERE p.price BETWEEN ? AND ? +` + +type GetBetweenPricesTableAliasParams struct { + FromPrice int32 + ToPrice int32 +} + +func (q *Queries) GetBetweenPricesTableAlias(ctx context.Context, arg GetBetweenPricesTableAliasParams) ([]Product, error) { + rows, err := q.db.QueryContext(ctx, getBetweenPricesTableAlias, arg.FromPrice, arg.ToPrice) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Product + for rows.Next() { + var i Product + if err := rows.Scan(&i.ID, &i.Name, &i.Price); 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/between_args/mysql/query.sql b/internal/endtoend/testdata/between_args/mysql/query.sql new file mode 100644 index 0000000..3632dfb --- /dev/null +++ b/internal/endtoend/testdata/between_args/mysql/query.sql @@ -0,0 +1,19 @@ +-- name: GetBetweenPrices :many +SELECT * +FROM products +WHERE price BETWEEN ? AND ?; + +-- name: GetBetweenPricesTable :many +SELECT * +FROM products +WHERE products.price BETWEEN ? AND ?; + +-- name: GetBetweenPricesTableAlias :many +SELECT * +FROM products as p +WHERE p.price BETWEEN ? AND ?; + +-- name: GetBetweenPricesNamed :many +SELECT * +FROM products +WHERE price BETWEEN sqlc.arg(min_price) AND sqlc.arg(max_price); diff --git a/internal/endtoend/testdata/between_args/mysql/schema.sql b/internal/endtoend/testdata/between_args/mysql/schema.sql new file mode 100644 index 0000000..76f64e9 --- /dev/null +++ b/internal/endtoend/testdata/between_args/mysql/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE products ( + id BIGINT NOT NULL AUTO_INCREMENT, + name TEXT NOT NULL, + price INT NOT NULL, + PRIMARY KEY (id) +); + diff --git a/internal/endtoend/testdata/between_args/mysql/sqlc.json b/internal/endtoend/testdata/between_args/mysql/sqlc.json new file mode 100644 index 0000000..f0d61c7 --- /dev/null +++ b/internal/endtoend/testdata/between_args/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/between_args/sqlite/go/db.go b/internal/endtoend/testdata/between_args/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/between_args/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/between_args/sqlite/go/models.go b/internal/endtoend/testdata/between_args/sqlite/go/models.go new file mode 100644 index 0000000..f67b77a --- /dev/null +++ b/internal/endtoend/testdata/between_args/sqlite/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Product struct { + Name string + Price int64 +} diff --git a/internal/endtoend/testdata/between_args/sqlite/go/query.sql.go b/internal/endtoend/testdata/between_args/sqlite/go/query.sql.go new file mode 100644 index 0000000..2083abf --- /dev/null +++ b/internal/endtoend/testdata/between_args/sqlite/go/query.sql.go @@ -0,0 +1,112 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getBetweenPrices = `-- name: GetBetweenPrices :many +SELECT name, price +FROM products +WHERE price BETWEEN ? AND ? +` + +type GetBetweenPricesParams struct { + FromPrice int64 + ToPrice int64 +} + +func (q *Queries) GetBetweenPrices(ctx context.Context, arg GetBetweenPricesParams) ([]Product, error) { + rows, err := q.db.QueryContext(ctx, getBetweenPrices, arg.FromPrice, arg.ToPrice) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Product + for rows.Next() { + var i Product + if err := rows.Scan(&i.Name, &i.Price); 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 getBetweenPricesTable = `-- name: GetBetweenPricesTable :many +SELECT name, price +FROM products +WHERE products.price BETWEEN ? AND ? +` + +type GetBetweenPricesTableParams struct { + FromPrice int64 + ToPrice int64 +} + +func (q *Queries) GetBetweenPricesTable(ctx context.Context, arg GetBetweenPricesTableParams) ([]Product, error) { + rows, err := q.db.QueryContext(ctx, getBetweenPricesTable, arg.FromPrice, arg.ToPrice) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Product + for rows.Next() { + var i Product + if err := rows.Scan(&i.Name, &i.Price); 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 getBetweenPricesTableAlias = `-- name: GetBetweenPricesTableAlias :many +SELECT name, price +FROM products AS p +WHERE p.price BETWEEN ? AND ? +` + +type GetBetweenPricesTableAliasParams struct { + FromPrice int64 + ToPrice int64 +} + +func (q *Queries) GetBetweenPricesTableAlias(ctx context.Context, arg GetBetweenPricesTableAliasParams) ([]Product, error) { + rows, err := q.db.QueryContext(ctx, getBetweenPricesTableAlias, arg.FromPrice, arg.ToPrice) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Product + for rows.Next() { + var i Product + if err := rows.Scan(&i.Name, &i.Price); 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/between_args/sqlite/query.sql b/internal/endtoend/testdata/between_args/sqlite/query.sql new file mode 100644 index 0000000..14dd15f --- /dev/null +++ b/internal/endtoend/testdata/between_args/sqlite/query.sql @@ -0,0 +1,14 @@ +-- name: GetBetweenPrices :many +SELECT * +FROM products +WHERE price BETWEEN ? AND ?; + +-- name: GetBetweenPricesTable :many +SELECT * +FROM products +WHERE products.price BETWEEN ? AND ?; + +-- name: GetBetweenPricesTableAlias :many +SELECT * +FROM products AS p +WHERE p.price BETWEEN ? AND ?; diff --git a/internal/endtoend/testdata/between_args/sqlite/schema.sql b/internal/endtoend/testdata/between_args/sqlite/schema.sql new file mode 100644 index 0000000..b13fafb --- /dev/null +++ b/internal/endtoend/testdata/between_args/sqlite/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE products ( + name TEXT NOT NULL, + price INT NOT NULL +); + diff --git a/internal/endtoend/testdata/between_args/sqlite/sqlc.json b/internal/endtoend/testdata/between_args/sqlite/sqlc.json new file mode 100644 index 0000000..494a33e --- /dev/null +++ b/internal/endtoend/testdata/between_args/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} 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 0000000..9ca5876 --- /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.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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 0000000..3dc085d --- /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.31.1 + +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 0000000..fe8f861 --- /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.31.1 +// 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 0000000..3ab56ee --- /dev/null +++ b/internal/endtoend/testdata/bit_string/pgx/v4/query.sql @@ -0,0 +1,3 @@ +-- name: SelectTest :many +SELECT * +from test_table; diff --git a/internal/endtoend/testdata/bit_string/pgx/v4/schema.sql b/internal/endtoend/testdata/bit_string/pgx/v4/schema.sql new file mode 100644 index 0000000..0790c78 --- /dev/null +++ b/internal/endtoend/testdata/bit_string/pgx/v4/schema.sql @@ -0,0 +1,8 @@ +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 +); + 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 0000000..d1244c9 --- /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": "schema.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 0000000..2666c1c --- /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.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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 0000000..a53a6f8 --- /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.31.1 + +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 0000000..fe8f861 --- /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.31.1 +// 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 0000000..3ab56ee --- /dev/null +++ b/internal/endtoend/testdata/bit_string/pgx/v5/query.sql @@ -0,0 +1,3 @@ +-- name: SelectTest :many +SELECT * +from test_table; diff --git a/internal/endtoend/testdata/bit_string/pgx/v5/schema.sql b/internal/endtoend/testdata/bit_string/pgx/v5/schema.sql new file mode 100644 index 0000000..0790c78 --- /dev/null +++ b/internal/endtoend/testdata/bit_string/pgx/v5/schema.sql @@ -0,0 +1,8 @@ +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 +); + 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 0000000..32ede07 --- /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": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/build_tags/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/build_tags/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..cc3795d --- /dev/null +++ b/internal/endtoend/testdata/build_tags/postgresql/stdlib/go/db.go @@ -0,0 +1,33 @@ +//go:build some_tag + +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package authors + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/build_tags/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/build_tags/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..d556159 --- /dev/null +++ b/internal/endtoend/testdata/build_tags/postgresql/stdlib/go/models.go @@ -0,0 +1,17 @@ +//go:build some_tag + +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package authors + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/build_tags/postgresql/stdlib/go/querier.go b/internal/endtoend/testdata/build_tags/postgresql/stdlib/go/querier.go new file mode 100644 index 0000000..a3ae69a --- /dev/null +++ b/internal/endtoend/testdata/build_tags/postgresql/stdlib/go/querier.go @@ -0,0 +1,20 @@ +//go:build some_tag + +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package authors + +import ( + "context" +) + +type Querier interface { + CreateAuthor(ctx context.Context, arg CreateAuthorParams) (Author, error) + DeleteAuthor(ctx context.Context, id int64) error + GetAuthor(ctx context.Context, id int64) (Author, error) + ListAuthors(ctx context.Context) ([]Author, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/build_tags/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/build_tags/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..0cb38ae --- /dev/null +++ b/internal/endtoend/testdata/build_tags/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,84 @@ +//go:build some_tag + +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package authors + +import ( + "context" + "database/sql" +) + +const createAuthor = `-- name: CreateAuthor :one +INSERT INTO authors ( + name, bio +) VALUES ( + $1, $2 +) +RETURNING id, name, bio +` + +type CreateAuthorParams struct { + Name string + Bio sql.NullString +} + +func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (Author, error) { + row := q.db.QueryRowContext(ctx, createAuthor, arg.Name, arg.Bio) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const deleteAuthor = `-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = $1 +` + +func (q *Queries) DeleteAuthor(ctx context.Context, id int64) error { + _, err := q.db.ExecContext(ctx, deleteAuthor, id) + return err +} + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, bio FROM authors +WHERE id = $1 LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name, bio FROM authors +ORDER BY name +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); 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/build_tags/postgresql/stdlib/query.sql b/internal/endtoend/testdata/build_tags/postgresql/stdlib/query.sql new file mode 100644 index 0000000..75e38b2 --- /dev/null +++ b/internal/endtoend/testdata/build_tags/postgresql/stdlib/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/build_tags/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/build_tags/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..b4fad78 --- /dev/null +++ b/internal/endtoend/testdata/build_tags/postgresql/stdlib/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/build_tags/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/build_tags/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..3255dad --- /dev/null +++ b/internal/endtoend/testdata/build_tags/postgresql/stdlib/sqlc.json @@ -0,0 +1,15 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "authors", + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "omit_unused_structs": true, + "emit_interface": true, + "build_tags": "some_tag" + } + ] +} diff --git a/internal/endtoend/testdata/builtins/postgresql/exec.json b/internal/endtoend/testdata/builtins/postgresql/exec.json new file mode 100644 index 0000000..97f81fb --- /dev/null +++ b/internal/endtoend/testdata/builtins/postgresql/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/builtins/postgresql/go/db.go b/internal/endtoend/testdata/builtins/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/builtins/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/builtins/postgresql/go/models.go b/internal/endtoend/testdata/builtins/postgresql/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/builtins/postgresql/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/builtins/postgresql/go/query.sql.go b/internal/endtoend/testdata/builtins/postgresql/go/query.sql.go new file mode 100644 index 0000000..5dd7c16 --- /dev/null +++ b/internal/endtoend/testdata/builtins/postgresql/go/query.sql.go @@ -0,0 +1,274 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const abs = `-- name: Abs :one +SELECT abs(-17.4) +` + +func (q *Queries) Abs(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, abs) + var abs int64 + err := row.Scan(&abs) + return abs, err +} + +const cbrt = `-- name: Cbrt :one +SELECT cbrt(27.0) +` + +func (q *Queries) Cbrt(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, cbrt) + var cbrt float64 + err := row.Scan(&cbrt) + return cbrt, err +} + +const ceil = `-- name: Ceil :one +SELECT ceil(-42.8) +` + +func (q *Queries) Ceil(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, ceil) + var ceil float64 + err := row.Scan(&ceil) + return ceil, err +} + +const ceiling = `-- name: Ceiling :one +SELECT ceiling(-95.3) +` + +func (q *Queries) Ceiling(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, ceiling) + var ceiling float64 + err := row.Scan(&ceiling) + return ceiling, err +} + +const degrees = `-- name: Degrees :one +SELECT degrees(0.5) +` + +func (q *Queries) Degrees(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, degrees) + var degrees float64 + err := row.Scan(°rees) + return degrees, err +} + +const div = `-- name: Div :one +SELECT div(9,4) +` + +func (q *Queries) Div(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, div) + var div string + err := row.Scan(&div) + return div, err +} + +const exp = `-- name: Exp :one +SELECT exp(1.0) +` + +func (q *Queries) Exp(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, exp) + var exp float64 + err := row.Scan(&exp) + return exp, err +} + +const floor = `-- name: Floor :one +SELECT floor(-42.8) +` + +func (q *Queries) Floor(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, floor) + var floor float64 + err := row.Scan(&floor) + return floor, err +} + +const ln = `-- name: Ln :one +SELECT ln(2.0) +` + +func (q *Queries) Ln(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, ln) + var ln float64 + err := row.Scan(&ln) + return ln, err +} + +const log = `-- name: Log :one +SELECT log(100.0) +` + +func (q *Queries) Log(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, log) + var log float64 + err := row.Scan(&log) + return log, err +} + +const logs = `-- name: Logs :one +SELECT log(2.0, 64.0) +` + +func (q *Queries) Logs(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, logs) + var log string + err := row.Scan(&log) + return log, err +} + +const mod = `-- name: Mod :one +SELECT mod(9,4) +` + +func (q *Queries) Mod(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, mod) + var mod int64 + err := row.Scan(&mod) + return mod, err +} + +const pi = `-- name: Pi :one +SELECT pi() +` + +func (q *Queries) Pi(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, pi) + var pi float64 + err := row.Scan(&pi) + return pi, err +} + +const power = `-- name: Power :one +SELECT power(9.0, 3.0) +` + +func (q *Queries) Power(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, power) + var power float64 + err := row.Scan(&power) + return power, err +} + +const radians = `-- name: Radians :one +SELECT radians(45.0) +` + +func (q *Queries) Radians(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, radians) + var radians float64 + err := row.Scan(&radians) + return radians, err +} + +const round = `-- name: Round :one +SELECT round(42.4) +` + +func (q *Queries) Round(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, round) + var round float64 + err := row.Scan(&round) + return round, err +} + +const rounds = `-- name: Rounds :one +SELECT round(42.4382, 2) +` + +func (q *Queries) Rounds(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, rounds) + var round string + err := row.Scan(&round) + return round, err +} + +const scale = `-- name: Scale :one +SELECT scale(8.41) +` + +func (q *Queries) Scale(ctx context.Context) (int32, error) { + row := q.db.QueryRowContext(ctx, scale) + var scale int32 + err := row.Scan(&scale) + return scale, err +} + +const sign = `-- name: Sign :one +SELECT sign(-8.4) +` + +func (q *Queries) Sign(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, sign) + var sign float64 + err := row.Scan(&sign) + return sign, err +} + +const sqrt = `-- name: Sqrt :one +SELECT sqrt(2.0) +` + +func (q *Queries) Sqrt(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, sqrt) + var sqrt float64 + err := row.Scan(&sqrt) + return sqrt, err +} + +const trunc = `-- name: Trunc :one +SELECT trunc(42.8) +` + +func (q *Queries) Trunc(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, trunc) + var trunc float64 + err := row.Scan(&trunc) + return trunc, err +} + +const truncs = `-- name: Truncs :one +SELECT trunc(42.4382, 2) +` + +func (q *Queries) Truncs(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, truncs) + var trunc string + err := row.Scan(&trunc) + return trunc, err +} + +const widthBucketNumerics = `-- name: WidthBucketNumerics :one +SELECT width_bucket(5.35, 0.024, 10.06, 5) +` + +func (q *Queries) WidthBucketNumerics(ctx context.Context) (int32, error) { + row := q.db.QueryRowContext(ctx, widthBucketNumerics) + var width_bucket int32 + err := row.Scan(&width_bucket) + return width_bucket, err +} + +const widthBucketTimestamps = `-- name: WidthBucketTimestamps :one +SELECT width_bucket(now(), array['yesterday', 'today', 'tomorrow']::timestamptz[]) +` + +func (q *Queries) WidthBucketTimestamps(ctx context.Context) (int32, error) { + row := q.db.QueryRowContext(ctx, widthBucketTimestamps) + var width_bucket int32 + err := row.Scan(&width_bucket) + return width_bucket, err +} diff --git a/internal/endtoend/testdata/builtins/postgresql/query.sql b/internal/endtoend/testdata/builtins/postgresql/query.sql new file mode 100644 index 0000000..2c62e5f --- /dev/null +++ b/internal/endtoend/testdata/builtins/postgresql/query.sql @@ -0,0 +1,48 @@ +-- name: Abs :one +SELECT abs(-17.4); +-- name: Cbrt :one +SELECT cbrt(27.0); +-- name: Ceil :one +SELECT ceil(-42.8); +-- name: Ceiling :one +SELECT ceiling(-95.3); +-- name: Degrees :one +SELECT degrees(0.5); +-- name: Div :one +SELECT div(9,4); +-- name: Exp :one +SELECT exp(1.0); +-- name: Floor :one +SELECT floor(-42.8); +-- name: Ln :one +SELECT ln(2.0); +-- name: Log :one +SELECT log(100.0); +-- name: Logs :one +SELECT log(2.0, 64.0); +-- name: Mod :one +SELECT mod(9,4); +-- name: Pi :one +SELECT pi(); +-- name: Power :one +SELECT power(9.0, 3.0); +-- name: Radians :one +SELECT radians(45.0); +-- name: Round :one +SELECT round(42.4); +-- name: Rounds :one +SELECT round(42.4382, 2); +-- name: Scale :one +SELECT scale(8.41); +-- name: Sign :one +SELECT sign(-8.4); +-- name: Sqrt :one +SELECT sqrt(2.0); +-- name: Trunc :one +SELECT trunc(42.8); +-- name: Truncs :one +SELECT trunc(42.4382, 2); +-- name: WidthBucketNumerics :one +SELECT width_bucket(5.35, 0.024, 10.06, 5); +-- name: WidthBucketTimestamps :one +SELECT width_bucket(now(), array['yesterday', 'today', 'tomorrow']::timestamptz[]); diff --git a/internal/endtoend/testdata/builtins/postgresql/schema.sql b/internal/endtoend/testdata/builtins/postgresql/schema.sql new file mode 100644 index 0000000..1974548 --- /dev/null +++ b/internal/endtoend/testdata/builtins/postgresql/schema.sql @@ -0,0 +1,2 @@ +create schema if not exists sqlc; + diff --git a/internal/endtoend/testdata/builtins/postgresql/sqlc.json b/internal/endtoend/testdata/builtins/postgresql/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/builtins/postgresql/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/builtins/sqlite/go/aggfunc.sql.go b/internal/endtoend/testdata/builtins/sqlite/go/aggfunc.sql.go new file mode 100644 index 0000000..de2a1fa --- /dev/null +++ b/internal/endtoend/testdata/builtins/sqlite/go/aggfunc.sql.go @@ -0,0 +1,165 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: aggfunc.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const getAvg = `-- name: GetAvg :one +SELECT avg(int_val) FROM test +` + +func (q *Queries) GetAvg(ctx context.Context) (sql.NullFloat64, error) { + row := q.db.QueryRowContext(ctx, getAvg) + var avg sql.NullFloat64 + err := row.Scan(&avg) + return avg, err +} + +const getCount = `-- name: GetCount :one +SELECT count(*) FROM test +` + +func (q *Queries) GetCount(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, getCount) + var count int64 + err := row.Scan(&count) + return count, err +} + +const getCountId = `-- name: GetCountId :one +SELECT count(id) FROM test +` + +func (q *Queries) GetCountId(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, getCountId) + var count int64 + err := row.Scan(&count) + return count, err +} + +const getGroupConcatInt = `-- name: GetGroupConcatInt :one +SELECT group_concat(int_val) FROM test +` + +func (q *Queries) GetGroupConcatInt(ctx context.Context) (sql.NullString, error) { + row := q.db.QueryRowContext(ctx, getGroupConcatInt) + var group_concat sql.NullString + err := row.Scan(&group_concat) + return group_concat, err +} + +const getGroupConcatInt2 = `-- name: GetGroupConcatInt2 :one +SELECT group_concat(1, ':') FROM test +` + +func (q *Queries) GetGroupConcatInt2(ctx context.Context) (sql.NullString, error) { + row := q.db.QueryRowContext(ctx, getGroupConcatInt2) + var group_concat sql.NullString + err := row.Scan(&group_concat) + return group_concat, err +} + +const getGroupConcatText = `-- name: GetGroupConcatText :one +SELECT group_concat(text_val) FROM test +` + +func (q *Queries) GetGroupConcatText(ctx context.Context) (sql.NullString, error) { + row := q.db.QueryRowContext(ctx, getGroupConcatText) + var group_concat sql.NullString + err := row.Scan(&group_concat) + return group_concat, err +} + +const getGroupConcatText2 = `-- name: GetGroupConcatText2 :one +SELECT group_concat(text_val, ':') FROM test +` + +func (q *Queries) GetGroupConcatText2(ctx context.Context) (sql.NullString, error) { + row := q.db.QueryRowContext(ctx, getGroupConcatText2) + var group_concat sql.NullString + err := row.Scan(&group_concat) + return group_concat, err +} + +const getMaxInt = `-- name: GetMaxInt :one +SELECT max(int_val) FROM test +` + +func (q *Queries) GetMaxInt(ctx context.Context) (any, error) { + row := q.db.QueryRowContext(ctx, getMaxInt) + var max any + err := row.Scan(&max) + return max, err +} + +const getMaxText = `-- name: GetMaxText :one +SELECT max(text_val) FROM test +` + +func (q *Queries) GetMaxText(ctx context.Context) (any, error) { + row := q.db.QueryRowContext(ctx, getMaxText) + var max any + err := row.Scan(&max) + return max, err +} + +const getMinInt = `-- name: GetMinInt :one +SELECT min(int_val) FROM test +` + +func (q *Queries) GetMinInt(ctx context.Context) (any, error) { + row := q.db.QueryRowContext(ctx, getMinInt) + var min any + err := row.Scan(&min) + return min, err +} + +const getMinText = `-- name: GetMinText :one +SELECT min(text_val) FROM test +` + +func (q *Queries) GetMinText(ctx context.Context) (any, error) { + row := q.db.QueryRowContext(ctx, getMinText) + var min any + err := row.Scan(&min) + return min, err +} + +const getSumInt = `-- name: GetSumInt :one +SELECT sum(int_val) FROM test +` + +func (q *Queries) GetSumInt(ctx context.Context) (sql.NullFloat64, error) { + row := q.db.QueryRowContext(ctx, getSumInt) + var sum sql.NullFloat64 + err := row.Scan(&sum) + return sum, err +} + +const getSumText = `-- name: GetSumText :one +SELECT sum(text_val) FROM test +` + +func (q *Queries) GetSumText(ctx context.Context) (sql.NullFloat64, error) { + row := q.db.QueryRowContext(ctx, getSumText) + var sum sql.NullFloat64 + err := row.Scan(&sum) + return sum, err +} + +const getTotalInt = `-- name: GetTotalInt :one +SELECT total(int_val) FROM test +` + +func (q *Queries) GetTotalInt(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getTotalInt) + var total float64 + err := row.Scan(&total) + return total, err +} diff --git a/internal/endtoend/testdata/builtins/sqlite/go/db.go b/internal/endtoend/testdata/builtins/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/builtins/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/builtins/sqlite/go/mathfunc.sql.go b/internal/endtoend/testdata/builtins/sqlite/go/mathfunc.sql.go new file mode 100644 index 0000000..152d80a --- /dev/null +++ b/internal/endtoend/testdata/builtins/sqlite/go/mathfunc.sql.go @@ -0,0 +1,329 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: mathfunc.sql + +package querytest + +import ( + "context" +) + +const getAcos = `-- name: GetAcos :one +SELECT acos(1.0) +` + +func (q *Queries) GetAcos(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getAcos) + var acos float64 + err := row.Scan(&acos) + return acos, err +} + +const getAcosh = `-- name: GetAcosh :one +SELECT acosh(1.0) +` + +func (q *Queries) GetAcosh(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getAcosh) + var acosh float64 + err := row.Scan(&acosh) + return acosh, err +} + +const getAsin = `-- name: GetAsin :one +SELECT asin(1.0) +` + +func (q *Queries) GetAsin(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getAsin) + var asin float64 + err := row.Scan(&asin) + return asin, err +} + +const getAsinh = `-- name: GetAsinh :one +SELECT asinh(1.0) +` + +func (q *Queries) GetAsinh(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getAsinh) + var asinh float64 + err := row.Scan(&asinh) + return asinh, err +} + +const getAtan = `-- name: GetAtan :one +SELECT atan(1.0) +` + +func (q *Queries) GetAtan(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getAtan) + var atan float64 + err := row.Scan(&atan) + return atan, err +} + +const getAtan2 = `-- name: GetAtan2 :one +SELECT atan2(1.0, 0.5) +` + +func (q *Queries) GetAtan2(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getAtan2) + var atan2 float64 + err := row.Scan(&atan2) + return atan2, err +} + +const getAtanh = `-- name: GetAtanh :one +SELECT atanh(1.0) +` + +func (q *Queries) GetAtanh(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getAtanh) + var atanh float64 + err := row.Scan(&atanh) + return atanh, err +} + +const getCeil = `-- name: GetCeil :one +SELECT ceil(1.0) +` + +func (q *Queries) GetCeil(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getCeil) + var ceil float64 + err := row.Scan(&ceil) + return ceil, err +} + +const getCeilin = `-- name: GetCeilin :one +SELECT ceiling(1.0) +` + +func (q *Queries) GetCeilin(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getCeilin) + var ceiling float64 + err := row.Scan(&ceiling) + return ceiling, err +} + +const getCos = `-- name: GetCos :one +SELECT cos(1.0) +` + +func (q *Queries) GetCos(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getCos) + var cos float64 + err := row.Scan(&cos) + return cos, err +} + +const getCosh = `-- name: GetCosh :one +SELECT cosh(1.0) +` + +func (q *Queries) GetCosh(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getCosh) + var cosh float64 + err := row.Scan(&cosh) + return cosh, err +} + +const getDegrees = `-- name: GetDegrees :one +SELECT degrees(1.0) +` + +func (q *Queries) GetDegrees(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getDegrees) + var degrees float64 + err := row.Scan(°rees) + return degrees, err +} + +const getExp = `-- name: GetExp :one +SELECT exp(1.0) +` + +func (q *Queries) GetExp(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getExp) + var exp float64 + err := row.Scan(&exp) + return exp, err +} + +const getFloor = `-- name: GetFloor :one +SELECT floor(1.0) +` + +func (q *Queries) GetFloor(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getFloor) + var floor float64 + err := row.Scan(&floor) + return floor, err +} + +const getLn = `-- name: GetLn :one +SELECT ln(1.0) +` + +func (q *Queries) GetLn(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getLn) + var ln float64 + err := row.Scan(&ln) + return ln, err +} + +const getLog = `-- name: GetLog :one +SELECT log(1.0) +` + +func (q *Queries) GetLog(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getLog) + var log float64 + err := row.Scan(&log) + return log, err +} + +const getLog10 = `-- name: GetLog10 :one +SELECT log10(1.0) +` + +func (q *Queries) GetLog10(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getLog10) + var log10 float64 + err := row.Scan(&log10) + return log10, err +} + +const getLog2 = `-- name: GetLog2 :one +SELECT log2(1.0) +` + +func (q *Queries) GetLog2(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getLog2) + var log2 float64 + err := row.Scan(&log2) + return log2, err +} + +const getLogBase = `-- name: GetLogBase :one +SELECT log(1.0, 2.0) +` + +func (q *Queries) GetLogBase(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getLogBase) + var log float64 + err := row.Scan(&log) + return log, err +} + +const getMod = `-- name: GetMod :one +SELECT mod(1, 2) +` + +func (q *Queries) GetMod(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getMod) + var mod float64 + err := row.Scan(&mod) + return mod, err +} + +const getPi = `-- name: GetPi :one +SELECT pi() +` + +func (q *Queries) GetPi(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getPi) + var pi float64 + err := row.Scan(&pi) + return pi, err +} + +const getPow = `-- name: GetPow :one +SELECT pow(1, 2) +` + +func (q *Queries) GetPow(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getPow) + var pow float64 + err := row.Scan(&pow) + return pow, err +} + +const getPower = `-- name: GetPower :one +SELECT power(1, 2) +` + +func (q *Queries) GetPower(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getPower) + var power float64 + err := row.Scan(&power) + return power, err +} + +const getRadians = `-- name: GetRadians :one +SELECT radians(1) +` + +func (q *Queries) GetRadians(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getRadians) + var radians float64 + err := row.Scan(&radians) + return radians, err +} + +const getSin = `-- name: GetSin :one +SELECT sin(1.0) +` + +func (q *Queries) GetSin(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getSin) + var sin float64 + err := row.Scan(&sin) + return sin, err +} + +const getSinh = `-- name: GetSinh :one +SELECT sinh(1.0) +` + +func (q *Queries) GetSinh(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getSinh) + var sinh float64 + err := row.Scan(&sinh) + return sinh, err +} + +const getSqrt = `-- name: GetSqrt :one +SELECT sqrt(1.0) +` + +func (q *Queries) GetSqrt(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getSqrt) + var sqrt float64 + err := row.Scan(&sqrt) + return sqrt, err +} + +const getTan = `-- name: GetTan :one +SELECT tan(1.0) +` + +func (q *Queries) GetTan(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getTan) + var tan float64 + err := row.Scan(&tan) + return tan, err +} + +const getTrunc = `-- name: GetTrunc :one +SELECT trunc(1.0) +` + +func (q *Queries) GetTrunc(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getTrunc) + var trunc float64 + err := row.Scan(&trunc) + return trunc, err +} diff --git a/internal/endtoend/testdata/builtins/sqlite/go/models.go b/internal/endtoend/testdata/builtins/sqlite/go/models.go new file mode 100644 index 0000000..c7e7054 --- /dev/null +++ b/internal/endtoend/testdata/builtins/sqlite/go/models.go @@ -0,0 +1,11 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Test struct { + ID int64 + IntVal int64 + TextVal string +} diff --git a/internal/endtoend/testdata/builtins/sqlite/go/scalarfunc.sql.go b/internal/endtoend/testdata/builtins/sqlite/go/scalarfunc.sql.go new file mode 100644 index 0000000..06ec043 --- /dev/null +++ b/internal/endtoend/testdata/builtins/sqlite/go/scalarfunc.sql.go @@ -0,0 +1,561 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: scalarfunc.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const getAbs = `-- name: GetAbs :one +SELECT abs(int_val) FROM test +` + +func (q *Queries) GetAbs(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getAbs) + var abs float64 + err := row.Scan(&abs) + return abs, err +} + +const getChanges = `-- name: GetChanges :one +SELECT changes() +` + +func (q *Queries) GetChanges(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, getChanges) + var changes int64 + err := row.Scan(&changes) + return changes, err +} + +const getChar1 = `-- name: GetChar1 :one +SELECT char(65) +` + +func (q *Queries) GetChar1(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, getChar1) + var char string + err := row.Scan(&char) + return char, err +} + +const getChar3 = `-- name: GetChar3 :one +SELECT char(65, 66, 67) +` + +func (q *Queries) GetChar3(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, getChar3) + var char string + err := row.Scan(&char) + return char, err +} + +const getCoalesce = `-- name: GetCoalesce :one +SELECT coalesce(NULL, 1, 'test') +` + +func (q *Queries) GetCoalesce(ctx context.Context) (any, error) { + row := q.db.QueryRowContext(ctx, getCoalesce) + var coalesce any + err := row.Scan(&coalesce) + return coalesce, err +} + +const getFormat = `-- name: GetFormat :one +SELECT format('Hello %s', 'world') +` + +func (q *Queries) GetFormat(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, getFormat) + var format string + err := row.Scan(&format) + return format, err +} + +const getGlob = `-- name: GetGlob :one +SELECT glob('a*c', 'abc') +` + +func (q *Queries) GetGlob(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, getGlob) + var glob int64 + err := row.Scan(&glob) + return glob, err +} + +const getHex = `-- name: GetHex :one +SELECT hex(123456) +` + +func (q *Queries) GetHex(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, getHex) + var hex string + err := row.Scan(&hex) + return hex, err +} + +const getIfnull = `-- name: GetIfnull :one +SELECT ifnull(1, 2) +` + +func (q *Queries) GetIfnull(ctx context.Context) (any, error) { + row := q.db.QueryRowContext(ctx, getIfnull) + var ifnull any + err := row.Scan(&ifnull) + return ifnull, err +} + +const getIif = `-- name: GetIif :one +SELECT iif(1, 2, 3) +` + +func (q *Queries) GetIif(ctx context.Context) (any, error) { + row := q.db.QueryRowContext(ctx, getIif) + var iif any + err := row.Scan(&iif) + return iif, err +} + +const getInstr = `-- name: GetInstr :one +SELECT instr('hello', 'l') +` + +func (q *Queries) GetInstr(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, getInstr) + var instr int64 + err := row.Scan(&instr) + return instr, err +} + +const getLastInsertRowID = `-- name: GetLastInsertRowID :one +SELECT last_insert_rowid() +` + +func (q *Queries) GetLastInsertRowID(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, getLastInsertRowID) + var last_insert_rowid int64 + err := row.Scan(&last_insert_rowid) + return last_insert_rowid, err +} + +const getLength = `-- name: GetLength :one +SELECT length('12345') +` + +func (q *Queries) GetLength(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, getLength) + var length int64 + err := row.Scan(&length) + return length, err +} + +const getLike2 = `-- name: GetLike2 :one +SELECT like('%bc%', 'abcd') +` + +func (q *Queries) GetLike2(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, getLike2) + var like int64 + err := row.Scan(&like) + return like, err +} + +const getLike3 = `-- name: GetLike3 :one +SELECT like('$%1%', '%100', '$') +` + +func (q *Queries) GetLike3(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, getLike3) + var like int64 + err := row.Scan(&like) + return like, err +} + +const getLikelihood = `-- name: GetLikelihood :one +SELECT likelihood('12345', 0.5) +` + +func (q *Queries) GetLikelihood(ctx context.Context) (any, error) { + row := q.db.QueryRowContext(ctx, getLikelihood) + var likelihood any + err := row.Scan(&likelihood) + return likelihood, err +} + +const getLikely = `-- name: GetLikely :one +SELECT likely('12345') +` + +func (q *Queries) GetLikely(ctx context.Context) (any, error) { + row := q.db.QueryRowContext(ctx, getLikely) + var likely any + err := row.Scan(&likely) + return likely, err +} + +const getLower = `-- name: GetLower :one +SELECT lower('ABCDE') +` + +func (q *Queries) GetLower(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, getLower) + var lower string + err := row.Scan(&lower) + return lower, err +} + +const getLtrim = `-- name: GetLtrim :one +SELECT ltrim(' ABCDE') +` + +func (q *Queries) GetLtrim(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, getLtrim) + var ltrim string + err := row.Scan(<rim) + return ltrim, err +} + +const getLtrim2 = `-- name: GetLtrim2 :one +SELECT ltrim(':ABCDE', ':') +` + +func (q *Queries) GetLtrim2(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, getLtrim2) + var ltrim string + err := row.Scan(<rim) + return ltrim, err +} + +const getMax3 = `-- name: GetMax3 :one +SELECT max(1, 3, 2) +` + +func (q *Queries) GetMax3(ctx context.Context) (any, error) { + row := q.db.QueryRowContext(ctx, getMax3) + var max any + err := row.Scan(&max) + return max, err +} + +const getMin3 = `-- name: GetMin3 :one +SELECT min(1, 3, 2) +` + +func (q *Queries) GetMin3(ctx context.Context) (any, error) { + row := q.db.QueryRowContext(ctx, getMin3) + var min any + err := row.Scan(&min) + return min, err +} + +const getNullif = `-- name: GetNullif :one +SELECT nullif(1, 2) +` + +func (q *Queries) GetNullif(ctx context.Context) (any, error) { + row := q.db.QueryRowContext(ctx, getNullif) + var nullif any + err := row.Scan(&nullif) + return nullif, err +} + +const getPrintf = `-- name: GetPrintf :one +SELECT printf('Hello %s', 'world') +` + +func (q *Queries) GetPrintf(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, getPrintf) + var printf string + err := row.Scan(&printf) + return printf, err +} + +const getQuote = `-- name: GetQuote :one +SELECT quote(1) +` + +func (q *Queries) GetQuote(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, getQuote) + var quote string + err := row.Scan("e) + return quote, err +} + +const getRandom = `-- name: GetRandom :one +SELECT random() +` + +func (q *Queries) GetRandom(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, getRandom) + var random int64 + err := row.Scan(&random) + return random, err +} + +const getRandomBlob = `-- name: GetRandomBlob :one +SELECT randomblob(16) +` + +func (q *Queries) GetRandomBlob(ctx context.Context) ([]byte, error) { + row := q.db.QueryRowContext(ctx, getRandomBlob) + var randomblob []byte + err := row.Scan(&randomblob) + return randomblob, err +} + +const getReplace = `-- name: GetReplace :one +SELECT replace('abc', 'bc', 'df') +` + +func (q *Queries) GetReplace(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, getReplace) + var replace string + err := row.Scan(&replace) + return replace, err +} + +const getRound = `-- name: GetRound :one +SELECT round(1.1) +` + +func (q *Queries) GetRound(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getRound) + var round float64 + err := row.Scan(&round) + return round, err +} + +const getRound2 = `-- name: GetRound2 :one +SELECT round(1.1, 2) +` + +func (q *Queries) GetRound2(ctx context.Context) (float64, error) { + row := q.db.QueryRowContext(ctx, getRound2) + var round float64 + err := row.Scan(&round) + return round, err +} + +const getRtrim = `-- name: GetRtrim :one +SELECT rtrim('ABCDE ') +` + +func (q *Queries) GetRtrim(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, getRtrim) + var rtrim string + err := row.Scan(&rtrim) + return rtrim, err +} + +const getRtrim2 = `-- name: GetRtrim2 :one +SELECT rtrim('ABCDE:', ':') +` + +func (q *Queries) GetRtrim2(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, getRtrim2) + var rtrim string + err := row.Scan(&rtrim) + return rtrim, err +} + +const getSQLiteCompileOptionGet = `-- name: GetSQLiteCompileOptionGet :one +SELECT sqlite_compileoption_get(1) +` + +func (q *Queries) GetSQLiteCompileOptionGet(ctx context.Context) (sql.NullString, error) { + row := q.db.QueryRowContext(ctx, getSQLiteCompileOptionGet) + var sqlite_compileoption_get sql.NullString + err := row.Scan(&sqlite_compileoption_get) + return sqlite_compileoption_get, err +} + +const getSQLiteCompileOptionUsed = `-- name: GetSQLiteCompileOptionUsed :one +SELECT sqlite_compileoption_used(1) +` + +func (q *Queries) GetSQLiteCompileOptionUsed(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, getSQLiteCompileOptionUsed) + var sqlite_compileoption_used int64 + err := row.Scan(&sqlite_compileoption_used) + return sqlite_compileoption_used, err +} + +const getSQLiteSourceID = `-- name: GetSQLiteSourceID :one +SELECT sqlite_source_id() +` + +func (q *Queries) GetSQLiteSourceID(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, getSQLiteSourceID) + var sqlite_source_id string + err := row.Scan(&sqlite_source_id) + return sqlite_source_id, err +} + +const getSQLiteVersion = `-- name: GetSQLiteVersion :one +SELECT sqlite_version() +` + +func (q *Queries) GetSQLiteVersion(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, getSQLiteVersion) + var sqlite_version string + err := row.Scan(&sqlite_version) + return sqlite_version, err +} + +const getSign = `-- name: GetSign :one +SELECT sign(1) +` + +func (q *Queries) GetSign(ctx context.Context) (sql.NullInt64, error) { + row := q.db.QueryRowContext(ctx, getSign) + var sign sql.NullInt64 + err := row.Scan(&sign) + return sign, err +} + +const getSoundex = `-- name: GetSoundex :one +SELECT soundex('abc') +` + +func (q *Queries) GetSoundex(ctx context.Context) (any, error) { + row := q.db.QueryRowContext(ctx, getSoundex) + var soundex any + err := row.Scan(&soundex) + return soundex, err +} + +const getSubstr2 = `-- name: GetSubstr2 :one +SELECT substr('abcdef', 2) +` + +func (q *Queries) GetSubstr2(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, getSubstr2) + var substr string + err := row.Scan(&substr) + return substr, err +} + +const getSubstr3 = `-- name: GetSubstr3 :one +SELECT substr('abcdef', 1, 2) +` + +func (q *Queries) GetSubstr3(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, getSubstr3) + var substr string + err := row.Scan(&substr) + return substr, err +} + +const getSubstring2 = `-- name: GetSubstring2 :one +SELECT substring('abcdef', 1) +` + +func (q *Queries) GetSubstring2(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, getSubstring2) + var substring string + err := row.Scan(&substring) + return substring, err +} + +const getSusbstring3 = `-- name: GetSusbstring3 :one +SELECT substring('abcdef', 1, 2) +` + +func (q *Queries) GetSusbstring3(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, getSusbstring3) + var substring string + err := row.Scan(&substring) + return substring, err +} + +const getTotalChanges = `-- name: GetTotalChanges :one +SELECT total_changes() +` + +func (q *Queries) GetTotalChanges(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, getTotalChanges) + var total_changes int64 + err := row.Scan(&total_changes) + return total_changes, err +} + +const getTrim = `-- name: GetTrim :one +SELECT trim(' ABCDE ') +` + +func (q *Queries) GetTrim(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, getTrim) + var trim string + err := row.Scan(&trim) + return trim, err +} + +const getTrim2 = `-- name: GetTrim2 :one +SELECT trim(':ABCDE:', ':') +` + +func (q *Queries) GetTrim2(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, getTrim2) + var trim string + err := row.Scan(&trim) + return trim, err +} + +const getTypeof = `-- name: GetTypeof :one +SELECT typeof('ABCDE') +` + +func (q *Queries) GetTypeof(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, getTypeof) + var typeof string + err := row.Scan(&typeof) + return typeof, err +} + +const getUnicode = `-- name: GetUnicode :one +SELECT unicode('A') +` + +func (q *Queries) GetUnicode(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, getUnicode) + var unicode int64 + err := row.Scan(&unicode) + return unicode, err +} + +const getUnlikely = `-- name: GetUnlikely :one +SELECT unlikely('12345') +` + +func (q *Queries) GetUnlikely(ctx context.Context) (any, error) { + row := q.db.QueryRowContext(ctx, getUnlikely) + var unlikely any + err := row.Scan(&unlikely) + return unlikely, err +} + +const getUpper = `-- name: GetUpper :one +SELECT upper('abcde') +` + +func (q *Queries) GetUpper(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, getUpper) + var upper string + err := row.Scan(&upper) + return upper, err +} + +const getZeroblob = `-- name: GetZeroblob :one +SELECT zeroblob(16) +` + +func (q *Queries) GetZeroblob(ctx context.Context) ([]byte, error) { + row := q.db.QueryRowContext(ctx, getZeroblob) + var zeroblob []byte + err := row.Scan(&zeroblob) + return zeroblob, err +} diff --git a/internal/endtoend/testdata/builtins/sqlite/queries/aggfunc.sql b/internal/endtoend/testdata/builtins/sqlite/queries/aggfunc.sql new file mode 100644 index 0000000..5af32cd --- /dev/null +++ b/internal/endtoend/testdata/builtins/sqlite/queries/aggfunc.sql @@ -0,0 +1,41 @@ +-- name: GetAvg :one +SELECT avg(int_val) FROM test; + +-- name: GetCount :one +SELECT count(*) FROM test; + +-- name: GetCountId :one +SELECT count(id) FROM test; + +-- name: GetGroupConcatInt :one +SELECT group_concat(int_val) FROM test; + +-- name: GetGroupConcatInt2 :one +SELECT group_concat(1, ':') FROM test; + +-- name: GetGroupConcatText :one +SELECT group_concat(text_val) FROM test; + +-- name: GetGroupConcatText2 :one +SELECT group_concat(text_val, ':') FROM test; + +-- name: GetMaxInt :one +SELECT max(int_val) FROM test; + +-- name: GetMaxText :one +SELECT max(text_val) FROM test; + +-- name: GetMinInt :one +SELECT min(int_val) FROM test; + +-- name: GetMinText :one +SELECT min(text_val) FROM test; + +-- name: GetSumInt :one +SELECT sum(int_val) FROM test; + +-- name: GetSumText :one +SELECT sum(text_val) FROM test; + +-- name: GetTotalInt :one +SELECT total(int_val) FROM test; diff --git a/internal/endtoend/testdata/builtins/sqlite/queries/mathfunc.sql b/internal/endtoend/testdata/builtins/sqlite/queries/mathfunc.sql new file mode 100644 index 0000000..cf3e2f5 --- /dev/null +++ b/internal/endtoend/testdata/builtins/sqlite/queries/mathfunc.sql @@ -0,0 +1,86 @@ +-- name: GetAcos :one +SELECT acos(1.0); + +-- name: GetAcosh :one +SELECT acosh(1.0); + +-- name: GetAsin :one +SELECT asin(1.0); + +-- name: GetAsinh :one +SELECT asinh(1.0); + +-- name: GetAtan :one +SELECT atan(1.0); + +-- name: GetAtan2 :one +SELECT atan2(1.0, 0.5); + +-- name: GetAtanh :one +SELECT atanh(1.0); + +-- name: GetCeil :one +SELECT ceil(1.0); + +-- name: GetCeilin :one +SELECT ceiling(1.0); + +-- name: GetCos :one +SELECT cos(1.0); + +-- name: GetCosh :one +SELECT cosh(1.0); + +-- name: GetDegrees :one +SELECT degrees(1.0); + +-- name: GetExp :one +SELECT exp(1.0); + +-- name: GetFloor :one +SELECT floor(1.0); + +-- name: GetLn :one +SELECT ln(1.0); + +-- name: GetLog :one +SELECT log(1.0); + +-- name: GetLog10 :one +SELECT log10(1.0); + +-- name: GetLogBase :one +SELECT log(1.0, 2.0); + +-- name: GetLog2 :one +SELECT log2(1.0); + +-- name: GetMod :one +SELECT mod(1, 2); + +-- name: GetPi :one +SELECT pi(); + +-- name: GetPow :one +SELECT pow(1, 2); + +-- name: GetPower :one +SELECT power(1, 2); + +-- name: GetRadians :one +SELECT radians(1); + +-- name: GetSin :one +SELECT sin(1.0); + +-- name: GetSinh :one +SELECT sinh(1.0); + +-- name: GetSqrt :one +SELECT sqrt(1.0); + +-- name: GetTan :one +SELECT tan(1.0); + +-- name: GetTrunc :one +SELECT trunc(1.0); diff --git a/internal/endtoend/testdata/builtins/sqlite/queries/scalarfunc.sql b/internal/endtoend/testdata/builtins/sqlite/queries/scalarfunc.sql new file mode 100644 index 0000000..571cdb9 --- /dev/null +++ b/internal/endtoend/testdata/builtins/sqlite/queries/scalarfunc.sql @@ -0,0 +1,149 @@ +-- name: GetAbs :one +SELECT abs(int_val) FROM test; + +-- name: GetChanges :one +SELECT changes(); + +-- name: GetChar1 :one +SELECT char(65); + +-- name: GetChar3 :one +SELECT char(65, 66, 67); + +-- name: GetCoalesce :one +SELECT coalesce(NULL, 1, 'test'); + +-- name: GetFormat :one +SELECT format('Hello %s', 'world'); + +-- name: GetGlob :one +SELECT glob('a*c', 'abc'); + +-- name: GetHex :one +SELECT hex(123456); + +-- name: GetIfnull :one +SELECT ifnull(1, 2); + +-- name: GetIif :one +SELECT iif(1, 2, 3); + +-- name: GetLastInsertRowID :one +SELECT last_insert_rowid(); + +-- name: GetInstr :one +SELECT instr('hello', 'l'); + +-- name: GetLength :one +SELECT length('12345'); + +-- name: GetLike2 :one +SELECT like('%bc%', 'abcd'); + +-- name: GetLike3 :one +SELECT like('$%1%', '%100', '$'); + +-- name: GetLikelihood :one +SELECT likelihood('12345', 0.5); + +-- name: GetLikely :one +SELECT likely('12345'); + +-- name: GetLower :one +SELECT lower('ABCDE'); + +-- name: GetLtrim :one +SELECT ltrim(' ABCDE'); + +-- name: GetLtrim2 :one +SELECT ltrim(':ABCDE', ':'); + +-- name: GetMax3 :one +SELECT max(1, 3, 2); + +-- name: GetMin3 :one +SELECT min(1, 3, 2); + +-- name: GetNullif :one +SELECT nullif(1, 2); + +-- name: GetPrintf :one +SELECT printf('Hello %s', 'world'); + +-- name: GetQuote :one +SELECT quote(1); + +-- name: GetRandom :one +SELECT random(); + +-- name: GetRandomBlob :one +SELECT randomblob(16); + +-- name: GetRound :one +SELECT round(1.1); + +-- name: GetRound2 :one +SELECT round(1.1, 2); + +-- name: GetReplace :one +SELECT replace('abc', 'bc', 'df'); + +-- name: GetRtrim :one +SELECT rtrim('ABCDE '); + +-- name: GetRtrim2 :one +SELECT rtrim('ABCDE:', ':'); + +-- name: GetSign :one +SELECT sign(1); + +-- name: GetSoundex :one +SELECT soundex('abc'); + +-- name: GetSQLiteCompileOptionGet :one +SELECT sqlite_compileoption_get(1); + +-- name: GetSQLiteCompileOptionUsed :one +SELECT sqlite_compileoption_used(1); + +-- name: GetSQLiteSourceID :one +SELECT sqlite_source_id(); + +-- name: GetSQLiteVersion :one +SELECT sqlite_version(); + +-- name: GetSubstr3 :one +SELECT substr('abcdef', 1, 2); + +-- name: GetSubstr2 :one +SELECT substr('abcdef', 2); + +-- name: GetSusbstring3 :one +SELECT substring('abcdef', 1, 2); + +-- name: GetSubstring2 :one +SELECT substring('abcdef', 1); + +-- name: GetTotalChanges :one +SELECT total_changes(); + +-- name: GetTrim :one +SELECT trim(' ABCDE '); + +-- name: GetTrim2 :one +SELECT trim(':ABCDE:', ':'); + +-- name: GetTypeof :one +SELECT typeof('ABCDE'); + +-- name: GetUnicode :one +SELECT unicode('A'); + +-- name: GetUnlikely :one +SELECT unlikely('12345'); + +-- name: GetUpper :one +SELECT upper('abcde'); + +-- name: GetZeroblob :one +SELECT zeroblob(16); diff --git a/internal/endtoend/testdata/builtins/sqlite/schema.sql b/internal/endtoend/testdata/builtins/sqlite/schema.sql new file mode 100644 index 0000000..1c3d00e --- /dev/null +++ b/internal/endtoend/testdata/builtins/sqlite/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE test ( + id integer NOT NULL PRIMARY KEY AUTOINCREMENT, + int_val integer NOT NULL, + text_val text NOT NULL +); + \ No newline at end of file diff --git a/internal/endtoend/testdata/builtins/sqlite/sqlc.json b/internal/endtoend/testdata/builtins/sqlite/sqlc.json new file mode 100644 index 0000000..ca46447 --- /dev/null +++ b/internal/endtoend/testdata/builtins/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "queries/", + "engine": "sqlite" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/case_named_params/mysql/go/db.go b/internal/endtoend/testdata/case_named_params/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/case_named_params/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/case_named_params/mysql/go/models.go b/internal/endtoend/testdata/case_named_params/mysql/go/models.go new file mode 100644 index 0000000..9fa3edb --- /dev/null +++ b/internal/endtoend/testdata/case_named_params/mysql/go/models.go @@ -0,0 +1,17 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Username sql.NullString + Email sql.NullString + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/case_named_params/mysql/go/query.sql.go b/internal/endtoend/testdata/case_named_params/mysql/go/query.sql.go new file mode 100644 index 0000000..638b3ac --- /dev/null +++ b/internal/endtoend/testdata/case_named_params/mysql/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const listAuthors = `-- name: ListAuthors :one +SELECT id, username, email, name, bio +FROM authors +WHERE email = CASE WHEN ? = '' then NULL else ? END + OR username = CASE WHEN ? = '' then NULL else ? END +LIMIT 1 +` + +type ListAuthorsParams struct { + Email sql.NullString + Username sql.NullString +} + +func (q *Queries) ListAuthors(ctx context.Context, arg ListAuthorsParams) (Author, error) { + row := q.db.QueryRowContext(ctx, listAuthors, + arg.Email, + arg.Email, + arg.Username, + arg.Username, + ) + var i Author + err := row.Scan( + &i.ID, + &i.Username, + &i.Email, + &i.Name, + &i.Bio, + ) + return i, err +} diff --git a/internal/endtoend/testdata/case_named_params/mysql/query.sql b/internal/endtoend/testdata/case_named_params/mysql/query.sql new file mode 100644 index 0000000..523c946 --- /dev/null +++ b/internal/endtoend/testdata/case_named_params/mysql/query.sql @@ -0,0 +1,6 @@ +-- name: ListAuthors :one +SELECT * +FROM authors +WHERE email = CASE WHEN sqlc.arg(email) = '' then NULL else sqlc.arg(email) END + OR username = CASE WHEN sqlc.arg(username) = '' then NULL else sqlc.arg(username) END +LIMIT 1; diff --git a/internal/endtoend/testdata/case_named_params/mysql/schema.sql b/internal/endtoend/testdata/case_named_params/mysql/schema.sql new file mode 100644 index 0000000..5e2bcfa --- /dev/null +++ b/internal/endtoend/testdata/case_named_params/mysql/schema.sql @@ -0,0 +1,12 @@ +-- https://github.com/sqlc-dev/sqlc/issues/1195 + +CREATE TABLE authors ( + id BIGINT PRIMARY KEY, + username VARCHAR(10) NULL, + email VARCHAR(10) NULL, + name TEXT NOT NULL, + bio TEXT, + UNIQUE KEY idx_username (username), + UNIQUE KEY ids_email (email) +); + diff --git a/internal/endtoend/testdata/case_named_params/mysql/sqlc.json b/internal/endtoend/testdata/case_named_params/mysql/sqlc.json new file mode 100644 index 0000000..0390f67 --- /dev/null +++ b/internal/endtoend/testdata/case_named_params/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/case_named_params/postgresql/go/db.go b/internal/endtoend/testdata/case_named_params/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/case_named_params/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/case_named_params/postgresql/go/models.go b/internal/endtoend/testdata/case_named_params/postgresql/go/models.go new file mode 100644 index 0000000..9fa3edb --- /dev/null +++ b/internal/endtoend/testdata/case_named_params/postgresql/go/models.go @@ -0,0 +1,17 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Username sql.NullString + Email sql.NullString + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/case_named_params/postgresql/go/query.sql.go b/internal/endtoend/testdata/case_named_params/postgresql/go/query.sql.go new file mode 100644 index 0000000..62c41ca --- /dev/null +++ b/internal/endtoend/testdata/case_named_params/postgresql/go/query.sql.go @@ -0,0 +1,36 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listAuthors = `-- name: ListAuthors :one +SELECT id, username, email, name, bio +FROM authors +WHERE email = CASE WHEN $1::text = '' then NULL else $1::text END + OR username = CASE WHEN $2::text = '' then NULL else $2::text END +LIMIT 1 +` + +type ListAuthorsParams struct { + Email string + Username string +} + +func (q *Queries) ListAuthors(ctx context.Context, arg ListAuthorsParams) (Author, error) { + row := q.db.QueryRowContext(ctx, listAuthors, arg.Email, arg.Username) + var i Author + err := row.Scan( + &i.ID, + &i.Username, + &i.Email, + &i.Name, + &i.Bio, + ) + return i, err +} diff --git a/internal/endtoend/testdata/case_named_params/postgresql/query.sql b/internal/endtoend/testdata/case_named_params/postgresql/query.sql new file mode 100644 index 0000000..d677a6f --- /dev/null +++ b/internal/endtoend/testdata/case_named_params/postgresql/query.sql @@ -0,0 +1,6 @@ +-- name: ListAuthors :one +SELECT * +FROM authors +WHERE email = CASE WHEN sqlc.arg(email)::text = '' then NULL else sqlc.arg(email)::text END + OR username = CASE WHEN sqlc.arg(username)::text = '' then NULL else sqlc.arg(username)::text END +LIMIT 1; diff --git a/internal/endtoend/testdata/case_named_params/postgresql/schema.sql b/internal/endtoend/testdata/case_named_params/postgresql/schema.sql new file mode 100644 index 0000000..c9b66c8 --- /dev/null +++ b/internal/endtoend/testdata/case_named_params/postgresql/schema.sql @@ -0,0 +1,10 @@ +-- https://github.com/sqlc-dev/sqlc/issues/1195 + +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + username TEXT NULL, + email TEXT NULL, + name TEXT NOT NULL, + bio TEXT +); + diff --git a/internal/endtoend/testdata/case_named_params/postgresql/sqlc.json b/internal/endtoend/testdata/case_named_params/postgresql/sqlc.json new file mode 100644 index 0000000..a590361 --- /dev/null +++ b/internal/endtoend/testdata/case_named_params/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/case_named_params/sqlite/go/db.go b/internal/endtoend/testdata/case_named_params/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/case_named_params/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/case_named_params/sqlite/go/models.go b/internal/endtoend/testdata/case_named_params/sqlite/go/models.go new file mode 100644 index 0000000..9fa3edb --- /dev/null +++ b/internal/endtoend/testdata/case_named_params/sqlite/go/models.go @@ -0,0 +1,17 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Username sql.NullString + Email sql.NullString + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/case_named_params/sqlite/go/query.sql.go b/internal/endtoend/testdata/case_named_params/sqlite/go/query.sql.go new file mode 100644 index 0000000..318977f --- /dev/null +++ b/internal/endtoend/testdata/case_named_params/sqlite/go/query.sql.go @@ -0,0 +1,36 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listAuthors = `-- name: ListAuthors :one +SELECT id, username, email, name, bio +FROM authors +WHERE email = CASE WHEN ?1 = '' then NULL else ?1 END + OR username = CASE WHEN ?2 = '' then NULL else ?2 END +LIMIT 1 +` + +type ListAuthorsParams struct { + Email any + Username any +} + +func (q *Queries) ListAuthors(ctx context.Context, arg ListAuthorsParams) (Author, error) { + row := q.db.QueryRowContext(ctx, listAuthors, arg.Email, arg.Username) + var i Author + err := row.Scan( + &i.ID, + &i.Username, + &i.Email, + &i.Name, + &i.Bio, + ) + return i, err +} diff --git a/internal/endtoend/testdata/case_named_params/sqlite/query.sql b/internal/endtoend/testdata/case_named_params/sqlite/query.sql new file mode 100644 index 0000000..39d9909 --- /dev/null +++ b/internal/endtoend/testdata/case_named_params/sqlite/query.sql @@ -0,0 +1,6 @@ +-- name: ListAuthors :one +SELECT * +FROM authors +WHERE email = CASE WHEN sqlc.arg(email) = '' then NULL else sqlc.arg(email) END + OR username = CASE WHEN sqlc.arg(username) = '' then NULL else sqlc.arg(username) END +LIMIT 1; diff --git a/internal/endtoend/testdata/case_named_params/sqlite/schema.sql b/internal/endtoend/testdata/case_named_params/sqlite/schema.sql new file mode 100644 index 0000000..0d6facc --- /dev/null +++ b/internal/endtoend/testdata/case_named_params/sqlite/schema.sql @@ -0,0 +1,8 @@ +CREATE TABLE authors ( + id INTEGER PRIMARY KEY, + username TEXT NULL, + email TEXT NULL, + name TEXT NOT NULL, + bio TEXT +); + diff --git a/internal/endtoend/testdata/case_named_params/sqlite/sqlc.json b/internal/endtoend/testdata/case_named_params/sqlite/sqlc.json new file mode 100644 index 0000000..95b9cd0 --- /dev/null +++ b/internal/endtoend/testdata/case_named_params/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/case_sensitive/sqlite/go/db.go b/internal/endtoend/testdata/case_sensitive/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/case_sensitive/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/case_sensitive/sqlite/go/models.go b/internal/endtoend/testdata/case_sensitive/sqlite/go/models.go new file mode 100644 index 0000000..7954f73 --- /dev/null +++ b/internal/endtoend/testdata/case_sensitive/sqlite/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Contact struct { + Pid sql.NullString + Customername sql.NullString +} diff --git a/internal/endtoend/testdata/case_sensitive/sqlite/go/query.sql.go b/internal/endtoend/testdata/case_sensitive/sqlite/go/query.sql.go new file mode 100644 index 0000000..a1c5a53 --- /dev/null +++ b/internal/endtoend/testdata/case_sensitive/sqlite/go/query.sql.go @@ -0,0 +1,29 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const insertContact = `-- name: InsertContact :exec +INSERT INTO contacts ( + pid, + customername +) +VALUES (?, ?) +` + +type InsertContactParams struct { + Pid sql.NullString + Customername sql.NullString +} + +func (q *Queries) InsertContact(ctx context.Context, arg InsertContactParams) error { + _, err := q.db.ExecContext(ctx, insertContact, arg.Pid, arg.Customername) + return err +} diff --git a/internal/endtoend/testdata/case_sensitive/sqlite/query.sql b/internal/endtoend/testdata/case_sensitive/sqlite/query.sql new file mode 100644 index 0000000..20dafb2 --- /dev/null +++ b/internal/endtoend/testdata/case_sensitive/sqlite/query.sql @@ -0,0 +1,6 @@ +-- name: InsertContact :exec +INSERT INTO contacts ( + pid, + customername +) +VALUES (?, ?); diff --git a/internal/endtoend/testdata/case_sensitive/sqlite/schema.sql b/internal/endtoend/testdata/case_sensitive/sqlite/schema.sql new file mode 100644 index 0000000..af6e113 --- /dev/null +++ b/internal/endtoend/testdata/case_sensitive/sqlite/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE contacts ( + pid TEXT, + CustomerName TEXT +); + diff --git a/internal/endtoend/testdata/case_sensitive/sqlite/sqlc.json b/internal/endtoend/testdata/case_sensitive/sqlite/sqlc.json new file mode 100644 index 0000000..99b3b5f --- /dev/null +++ b/internal/endtoend/testdata/case_sensitive/sqlite/sqlc.json @@ -0,0 +1 @@ +{"version": "1", "packages": [{"path": "go", "engine": "sqlite", "schema": "schema.sql", "queries": "query.sql", "name": "querytest"}]} \ No newline at end of file diff --git a/internal/endtoend/testdata/case_stmt_bool/pgx/v4/go/db.go b/internal/endtoend/testdata/case_stmt_bool/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/case_stmt_bool/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/case_stmt_bool/pgx/v4/go/models.go b/internal/endtoend/testdata/case_stmt_bool/pgx/v4/go/models.go new file mode 100644 index 0000000..e954fe1 --- /dev/null +++ b/internal/endtoend/testdata/case_stmt_bool/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + ID string +} diff --git a/internal/endtoend/testdata/case_stmt_bool/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/case_stmt_bool/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..247c97e --- /dev/null +++ b/internal/endtoend/testdata/case_stmt_bool/pgx/v4/go/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const caseStatementBoolean = `-- name: CaseStatementBoolean :many +SELECT CASE + WHEN id = $1 THEN true + ELSE false +END is_one +FROM foo +` + +func (q *Queries) CaseStatementBoolean(ctx context.Context, id string) ([]bool, error) { + rows, err := q.db.Query(ctx, caseStatementBoolean, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var is_one bool + if err := rows.Scan(&is_one); err != nil { + return nil, err + } + items = append(items, is_one) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/case_stmt_bool/pgx/v4/query.sql b/internal/endtoend/testdata/case_stmt_bool/pgx/v4/query.sql new file mode 100644 index 0000000..604393b --- /dev/null +++ b/internal/endtoend/testdata/case_stmt_bool/pgx/v4/query.sql @@ -0,0 +1,6 @@ +-- name: CaseStatementBoolean :many +SELECT CASE + WHEN id = $1 THEN true + ELSE false +END is_one +FROM foo; diff --git a/internal/endtoend/testdata/case_stmt_bool/pgx/v4/schema.sql b/internal/endtoend/testdata/case_stmt_bool/pgx/v4/schema.sql new file mode 100644 index 0000000..1576c81 --- /dev/null +++ b/internal/endtoend/testdata/case_stmt_bool/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (id text not null); + diff --git a/internal/endtoend/testdata/case_stmt_bool/pgx/v4/sqlc.json b/internal/endtoend/testdata/case_stmt_bool/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/case_stmt_bool/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/case_stmt_bool/pgx/v5/go/db.go b/internal/endtoend/testdata/case_stmt_bool/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/case_stmt_bool/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/case_stmt_bool/pgx/v5/go/models.go b/internal/endtoend/testdata/case_stmt_bool/pgx/v5/go/models.go new file mode 100644 index 0000000..e954fe1 --- /dev/null +++ b/internal/endtoend/testdata/case_stmt_bool/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + ID string +} diff --git a/internal/endtoend/testdata/case_stmt_bool/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/case_stmt_bool/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..247c97e --- /dev/null +++ b/internal/endtoend/testdata/case_stmt_bool/pgx/v5/go/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const caseStatementBoolean = `-- name: CaseStatementBoolean :many +SELECT CASE + WHEN id = $1 THEN true + ELSE false +END is_one +FROM foo +` + +func (q *Queries) CaseStatementBoolean(ctx context.Context, id string) ([]bool, error) { + rows, err := q.db.Query(ctx, caseStatementBoolean, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var is_one bool + if err := rows.Scan(&is_one); err != nil { + return nil, err + } + items = append(items, is_one) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/case_stmt_bool/pgx/v5/query.sql b/internal/endtoend/testdata/case_stmt_bool/pgx/v5/query.sql new file mode 100644 index 0000000..604393b --- /dev/null +++ b/internal/endtoend/testdata/case_stmt_bool/pgx/v5/query.sql @@ -0,0 +1,6 @@ +-- name: CaseStatementBoolean :many +SELECT CASE + WHEN id = $1 THEN true + ELSE false +END is_one +FROM foo; diff --git a/internal/endtoend/testdata/case_stmt_bool/pgx/v5/schema.sql b/internal/endtoend/testdata/case_stmt_bool/pgx/v5/schema.sql new file mode 100644 index 0000000..1576c81 --- /dev/null +++ b/internal/endtoend/testdata/case_stmt_bool/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (id text not null); + diff --git a/internal/endtoend/testdata/case_stmt_bool/pgx/v5/sqlc.json b/internal/endtoend/testdata/case_stmt_bool/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/case_stmt_bool/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/case_stmt_bool/stdlib/go/db.go b/internal/endtoend/testdata/case_stmt_bool/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/case_stmt_bool/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/case_stmt_bool/stdlib/go/models.go b/internal/endtoend/testdata/case_stmt_bool/stdlib/go/models.go new file mode 100644 index 0000000..e954fe1 --- /dev/null +++ b/internal/endtoend/testdata/case_stmt_bool/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + ID string +} diff --git a/internal/endtoend/testdata/case_stmt_bool/stdlib/go/query.sql.go b/internal/endtoend/testdata/case_stmt_bool/stdlib/go/query.sql.go new file mode 100644 index 0000000..2799614 --- /dev/null +++ b/internal/endtoend/testdata/case_stmt_bool/stdlib/go/query.sql.go @@ -0,0 +1,41 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const caseStatementBoolean = `-- name: CaseStatementBoolean :many +SELECT CASE + WHEN id = $1 THEN true + ELSE false +END is_one +FROM foo +` + +func (q *Queries) CaseStatementBoolean(ctx context.Context, id string) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, caseStatementBoolean, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var is_one bool + if err := rows.Scan(&is_one); err != nil { + return nil, err + } + items = append(items, is_one) + } + 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/case_stmt_bool/stdlib/query.sql b/internal/endtoend/testdata/case_stmt_bool/stdlib/query.sql new file mode 100644 index 0000000..604393b --- /dev/null +++ b/internal/endtoend/testdata/case_stmt_bool/stdlib/query.sql @@ -0,0 +1,6 @@ +-- name: CaseStatementBoolean :many +SELECT CASE + WHEN id = $1 THEN true + ELSE false +END is_one +FROM foo; diff --git a/internal/endtoend/testdata/case_stmt_bool/stdlib/schema.sql b/internal/endtoend/testdata/case_stmt_bool/stdlib/schema.sql new file mode 100644 index 0000000..1576c81 --- /dev/null +++ b/internal/endtoend/testdata/case_stmt_bool/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (id text not null); + diff --git a/internal/endtoend/testdata/case_stmt_bool/stdlib/sqlc.json b/internal/endtoend/testdata/case_stmt_bool/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/case_stmt_bool/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/case_text/pgx/v4/go/db.go b/internal/endtoend/testdata/case_text/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/case_text/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/case_text/pgx/v4/go/models.go b/internal/endtoend/testdata/case_text/pgx/v4/go/models.go new file mode 100644 index 0000000..e954fe1 --- /dev/null +++ b/internal/endtoend/testdata/case_text/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + ID string +} diff --git a/internal/endtoend/testdata/case_text/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/case_text/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..20483db --- /dev/null +++ b/internal/endtoend/testdata/case_text/pgx/v4/go/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const caseStatementText = `-- name: CaseStatementText :many +SELECT CASE + WHEN id = $1 THEN 'foo' + ELSE 'bar' +END is_one +FROM foo +` + +func (q *Queries) CaseStatementText(ctx context.Context, id string) ([]string, error) { + rows, err := q.db.Query(ctx, caseStatementText, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var is_one string + if err := rows.Scan(&is_one); err != nil { + return nil, err + } + items = append(items, is_one) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/case_text/pgx/v4/query.sql b/internal/endtoend/testdata/case_text/pgx/v4/query.sql new file mode 100644 index 0000000..eff5ec2 --- /dev/null +++ b/internal/endtoend/testdata/case_text/pgx/v4/query.sql @@ -0,0 +1,6 @@ +-- name: CaseStatementText :many +SELECT CASE + WHEN id = $1 THEN 'foo' + ELSE 'bar' +END is_one +FROM foo; diff --git a/internal/endtoend/testdata/case_text/pgx/v4/schema.sql b/internal/endtoend/testdata/case_text/pgx/v4/schema.sql new file mode 100644 index 0000000..1576c81 --- /dev/null +++ b/internal/endtoend/testdata/case_text/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (id text not null); + diff --git a/internal/endtoend/testdata/case_text/pgx/v4/sqlc.json b/internal/endtoend/testdata/case_text/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/case_text/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/case_text/pgx/v5/go/db.go b/internal/endtoend/testdata/case_text/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/case_text/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/case_text/pgx/v5/go/models.go b/internal/endtoend/testdata/case_text/pgx/v5/go/models.go new file mode 100644 index 0000000..e954fe1 --- /dev/null +++ b/internal/endtoend/testdata/case_text/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + ID string +} diff --git a/internal/endtoend/testdata/case_text/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/case_text/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..20483db --- /dev/null +++ b/internal/endtoend/testdata/case_text/pgx/v5/go/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const caseStatementText = `-- name: CaseStatementText :many +SELECT CASE + WHEN id = $1 THEN 'foo' + ELSE 'bar' +END is_one +FROM foo +` + +func (q *Queries) CaseStatementText(ctx context.Context, id string) ([]string, error) { + rows, err := q.db.Query(ctx, caseStatementText, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var is_one string + if err := rows.Scan(&is_one); err != nil { + return nil, err + } + items = append(items, is_one) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/case_text/pgx/v5/query.sql b/internal/endtoend/testdata/case_text/pgx/v5/query.sql new file mode 100644 index 0000000..eff5ec2 --- /dev/null +++ b/internal/endtoend/testdata/case_text/pgx/v5/query.sql @@ -0,0 +1,6 @@ +-- name: CaseStatementText :many +SELECT CASE + WHEN id = $1 THEN 'foo' + ELSE 'bar' +END is_one +FROM foo; diff --git a/internal/endtoend/testdata/case_text/pgx/v5/schema.sql b/internal/endtoend/testdata/case_text/pgx/v5/schema.sql new file mode 100644 index 0000000..1576c81 --- /dev/null +++ b/internal/endtoend/testdata/case_text/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (id text not null); + diff --git a/internal/endtoend/testdata/case_text/pgx/v5/sqlc.json b/internal/endtoend/testdata/case_text/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/case_text/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/case_text/stdlib/go/db.go b/internal/endtoend/testdata/case_text/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/case_text/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/case_text/stdlib/go/models.go b/internal/endtoend/testdata/case_text/stdlib/go/models.go new file mode 100644 index 0000000..e954fe1 --- /dev/null +++ b/internal/endtoend/testdata/case_text/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + ID string +} diff --git a/internal/endtoend/testdata/case_text/stdlib/go/query.sql.go b/internal/endtoend/testdata/case_text/stdlib/go/query.sql.go new file mode 100644 index 0000000..a001773 --- /dev/null +++ b/internal/endtoend/testdata/case_text/stdlib/go/query.sql.go @@ -0,0 +1,41 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const caseStatementText = `-- name: CaseStatementText :many +SELECT CASE + WHEN id = $1 THEN 'foo' + ELSE 'bar' +END is_one +FROM foo +` + +func (q *Queries) CaseStatementText(ctx context.Context, id string) ([]string, error) { + rows, err := q.db.QueryContext(ctx, caseStatementText, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var is_one string + if err := rows.Scan(&is_one); err != nil { + return nil, err + } + items = append(items, is_one) + } + 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/case_text/stdlib/query.sql b/internal/endtoend/testdata/case_text/stdlib/query.sql new file mode 100644 index 0000000..eff5ec2 --- /dev/null +++ b/internal/endtoend/testdata/case_text/stdlib/query.sql @@ -0,0 +1,6 @@ +-- name: CaseStatementText :many +SELECT CASE + WHEN id = $1 THEN 'foo' + ELSE 'bar' +END is_one +FROM foo; diff --git a/internal/endtoend/testdata/case_text/stdlib/schema.sql b/internal/endtoend/testdata/case_text/stdlib/schema.sql new file mode 100644 index 0000000..1576c81 --- /dev/null +++ b/internal/endtoend/testdata/case_text/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (id text not null); + diff --git a/internal/endtoend/testdata/case_text/stdlib/sqlc.json b/internal/endtoend/testdata/case_text/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/case_text/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/case_value_param/issue.md b/internal/endtoend/testdata/case_value_param/issue.md new file mode 100644 index 0000000..c8ac2fa --- /dev/null +++ b/internal/endtoend/testdata/case_value_param/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/2847 diff --git a/internal/endtoend/testdata/case_value_param/mysql/go/db.go b/internal/endtoend/testdata/case_value_param/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/case_value_param/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/case_value_param/mysql/go/models.go b/internal/endtoend/testdata/case_value_param/mysql/go/models.go new file mode 100644 index 0000000..dcf6db9 --- /dev/null +++ b/internal/endtoend/testdata/case_value_param/mysql/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Testing struct { + ID int32 + Value sql.NullString +} diff --git a/internal/endtoend/testdata/case_value_param/mysql/go/query.sql.go b/internal/endtoend/testdata/case_value_param/mysql/go/query.sql.go new file mode 100644 index 0000000..b98b3ce --- /dev/null +++ b/internal/endtoend/testdata/case_value_param/mysql/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const update = `-- name: Update :exec +UPDATE testing +SET value = CASE ? WHEN true THEN 'Hello' WHEN false THEN 'Goodbye' ELSE value END +` + +func (q *Queries) Update(ctx context.Context, value sql.NullString) error { + _, err := q.db.ExecContext(ctx, update, value) + return err +} diff --git a/internal/endtoend/testdata/case_value_param/mysql/query.sql b/internal/endtoend/testdata/case_value_param/mysql/query.sql new file mode 100644 index 0000000..2c4e1f9 --- /dev/null +++ b/internal/endtoend/testdata/case_value_param/mysql/query.sql @@ -0,0 +1,3 @@ +-- name: Update :exec +UPDATE testing +SET value = CASE ? WHEN true THEN 'Hello' WHEN false THEN 'Goodbye' ELSE value END; diff --git a/internal/endtoend/testdata/case_value_param/mysql/schema.sql b/internal/endtoend/testdata/case_value_param/mysql/schema.sql new file mode 100644 index 0000000..556ca0b --- /dev/null +++ b/internal/endtoend/testdata/case_value_param/mysql/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE testing ( + id int PRIMARY KEY, + value text +); diff --git a/internal/endtoend/testdata/case_value_param/mysql/sqlc.yaml b/internal/endtoend/testdata/case_value_param/mysql/sqlc.yaml new file mode 100644 index 0000000..b843ef5 --- /dev/null +++ b/internal/endtoend/testdata/case_value_param/mysql/sqlc.yaml @@ -0,0 +1,9 @@ +version: "2" +sql: + - engine: "mysql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" diff --git a/internal/endtoend/testdata/case_value_param/postgresql/exec.json b/internal/endtoend/testdata/case_value_param/postgresql/exec.json new file mode 100644 index 0000000..97f81fb --- /dev/null +++ b/internal/endtoend/testdata/case_value_param/postgresql/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/case_value_param/postgresql/go/db.go b/internal/endtoend/testdata/case_value_param/postgresql/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/case_value_param/postgresql/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/case_value_param/postgresql/go/models.go b/internal/endtoend/testdata/case_value_param/postgresql/go/models.go new file mode 100644 index 0000000..ca63c2d --- /dev/null +++ b/internal/endtoend/testdata/case_value_param/postgresql/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Testing struct { + ID int32 + Value pgtype.Text +} diff --git a/internal/endtoend/testdata/case_value_param/postgresql/go/query.sql.go b/internal/endtoend/testdata/case_value_param/postgresql/go/query.sql.go new file mode 100644 index 0000000..5050fb8 --- /dev/null +++ b/internal/endtoend/testdata/case_value_param/postgresql/go/query.sql.go @@ -0,0 +1,22 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const update = `-- name: Update :exec +UPDATE testing +SET value = CASE $1 WHEN true THEN 'Hello' WHEN false THEN 'Goodbye' ELSE value END +` + +func (q *Queries) Update(ctx context.Context, value pgtype.Text) error { + _, err := q.db.Exec(ctx, update, value) + return err +} diff --git a/internal/endtoend/testdata/case_value_param/postgresql/query.sql b/internal/endtoend/testdata/case_value_param/postgresql/query.sql new file mode 100644 index 0000000..106653b --- /dev/null +++ b/internal/endtoend/testdata/case_value_param/postgresql/query.sql @@ -0,0 +1,3 @@ +-- name: Update :exec +UPDATE testing +SET value = CASE $1 WHEN true THEN 'Hello' WHEN false THEN 'Goodbye' ELSE value END; diff --git a/internal/endtoend/testdata/case_value_param/postgresql/schema.sql b/internal/endtoend/testdata/case_value_param/postgresql/schema.sql new file mode 100644 index 0000000..556ca0b --- /dev/null +++ b/internal/endtoend/testdata/case_value_param/postgresql/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE testing ( + id int PRIMARY KEY, + value text +); diff --git a/internal/endtoend/testdata/case_value_param/postgresql/sqlc.yaml b/internal/endtoend/testdata/case_value_param/postgresql/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/case_value_param/postgresql/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/cast_coalesce/pgx/v4/go/db.go b/internal/endtoend/testdata/cast_coalesce/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/cast_coalesce/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/cast_coalesce/pgx/v4/go/models.go b/internal/endtoend/testdata/cast_coalesce/pgx/v4/go/models.go new file mode 100644 index 0000000..b5395d4 --- /dev/null +++ b/internal/endtoend/testdata/cast_coalesce/pgx/v4/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString +} diff --git a/internal/endtoend/testdata/cast_coalesce/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/cast_coalesce/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..bda512f --- /dev/null +++ b/internal/endtoend/testdata/cast_coalesce/pgx/v4/go/query.sql.go @@ -0,0 +1,35 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const castCoalesce = `-- name: CastCoalesce :many +SELECT coalesce(bar, '')::text as login +FROM foo +` + +func (q *Queries) CastCoalesce(ctx context.Context) ([]string, error) { + rows, err := q.db.Query(ctx, castCoalesce) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var login string + if err := rows.Scan(&login); err != nil { + return nil, err + } + items = append(items, login) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/cast_coalesce/pgx/v4/query.sql b/internal/endtoend/testdata/cast_coalesce/pgx/v4/query.sql new file mode 100644 index 0000000..db193da --- /dev/null +++ b/internal/endtoend/testdata/cast_coalesce/pgx/v4/query.sql @@ -0,0 +1,3 @@ +-- name: CastCoalesce :many +SELECT coalesce(bar, '')::text as login +FROM foo; diff --git a/internal/endtoend/testdata/cast_coalesce/pgx/v4/schema.sql b/internal/endtoend/testdata/cast_coalesce/pgx/v4/schema.sql new file mode 100644 index 0000000..bd55621 --- /dev/null +++ b/internal/endtoend/testdata/cast_coalesce/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text); + diff --git a/internal/endtoend/testdata/cast_coalesce/pgx/v4/sqlc.json b/internal/endtoend/testdata/cast_coalesce/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/cast_coalesce/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/cast_coalesce/pgx/v5/go/db.go b/internal/endtoend/testdata/cast_coalesce/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/cast_coalesce/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/cast_coalesce/pgx/v5/go/models.go b/internal/endtoend/testdata/cast_coalesce/pgx/v5/go/models.go new file mode 100644 index 0000000..d867cae --- /dev/null +++ b/internal/endtoend/testdata/cast_coalesce/pgx/v5/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + Bar pgtype.Text +} diff --git a/internal/endtoend/testdata/cast_coalesce/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/cast_coalesce/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..bda512f --- /dev/null +++ b/internal/endtoend/testdata/cast_coalesce/pgx/v5/go/query.sql.go @@ -0,0 +1,35 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const castCoalesce = `-- name: CastCoalesce :many +SELECT coalesce(bar, '')::text as login +FROM foo +` + +func (q *Queries) CastCoalesce(ctx context.Context) ([]string, error) { + rows, err := q.db.Query(ctx, castCoalesce) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var login string + if err := rows.Scan(&login); err != nil { + return nil, err + } + items = append(items, login) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/cast_coalesce/pgx/v5/query.sql b/internal/endtoend/testdata/cast_coalesce/pgx/v5/query.sql new file mode 100644 index 0000000..db193da --- /dev/null +++ b/internal/endtoend/testdata/cast_coalesce/pgx/v5/query.sql @@ -0,0 +1,3 @@ +-- name: CastCoalesce :many +SELECT coalesce(bar, '')::text as login +FROM foo; diff --git a/internal/endtoend/testdata/cast_coalesce/pgx/v5/schema.sql b/internal/endtoend/testdata/cast_coalesce/pgx/v5/schema.sql new file mode 100644 index 0000000..bd55621 --- /dev/null +++ b/internal/endtoend/testdata/cast_coalesce/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text); + diff --git a/internal/endtoend/testdata/cast_coalesce/pgx/v5/sqlc.json b/internal/endtoend/testdata/cast_coalesce/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/cast_coalesce/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/cast_coalesce/stdlib/go/db.go b/internal/endtoend/testdata/cast_coalesce/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/cast_coalesce/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/cast_coalesce/stdlib/go/models.go b/internal/endtoend/testdata/cast_coalesce/stdlib/go/models.go new file mode 100644 index 0000000..b5395d4 --- /dev/null +++ b/internal/endtoend/testdata/cast_coalesce/stdlib/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString +} diff --git a/internal/endtoend/testdata/cast_coalesce/stdlib/go/query.sql.go b/internal/endtoend/testdata/cast_coalesce/stdlib/go/query.sql.go new file mode 100644 index 0000000..64c60f9 --- /dev/null +++ b/internal/endtoend/testdata/cast_coalesce/stdlib/go/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const castCoalesce = `-- name: CastCoalesce :many +SELECT coalesce(bar, '')::text as login +FROM foo +` + +func (q *Queries) CastCoalesce(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, castCoalesce) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var login string + if err := rows.Scan(&login); err != nil { + return nil, err + } + items = append(items, login) + } + 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/cast_coalesce/stdlib/query.sql b/internal/endtoend/testdata/cast_coalesce/stdlib/query.sql new file mode 100644 index 0000000..db193da --- /dev/null +++ b/internal/endtoend/testdata/cast_coalesce/stdlib/query.sql @@ -0,0 +1,3 @@ +-- name: CastCoalesce :many +SELECT coalesce(bar, '')::text as login +FROM foo; diff --git a/internal/endtoend/testdata/cast_coalesce/stdlib/schema.sql b/internal/endtoend/testdata/cast_coalesce/stdlib/schema.sql new file mode 100644 index 0000000..bd55621 --- /dev/null +++ b/internal/endtoend/testdata/cast_coalesce/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text); + diff --git a/internal/endtoend/testdata/cast_coalesce/stdlib/sqlc.json b/internal/endtoend/testdata/cast_coalesce/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/cast_coalesce/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/cast_null/pgx/v4/go/db.go b/internal/endtoend/testdata/cast_null/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/cast_null/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/cast_null/pgx/v4/go/models.go b/internal/endtoend/testdata/cast_null/pgx/v4/go/models.go new file mode 100644 index 0000000..b5395d4 --- /dev/null +++ b/internal/endtoend/testdata/cast_null/pgx/v4/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString +} diff --git a/internal/endtoend/testdata/cast_null/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/cast_null/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..f92cad1 --- /dev/null +++ b/internal/endtoend/testdata/cast_null/pgx/v4/go/query.sql.go @@ -0,0 +1,52 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const listNullable = `-- name: ListNullable :many +SELECT + NULL::text as a, + NULL::integer as b, + NULL::bigint as c, + NULL::time as d +FROM foo +` + +type ListNullableRow struct { + A sql.NullString + B sql.NullInt32 + C sql.NullInt64 + D sql.NullTime +} + +func (q *Queries) ListNullable(ctx context.Context) ([]ListNullableRow, error) { + rows, err := q.db.Query(ctx, listNullable) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListNullableRow + for rows.Next() { + var i ListNullableRow + if err := rows.Scan( + &i.A, + &i.B, + &i.C, + &i.D, + ); 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/cast_null/pgx/v4/query.sql b/internal/endtoend/testdata/cast_null/pgx/v4/query.sql new file mode 100644 index 0000000..ca3a949 --- /dev/null +++ b/internal/endtoend/testdata/cast_null/pgx/v4/query.sql @@ -0,0 +1,7 @@ +-- name: ListNullable :many +SELECT + NULL::text as a, + NULL::integer as b, + NULL::bigint as c, + NULL::time as d +FROM foo; diff --git a/internal/endtoend/testdata/cast_null/pgx/v4/schema.sql b/internal/endtoend/testdata/cast_null/pgx/v4/schema.sql new file mode 100644 index 0000000..bd55621 --- /dev/null +++ b/internal/endtoend/testdata/cast_null/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text); + diff --git a/internal/endtoend/testdata/cast_null/pgx/v4/sqlc.json b/internal/endtoend/testdata/cast_null/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/cast_null/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/cast_null/pgx/v5/go/db.go b/internal/endtoend/testdata/cast_null/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/cast_null/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/cast_null/pgx/v5/go/models.go b/internal/endtoend/testdata/cast_null/pgx/v5/go/models.go new file mode 100644 index 0000000..d867cae --- /dev/null +++ b/internal/endtoend/testdata/cast_null/pgx/v5/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + Bar pgtype.Text +} diff --git a/internal/endtoend/testdata/cast_null/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/cast_null/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..3951ae9 --- /dev/null +++ b/internal/endtoend/testdata/cast_null/pgx/v5/go/query.sql.go @@ -0,0 +1,53 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const listNullable = `-- name: ListNullable :many +SELECT + NULL::text as a, + NULL::integer as b, + NULL::bigint as c, + NULL::time as d +FROM foo +` + +type ListNullableRow struct { + A pgtype.Text + B pgtype.Int4 + C pgtype.Int8 + D pgtype.Time +} + +func (q *Queries) ListNullable(ctx context.Context) ([]ListNullableRow, error) { + rows, err := q.db.Query(ctx, listNullable) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListNullableRow + for rows.Next() { + var i ListNullableRow + if err := rows.Scan( + &i.A, + &i.B, + &i.C, + &i.D, + ); 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/cast_null/pgx/v5/query.sql b/internal/endtoend/testdata/cast_null/pgx/v5/query.sql new file mode 100644 index 0000000..ca3a949 --- /dev/null +++ b/internal/endtoend/testdata/cast_null/pgx/v5/query.sql @@ -0,0 +1,7 @@ +-- name: ListNullable :many +SELECT + NULL::text as a, + NULL::integer as b, + NULL::bigint as c, + NULL::time as d +FROM foo; diff --git a/internal/endtoend/testdata/cast_null/pgx/v5/schema.sql b/internal/endtoend/testdata/cast_null/pgx/v5/schema.sql new file mode 100644 index 0000000..bd55621 --- /dev/null +++ b/internal/endtoend/testdata/cast_null/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text); + diff --git a/internal/endtoend/testdata/cast_null/pgx/v5/sqlc.json b/internal/endtoend/testdata/cast_null/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/cast_null/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/cast_null/stdlib/go/db.go b/internal/endtoend/testdata/cast_null/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/cast_null/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/cast_null/stdlib/go/models.go b/internal/endtoend/testdata/cast_null/stdlib/go/models.go new file mode 100644 index 0000000..b5395d4 --- /dev/null +++ b/internal/endtoend/testdata/cast_null/stdlib/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString +} diff --git a/internal/endtoend/testdata/cast_null/stdlib/go/query.sql.go b/internal/endtoend/testdata/cast_null/stdlib/go/query.sql.go new file mode 100644 index 0000000..773e68c --- /dev/null +++ b/internal/endtoend/testdata/cast_null/stdlib/go/query.sql.go @@ -0,0 +1,55 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const listNullable = `-- name: ListNullable :many +SELECT + NULL::text as a, + NULL::integer as b, + NULL::bigint as c, + NULL::time as d +FROM foo +` + +type ListNullableRow struct { + A sql.NullString + B sql.NullInt32 + C sql.NullInt64 + D sql.NullTime +} + +func (q *Queries) ListNullable(ctx context.Context) ([]ListNullableRow, error) { + rows, err := q.db.QueryContext(ctx, listNullable) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListNullableRow + for rows.Next() { + var i ListNullableRow + if err := rows.Scan( + &i.A, + &i.B, + &i.C, + &i.D, + ); 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/cast_null/stdlib/query.sql b/internal/endtoend/testdata/cast_null/stdlib/query.sql new file mode 100644 index 0000000..ca3a949 --- /dev/null +++ b/internal/endtoend/testdata/cast_null/stdlib/query.sql @@ -0,0 +1,7 @@ +-- name: ListNullable :many +SELECT + NULL::text as a, + NULL::integer as b, + NULL::bigint as c, + NULL::time as d +FROM foo; diff --git a/internal/endtoend/testdata/cast_null/stdlib/schema.sql b/internal/endtoend/testdata/cast_null/stdlib/schema.sql new file mode 100644 index 0000000..bd55621 --- /dev/null +++ b/internal/endtoend/testdata/cast_null/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text); + diff --git a/internal/endtoend/testdata/cast_null/stdlib/sqlc.json b/internal/endtoend/testdata/cast_null/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/cast_null/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/cast_param/sqlite/go/db.go b/internal/endtoend/testdata/cast_param/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/cast_param/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/cast_param/sqlite/go/models.go b/internal/endtoend/testdata/cast_param/sqlite/go/models.go new file mode 100644 index 0000000..32dd99b --- /dev/null +++ b/internal/endtoend/testdata/cast_param/sqlite/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type MyTable struct { + Invalid sql.NullBool + Foo sql.NullString +} diff --git a/internal/endtoend/testdata/cast_param/sqlite/go/query.sql.go b/internal/endtoend/testdata/cast_param/sqlite/go/query.sql.go new file mode 100644 index 0000000..9d4bcff --- /dev/null +++ b/internal/endtoend/testdata/cast_param/sqlite/go/query.sql.go @@ -0,0 +1,39 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getData = `-- name: GetData :many +select invalid, foo +from my_table +where (cast(?1 as boolean) or not invalid) +` + +func (q *Queries) GetData(ctx context.Context, allowInvalid bool) ([]MyTable, error) { + rows, err := q.db.QueryContext(ctx, getData, allowInvalid) + if err != nil { + return nil, err + } + defer rows.Close() + var items []MyTable + for rows.Next() { + var i MyTable + if err := rows.Scan(&i.Invalid, &i.Foo); 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/cast_param/sqlite/query.sql b/internal/endtoend/testdata/cast_param/sqlite/query.sql new file mode 100644 index 0000000..53f8c03 --- /dev/null +++ b/internal/endtoend/testdata/cast_param/sqlite/query.sql @@ -0,0 +1,4 @@ +-- name: GetData :many +select * +from my_table +where (cast(sqlc.arg(allow_invalid) as boolean) or not invalid); \ No newline at end of file diff --git a/internal/endtoend/testdata/cast_param/sqlite/schema.sql b/internal/endtoend/testdata/cast_param/sqlite/schema.sql new file mode 100644 index 0000000..831af7c --- /dev/null +++ b/internal/endtoend/testdata/cast_param/sqlite/schema.sql @@ -0,0 +1,6 @@ +create table my_table +( + invalid boolean, + foo varchar +); + diff --git a/internal/endtoend/testdata/cast_param/sqlite/sqlc.json b/internal/endtoend/testdata/cast_param/sqlite/sqlc.json new file mode 100644 index 0000000..ea4a234 --- /dev/null +++ b/internal/endtoend/testdata/cast_param/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "schema": "schema.sql", + "queries": "query.sql", + "name": "querytest" + } + ] +} \ No newline at end of file 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 0000000..9ca5876 --- /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.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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 0000000..dcc5636 --- /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.31.1 + +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 0000000..c15f2a1 --- /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.31.1 +// 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 0000000..3ab56ee --- /dev/null +++ b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/query.sql @@ -0,0 +1,3 @@ +-- name: SelectTest :many +SELECT * +from test_table; diff --git a/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/schema.sql b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/schema.sql new file mode 100644 index 0000000..ecd09ac --- /dev/null +++ b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/schema.sql @@ -0,0 +1,12 @@ +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 +); + 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 0000000..d1244c9 --- /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": "schema.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 0000000..2666c1c --- /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.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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 0000000..073b2b0 --- /dev/null +++ b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/go/models.go @@ -0,0 +1,22 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type TestTable struct { + VCidNull pgtype.Uint32 + VOidNull pgtype.Uint32 + VTidNull pgtype.TID + VXidNull pgtype.Uint32 + VXid8Null pgtype.Uint64 + VCid pgtype.Uint32 + VOid pgtype.Uint32 + VTid pgtype.TID + VXid pgtype.Uint32 + VXid8 pgtype.Uint64 +} 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 0000000..3e3f4c0 --- /dev/null +++ b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/go/query.sql.go @@ -0,0 +1,46 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// 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_xid8_null, v_cid, v_oid, v_tid, v_xid, v_xid8 +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.VXid8Null, + &i.VCid, + &i.VOid, + &i.VTid, + &i.VXid, + &i.VXid8, + ); 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 0000000..3ab56ee --- /dev/null +++ b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/query.sql @@ -0,0 +1,3 @@ +-- name: SelectTest :many +SELECT * +from test_table; diff --git a/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/schema.sql b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/schema.sql new file mode 100644 index 0000000..bd6f114 --- /dev/null +++ b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/schema.sql @@ -0,0 +1,14 @@ +CREATE TABLE test_table +( + v_cid_null cid, + v_oid_null oid, + v_tid_null tid, + v_xid_null xid, + v_xid8_null xid8, + v_cid cid not null, + v_oid oid not null, + v_tid tid not null, + v_xid xid not null, + v_xid8 xid8 not null +); + 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 0000000..32ede07 --- /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": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/citext/pgx/go/db.go b/internal/endtoend/testdata/citext/pgx/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/citext/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/citext/pgx/go/models.go b/internal/endtoend/testdata/citext/pgx/go/models.go new file mode 100644 index 0000000..5da5060 --- /dev/null +++ b/internal/endtoend/testdata/citext/pgx/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString + Bat string +} diff --git a/internal/endtoend/testdata/citext/pgx/go/query.sql.go b/internal/endtoend/testdata/citext/pgx/go/query.sql.go new file mode 100644 index 0000000..f96e754 --- /dev/null +++ b/internal/endtoend/testdata/citext/pgx/go/query.sql.go @@ -0,0 +1,35 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getCitexts = `-- name: GetCitexts :many +SELECT bar, bat +FROM foo +` + +func (q *Queries) GetCitexts(ctx context.Context) ([]Foo, error) { + rows, err := q.db.Query(ctx, getCitexts) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.Bar, &i.Bat); 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/citext/pgx/query.sql b/internal/endtoend/testdata/citext/pgx/query.sql new file mode 100644 index 0000000..0c151ef --- /dev/null +++ b/internal/endtoend/testdata/citext/pgx/query.sql @@ -0,0 +1,3 @@ +-- name: GetCitexts :many +SELECT bar, bat +FROM foo; diff --git a/internal/endtoend/testdata/citext/pgx/schema.sql b/internal/endtoend/testdata/citext/pgx/schema.sql new file mode 100644 index 0000000..60c0678 --- /dev/null +++ b/internal/endtoend/testdata/citext/pgx/schema.sql @@ -0,0 +1,7 @@ +CREATE EXTENSION IF NOT EXISTS citext; + +CREATE TABLE foo ( + bar citext, + bat citext not null +); + diff --git a/internal/endtoend/testdata/citext/pgx/sqlc.json b/internal/endtoend/testdata/citext/pgx/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/citext/pgx/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/citext/stdlib/go/db.go b/internal/endtoend/testdata/citext/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/citext/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/citext/stdlib/go/models.go b/internal/endtoend/testdata/citext/stdlib/go/models.go new file mode 100644 index 0000000..5da5060 --- /dev/null +++ b/internal/endtoend/testdata/citext/stdlib/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString + Bat string +} diff --git a/internal/endtoend/testdata/citext/stdlib/go/query.sql.go b/internal/endtoend/testdata/citext/stdlib/go/query.sql.go new file mode 100644 index 0000000..cf68039 --- /dev/null +++ b/internal/endtoend/testdata/citext/stdlib/go/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getCitexts = `-- name: GetCitexts :many +SELECT bar, bat +FROM foo +` + +func (q *Queries) GetCitexts(ctx context.Context) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, getCitexts) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.Bar, &i.Bat); 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/citext/stdlib/query.sql b/internal/endtoend/testdata/citext/stdlib/query.sql new file mode 100644 index 0000000..b6b08d2 --- /dev/null +++ b/internal/endtoend/testdata/citext/stdlib/query.sql @@ -0,0 +1,5 @@ +-- name: GetCitexts :many +SELECT bar, bat +FROM foo; + + diff --git a/internal/endtoend/testdata/citext/stdlib/schema.sql b/internal/endtoend/testdata/citext/stdlib/schema.sql new file mode 100644 index 0000000..60c0678 --- /dev/null +++ b/internal/endtoend/testdata/citext/stdlib/schema.sql @@ -0,0 +1,7 @@ +CREATE EXTENSION IF NOT EXISTS citext; + +CREATE TABLE foo ( + bar citext, + bat citext not null +); + diff --git a/internal/endtoend/testdata/citext/stdlib/sqlc.json b/internal/endtoend/testdata/citext/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/citext/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/coalesce/mysql/go/db.go b/internal/endtoend/testdata/coalesce/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/coalesce/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/coalesce/mysql/go/models.go b/internal/endtoend/testdata/coalesce/mysql/go/models.go new file mode 100644 index 0000000..5da5060 --- /dev/null +++ b/internal/endtoend/testdata/coalesce/mysql/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString + Bat string +} diff --git a/internal/endtoend/testdata/coalesce/mysql/go/query.sql.go b/internal/endtoend/testdata/coalesce/mysql/go/query.sql.go new file mode 100644 index 0000000..c98120b --- /dev/null +++ b/internal/endtoend/testdata/coalesce/mysql/go/query.sql.go @@ -0,0 +1,73 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const coalesce = `-- name: Coalesce :many +SELECT coalesce(bar, '') as login +FROM foo +` + +func (q *Queries) Coalesce(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, coalesce) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var login string + if err := rows.Scan(&login); err != nil { + return nil, err + } + items = append(items, login) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const coalesceColumns = `-- name: CoalesceColumns :many +SELECT bar, bat, coalesce(bar, bat) +FROM foo +` + +type CoalesceColumnsRow struct { + Bar sql.NullString + Bat string + Bar_2 string +} + +func (q *Queries) CoalesceColumns(ctx context.Context) ([]CoalesceColumnsRow, error) { + rows, err := q.db.QueryContext(ctx, coalesceColumns) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CoalesceColumnsRow + for rows.Next() { + var i CoalesceColumnsRow + if err := rows.Scan(&i.Bar, &i.Bat, &i.Bar_2); 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/coalesce/mysql/query.sql b/internal/endtoend/testdata/coalesce/mysql/query.sql new file mode 100644 index 0000000..4cc0de9 --- /dev/null +++ b/internal/endtoend/testdata/coalesce/mysql/query.sql @@ -0,0 +1,7 @@ +-- name: Coalesce :many +SELECT coalesce(bar, '') as login +FROM foo; + +-- name: CoalesceColumns :many +SELECT bar, bat, coalesce(bar, bat) +FROM foo; diff --git a/internal/endtoend/testdata/coalesce/mysql/schema.sql b/internal/endtoend/testdata/coalesce/mysql/schema.sql new file mode 100644 index 0000000..c5002ec --- /dev/null +++ b/internal/endtoend/testdata/coalesce/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text, bat text not null); + diff --git a/internal/endtoend/testdata/coalesce/mysql/sqlc.json b/internal/endtoend/testdata/coalesce/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/coalesce/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/coalesce/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/coalesce/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/coalesce/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/coalesce/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/coalesce/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..741f099 --- /dev/null +++ b/internal/endtoend/testdata/coalesce/postgresql/pgx/v4/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString + Bat string + Baz sql.NullInt64 + Qux int64 +} diff --git a/internal/endtoend/testdata/coalesce/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/coalesce/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..061579c --- /dev/null +++ b/internal/endtoend/testdata/coalesce/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,183 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const coalesceNumeric = `-- name: CoalesceNumeric :many +SELECT coalesce(baz, 0) as login +FROM foo +` + +func (q *Queries) CoalesceNumeric(ctx context.Context) ([]int64, error) { + rows, err := q.db.Query(ctx, coalesceNumeric) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var login int64 + if err := rows.Scan(&login); err != nil { + return nil, err + } + items = append(items, login) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const coalesceNumericColumns = `-- name: CoalesceNumericColumns :many +SELECT baz, qux, coalesce(baz, qux) +FROM foo +` + +type CoalesceNumericColumnsRow struct { + Baz sql.NullInt64 + Qux int64 + Baz_2 int64 +} + +func (q *Queries) CoalesceNumericColumns(ctx context.Context) ([]CoalesceNumericColumnsRow, error) { + rows, err := q.db.Query(ctx, coalesceNumericColumns) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CoalesceNumericColumnsRow + for rows.Next() { + var i CoalesceNumericColumnsRow + if err := rows.Scan(&i.Baz, &i.Qux, &i.Baz_2); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const coalesceNumericNull = `-- name: CoalesceNumericNull :many +SELECT baz, coalesce(baz) +FROM foo +` + +type CoalesceNumericNullRow struct { + Baz sql.NullInt64 + Baz_2 sql.NullInt64 +} + +func (q *Queries) CoalesceNumericNull(ctx context.Context) ([]CoalesceNumericNullRow, error) { + rows, err := q.db.Query(ctx, coalesceNumericNull) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CoalesceNumericNullRow + for rows.Next() { + var i CoalesceNumericNullRow + if err := rows.Scan(&i.Baz, &i.Baz_2); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const coalesceString = `-- name: CoalesceString :many +SELECT coalesce(bar, '') as login +FROM foo +` + +func (q *Queries) CoalesceString(ctx context.Context) ([]string, error) { + rows, err := q.db.Query(ctx, coalesceString) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var login string + if err := rows.Scan(&login); err != nil { + return nil, err + } + items = append(items, login) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const coalesceStringColumns = `-- name: CoalesceStringColumns :many +SELECT bar, bat, coalesce(bar, bat) +FROM foo +` + +type CoalesceStringColumnsRow struct { + Bar sql.NullString + Bat string + Bar_2 string +} + +func (q *Queries) CoalesceStringColumns(ctx context.Context) ([]CoalesceStringColumnsRow, error) { + rows, err := q.db.Query(ctx, coalesceStringColumns) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CoalesceStringColumnsRow + for rows.Next() { + var i CoalesceStringColumnsRow + if err := rows.Scan(&i.Bar, &i.Bat, &i.Bar_2); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const coalesceStringNull = `-- name: CoalesceStringNull :many +SELECT bar, coalesce(bar) +FROM foo +` + +type CoalesceStringNullRow struct { + Bar sql.NullString + Bar_2 sql.NullString +} + +func (q *Queries) CoalesceStringNull(ctx context.Context) ([]CoalesceStringNullRow, error) { + rows, err := q.db.Query(ctx, coalesceStringNull) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CoalesceStringNullRow + for rows.Next() { + var i CoalesceStringNullRow + if err := rows.Scan(&i.Bar, &i.Bar_2); 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/coalesce/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/coalesce/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..73d0693 --- /dev/null +++ b/internal/endtoend/testdata/coalesce/postgresql/pgx/v4/query.sql @@ -0,0 +1,23 @@ +-- name: CoalesceString :many +SELECT coalesce(bar, '') as login +FROM foo; + +-- name: CoalesceNumeric :many +SELECT coalesce(baz, 0) as login +FROM foo; + +-- name: CoalesceStringColumns :many +SELECT bar, bat, coalesce(bar, bat) +FROM foo; + +-- name: CoalesceNumericColumns :many +SELECT baz, qux, coalesce(baz, qux) +FROM foo; + +-- name: CoalesceStringNull :many +SELECT bar, coalesce(bar) +FROM foo; + +-- name: CoalesceNumericNull :many +SELECT baz, coalesce(baz) +FROM foo; diff --git a/internal/endtoend/testdata/coalesce/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/coalesce/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..0dc995d --- /dev/null +++ b/internal/endtoend/testdata/coalesce/postgresql/pgx/v4/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE foo ( + bar text, + bat text not null, + baz bigint, + qux bigint not null +); + diff --git a/internal/endtoend/testdata/coalesce/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/coalesce/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/coalesce/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/coalesce/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/coalesce/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/coalesce/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/coalesce/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/coalesce/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..30ba3e8 --- /dev/null +++ b/internal/endtoend/testdata/coalesce/postgresql/pgx/v5/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + Bar pgtype.Text + Bat string + Baz pgtype.Int8 + Qux int64 +} diff --git a/internal/endtoend/testdata/coalesce/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/coalesce/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..f674fa0 --- /dev/null +++ b/internal/endtoend/testdata/coalesce/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,184 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const coalesceNumeric = `-- name: CoalesceNumeric :many +SELECT coalesce(baz, 0) as login +FROM foo +` + +func (q *Queries) CoalesceNumeric(ctx context.Context) ([]int64, error) { + rows, err := q.db.Query(ctx, coalesceNumeric) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var login int64 + if err := rows.Scan(&login); err != nil { + return nil, err + } + items = append(items, login) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const coalesceNumericColumns = `-- name: CoalesceNumericColumns :many +SELECT baz, qux, coalesce(baz, qux) +FROM foo +` + +type CoalesceNumericColumnsRow struct { + Baz pgtype.Int8 + Qux int64 + Baz_2 int64 +} + +func (q *Queries) CoalesceNumericColumns(ctx context.Context) ([]CoalesceNumericColumnsRow, error) { + rows, err := q.db.Query(ctx, coalesceNumericColumns) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CoalesceNumericColumnsRow + for rows.Next() { + var i CoalesceNumericColumnsRow + if err := rows.Scan(&i.Baz, &i.Qux, &i.Baz_2); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const coalesceNumericNull = `-- name: CoalesceNumericNull :many +SELECT baz, coalesce(baz) +FROM foo +` + +type CoalesceNumericNullRow struct { + Baz pgtype.Int8 + Baz_2 pgtype.Int8 +} + +func (q *Queries) CoalesceNumericNull(ctx context.Context) ([]CoalesceNumericNullRow, error) { + rows, err := q.db.Query(ctx, coalesceNumericNull) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CoalesceNumericNullRow + for rows.Next() { + var i CoalesceNumericNullRow + if err := rows.Scan(&i.Baz, &i.Baz_2); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const coalesceString = `-- name: CoalesceString :many +SELECT coalesce(bar, '') as login +FROM foo +` + +func (q *Queries) CoalesceString(ctx context.Context) ([]string, error) { + rows, err := q.db.Query(ctx, coalesceString) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var login string + if err := rows.Scan(&login); err != nil { + return nil, err + } + items = append(items, login) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const coalesceStringColumns = `-- name: CoalesceStringColumns :many +SELECT bar, bat, coalesce(bar, bat) +FROM foo +` + +type CoalesceStringColumnsRow struct { + Bar pgtype.Text + Bat string + Bar_2 string +} + +func (q *Queries) CoalesceStringColumns(ctx context.Context) ([]CoalesceStringColumnsRow, error) { + rows, err := q.db.Query(ctx, coalesceStringColumns) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CoalesceStringColumnsRow + for rows.Next() { + var i CoalesceStringColumnsRow + if err := rows.Scan(&i.Bar, &i.Bat, &i.Bar_2); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const coalesceStringNull = `-- name: CoalesceStringNull :many +SELECT bar, coalesce(bar) +FROM foo +` + +type CoalesceStringNullRow struct { + Bar pgtype.Text + Bar_2 pgtype.Text +} + +func (q *Queries) CoalesceStringNull(ctx context.Context) ([]CoalesceStringNullRow, error) { + rows, err := q.db.Query(ctx, coalesceStringNull) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CoalesceStringNullRow + for rows.Next() { + var i CoalesceStringNullRow + if err := rows.Scan(&i.Bar, &i.Bar_2); 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/coalesce/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/coalesce/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..73d0693 --- /dev/null +++ b/internal/endtoend/testdata/coalesce/postgresql/pgx/v5/query.sql @@ -0,0 +1,23 @@ +-- name: CoalesceString :many +SELECT coalesce(bar, '') as login +FROM foo; + +-- name: CoalesceNumeric :many +SELECT coalesce(baz, 0) as login +FROM foo; + +-- name: CoalesceStringColumns :many +SELECT bar, bat, coalesce(bar, bat) +FROM foo; + +-- name: CoalesceNumericColumns :many +SELECT baz, qux, coalesce(baz, qux) +FROM foo; + +-- name: CoalesceStringNull :many +SELECT bar, coalesce(bar) +FROM foo; + +-- name: CoalesceNumericNull :many +SELECT baz, coalesce(baz) +FROM foo; diff --git a/internal/endtoend/testdata/coalesce/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/coalesce/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..0dc995d --- /dev/null +++ b/internal/endtoend/testdata/coalesce/postgresql/pgx/v5/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE foo ( + bar text, + bat text not null, + baz bigint, + qux bigint not null +); + diff --git a/internal/endtoend/testdata/coalesce/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/coalesce/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/coalesce/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/coalesce/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/coalesce/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/coalesce/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/coalesce/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/coalesce/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..741f099 --- /dev/null +++ b/internal/endtoend/testdata/coalesce/postgresql/stdlib/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString + Bat string + Baz sql.NullInt64 + Qux int64 +} diff --git a/internal/endtoend/testdata/coalesce/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/coalesce/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..2c37a8b --- /dev/null +++ b/internal/endtoend/testdata/coalesce/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,201 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const coalesceNumeric = `-- name: CoalesceNumeric :many +SELECT coalesce(baz, 0) as login +FROM foo +` + +func (q *Queries) CoalesceNumeric(ctx context.Context) ([]int64, error) { + rows, err := q.db.QueryContext(ctx, coalesceNumeric) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var login int64 + if err := rows.Scan(&login); err != nil { + return nil, err + } + items = append(items, login) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const coalesceNumericColumns = `-- name: CoalesceNumericColumns :many +SELECT baz, qux, coalesce(baz, qux) +FROM foo +` + +type CoalesceNumericColumnsRow struct { + Baz sql.NullInt64 + Qux int64 + Baz_2 int64 +} + +func (q *Queries) CoalesceNumericColumns(ctx context.Context) ([]CoalesceNumericColumnsRow, error) { + rows, err := q.db.QueryContext(ctx, coalesceNumericColumns) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CoalesceNumericColumnsRow + for rows.Next() { + var i CoalesceNumericColumnsRow + if err := rows.Scan(&i.Baz, &i.Qux, &i.Baz_2); 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 coalesceNumericNull = `-- name: CoalesceNumericNull :many +SELECT baz, coalesce(baz) +FROM foo +` + +type CoalesceNumericNullRow struct { + Baz sql.NullInt64 + Baz_2 sql.NullInt64 +} + +func (q *Queries) CoalesceNumericNull(ctx context.Context) ([]CoalesceNumericNullRow, error) { + rows, err := q.db.QueryContext(ctx, coalesceNumericNull) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CoalesceNumericNullRow + for rows.Next() { + var i CoalesceNumericNullRow + if err := rows.Scan(&i.Baz, &i.Baz_2); 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 coalesceString = `-- name: CoalesceString :many +SELECT coalesce(bar, '') as login +FROM foo +` + +func (q *Queries) CoalesceString(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, coalesceString) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var login string + if err := rows.Scan(&login); err != nil { + return nil, err + } + items = append(items, login) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const coalesceStringColumns = `-- name: CoalesceStringColumns :many +SELECT bar, bat, coalesce(bar, bat) +FROM foo +` + +type CoalesceStringColumnsRow struct { + Bar sql.NullString + Bat string + Bar_2 string +} + +func (q *Queries) CoalesceStringColumns(ctx context.Context) ([]CoalesceStringColumnsRow, error) { + rows, err := q.db.QueryContext(ctx, coalesceStringColumns) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CoalesceStringColumnsRow + for rows.Next() { + var i CoalesceStringColumnsRow + if err := rows.Scan(&i.Bar, &i.Bat, &i.Bar_2); 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 coalesceStringNull = `-- name: CoalesceStringNull :many +SELECT bar, coalesce(bar) +FROM foo +` + +type CoalesceStringNullRow struct { + Bar sql.NullString + Bar_2 sql.NullString +} + +func (q *Queries) CoalesceStringNull(ctx context.Context) ([]CoalesceStringNullRow, error) { + rows, err := q.db.QueryContext(ctx, coalesceStringNull) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CoalesceStringNullRow + for rows.Next() { + var i CoalesceStringNullRow + if err := rows.Scan(&i.Bar, &i.Bar_2); 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/coalesce/postgresql/stdlib/query.sql b/internal/endtoend/testdata/coalesce/postgresql/stdlib/query.sql new file mode 100644 index 0000000..73d0693 --- /dev/null +++ b/internal/endtoend/testdata/coalesce/postgresql/stdlib/query.sql @@ -0,0 +1,23 @@ +-- name: CoalesceString :many +SELECT coalesce(bar, '') as login +FROM foo; + +-- name: CoalesceNumeric :many +SELECT coalesce(baz, 0) as login +FROM foo; + +-- name: CoalesceStringColumns :many +SELECT bar, bat, coalesce(bar, bat) +FROM foo; + +-- name: CoalesceNumericColumns :many +SELECT baz, qux, coalesce(baz, qux) +FROM foo; + +-- name: CoalesceStringNull :many +SELECT bar, coalesce(bar) +FROM foo; + +-- name: CoalesceNumericNull :many +SELECT baz, coalesce(baz) +FROM foo; diff --git a/internal/endtoend/testdata/coalesce/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/coalesce/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..0dc995d --- /dev/null +++ b/internal/endtoend/testdata/coalesce/postgresql/stdlib/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE foo ( + bar text, + bat text not null, + baz bigint, + qux bigint not null +); + diff --git a/internal/endtoend/testdata/coalesce/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/coalesce/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/coalesce/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/coalesce/sqlite/go/db.go b/internal/endtoend/testdata/coalesce/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/coalesce/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/coalesce/sqlite/go/models.go b/internal/endtoend/testdata/coalesce/sqlite/go/models.go new file mode 100644 index 0000000..5da5060 --- /dev/null +++ b/internal/endtoend/testdata/coalesce/sqlite/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString + Bat string +} diff --git a/internal/endtoend/testdata/coalesce/sqlite/go/query.sql.go b/internal/endtoend/testdata/coalesce/sqlite/go/query.sql.go new file mode 100644 index 0000000..4324a03 --- /dev/null +++ b/internal/endtoend/testdata/coalesce/sqlite/go/query.sql.go @@ -0,0 +1,73 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const coalesce = `-- name: Coalesce :many +SELECT coalesce(bar, '') AS login +FROM foo +` + +func (q *Queries) Coalesce(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, coalesce) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var login string + if err := rows.Scan(&login); err != nil { + return nil, err + } + items = append(items, login) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const coalesceColumns = `-- name: CoalesceColumns :many +SELECT bar, bat, coalesce(bar, bat) +FROM foo +` + +type CoalesceColumnsRow struct { + Bar sql.NullString + Bat string + Bar_2 string +} + +func (q *Queries) CoalesceColumns(ctx context.Context) ([]CoalesceColumnsRow, error) { + rows, err := q.db.QueryContext(ctx, coalesceColumns) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CoalesceColumnsRow + for rows.Next() { + var i CoalesceColumnsRow + if err := rows.Scan(&i.Bar, &i.Bat, &i.Bar_2); 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/coalesce/sqlite/query.sql b/internal/endtoend/testdata/coalesce/sqlite/query.sql new file mode 100644 index 0000000..f7b1c92 --- /dev/null +++ b/internal/endtoend/testdata/coalesce/sqlite/query.sql @@ -0,0 +1,7 @@ +-- name: Coalesce :many +SELECT coalesce(bar, '') AS login +FROM foo; + +-- name: CoalesceColumns :many +SELECT bar, bat, coalesce(bar, bat) +FROM foo; diff --git a/internal/endtoend/testdata/coalesce/sqlite/schema.sql b/internal/endtoend/testdata/coalesce/sqlite/schema.sql new file mode 100644 index 0000000..c5002ec --- /dev/null +++ b/internal/endtoend/testdata/coalesce/sqlite/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text, bat text not null); + diff --git a/internal/endtoend/testdata/coalesce/sqlite/sqlc.json b/internal/endtoend/testdata/coalesce/sqlite/sqlc.json new file mode 100644 index 0000000..d4963e7 --- /dev/null +++ b/internal/endtoend/testdata/coalesce/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/coalesce_as/mysql/go/db.go b/internal/endtoend/testdata/coalesce_as/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/coalesce_as/mysql/go/models.go b/internal/endtoend/testdata/coalesce_as/mysql/go/models.go new file mode 100644 index 0000000..7df949f --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/mysql/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString + Baz sql.NullInt32 +} diff --git a/internal/endtoend/testdata/coalesce_as/mysql/go/query.sql.go b/internal/endtoend/testdata/coalesce_as/mysql/go/query.sql.go new file mode 100644 index 0000000..8ce06bb --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/mysql/go/query.sql.go @@ -0,0 +1,45 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const sumBaz = `-- name: SumBaz :many +SELECT bar, coalesce(sum(baz), 0) as quantity +FROM foo +GROUP BY 1 +` + +type SumBazRow struct { + Bar sql.NullString + Quantity any +} + +func (q *Queries) SumBaz(ctx context.Context) ([]SumBazRow, error) { + rows, err := q.db.QueryContext(ctx, sumBaz) + if err != nil { + return nil, err + } + defer rows.Close() + var items []SumBazRow + for rows.Next() { + var i SumBazRow + if err := rows.Scan(&i.Bar, &i.Quantity); 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/coalesce_as/mysql/query.sql b/internal/endtoend/testdata/coalesce_as/mysql/query.sql new file mode 100644 index 0000000..3f51061 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/mysql/query.sql @@ -0,0 +1,4 @@ +-- name: SumBaz :many +SELECT bar, coalesce(sum(baz), 0) as quantity +FROM foo +GROUP BY 1; diff --git a/internal/endtoend/testdata/coalesce_as/mysql/schema.sql b/internal/endtoend/testdata/coalesce_as/mysql/schema.sql new file mode 100644 index 0000000..eb1099a --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/mysql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE foo ( + bar text, + baz integer +); + diff --git a/internal/endtoend/testdata/coalesce_as/mysql/sqlc.json b/internal/endtoend/testdata/coalesce_as/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/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/coalesce_as/postgresql/pganalyze/exec.json b/internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/go/db.go b/internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/coalesce_as/postgresql/pganalyze/go/models.go b/internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/go/models.go new file mode 100644 index 0000000..081444a --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + Bar pgtype.Text + Baz pgtype.Int8 +} diff --git a/internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/go/query.sql.go b/internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/go/query.sql.go new file mode 100644 index 0000000..cd1ead7 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/go/query.sql.go @@ -0,0 +1,43 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const sumBaz = `-- name: SumBaz :many +SELECT bar, coalesce(sum(baz), 0) as quantity +FROM foo +GROUP BY 1 +` + +type SumBazRow struct { + Bar pgtype.Text + Quantity pgtype.Numeric +} + +func (q *Queries) SumBaz(ctx context.Context) ([]SumBazRow, error) { + rows, err := q.db.Query(ctx, sumBaz) + if err != nil { + return nil, err + } + defer rows.Close() + var items []SumBazRow + for rows.Next() { + var i SumBazRow + if err := rows.Scan(&i.Bar, &i.Quantity); 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/coalesce_as/postgresql/pganalyze/query.sql b/internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/query.sql new file mode 100644 index 0000000..3f51061 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/query.sql @@ -0,0 +1,4 @@ +-- name: SumBaz :many +SELECT bar, coalesce(sum(baz), 0) as quantity +FROM foo +GROUP BY 1; diff --git a/internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/schema.sql b/internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/schema.sql new file mode 100644 index 0000000..b7a16c0 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE foo ( + bar text, + baz bigint +); + diff --git a/internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/sqlc.json b/internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/sqlc.json new file mode 100644 index 0000000..f5e2653 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/pganalyze/sqlc.json @@ -0,0 +1,19 @@ +{ + "version": "1", + "cloud": { + "project": "01HAQMMECEYQYKFJN8MP16QC41" + }, + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "database": { + "managed": true + }, + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/exec.json b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/coalesce_as/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..72e354f --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString + Baz sql.NullInt64 +} diff --git a/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..0471727 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const sumBaz = `-- name: SumBaz :many +SELECT bar, coalesce(sum(baz), 0) as quantity +FROM foo +GROUP BY 1 +` + +type SumBazRow struct { + Bar sql.NullString + Quantity any +} + +func (q *Queries) SumBaz(ctx context.Context) ([]SumBazRow, error) { + rows, err := q.db.Query(ctx, sumBaz) + if err != nil { + return nil, err + } + defer rows.Close() + var items []SumBazRow + for rows.Next() { + var i SumBazRow + if err := rows.Scan(&i.Bar, &i.Quantity); 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/coalesce_as/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..3f51061 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/query.sql @@ -0,0 +1,4 @@ +-- name: SumBaz :many +SELECT bar, coalesce(sum(baz), 0) as quantity +FROM foo +GROUP BY 1; diff --git a/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..b7a16c0 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE foo ( + bar text, + baz bigint +); + diff --git a/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/exec.json b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/coalesce_as/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..081444a --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + Bar pgtype.Text + Baz pgtype.Int8 +} diff --git a/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..cb54b62 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,43 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const sumBaz = `-- name: SumBaz :many +SELECT bar, coalesce(sum(baz), 0) as quantity +FROM foo +GROUP BY 1 +` + +type SumBazRow struct { + Bar pgtype.Text + Quantity any +} + +func (q *Queries) SumBaz(ctx context.Context) ([]SumBazRow, error) { + rows, err := q.db.Query(ctx, sumBaz) + if err != nil { + return nil, err + } + defer rows.Close() + var items []SumBazRow + for rows.Next() { + var i SumBazRow + if err := rows.Scan(&i.Bar, &i.Quantity); 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/coalesce_as/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..3f51061 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/query.sql @@ -0,0 +1,4 @@ +-- name: SumBaz :many +SELECT bar, coalesce(sum(baz), 0) as quantity +FROM foo +GROUP BY 1; diff --git a/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..b7a16c0 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE foo ( + bar text, + baz bigint +); + diff --git a/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/coalesce_as/postgresql/stdlib/exec.json b/internal/endtoend/testdata/coalesce_as/postgresql/stdlib/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/stdlib/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/coalesce_as/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/coalesce_as/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/coalesce_as/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/coalesce_as/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..72e354f --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/stdlib/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString + Baz sql.NullInt64 +} diff --git a/internal/endtoend/testdata/coalesce_as/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/coalesce_as/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..8ce06bb --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,45 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const sumBaz = `-- name: SumBaz :many +SELECT bar, coalesce(sum(baz), 0) as quantity +FROM foo +GROUP BY 1 +` + +type SumBazRow struct { + Bar sql.NullString + Quantity any +} + +func (q *Queries) SumBaz(ctx context.Context) ([]SumBazRow, error) { + rows, err := q.db.QueryContext(ctx, sumBaz) + if err != nil { + return nil, err + } + defer rows.Close() + var items []SumBazRow + for rows.Next() { + var i SumBazRow + if err := rows.Scan(&i.Bar, &i.Quantity); 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/coalesce_as/postgresql/stdlib/query.sql b/internal/endtoend/testdata/coalesce_as/postgresql/stdlib/query.sql new file mode 100644 index 0000000..3f51061 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/stdlib/query.sql @@ -0,0 +1,4 @@ +-- name: SumBaz :many +SELECT bar, coalesce(sum(baz), 0) as quantity +FROM foo +GROUP BY 1; diff --git a/internal/endtoend/testdata/coalesce_as/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/coalesce_as/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..b7a16c0 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/stdlib/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE foo ( + bar text, + baz bigint +); + diff --git a/internal/endtoend/testdata/coalesce_as/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/coalesce_as/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/coalesce_as/sqlite/go/db.go b/internal/endtoend/testdata/coalesce_as/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/coalesce_as/sqlite/go/models.go b/internal/endtoend/testdata/coalesce_as/sqlite/go/models.go new file mode 100644 index 0000000..72e354f --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/sqlite/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString + Baz sql.NullInt64 +} diff --git a/internal/endtoend/testdata/coalesce_as/sqlite/go/query.sql.go b/internal/endtoend/testdata/coalesce_as/sqlite/go/query.sql.go new file mode 100644 index 0000000..556c5b5 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/sqlite/go/query.sql.go @@ -0,0 +1,45 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const sumBaz = `-- name: SumBaz :many +SELECT bar, coalesce(sum(baz), 0) AS quantity +FROM foo +GROUP BY 1 +` + +type SumBazRow struct { + Bar sql.NullString + Quantity any +} + +func (q *Queries) SumBaz(ctx context.Context) ([]SumBazRow, error) { + rows, err := q.db.QueryContext(ctx, sumBaz) + if err != nil { + return nil, err + } + defer rows.Close() + var items []SumBazRow + for rows.Next() { + var i SumBazRow + if err := rows.Scan(&i.Bar, &i.Quantity); 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/coalesce_as/sqlite/query.sql b/internal/endtoend/testdata/coalesce_as/sqlite/query.sql new file mode 100644 index 0000000..d092958 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/sqlite/query.sql @@ -0,0 +1,4 @@ +-- name: SumBaz :many +SELECT bar, coalesce(sum(baz), 0) AS quantity +FROM foo +GROUP BY 1; diff --git a/internal/endtoend/testdata/coalesce_as/sqlite/schema.sql b/internal/endtoend/testdata/coalesce_as/sqlite/schema.sql new file mode 100644 index 0000000..eb1099a --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/sqlite/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE foo ( + bar text, + baz integer +); + diff --git a/internal/endtoend/testdata/coalesce_as/sqlite/sqlc.json b/internal/endtoend/testdata/coalesce_as/sqlite/sqlc.json new file mode 100644 index 0000000..d4963e7 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/coalesce_join/postgresql/go/db.go b/internal/endtoend/testdata/coalesce_join/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/coalesce_join/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/coalesce_join/postgresql/go/models.go b/internal/endtoend/testdata/coalesce_join/postgresql/go/models.go new file mode 100644 index 0000000..00ba67c --- /dev/null +++ b/internal/endtoend/testdata/coalesce_join/postgresql/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int64 +} + +type Foo struct { + ID int64 +} diff --git a/internal/endtoend/testdata/coalesce_join/postgresql/go/query.sql.go b/internal/endtoend/testdata/coalesce_join/postgresql/go/query.sql.go new file mode 100644 index 0000000..15250f9 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_join/postgresql/go/query.sql.go @@ -0,0 +1,44 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getBar = `-- name: GetBar :many +SELECT foo.id, COALESCE(bar.id, 0) AS bar_id +FROM foo +LEFT JOIN bar ON foo.id = bar.id +` + +type GetBarRow struct { + ID int64 + BarID int64 +} + +func (q *Queries) GetBar(ctx context.Context) ([]GetBarRow, error) { + rows, err := q.db.QueryContext(ctx, getBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetBarRow + for rows.Next() { + var i GetBarRow + if err := rows.Scan(&i.ID, &i.BarID); 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/coalesce_join/postgresql/query.sql b/internal/endtoend/testdata/coalesce_join/postgresql/query.sql new file mode 100644 index 0000000..d91add8 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_join/postgresql/query.sql @@ -0,0 +1,4 @@ +-- name: GetBar :many +SELECT foo.*, COALESCE(bar.id, 0) AS bar_id +FROM foo +LEFT JOIN bar ON foo.id = bar.id; diff --git a/internal/endtoend/testdata/coalesce_join/postgresql/schema.sql b/internal/endtoend/testdata/coalesce_join/postgresql/schema.sql new file mode 100644 index 0000000..ed9393c --- /dev/null +++ b/internal/endtoend/testdata/coalesce_join/postgresql/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo(id bigserial primary key); +CREATE TABLE bar(id bigserial primary key); + diff --git a/internal/endtoend/testdata/coalesce_join/postgresql/sqlc.json b/internal/endtoend/testdata/coalesce_join/postgresql/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_join/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/coalesce_params/issue.md b/internal/endtoend/testdata/coalesce_params/issue.md new file mode 100644 index 0000000..ad6db41 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_params/issue.md @@ -0,0 +1,2 @@ +https://github.com/sqlc-dev/sqlc/issues/2748 +https://github.com/sqlc-dev/sqlc/issues/2786 diff --git a/internal/endtoend/testdata/coalesce_params/mysql/exec.json b/internal/endtoend/testdata/coalesce_params/mysql/exec.json new file mode 100644 index 0000000..c85ca2d --- /dev/null +++ b/internal/endtoend/testdata/coalesce_params/mysql/exec.json @@ -0,0 +1,6 @@ +{ + "contexts": ["base"], + "meta": { + "invalid_schema": true + } +} diff --git a/internal/endtoend/testdata/coalesce_params/mysql/go/db.go b/internal/endtoend/testdata/coalesce_params/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/coalesce_params/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/coalesce_params/mysql/go/models.go b/internal/endtoend/testdata/coalesce_params/mysql/go/models.go new file mode 100644 index 0000000..1e9a534 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_params/mysql/go/models.go @@ -0,0 +1,87 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + "database/sql/driver" + "fmt" + "time" +) + +type CalendarMaincalendar string + +const ( + CalendarMaincalendarTrue CalendarMaincalendar = "true" + CalendarMaincalendarFalse CalendarMaincalendar = "false" +) + +func (e *CalendarMaincalendar) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = CalendarMaincalendar(s) + case string: + *e = CalendarMaincalendar(s) + default: + return fmt.Errorf("unsupported scan type for CalendarMaincalendar: %T", src) + } + return nil +} + +type NullCalendarMaincalendar struct { + CalendarMaincalendar CalendarMaincalendar + Valid bool // Valid is true if CalendarMaincalendar is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullCalendarMaincalendar) Scan(value any) error { + if value == nil { + ns.CalendarMaincalendar, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.CalendarMaincalendar.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullCalendarMaincalendar) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.CalendarMaincalendar), nil +} + +type Author struct { + ID int64 + Address string + Name string + Bio string +} + +type Calendar struct { + ID uint64 + Relation uint64 + Calendarname []byte + Title []byte + Description []byte + Timezone string + Uniquekey string + Idkey string + Maincalendar CalendarMaincalendar + Createdate time.Time + Modifydate time.Time +} + +type Event struct { + ID uint64 + Relation uint64 + Calendarreference uint64 + Uniquekey string + Eventname []byte + Description []byte + Location string + Timezone string + Idkey sql.NullString +} diff --git a/internal/endtoend/testdata/coalesce_params/mysql/go/query.sql.go b/internal/endtoend/testdata/coalesce_params/mysql/go/query.sql.go new file mode 100644 index 0000000..689806e --- /dev/null +++ b/internal/endtoend/testdata/coalesce_params/mysql/go/query.sql.go @@ -0,0 +1,57 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const addAuthor = `-- name: AddAuthor :execlastid +INSERT INTO authors ( + address, + name, + bio +) VALUES ( + ?, + COALESCE(?, ""), + COALESCE(?, "") +) +` + +type AddAuthorParams struct { + Address string + CalName any + CalDescription any +} + +func (q *Queries) AddAuthor(ctx context.Context, arg AddAuthorParams) (int64, error) { + result, err := q.db.ExecContext(ctx, addAuthor, arg.Address, arg.CalName, arg.CalDescription) + if err != nil { + return 0, err + } + return result.LastInsertId() +} + +const addEvent = `-- name: AddEvent :execlastid +INSERT INTO ` + "`" + `Event` + "`" + ` ( + Timezone +) VALUES ( + (CASE WHEN ? = "calendar" THEN (SELECT cal.Timezone FROM Calendar cal WHERE cal.IdKey = ?) ELSE ? END) +) +` + +type AddEventParams struct { + Timezone any + CalendarIdKey string +} + +func (q *Queries) AddEvent(ctx context.Context, arg AddEventParams) (int64, error) { + result, err := q.db.ExecContext(ctx, addEvent, arg.Timezone, arg.CalendarIdKey, arg.Timezone) + if err != nil { + return 0, err + } + return result.LastInsertId() +} diff --git a/internal/endtoend/testdata/coalesce_params/mysql/query.sql b/internal/endtoend/testdata/coalesce_params/mysql/query.sql new file mode 100644 index 0000000..f6df77d --- /dev/null +++ b/internal/endtoend/testdata/coalesce_params/mysql/query.sql @@ -0,0 +1,17 @@ +-- name: AddEvent :execlastid +INSERT INTO `Event` ( + Timezone +) VALUES ( + (CASE WHEN sqlc.arg("Timezone") = "calendar" THEN (SELECT cal.Timezone FROM Calendar cal WHERE cal.IdKey = sqlc.arg("calendarIdKey")) ELSE sqlc.arg("Timezone") END) +); + +-- name: AddAuthor :execlastid +INSERT INTO authors ( + address, + name, + bio +) VALUES ( + ?, + COALESCE(sqlc.narg("calName"), ""), + COALESCE(sqlc.narg("calDescription"), "") +); diff --git a/internal/endtoend/testdata/coalesce_params/mysql/schema.sql b/internal/endtoend/testdata/coalesce_params/mysql/schema.sql new file mode 100644 index 0000000..0b1b346 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_params/mysql/schema.sql @@ -0,0 +1,43 @@ +CREATE TABLE `Calendar` ( + `Id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `Relation` bigint(20) unsigned NOT NULL, + `CalendarName` longblob NOT NULL, + `Title` longblob NOT NULL, + `Description` longblob NOT NULL, + `Timezone` varchar(50) NOT NULL, + `UniqueKey` varchar(50) NOT NULL, + `IdKey` varchar(50) NOT NULL, + `MainCalendar` enum('true','false') NOT NULL DEFAULT 'false', + `CreateDate` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `ModifyDate` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`Id`), + KEY `Relation` (`Relation`), + KEY `UniqueKey` (`UniqueKey`), + KEY `IdKey` (`IdKey`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + + +CREATE TABLE `Event` ( + `Id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `Relation` bigint(20) unsigned NOT NULL, + `CalendarReference` bigint(20) unsigned NOT NULL, + `UniqueKey` varchar(50) NOT NULL, + `EventName` longblob NOT NULL, + `Description` longblob NOT NULL, + `Location` varchar(500) NOT NULL, + `Timezone` varchar(50) NOT NULL, + `IdKey` varchar(48) DEFAULT NULL, + PRIMARY KEY (`Id`), + KEY `Relation` (`Relation`), + KEY `CalendarReference` (`CalendarReference`), + KEY `UniqueKey` (`UniqueKey`), + KEY `IdKey` (`IdKey`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + + +CREATE TABLE authors ( + id BIGINT AUTO_INCREMENT NOT NULL, + address VARCHAR(200) NOT NULL, + name VARCHAR(20) NOT NULL, + bio LONGTEXT NOT NULL +); diff --git a/internal/endtoend/testdata/coalesce_params/mysql/sqlc.yaml b/internal/endtoend/testdata/coalesce_params/mysql/sqlc.yaml new file mode 100644 index 0000000..b843ef5 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_params/mysql/sqlc.yaml @@ -0,0 +1,9 @@ +version: "2" +sql: + - engine: "mysql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" diff --git a/internal/endtoend/testdata/codegen_json/exec.json b/internal/endtoend/testdata/codegen_json/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/codegen_json/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/codegen_json/postgresql/query.sql b/internal/endtoend/testdata/codegen_json/postgresql/query.sql new file mode 100644 index 0000000..75e38b2 --- /dev/null +++ b/internal/endtoend/testdata/codegen_json/postgresql/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/codegen_json/postgresql/schema.sql b/internal/endtoend/testdata/codegen_json/postgresql/schema.sql new file mode 100644 index 0000000..b4fad78 --- /dev/null +++ b/internal/endtoend/testdata/codegen_json/postgresql/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/codegen_json/sqlc.json b/internal/endtoend/testdata/codegen_json/sqlc.json new file mode 100644 index 0000000..cbbf974 --- /dev/null +++ b/internal/endtoend/testdata/codegen_json/sqlc.json @@ -0,0 +1,17 @@ +{ + "version": "2", + "sql": [ + { + "schema": "postgresql/schema.sql", + "queries": "postgresql/query.sql", + "engine": "postgresql", + "gen": { + "json": { + "out": "gen", + "indent": " ", + "filename": "codegen.json" + } + } + } + ] +} diff --git a/internal/endtoend/testdata/codegen_struct_field_names/stdlib/README.md b/internal/endtoend/testdata/codegen_struct_field_names/stdlib/README.md new file mode 100644 index 0000000..910e4f7 --- /dev/null +++ b/internal/endtoend/testdata/codegen_struct_field_names/stdlib/README.md @@ -0,0 +1 @@ +This tests that Go struct field names are proper Go identifiers. \ No newline at end of file diff --git a/internal/endtoend/testdata/codegen_struct_field_names/stdlib/go/db.go b/internal/endtoend/testdata/codegen_struct_field_names/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/codegen_struct_field_names/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/codegen_struct_field_names/stdlib/go/models.go b/internal/endtoend/testdata/codegen_struct_field_names/stdlib/go/models.go new file mode 100644 index 0000000..1a770e5 --- /dev/null +++ b/internal/endtoend/testdata/codegen_struct_field_names/stdlib/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ID int32 + NobodyWouldBelieveThis sql.NullInt32 + ParentID sql.NullInt32 +} diff --git a/internal/endtoend/testdata/codegen_struct_field_names/stdlib/go/query.sql.go b/internal/endtoend/testdata/codegen_struct_field_names/stdlib/go/query.sql.go new file mode 100644 index 0000000..5675e7c --- /dev/null +++ b/internal/endtoend/testdata/codegen_struct_field_names/stdlib/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const test = `-- name: test :one +SELECT id, "!!!nobody,_,-would-believe---this-...?!", "parent id" from bar limit 1 +` + +func (q *Queries) test(ctx context.Context) (Bar, error) { + row := q.db.QueryRowContext(ctx, test) + var i Bar + err := row.Scan(&i.ID, &i.NobodyWouldBelieveThis, &i.ParentID) + return i, err +} diff --git a/internal/endtoend/testdata/codegen_struct_field_names/stdlib/query.sql b/internal/endtoend/testdata/codegen_struct_field_names/stdlib/query.sql new file mode 100644 index 0000000..252d207 --- /dev/null +++ b/internal/endtoend/testdata/codegen_struct_field_names/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: test :one +SELECT * from bar limit 1; diff --git a/internal/endtoend/testdata/codegen_struct_field_names/stdlib/schema.sql b/internal/endtoend/testdata/codegen_struct_field_names/stdlib/schema.sql new file mode 100644 index 0000000..68a6c9b --- /dev/null +++ b/internal/endtoend/testdata/codegen_struct_field_names/stdlib/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE bar ( + id INT NOT NULL, + "!!!nobody,_,-would-believe---this-...?!" INT, + "parent id" INT); + diff --git a/internal/endtoend/testdata/codegen_struct_field_names/stdlib/sqlc.json b/internal/endtoend/testdata/codegen_struct_field_names/stdlib/sqlc.json new file mode 100644 index 0000000..4f08376 --- /dev/null +++ b/internal/endtoend/testdata/codegen_struct_field_names/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/column_alias/issue.md b/internal/endtoend/testdata/column_alias/issue.md new file mode 100644 index 0000000..fc16c2a --- /dev/null +++ b/internal/endtoend/testdata/column_alias/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1739 diff --git a/internal/endtoend/testdata/column_alias/stdlib/exec.json b/internal/endtoend/testdata/column_alias/stdlib/exec.json new file mode 100644 index 0000000..e5dfda7 --- /dev/null +++ b/internal/endtoend/testdata/column_alias/stdlib/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/column_alias/stdlib/go/db.go b/internal/endtoend/testdata/column_alias/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/column_alias/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/column_alias/stdlib/go/models.go b/internal/endtoend/testdata/column_alias/stdlib/go/models.go new file mode 100644 index 0000000..bdd8c70 --- /dev/null +++ b/internal/endtoend/testdata/column_alias/stdlib/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "time" +) + +type User struct { + ID int32 + Fname string + Lname string + Email string + EncPasswd string + CreatedAt time.Time +} diff --git a/internal/endtoend/testdata/column_alias/stdlib/go/query.sql.go b/internal/endtoend/testdata/column_alias/stdlib/go/query.sql.go new file mode 100644 index 0000000..a4b43d3 --- /dev/null +++ b/internal/endtoend/testdata/column_alias/stdlib/go/query.sql.go @@ -0,0 +1,80 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" + "time" +) + +const getUsers = `-- name: GetUsers :many +SELECT + users.id, + users.fname, + users.lname, + users.email, + users.created_at, + rank_email, + rank_fname, + rank_lname, + similarity +FROM + users, + to_tsvector(users.email || users.fname || users.lname) document, + to_tsquery($1::TEXT) query, + NULLIF(ts_rank(to_tsvector(users.email), query), 0) rank_email, + NULLIF(ts_rank(to_tsvector(users.fname), query), 0) rank_fname, + NULLIF(ts_rank(to_tsvector(users.lname), query), 0) rank_lname, + SIMILARITY($1::TEXT, users.email || users.fname || users.lname) similarity +WHERE query @@ document OR similarity > 0 +ORDER BY rank_email, rank_lname, rank_fname, similarity DESC NULLS LAST +` + +type GetUsersRow struct { + ID int32 + Fname string + Lname string + Email string + CreatedAt time.Time + RankEmail sql.NullFloat64 + RankFname sql.NullFloat64 + RankLname sql.NullFloat64 + Similarity sql.NullFloat64 +} + +func (q *Queries) GetUsers(ctx context.Context, searchTerm string) ([]GetUsersRow, error) { + rows, err := q.db.QueryContext(ctx, getUsers, searchTerm) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetUsersRow + for rows.Next() { + var i GetUsersRow + if err := rows.Scan( + &i.ID, + &i.Fname, + &i.Lname, + &i.Email, + &i.CreatedAt, + &i.RankEmail, + &i.RankFname, + &i.RankLname, + &i.Similarity, + ); 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/column_alias/stdlib/query.sql b/internal/endtoend/testdata/column_alias/stdlib/query.sql new file mode 100644 index 0000000..9877fad --- /dev/null +++ b/internal/endtoend/testdata/column_alias/stdlib/query.sql @@ -0,0 +1,21 @@ +-- name: GetUsers :many +SELECT + users.id, + users.fname, + users.lname, + users.email, + users.created_at, + rank_email, + rank_fname, + rank_lname, + similarity +FROM + users, + to_tsvector(users.email || users.fname || users.lname) document, + to_tsquery(@search_term::TEXT) query, + NULLIF(ts_rank(to_tsvector(users.email), query), 0) rank_email, + NULLIF(ts_rank(to_tsvector(users.fname), query), 0) rank_fname, + NULLIF(ts_rank(to_tsvector(users.lname), query), 0) rank_lname, + SIMILARITY(@search_term::TEXT, users.email || users.fname || users.lname) similarity +WHERE query @@ document OR similarity > 0 +ORDER BY rank_email, rank_lname, rank_fname, similarity DESC NULLS LAST; diff --git a/internal/endtoend/testdata/column_alias/stdlib/schema.sql b/internal/endtoend/testdata/column_alias/stdlib/schema.sql new file mode 100644 index 0000000..9205a14 --- /dev/null +++ b/internal/endtoend/testdata/column_alias/stdlib/schema.sql @@ -0,0 +1,12 @@ +CREATE EXTENSION pg_trgm; +CREATE EXTENSION pgcrypto; + +CREATE TABLE users( + id INT GENERATED ALWAYS AS IDENTITY NOT NULL, + fname VARCHAR(100) NOT NULL, + lname VARCHAR(100) NOT NULL, + email VARCHAR(100) NOT NULL UNIQUE, + enc_passwd TEXT NOT NULL, + created_at TIMESTAMP WITH TIME ZONE NOT NULL default (NOW() AT TIME ZONE 'utc'), + PRIMARY KEY(id) +); diff --git a/internal/endtoend/testdata/column_alias/stdlib/sqlc.yaml b/internal/endtoend/testdata/column_alias/stdlib/sqlc.yaml new file mode 100644 index 0000000..8c68222 --- /dev/null +++ b/internal/endtoend/testdata/column_alias/stdlib/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "database/sql" diff --git a/internal/endtoend/testdata/column_as/mysql/go/db.go b/internal/endtoend/testdata/column_as/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/column_as/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/column_as/mysql/go/models.go b/internal/endtoend/testdata/column_as/mysql/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/column_as/mysql/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/column_as/mysql/go/query.sql.go b/internal/endtoend/testdata/column_as/mysql/go/query.sql.go new file mode 100644 index 0000000..a4636a1 --- /dev/null +++ b/internal/endtoend/testdata/column_as/mysql/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const withAs = `-- name: WithAs :one +SELECT 1 AS x, 2 AS y +` + +type WithAsRow struct { + X int32 + Y int32 +} + +func (q *Queries) WithAs(ctx context.Context) (WithAsRow, error) { + row := q.db.QueryRowContext(ctx, withAs) + var i WithAsRow + err := row.Scan(&i.X, &i.Y) + return i, err +} + +const withoutAs = `-- name: WithoutAs :one +SELECT 1 x, 2 y +` + +type WithoutAsRow struct { + X int32 + Y int32 +} + +func (q *Queries) WithoutAs(ctx context.Context) (WithoutAsRow, error) { + row := q.db.QueryRowContext(ctx, withoutAs) + var i WithoutAsRow + err := row.Scan(&i.X, &i.Y) + return i, err +} diff --git a/internal/endtoend/testdata/column_as/mysql/query.sql b/internal/endtoend/testdata/column_as/mysql/query.sql new file mode 100644 index 0000000..3501445 --- /dev/null +++ b/internal/endtoend/testdata/column_as/mysql/query.sql @@ -0,0 +1,5 @@ +-- name: WithAs :one +SELECT 1 AS x, 2 AS y; + +-- name: WithoutAs :one +SELECT 1 x, 2 y; \ No newline at end of file diff --git a/internal/endtoend/testdata/column_as/mysql/schema.sql b/internal/endtoend/testdata/column_as/mysql/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/column_as/mysql/sqlc.json b/internal/endtoend/testdata/column_as/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/column_as/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/column_as/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/column_as/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/column_as/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/column_as/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/column_as/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/column_as/postgresql/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/column_as/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/column_as/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..ddaee5d --- /dev/null +++ b/internal/endtoend/testdata/column_as/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const withAs = `-- name: WithAs :one +SELECT 1 AS x, 2 AS y +` + +type WithAsRow struct { + X int32 + Y int32 +} + +func (q *Queries) WithAs(ctx context.Context) (WithAsRow, error) { + row := q.db.QueryRow(ctx, withAs) + var i WithAsRow + err := row.Scan(&i.X, &i.Y) + return i, err +} + +const withoutAs = `-- name: WithoutAs :one +SELECT 1 x, 2 y +` + +type WithoutAsRow struct { + X int32 + Y int32 +} + +func (q *Queries) WithoutAs(ctx context.Context) (WithoutAsRow, error) { + row := q.db.QueryRow(ctx, withoutAs) + var i WithoutAsRow + err := row.Scan(&i.X, &i.Y) + return i, err +} diff --git a/internal/endtoend/testdata/column_as/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/column_as/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..3501445 --- /dev/null +++ b/internal/endtoend/testdata/column_as/postgresql/pgx/v4/query.sql @@ -0,0 +1,5 @@ +-- name: WithAs :one +SELECT 1 AS x, 2 AS y; + +-- name: WithoutAs :one +SELECT 1 x, 2 y; \ No newline at end of file diff --git a/internal/endtoend/testdata/column_as/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/column_as/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/column_as/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/column_as/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..4c0b278 --- /dev/null +++ b/internal/endtoend/testdata/column_as/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "sql_package": "pgx/v4", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/column_as/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/column_as/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/column_as/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/column_as/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/column_as/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/column_as/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/column_as/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/column_as/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..ddaee5d --- /dev/null +++ b/internal/endtoend/testdata/column_as/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const withAs = `-- name: WithAs :one +SELECT 1 AS x, 2 AS y +` + +type WithAsRow struct { + X int32 + Y int32 +} + +func (q *Queries) WithAs(ctx context.Context) (WithAsRow, error) { + row := q.db.QueryRow(ctx, withAs) + var i WithAsRow + err := row.Scan(&i.X, &i.Y) + return i, err +} + +const withoutAs = `-- name: WithoutAs :one +SELECT 1 x, 2 y +` + +type WithoutAsRow struct { + X int32 + Y int32 +} + +func (q *Queries) WithoutAs(ctx context.Context) (WithoutAsRow, error) { + row := q.db.QueryRow(ctx, withoutAs) + var i WithoutAsRow + err := row.Scan(&i.X, &i.Y) + return i, err +} diff --git a/internal/endtoend/testdata/column_as/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/column_as/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..3501445 --- /dev/null +++ b/internal/endtoend/testdata/column_as/postgresql/pgx/v5/query.sql @@ -0,0 +1,5 @@ +-- name: WithAs :one +SELECT 1 AS x, 2 AS y; + +-- name: WithoutAs :one +SELECT 1 x, 2 y; \ No newline at end of file diff --git a/internal/endtoend/testdata/column_as/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/column_as/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/column_as/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/column_as/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..d12b82a --- /dev/null +++ b/internal/endtoend/testdata/column_as/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "sql_package": "pgx/v5", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/column_as/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/column_as/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/column_as/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/column_as/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/column_as/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/column_as/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/column_as/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/column_as/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..a4636a1 --- /dev/null +++ b/internal/endtoend/testdata/column_as/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const withAs = `-- name: WithAs :one +SELECT 1 AS x, 2 AS y +` + +type WithAsRow struct { + X int32 + Y int32 +} + +func (q *Queries) WithAs(ctx context.Context) (WithAsRow, error) { + row := q.db.QueryRowContext(ctx, withAs) + var i WithAsRow + err := row.Scan(&i.X, &i.Y) + return i, err +} + +const withoutAs = `-- name: WithoutAs :one +SELECT 1 x, 2 y +` + +type WithoutAsRow struct { + X int32 + Y int32 +} + +func (q *Queries) WithoutAs(ctx context.Context) (WithoutAsRow, error) { + row := q.db.QueryRowContext(ctx, withoutAs) + var i WithoutAsRow + err := row.Scan(&i.X, &i.Y) + return i, err +} diff --git a/internal/endtoend/testdata/column_as/postgresql/stdlib/query.sql b/internal/endtoend/testdata/column_as/postgresql/stdlib/query.sql new file mode 100644 index 0000000..3501445 --- /dev/null +++ b/internal/endtoend/testdata/column_as/postgresql/stdlib/query.sql @@ -0,0 +1,5 @@ +-- name: WithAs :one +SELECT 1 AS x, 2 AS y; + +-- name: WithoutAs :one +SELECT 1 x, 2 y; \ No newline at end of file diff --git a/internal/endtoend/testdata/column_as/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/column_as/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/column_as/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/column_as/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..cd51867 --- /dev/null +++ b/internal/endtoend/testdata/column_as/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/column_as/sqlite/go/db.go b/internal/endtoend/testdata/column_as/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/column_as/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/column_as/sqlite/go/models.go b/internal/endtoend/testdata/column_as/sqlite/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/column_as/sqlite/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/column_as/sqlite/go/query.sql.go b/internal/endtoend/testdata/column_as/sqlite/go/query.sql.go new file mode 100644 index 0000000..66d96ac --- /dev/null +++ b/internal/endtoend/testdata/column_as/sqlite/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const withAs = `-- name: WithAs :one +SELECT 1 AS x, 2 AS y +` + +type WithAsRow struct { + X int64 + Y int64 +} + +func (q *Queries) WithAs(ctx context.Context) (WithAsRow, error) { + row := q.db.QueryRowContext(ctx, withAs) + var i WithAsRow + err := row.Scan(&i.X, &i.Y) + return i, err +} + +const withoutAs = `-- name: WithoutAs :one +SELECT 1 AS x, 2 AS y +` + +type WithoutAsRow struct { + X int64 + Y int64 +} + +func (q *Queries) WithoutAs(ctx context.Context) (WithoutAsRow, error) { + row := q.db.QueryRowContext(ctx, withoutAs) + var i WithoutAsRow + err := row.Scan(&i.X, &i.Y) + return i, err +} diff --git a/internal/endtoend/testdata/column_as/sqlite/query.sql b/internal/endtoend/testdata/column_as/sqlite/query.sql new file mode 100644 index 0000000..e783582 --- /dev/null +++ b/internal/endtoend/testdata/column_as/sqlite/query.sql @@ -0,0 +1,5 @@ +-- name: WithAs :one +SELECT 1 AS x, 2 AS y; + +-- name: WithoutAs :one +SELECT 1 AS x, 2 AS y; diff --git a/internal/endtoend/testdata/column_as/sqlite/schema.sql b/internal/endtoend/testdata/column_as/sqlite/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/column_as/sqlite/sqlc.json b/internal/endtoend/testdata/column_as/sqlite/sqlc.json new file mode 100644 index 0000000..f8e8051 --- /dev/null +++ b/internal/endtoend/testdata/column_as/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "sqlite", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/comment_godoc/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..b5395d4 --- /dev/null +++ b/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v4/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString +} diff --git a/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8d1169a --- /dev/null +++ b/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,82 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" + + "github.com/jackc/pgconn" +) + +const execFoo = `-- name: ExecFoo :exec +INSERT INTO foo (bar) VALUES ('bar') +` + +// This function creates a Foo via :exec +func (q *Queries) ExecFoo(ctx context.Context) error { + _, err := q.db.Exec(ctx, execFoo) + return err +} + +const execResultFoo = `-- name: ExecResultFoo :execresult +INSERT INTO foo (bar) VALUES ('bar') +` + +// This function creates a Foo via :execresult +func (q *Queries) ExecResultFoo(ctx context.Context) (pgconn.CommandTag, error) { + return q.db.Exec(ctx, execResultFoo) +} + +const execRowFoo = `-- name: ExecRowFoo :execrows +INSERT INTO foo (bar) VALUES ('bar') +` + +// This function creates a Foo via :execrows +func (q *Queries) ExecRowFoo(ctx context.Context) (int64, error) { + result, err := q.db.Exec(ctx, execRowFoo) + if err != nil { + return 0, err + } + return result.RowsAffected(), nil +} + +const manyFoo = `-- name: ManyFoo :many +SELECT bar FROM foo +` + +// This function returns a list of Foos +func (q *Queries) ManyFoo(ctx context.Context) ([]sql.NullString, error) { + rows, err := q.db.Query(ctx, manyFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var bar sql.NullString + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const oneFoo = `-- name: OneFoo :one +SELECT bar FROM foo +` + +// This function returns one Foo +func (q *Queries) OneFoo(ctx context.Context) (sql.NullString, error) { + row := q.db.QueryRow(ctx, oneFoo) + var bar sql.NullString + err := row.Scan(&bar) + return bar, err +} diff --git a/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..b5fab38 --- /dev/null +++ b/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v4/query.sql @@ -0,0 +1,19 @@ +-- name: ManyFoo :many +-- This function returns a list of Foos +SELECT * FROM foo; + +-- name: OneFoo :one +-- This function returns one Foo +SELECT * FROM foo; + +-- name: ExecFoo :exec +-- This function creates a Foo via :exec +INSERT INTO foo (bar) VALUES ('bar'); + +-- name: ExecRowFoo :execrows +-- This function creates a Foo via :execrows +INSERT INTO foo (bar) VALUES ('bar'); + +-- name: ExecResultFoo :execresult +-- This function creates a Foo via :execresult +INSERT INTO foo (bar) VALUES ('bar'); diff --git a/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..31bcf76 --- /dev/null +++ b/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v4/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE foo ( + bar text +); + diff --git a/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..5ffafef --- /dev/null +++ b/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "sql_package": "pgx/v4" + } + ] +} + diff --git a/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/comment_godoc/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..d867cae --- /dev/null +++ b/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v5/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + Bar pgtype.Text +} diff --git a/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..22975b4 --- /dev/null +++ b/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,82 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgconn" + "github.com/jackc/pgx/v5/pgtype" +) + +const execFoo = `-- name: ExecFoo :exec +INSERT INTO foo (bar) VALUES ('bar') +` + +// This function creates a Foo via :exec +func (q *Queries) ExecFoo(ctx context.Context) error { + _, err := q.db.Exec(ctx, execFoo) + return err +} + +const execResultFoo = `-- name: ExecResultFoo :execresult +INSERT INTO foo (bar) VALUES ('bar') +` + +// This function creates a Foo via :execresult +func (q *Queries) ExecResultFoo(ctx context.Context) (pgconn.CommandTag, error) { + return q.db.Exec(ctx, execResultFoo) +} + +const execRowFoo = `-- name: ExecRowFoo :execrows +INSERT INTO foo (bar) VALUES ('bar') +` + +// This function creates a Foo via :execrows +func (q *Queries) ExecRowFoo(ctx context.Context) (int64, error) { + result, err := q.db.Exec(ctx, execRowFoo) + if err != nil { + return 0, err + } + return result.RowsAffected(), nil +} + +const manyFoo = `-- name: ManyFoo :many +SELECT bar FROM foo +` + +// This function returns a list of Foos +func (q *Queries) ManyFoo(ctx context.Context) ([]pgtype.Text, error) { + rows, err := q.db.Query(ctx, manyFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []pgtype.Text + for rows.Next() { + var bar pgtype.Text + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const oneFoo = `-- name: OneFoo :one +SELECT bar FROM foo +` + +// This function returns one Foo +func (q *Queries) OneFoo(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, oneFoo) + var bar pgtype.Text + err := row.Scan(&bar) + return bar, err +} diff --git a/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..b5fab38 --- /dev/null +++ b/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v5/query.sql @@ -0,0 +1,19 @@ +-- name: ManyFoo :many +-- This function returns a list of Foos +SELECT * FROM foo; + +-- name: OneFoo :one +-- This function returns one Foo +SELECT * FROM foo; + +-- name: ExecFoo :exec +-- This function creates a Foo via :exec +INSERT INTO foo (bar) VALUES ('bar'); + +-- name: ExecRowFoo :execrows +-- This function creates a Foo via :execrows +INSERT INTO foo (bar) VALUES ('bar'); + +-- name: ExecResultFoo :execresult +-- This function creates a Foo via :execresult +INSERT INTO foo (bar) VALUES ('bar'); diff --git a/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..31bcf76 --- /dev/null +++ b/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v5/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE foo ( + bar text +); + diff --git a/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..4905a64 --- /dev/null +++ b/internal/endtoend/testdata/comment_godoc/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "sql_package": "pgx/v5" + } + ] +} + diff --git a/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..abdbd0d --- /dev/null +++ b/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v4/go/db.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row +} + +func New() *Queries { + return &Queries{} +} + +type Queries struct { +} diff --git a/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..b5395d4 --- /dev/null +++ b/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v4/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString +} diff --git a/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..7512f5a --- /dev/null +++ b/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,82 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" + + "github.com/jackc/pgconn" +) + +const execFoo = `-- name: ExecFoo :exec +INSERT INTO foo (bar) VALUES ('bar') +` + +// This function creates a Foo via :exec +func (q *Queries) ExecFoo(ctx context.Context, db DBTX) error { + _, err := db.Exec(ctx, execFoo) + return err +} + +const execResultFoo = `-- name: ExecResultFoo :execresult +INSERT INTO foo (bar) VALUES ('bar') +` + +// This function creates a Foo via :execresult +func (q *Queries) ExecResultFoo(ctx context.Context, db DBTX) (pgconn.CommandTag, error) { + return db.Exec(ctx, execResultFoo) +} + +const execRowFoo = `-- name: ExecRowFoo :execrows +INSERT INTO foo (bar) VALUES ('bar') +` + +// This function creates a Foo via :execrows +func (q *Queries) ExecRowFoo(ctx context.Context, db DBTX) (int64, error) { + result, err := db.Exec(ctx, execRowFoo) + if err != nil { + return 0, err + } + return result.RowsAffected(), nil +} + +const manyFoo = `-- name: ManyFoo :many +SELECT bar FROM foo +` + +// This function returns a list of Foos +func (q *Queries) ManyFoo(ctx context.Context, db DBTX) ([]sql.NullString, error) { + rows, err := db.Query(ctx, manyFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var bar sql.NullString + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const oneFoo = `-- name: OneFoo :one +SELECT bar FROM foo +` + +// This function returns one Foo +func (q *Queries) OneFoo(ctx context.Context, db DBTX) (sql.NullString, error) { + row := db.QueryRow(ctx, oneFoo) + var bar sql.NullString + err := row.Scan(&bar) + return bar, err +} diff --git a/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..b5fab38 --- /dev/null +++ b/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v4/query.sql @@ -0,0 +1,19 @@ +-- name: ManyFoo :many +-- This function returns a list of Foos +SELECT * FROM foo; + +-- name: OneFoo :one +-- This function returns one Foo +SELECT * FROM foo; + +-- name: ExecFoo :exec +-- This function creates a Foo via :exec +INSERT INTO foo (bar) VALUES ('bar'); + +-- name: ExecRowFoo :execrows +-- This function creates a Foo via :execrows +INSERT INTO foo (bar) VALUES ('bar'); + +-- name: ExecResultFoo :execresult +-- This function creates a Foo via :execresult +INSERT INTO foo (bar) VALUES ('bar'); diff --git a/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..31bcf76 --- /dev/null +++ b/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v4/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE foo ( + bar text +); + diff --git a/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..6b0b6cd --- /dev/null +++ b/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "sql_package": "pgx/v4", + "emit_methods_with_db_argument": true + } + ] +} diff --git a/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..0a95f19 --- /dev/null +++ b/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v5/go/db.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row +} + +func New() *Queries { + return &Queries{} +} + +type Queries struct { +} diff --git a/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..d867cae --- /dev/null +++ b/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v5/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + Bar pgtype.Text +} diff --git a/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..d8d6296 --- /dev/null +++ b/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,82 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgconn" + "github.com/jackc/pgx/v5/pgtype" +) + +const execFoo = `-- name: ExecFoo :exec +INSERT INTO foo (bar) VALUES ('bar') +` + +// This function creates a Foo via :exec +func (q *Queries) ExecFoo(ctx context.Context, db DBTX) error { + _, err := db.Exec(ctx, execFoo) + return err +} + +const execResultFoo = `-- name: ExecResultFoo :execresult +INSERT INTO foo (bar) VALUES ('bar') +` + +// This function creates a Foo via :execresult +func (q *Queries) ExecResultFoo(ctx context.Context, db DBTX) (pgconn.CommandTag, error) { + return db.Exec(ctx, execResultFoo) +} + +const execRowFoo = `-- name: ExecRowFoo :execrows +INSERT INTO foo (bar) VALUES ('bar') +` + +// This function creates a Foo via :execrows +func (q *Queries) ExecRowFoo(ctx context.Context, db DBTX) (int64, error) { + result, err := db.Exec(ctx, execRowFoo) + if err != nil { + return 0, err + } + return result.RowsAffected(), nil +} + +const manyFoo = `-- name: ManyFoo :many +SELECT bar FROM foo +` + +// This function returns a list of Foos +func (q *Queries) ManyFoo(ctx context.Context, db DBTX) ([]pgtype.Text, error) { + rows, err := db.Query(ctx, manyFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []pgtype.Text + for rows.Next() { + var bar pgtype.Text + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const oneFoo = `-- name: OneFoo :one +SELECT bar FROM foo +` + +// This function returns one Foo +func (q *Queries) OneFoo(ctx context.Context, db DBTX) (pgtype.Text, error) { + row := db.QueryRow(ctx, oneFoo) + var bar pgtype.Text + err := row.Scan(&bar) + return bar, err +} diff --git a/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..b5fab38 --- /dev/null +++ b/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v5/query.sql @@ -0,0 +1,19 @@ +-- name: ManyFoo :many +-- This function returns a list of Foos +SELECT * FROM foo; + +-- name: OneFoo :one +-- This function returns one Foo +SELECT * FROM foo; + +-- name: ExecFoo :exec +-- This function creates a Foo via :exec +INSERT INTO foo (bar) VALUES ('bar'); + +-- name: ExecRowFoo :execrows +-- This function creates a Foo via :execrows +INSERT INTO foo (bar) VALUES ('bar'); + +-- name: ExecResultFoo :execresult +-- This function creates a Foo via :execresult +INSERT INTO foo (bar) VALUES ('bar'); diff --git a/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..31bcf76 --- /dev/null +++ b/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v5/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE foo ( + bar text +); + diff --git a/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..0e07b3a --- /dev/null +++ b/internal/endtoend/testdata/comment_godoc_db_argument/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "sql_package": "pgx/v5", + "emit_methods_with_db_argument": true + } + ] +} diff --git a/internal/endtoend/testdata/comment_on/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/comment_on/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/comment_on/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/comment_on/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/comment_on/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..fcc9510 --- /dev/null +++ b/internal/endtoend/testdata/comment_on/postgresql/pgx/v4/go/models.go @@ -0,0 +1,65 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +// this is the mood type +type FooMood string + +const ( + FooMoodSad FooMood = "sad" + FooMoodOk FooMood = "ok" + FooMoodHappy FooMood = "happy" +) + +func (e *FooMood) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = FooMood(s) + case string: + *e = FooMood(s) + default: + return fmt.Errorf("unsupported scan type for FooMood: %T", src) + } + return nil +} + +type NullFooMood struct { + FooMood FooMood + Valid bool // Valid is true if FooMood is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullFooMood) Scan(value any) error { + if value == nil { + ns.FooMood, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.FooMood.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullFooMood) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.FooMood), nil +} + +// this is the bar table +type FooBar struct { + // this is the baz column + Baz string +} + +// this is the bat view +type FooBat struct { + Baz string +} diff --git a/internal/endtoend/testdata/comment_on/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/comment_on/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..0ab2b79 --- /dev/null +++ b/internal/endtoend/testdata/comment_on/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,58 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listBar = `-- name: ListBar :many +SELECT baz FROM foo.bar +` + +func (q *Queries) ListBar(ctx context.Context) ([]string, error) { + rows, err := q.db.Query(ctx, listBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var baz string + if err := rows.Scan(&baz); err != nil { + return nil, err + } + items = append(items, baz) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listBat = `-- name: ListBat :many +SELECT baz FROM foo.bat +` + +func (q *Queries) ListBat(ctx context.Context) ([]string, error) { + rows, err := q.db.Query(ctx, listBat) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var baz string + if err := rows.Scan(&baz); err != nil { + return nil, err + } + items = append(items, baz) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/comment_on/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/comment_on/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..cda102c --- /dev/null +++ b/internal/endtoend/testdata/comment_on/postgresql/pgx/v4/query.sql @@ -0,0 +1,5 @@ +-- name: ListBar :many +SELECT * FROM foo.bar; + +-- name: ListBat :many +SELECT * FROM foo.bat; diff --git a/internal/endtoend/testdata/comment_on/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/comment_on/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..6e2052b --- /dev/null +++ b/internal/endtoend/testdata/comment_on/postgresql/pgx/v4/schema.sql @@ -0,0 +1,16 @@ +CREATE SCHEMA foo; + +CREATE TABLE foo.bar ( + baz text NOT NULL +); + +CREATE VIEW foo.bat AS SELECT * FROM foo.bar; + +CREATE TYPE foo.mood AS ENUM ('sad', 'ok', 'happy'); + +COMMENT ON SCHEMA foo IS 'this is the foo schema'; +COMMENT ON TYPE foo.mood IS 'this is the mood type'; +COMMENT ON TABLE foo.bar IS 'this is the bar table'; +COMMENT ON COLUMN foo.bar.baz IS 'this is the baz column'; +COMMENT ON VIEW foo.bat IS 'this is the bat view '; + diff --git a/internal/endtoend/testdata/comment_on/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/comment_on/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/comment_on/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/comment_on/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/comment_on/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/comment_on/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/comment_on/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/comment_on/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..fcc9510 --- /dev/null +++ b/internal/endtoend/testdata/comment_on/postgresql/pgx/v5/go/models.go @@ -0,0 +1,65 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +// this is the mood type +type FooMood string + +const ( + FooMoodSad FooMood = "sad" + FooMoodOk FooMood = "ok" + FooMoodHappy FooMood = "happy" +) + +func (e *FooMood) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = FooMood(s) + case string: + *e = FooMood(s) + default: + return fmt.Errorf("unsupported scan type for FooMood: %T", src) + } + return nil +} + +type NullFooMood struct { + FooMood FooMood + Valid bool // Valid is true if FooMood is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullFooMood) Scan(value any) error { + if value == nil { + ns.FooMood, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.FooMood.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullFooMood) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.FooMood), nil +} + +// this is the bar table +type FooBar struct { + // this is the baz column + Baz string +} + +// this is the bat view +type FooBat struct { + Baz string +} diff --git a/internal/endtoend/testdata/comment_on/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/comment_on/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..0ab2b79 --- /dev/null +++ b/internal/endtoend/testdata/comment_on/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,58 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listBar = `-- name: ListBar :many +SELECT baz FROM foo.bar +` + +func (q *Queries) ListBar(ctx context.Context) ([]string, error) { + rows, err := q.db.Query(ctx, listBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var baz string + if err := rows.Scan(&baz); err != nil { + return nil, err + } + items = append(items, baz) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listBat = `-- name: ListBat :many +SELECT baz FROM foo.bat +` + +func (q *Queries) ListBat(ctx context.Context) ([]string, error) { + rows, err := q.db.Query(ctx, listBat) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var baz string + if err := rows.Scan(&baz); err != nil { + return nil, err + } + items = append(items, baz) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/comment_on/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/comment_on/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..cda102c --- /dev/null +++ b/internal/endtoend/testdata/comment_on/postgresql/pgx/v5/query.sql @@ -0,0 +1,5 @@ +-- name: ListBar :many +SELECT * FROM foo.bar; + +-- name: ListBat :many +SELECT * FROM foo.bat; diff --git a/internal/endtoend/testdata/comment_on/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/comment_on/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..6e2052b --- /dev/null +++ b/internal/endtoend/testdata/comment_on/postgresql/pgx/v5/schema.sql @@ -0,0 +1,16 @@ +CREATE SCHEMA foo; + +CREATE TABLE foo.bar ( + baz text NOT NULL +); + +CREATE VIEW foo.bat AS SELECT * FROM foo.bar; + +CREATE TYPE foo.mood AS ENUM ('sad', 'ok', 'happy'); + +COMMENT ON SCHEMA foo IS 'this is the foo schema'; +COMMENT ON TYPE foo.mood IS 'this is the mood type'; +COMMENT ON TABLE foo.bar IS 'this is the bar table'; +COMMENT ON COLUMN foo.bar.baz IS 'this is the baz column'; +COMMENT ON VIEW foo.bat IS 'this is the bat view '; + diff --git a/internal/endtoend/testdata/comment_on/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/comment_on/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/comment_on/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/comment_on/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/comment_on/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/comment_on/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/comment_on/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/comment_on/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..fcc9510 --- /dev/null +++ b/internal/endtoend/testdata/comment_on/postgresql/stdlib/go/models.go @@ -0,0 +1,65 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +// this is the mood type +type FooMood string + +const ( + FooMoodSad FooMood = "sad" + FooMoodOk FooMood = "ok" + FooMoodHappy FooMood = "happy" +) + +func (e *FooMood) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = FooMood(s) + case string: + *e = FooMood(s) + default: + return fmt.Errorf("unsupported scan type for FooMood: %T", src) + } + return nil +} + +type NullFooMood struct { + FooMood FooMood + Valid bool // Valid is true if FooMood is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullFooMood) Scan(value any) error { + if value == nil { + ns.FooMood, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.FooMood.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullFooMood) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.FooMood), nil +} + +// this is the bar table +type FooBar struct { + // this is the baz column + Baz string +} + +// this is the bat view +type FooBat struct { + Baz string +} diff --git a/internal/endtoend/testdata/comment_on/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/comment_on/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..c18f189 --- /dev/null +++ b/internal/endtoend/testdata/comment_on/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,64 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listBar = `-- name: ListBar :many +SELECT baz FROM foo.bar +` + +func (q *Queries) ListBar(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, listBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var baz string + if err := rows.Scan(&baz); err != nil { + return nil, err + } + items = append(items, baz) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listBat = `-- name: ListBat :many +SELECT baz FROM foo.bat +` + +func (q *Queries) ListBat(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, listBat) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var baz string + if err := rows.Scan(&baz); err != nil { + return nil, err + } + items = append(items, baz) + } + 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/comment_on/postgresql/stdlib/query.sql b/internal/endtoend/testdata/comment_on/postgresql/stdlib/query.sql new file mode 100644 index 0000000..cda102c --- /dev/null +++ b/internal/endtoend/testdata/comment_on/postgresql/stdlib/query.sql @@ -0,0 +1,5 @@ +-- name: ListBar :many +SELECT * FROM foo.bar; + +-- name: ListBat :many +SELECT * FROM foo.bat; diff --git a/internal/endtoend/testdata/comment_on/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/comment_on/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..6e2052b --- /dev/null +++ b/internal/endtoend/testdata/comment_on/postgresql/stdlib/schema.sql @@ -0,0 +1,16 @@ +CREATE SCHEMA foo; + +CREATE TABLE foo.bar ( + baz text NOT NULL +); + +CREATE VIEW foo.bat AS SELECT * FROM foo.bar; + +CREATE TYPE foo.mood AS ENUM ('sad', 'ok', 'happy'); + +COMMENT ON SCHEMA foo IS 'this is the foo schema'; +COMMENT ON TYPE foo.mood IS 'this is the mood type'; +COMMENT ON TABLE foo.bar IS 'this is the bar table'; +COMMENT ON COLUMN foo.bar.baz IS 'this is the baz column'; +COMMENT ON VIEW foo.bat IS 'this is the bat view '; + diff --git a/internal/endtoend/testdata/comment_on/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/comment_on/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..3a3e2e5 --- /dev/null +++ b/internal/endtoend/testdata/comment_on/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/comment_syntax/mysql/go/db.go b/internal/endtoend/testdata/comment_syntax/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/comment_syntax/mysql/go/models.go b/internal/endtoend/testdata/comment_syntax/mysql/go/models.go new file mode 100644 index 0000000..b5395d4 --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/mysql/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString +} diff --git a/internal/endtoend/testdata/comment_syntax/mysql/go/query.sql.go b/internal/endtoend/testdata/comment_syntax/mysql/go/query.sql.go new file mode 100644 index 0000000..9305591 --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/mysql/go/query.sql.go @@ -0,0 +1,44 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const doubleDash = `-- name: DoubleDash :one +SELECT bar FROM foo LIMIT 1 +` + +func (q *Queries) DoubleDash(ctx context.Context) (sql.NullString, error) { + row := q.db.QueryRowContext(ctx, doubleDash) + var bar sql.NullString + err := row.Scan(&bar) + return bar, err +} + +const hash = `-- name: Hash :one +SELECT bar FROM foo LIMIT 1 +` + +func (q *Queries) Hash(ctx context.Context) (sql.NullString, error) { + row := q.db.QueryRowContext(ctx, hash) + var bar sql.NullString + err := row.Scan(&bar) + return bar, err +} + +const slashStar = `-- name: SlashStar :one +SELECT bar FROM foo LIMIT 1 +` + +func (q *Queries) SlashStar(ctx context.Context) (sql.NullString, error) { + row := q.db.QueryRowContext(ctx, slashStar) + var bar sql.NullString + err := row.Scan(&bar) + return bar, err +} diff --git a/internal/endtoend/testdata/comment_syntax/mysql/query.sql b/internal/endtoend/testdata/comment_syntax/mysql/query.sql new file mode 100644 index 0000000..1483275 --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/mysql/query.sql @@ -0,0 +1,8 @@ +-- name: DoubleDash :one +SELECT * FROM foo LIMIT 1; + +/* name: SlashStar :one */ +SELECT * FROM foo LIMIT 1; + +# name: Hash :one +SELECT * FROM foo LIMIT 1; diff --git a/internal/endtoend/testdata/comment_syntax/mysql/schema.sql b/internal/endtoend/testdata/comment_syntax/mysql/schema.sql new file mode 100644 index 0000000..bd55621 --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text); + diff --git a/internal/endtoend/testdata/comment_syntax/mysql/sqlc.json b/internal/endtoend/testdata/comment_syntax/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/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/comment_syntax/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/comment_syntax/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..b5395d4 --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v4/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString +} diff --git a/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..25a38d5 --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const doubleDash = `-- name: DoubleDash :one +SELECT bar FROM foo LIMIT 1 +` + +func (q *Queries) DoubleDash(ctx context.Context) (sql.NullString, error) { + row := q.db.QueryRow(ctx, doubleDash) + var bar sql.NullString + err := row.Scan(&bar) + return bar, err +} + +const slashStar = `-- name: SlashStar :one +SELECT bar FROM foo LIMIT 1 +` + +func (q *Queries) SlashStar(ctx context.Context) (sql.NullString, error) { + row := q.db.QueryRow(ctx, slashStar) + var bar sql.NullString + err := row.Scan(&bar) + return bar, err +} diff --git a/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..ddf6f4b --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v4/query.sql @@ -0,0 +1,5 @@ +-- name: DoubleDash :one +SELECT * FROM foo LIMIT 1; + +/* name: SlashStar :one */ +SELECT * FROM foo LIMIT 1; diff --git a/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..bd55621 --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text); + diff --git a/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..afdff35 --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "engine": "postgresql", + "sql_package": "pgx/v4", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/comment_syntax/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..d867cae --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v5/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + Bar pgtype.Text +} diff --git a/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..6b80af1 --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const doubleDash = `-- name: DoubleDash :one +SELECT bar FROM foo LIMIT 1 +` + +func (q *Queries) DoubleDash(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, doubleDash) + var bar pgtype.Text + err := row.Scan(&bar) + return bar, err +} + +const slashStar = `-- name: SlashStar :one +SELECT bar FROM foo LIMIT 1 +` + +func (q *Queries) SlashStar(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, slashStar) + var bar pgtype.Text + err := row.Scan(&bar) + return bar, err +} diff --git a/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..ddf6f4b --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v5/query.sql @@ -0,0 +1,5 @@ +-- name: DoubleDash :one +SELECT * FROM foo LIMIT 1; + +/* name: SlashStar :one */ +SELECT * FROM foo LIMIT 1; diff --git a/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..bd55621 --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text); + diff --git a/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..a690d83 --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "engine": "postgresql", + "sql_package": "pgx/v5", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/comment_syntax/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/comment_syntax/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/comment_syntax/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/comment_syntax/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..b5395d4 --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/postgresql/stdlib/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString +} diff --git a/internal/endtoend/testdata/comment_syntax/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/comment_syntax/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..ddb7c2a --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const doubleDash = `-- name: DoubleDash :one +SELECT bar FROM foo LIMIT 1 +` + +func (q *Queries) DoubleDash(ctx context.Context) (sql.NullString, error) { + row := q.db.QueryRowContext(ctx, doubleDash) + var bar sql.NullString + err := row.Scan(&bar) + return bar, err +} + +const slashStar = `-- name: SlashStar :one +SELECT bar FROM foo LIMIT 1 +` + +func (q *Queries) SlashStar(ctx context.Context) (sql.NullString, error) { + row := q.db.QueryRowContext(ctx, slashStar) + var bar sql.NullString + err := row.Scan(&bar) + return bar, err +} diff --git a/internal/endtoend/testdata/comment_syntax/postgresql/stdlib/query.sql b/internal/endtoend/testdata/comment_syntax/postgresql/stdlib/query.sql new file mode 100644 index 0000000..ddf6f4b --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/postgresql/stdlib/query.sql @@ -0,0 +1,5 @@ +-- name: DoubleDash :one +SELECT * FROM foo LIMIT 1; + +/* name: SlashStar :one */ +SELECT * FROM foo LIMIT 1; diff --git a/internal/endtoend/testdata/comment_syntax/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/comment_syntax/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..bd55621 --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text); + diff --git a/internal/endtoend/testdata/comment_syntax/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/comment_syntax/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/comment_syntax/sqlite/go/db.go b/internal/endtoend/testdata/comment_syntax/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/comment_syntax/sqlite/go/models.go b/internal/endtoend/testdata/comment_syntax/sqlite/go/models.go new file mode 100644 index 0000000..b5395d4 --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/sqlite/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString +} diff --git a/internal/endtoend/testdata/comment_syntax/sqlite/go/query.sql.go b/internal/endtoend/testdata/comment_syntax/sqlite/go/query.sql.go new file mode 100644 index 0000000..ddb7c2a --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/sqlite/go/query.sql.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const doubleDash = `-- name: DoubleDash :one +SELECT bar FROM foo LIMIT 1 +` + +func (q *Queries) DoubleDash(ctx context.Context) (sql.NullString, error) { + row := q.db.QueryRowContext(ctx, doubleDash) + var bar sql.NullString + err := row.Scan(&bar) + return bar, err +} + +const slashStar = `-- name: SlashStar :one +SELECT bar FROM foo LIMIT 1 +` + +func (q *Queries) SlashStar(ctx context.Context) (sql.NullString, error) { + row := q.db.QueryRowContext(ctx, slashStar) + var bar sql.NullString + err := row.Scan(&bar) + return bar, err +} diff --git a/internal/endtoend/testdata/comment_syntax/sqlite/query.sql b/internal/endtoend/testdata/comment_syntax/sqlite/query.sql new file mode 100644 index 0000000..ddf6f4b --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/sqlite/query.sql @@ -0,0 +1,5 @@ +-- name: DoubleDash :one +SELECT * FROM foo LIMIT 1; + +/* name: SlashStar :one */ +SELECT * FROM foo LIMIT 1; diff --git a/internal/endtoend/testdata/comment_syntax/sqlite/schema.sql b/internal/endtoend/testdata/comment_syntax/sqlite/schema.sql new file mode 100644 index 0000000..bd55621 --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/sqlite/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text); + diff --git a/internal/endtoend/testdata/comment_syntax/sqlite/sqlc.json b/internal/endtoend/testdata/comment_syntax/sqlite/sqlc.json new file mode 100644 index 0000000..d4963e7 --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/comparisons/mysql/go/db.go b/internal/endtoend/testdata/comparisons/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/comparisons/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/comparisons/mysql/go/models.go b/internal/endtoend/testdata/comparisons/mysql/go/models.go new file mode 100644 index 0000000..9ac222a --- /dev/null +++ b/internal/endtoend/testdata/comparisons/mysql/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID uint64 +} diff --git a/internal/endtoend/testdata/comparisons/mysql/go/query.sql.go b/internal/endtoend/testdata/comparisons/mysql/go/query.sql.go new file mode 100644 index 0000000..50d2309 --- /dev/null +++ b/internal/endtoend/testdata/comparisons/mysql/go/query.sql.go @@ -0,0 +1,253 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const alsoNotEqual = `-- name: AlsoNotEqual :many +SELECT count(*) <> 0 FROM bar +` + +func (q *Queries) AlsoNotEqual(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, alsoNotEqual) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const equal = `-- name: Equal :many +SELECT count(*) = 0 FROM bar +` + +func (q *Queries) Equal(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, equal) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const greaterThan = `-- name: GreaterThan :many +SELECT count(*) > 0 FROM bar +` + +func (q *Queries) GreaterThan(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, greaterThan) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const greaterThanOrEqual = `-- name: GreaterThanOrEqual :many +SELECT count(*) >= 0 FROM bar +` + +func (q *Queries) GreaterThanOrEqual(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, greaterThanOrEqual) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const isNotNull = `-- name: IsNotNull :many +SELECT id IS NOT NULL FROM bar +` + +func (q *Queries) IsNotNull(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, isNotNull) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const isNull = `-- name: IsNull :many +SELECT id IS NULL FROM bar +` + +func (q *Queries) IsNull(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, isNull) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const lessThan = `-- name: LessThan :many +SELECT count(*) < 0 FROM bar +` + +func (q *Queries) LessThan(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, lessThan) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const lessThanOrEqual = `-- name: LessThanOrEqual :many +SELECT count(*) <= 0 FROM bar +` + +func (q *Queries) LessThanOrEqual(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, lessThanOrEqual) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const notEqual = `-- name: NotEqual :many +SELECT count(*) != 0 FROM bar +` + +func (q *Queries) NotEqual(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, notEqual) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + 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/comparisons/mysql/query.sql b/internal/endtoend/testdata/comparisons/mysql/query.sql new file mode 100644 index 0000000..468a74f --- /dev/null +++ b/internal/endtoend/testdata/comparisons/mysql/query.sql @@ -0,0 +1,26 @@ +-- name: GreaterThan :many +SELECT count(*) > 0 FROM bar; + +-- name: LessThan :many +SELECT count(*) < 0 FROM bar; + +-- name: GreaterThanOrEqual :many +SELECT count(*) >= 0 FROM bar; + +-- name: LessThanOrEqual :many +SELECT count(*) <= 0 FROM bar; + +-- name: NotEqual :many +SELECT count(*) != 0 FROM bar; + +-- name: AlsoNotEqual :many +SELECT count(*) <> 0 FROM bar; + +-- name: Equal :many +SELECT count(*) = 0 FROM bar; + +-- name: IsNull :many +SELECT id IS NULL FROM bar; + +-- name: IsNotNull :many +SELECT id IS NOT NULL FROM bar; diff --git a/internal/endtoend/testdata/comparisons/mysql/schema.sql b/internal/endtoend/testdata/comparisons/mysql/schema.sql new file mode 100644 index 0000000..45cfd62 --- /dev/null +++ b/internal/endtoend/testdata/comparisons/mysql/schema.sql @@ -0,0 +1,5 @@ +-- Comparison Functions and Operators +-- https://www.postgresql.org/docs/current/functions-comparison.html + +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/comparisons/mysql/sqlc.json b/internal/endtoend/testdata/comparisons/mysql/sqlc.json new file mode 100644 index 0000000..b45b903 --- /dev/null +++ b/internal/endtoend/testdata/comparisons/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "engine": "mysql", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/comparisons/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/comparisons/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/comparisons/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/comparisons/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/comparisons/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/comparisons/postgresql/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/comparisons/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/comparisons/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..661d3db --- /dev/null +++ b/internal/endtoend/testdata/comparisons/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,178 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const alsoNotEqual = `-- name: AlsoNotEqual :many +SELECT count(*) <> 0 FROM bar +` + +func (q *Queries) AlsoNotEqual(ctx context.Context) ([]bool, error) { + rows, err := q.db.Query(ctx, alsoNotEqual) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const equal = `-- name: Equal :many +SELECT count(*) = 0 FROM bar +` + +func (q *Queries) Equal(ctx context.Context) ([]bool, error) { + rows, err := q.db.Query(ctx, equal) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const greaterThan = `-- name: GreaterThan :many +SELECT count(*) > 0 FROM bar +` + +func (q *Queries) GreaterThan(ctx context.Context) ([]bool, error) { + rows, err := q.db.Query(ctx, greaterThan) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const greaterThanOrEqual = `-- name: GreaterThanOrEqual :many +SELECT count(*) >= 0 FROM bar +` + +func (q *Queries) GreaterThanOrEqual(ctx context.Context) ([]bool, error) { + rows, err := q.db.Query(ctx, greaterThanOrEqual) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const lessThan = `-- name: LessThan :many +SELECT count(*) < 0 FROM bar +` + +func (q *Queries) LessThan(ctx context.Context) ([]bool, error) { + rows, err := q.db.Query(ctx, lessThan) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const lessThanOrEqual = `-- name: LessThanOrEqual :many +SELECT count(*) <= 0 FROM bar +` + +func (q *Queries) LessThanOrEqual(ctx context.Context) ([]bool, error) { + rows, err := q.db.Query(ctx, lessThanOrEqual) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const notEqual = `-- name: NotEqual :many +SELECT count(*) != 0 FROM bar +` + +func (q *Queries) NotEqual(ctx context.Context) ([]bool, error) { + rows, err := q.db.Query(ctx, notEqual) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/comparisons/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/comparisons/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..8763eda --- /dev/null +++ b/internal/endtoend/testdata/comparisons/postgresql/pgx/v4/query.sql @@ -0,0 +1,26 @@ +-- name: GreaterThan :many +SELECT count(*) > 0 FROM bar; + +-- name: LessThan :many +SELECT count(*) < 0 FROM bar; + +-- name: GreaterThanOrEqual :many +SELECT count(*) >= 0 FROM bar; + +-- name: LessThanOrEqual :many +SELECT count(*) <= 0 FROM bar; + +-- name: NotEqual :many +SELECT count(*) != 0 FROM bar; + +-- name: AlsoNotEqual :many +SELECT count(*) <> 0 FROM bar; + +-- name: Equal :many +SELECT count(*) = 0 FROM bar; + + + + + + diff --git a/internal/endtoend/testdata/comparisons/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/comparisons/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..45cfd62 --- /dev/null +++ b/internal/endtoend/testdata/comparisons/postgresql/pgx/v4/schema.sql @@ -0,0 +1,5 @@ +-- Comparison Functions and Operators +-- https://www.postgresql.org/docs/current/functions-comparison.html + +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/comparisons/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/comparisons/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..afdff35 --- /dev/null +++ b/internal/endtoend/testdata/comparisons/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "engine": "postgresql", + "sql_package": "pgx/v4", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/comparisons/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/comparisons/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/comparisons/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/comparisons/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/comparisons/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/comparisons/postgresql/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/comparisons/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/comparisons/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..661d3db --- /dev/null +++ b/internal/endtoend/testdata/comparisons/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,178 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const alsoNotEqual = `-- name: AlsoNotEqual :many +SELECT count(*) <> 0 FROM bar +` + +func (q *Queries) AlsoNotEqual(ctx context.Context) ([]bool, error) { + rows, err := q.db.Query(ctx, alsoNotEqual) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const equal = `-- name: Equal :many +SELECT count(*) = 0 FROM bar +` + +func (q *Queries) Equal(ctx context.Context) ([]bool, error) { + rows, err := q.db.Query(ctx, equal) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const greaterThan = `-- name: GreaterThan :many +SELECT count(*) > 0 FROM bar +` + +func (q *Queries) GreaterThan(ctx context.Context) ([]bool, error) { + rows, err := q.db.Query(ctx, greaterThan) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const greaterThanOrEqual = `-- name: GreaterThanOrEqual :many +SELECT count(*) >= 0 FROM bar +` + +func (q *Queries) GreaterThanOrEqual(ctx context.Context) ([]bool, error) { + rows, err := q.db.Query(ctx, greaterThanOrEqual) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const lessThan = `-- name: LessThan :many +SELECT count(*) < 0 FROM bar +` + +func (q *Queries) LessThan(ctx context.Context) ([]bool, error) { + rows, err := q.db.Query(ctx, lessThan) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const lessThanOrEqual = `-- name: LessThanOrEqual :many +SELECT count(*) <= 0 FROM bar +` + +func (q *Queries) LessThanOrEqual(ctx context.Context) ([]bool, error) { + rows, err := q.db.Query(ctx, lessThanOrEqual) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const notEqual = `-- name: NotEqual :many +SELECT count(*) != 0 FROM bar +` + +func (q *Queries) NotEqual(ctx context.Context) ([]bool, error) { + rows, err := q.db.Query(ctx, notEqual) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/comparisons/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/comparisons/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..8763eda --- /dev/null +++ b/internal/endtoend/testdata/comparisons/postgresql/pgx/v5/query.sql @@ -0,0 +1,26 @@ +-- name: GreaterThan :many +SELECT count(*) > 0 FROM bar; + +-- name: LessThan :many +SELECT count(*) < 0 FROM bar; + +-- name: GreaterThanOrEqual :many +SELECT count(*) >= 0 FROM bar; + +-- name: LessThanOrEqual :many +SELECT count(*) <= 0 FROM bar; + +-- name: NotEqual :many +SELECT count(*) != 0 FROM bar; + +-- name: AlsoNotEqual :many +SELECT count(*) <> 0 FROM bar; + +-- name: Equal :many +SELECT count(*) = 0 FROM bar; + + + + + + diff --git a/internal/endtoend/testdata/comparisons/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/comparisons/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..45cfd62 --- /dev/null +++ b/internal/endtoend/testdata/comparisons/postgresql/pgx/v5/schema.sql @@ -0,0 +1,5 @@ +-- Comparison Functions and Operators +-- https://www.postgresql.org/docs/current/functions-comparison.html + +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/comparisons/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/comparisons/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..a690d83 --- /dev/null +++ b/internal/endtoend/testdata/comparisons/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "engine": "postgresql", + "sql_package": "pgx/v5", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/comparisons/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/comparisons/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/comparisons/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/comparisons/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/comparisons/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/comparisons/postgresql/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/comparisons/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/comparisons/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..93f785a --- /dev/null +++ b/internal/endtoend/testdata/comparisons/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,199 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const alsoNotEqual = `-- name: AlsoNotEqual :many +SELECT count(*) <> 0 FROM bar +` + +func (q *Queries) AlsoNotEqual(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, alsoNotEqual) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const equal = `-- name: Equal :many +SELECT count(*) = 0 FROM bar +` + +func (q *Queries) Equal(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, equal) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const greaterThan = `-- name: GreaterThan :many +SELECT count(*) > 0 FROM bar +` + +func (q *Queries) GreaterThan(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, greaterThan) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const greaterThanOrEqual = `-- name: GreaterThanOrEqual :many +SELECT count(*) >= 0 FROM bar +` + +func (q *Queries) GreaterThanOrEqual(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, greaterThanOrEqual) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const lessThan = `-- name: LessThan :many +SELECT count(*) < 0 FROM bar +` + +func (q *Queries) LessThan(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, lessThan) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const lessThanOrEqual = `-- name: LessThanOrEqual :many +SELECT count(*) <= 0 FROM bar +` + +func (q *Queries) LessThanOrEqual(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, lessThanOrEqual) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const notEqual = `-- name: NotEqual :many +SELECT count(*) != 0 FROM bar +` + +func (q *Queries) NotEqual(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, notEqual) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + 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/comparisons/postgresql/stdlib/query.sql b/internal/endtoend/testdata/comparisons/postgresql/stdlib/query.sql new file mode 100644 index 0000000..8763eda --- /dev/null +++ b/internal/endtoend/testdata/comparisons/postgresql/stdlib/query.sql @@ -0,0 +1,26 @@ +-- name: GreaterThan :many +SELECT count(*) > 0 FROM bar; + +-- name: LessThan :many +SELECT count(*) < 0 FROM bar; + +-- name: GreaterThanOrEqual :many +SELECT count(*) >= 0 FROM bar; + +-- name: LessThanOrEqual :many +SELECT count(*) <= 0 FROM bar; + +-- name: NotEqual :many +SELECT count(*) != 0 FROM bar; + +-- name: AlsoNotEqual :many +SELECT count(*) <> 0 FROM bar; + +-- name: Equal :many +SELECT count(*) = 0 FROM bar; + + + + + + diff --git a/internal/endtoend/testdata/comparisons/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/comparisons/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..45cfd62 --- /dev/null +++ b/internal/endtoend/testdata/comparisons/postgresql/stdlib/schema.sql @@ -0,0 +1,5 @@ +-- Comparison Functions and Operators +-- https://www.postgresql.org/docs/current/functions-comparison.html + +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/comparisons/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/comparisons/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..3a3e2e5 --- /dev/null +++ b/internal/endtoend/testdata/comparisons/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/comparisons/sqlite/go/db.go b/internal/endtoend/testdata/comparisons/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/comparisons/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/comparisons/sqlite/go/models.go b/internal/endtoend/testdata/comparisons/sqlite/go/models.go new file mode 100644 index 0000000..bc354e0 --- /dev/null +++ b/internal/endtoend/testdata/comparisons/sqlite/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int64 +} diff --git a/internal/endtoend/testdata/comparisons/sqlite/go/query.sql.go b/internal/endtoend/testdata/comparisons/sqlite/go/query.sql.go new file mode 100644 index 0000000..93f785a --- /dev/null +++ b/internal/endtoend/testdata/comparisons/sqlite/go/query.sql.go @@ -0,0 +1,199 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const alsoNotEqual = `-- name: AlsoNotEqual :many +SELECT count(*) <> 0 FROM bar +` + +func (q *Queries) AlsoNotEqual(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, alsoNotEqual) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const equal = `-- name: Equal :many +SELECT count(*) = 0 FROM bar +` + +func (q *Queries) Equal(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, equal) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const greaterThan = `-- name: GreaterThan :many +SELECT count(*) > 0 FROM bar +` + +func (q *Queries) GreaterThan(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, greaterThan) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const greaterThanOrEqual = `-- name: GreaterThanOrEqual :many +SELECT count(*) >= 0 FROM bar +` + +func (q *Queries) GreaterThanOrEqual(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, greaterThanOrEqual) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const lessThan = `-- name: LessThan :many +SELECT count(*) < 0 FROM bar +` + +func (q *Queries) LessThan(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, lessThan) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const lessThanOrEqual = `-- name: LessThanOrEqual :many +SELECT count(*) <= 0 FROM bar +` + +func (q *Queries) LessThanOrEqual(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, lessThanOrEqual) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const notEqual = `-- name: NotEqual :many +SELECT count(*) != 0 FROM bar +` + +func (q *Queries) NotEqual(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, notEqual) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + 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/comparisons/sqlite/query.sql b/internal/endtoend/testdata/comparisons/sqlite/query.sql new file mode 100644 index 0000000..41ea9ab --- /dev/null +++ b/internal/endtoend/testdata/comparisons/sqlite/query.sql @@ -0,0 +1,20 @@ +-- name: GreaterThan :many +SELECT count(*) > 0 FROM bar; + +-- name: LessThan :many +SELECT count(*) < 0 FROM bar; + +-- name: GreaterThanOrEqual :many +SELECT count(*) >= 0 FROM bar; + +-- name: LessThanOrEqual :many +SELECT count(*) <= 0 FROM bar; + +-- name: NotEqual :many +SELECT count(*) != 0 FROM bar; + +-- name: AlsoNotEqual :many +SELECT count(*) <> 0 FROM bar; + +-- name: Equal :many +SELECT count(*) = 0 FROM bar; diff --git a/internal/endtoend/testdata/comparisons/sqlite/schema.sql b/internal/endtoend/testdata/comparisons/sqlite/schema.sql new file mode 100644 index 0000000..d45d58f --- /dev/null +++ b/internal/endtoend/testdata/comparisons/sqlite/schema.sql @@ -0,0 +1,5 @@ +-- Comparison Functions and Operators +-- https://www.postgresql.org/docs/current/functions-comparison.html + +CREATE TABLE bar (id integer not null primary key autoincrement); + diff --git a/internal/endtoend/testdata/comparisons/sqlite/sqlc.json b/internal/endtoend/testdata/comparisons/sqlite/sqlc.json new file mode 100644 index 0000000..2c041d7 --- /dev/null +++ b/internal/endtoend/testdata/comparisons/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "engine": "sqlite", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/composite_type/pgx/v4/go/db.go b/internal/endtoend/testdata/composite_type/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/composite_type/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/composite_type/pgx/v4/go/models.go b/internal/endtoend/testdata/composite_type/pgx/v4/go/models.go new file mode 100644 index 0000000..6e0affb --- /dev/null +++ b/internal/endtoend/testdata/composite_type/pgx/v4/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type FooPath struct { + PointOne sql.NullString + PointTwo sql.NullString +} diff --git a/internal/endtoend/testdata/composite_type/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/composite_type/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..fca6954 --- /dev/null +++ b/internal/endtoend/testdata/composite_type/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listPaths = `-- name: ListPaths :many +SELECT point_one, point_two FROM foo.paths +` + +func (q *Queries) ListPaths(ctx context.Context) ([]FooPath, error) { + rows, err := q.db.Query(ctx, listPaths) + if err != nil { + return nil, err + } + defer rows.Close() + var items []FooPath + for rows.Next() { + var i FooPath + if err := rows.Scan(&i.PointOne, &i.PointTwo); 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/composite_type/pgx/v4/query.sql b/internal/endtoend/testdata/composite_type/pgx/v4/query.sql new file mode 100644 index 0000000..dc1cf9e --- /dev/null +++ b/internal/endtoend/testdata/composite_type/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: ListPaths :many +SELECT * FROM foo.paths; diff --git a/internal/endtoend/testdata/composite_type/pgx/v4/schema.sql b/internal/endtoend/testdata/composite_type/pgx/v4/schema.sql new file mode 100644 index 0000000..e2d26b7 --- /dev/null +++ b/internal/endtoend/testdata/composite_type/pgx/v4/schema.sql @@ -0,0 +1,17 @@ +CREATE SCHEMA foo; + +CREATE TYPE point_type AS ( + x integer, + y integer +); + +CREATE TYPE foo.point_type AS ( + x integer, + y integer +); + +CREATE TABLE foo.paths ( + point_one point_type, + point_two foo.point_type +); + diff --git a/internal/endtoend/testdata/composite_type/pgx/v4/sqlc.json b/internal/endtoend/testdata/composite_type/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/composite_type/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/composite_type/pgx/v5/go/db.go b/internal/endtoend/testdata/composite_type/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/composite_type/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/composite_type/pgx/v5/go/models.go b/internal/endtoend/testdata/composite_type/pgx/v5/go/models.go new file mode 100644 index 0000000..6e0affb --- /dev/null +++ b/internal/endtoend/testdata/composite_type/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type FooPath struct { + PointOne sql.NullString + PointTwo sql.NullString +} diff --git a/internal/endtoend/testdata/composite_type/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/composite_type/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..fca6954 --- /dev/null +++ b/internal/endtoend/testdata/composite_type/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listPaths = `-- name: ListPaths :many +SELECT point_one, point_two FROM foo.paths +` + +func (q *Queries) ListPaths(ctx context.Context) ([]FooPath, error) { + rows, err := q.db.Query(ctx, listPaths) + if err != nil { + return nil, err + } + defer rows.Close() + var items []FooPath + for rows.Next() { + var i FooPath + if err := rows.Scan(&i.PointOne, &i.PointTwo); 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/composite_type/pgx/v5/query.sql b/internal/endtoend/testdata/composite_type/pgx/v5/query.sql new file mode 100644 index 0000000..dc1cf9e --- /dev/null +++ b/internal/endtoend/testdata/composite_type/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: ListPaths :many +SELECT * FROM foo.paths; diff --git a/internal/endtoend/testdata/composite_type/pgx/v5/schema.sql b/internal/endtoend/testdata/composite_type/pgx/v5/schema.sql new file mode 100644 index 0000000..e2d26b7 --- /dev/null +++ b/internal/endtoend/testdata/composite_type/pgx/v5/schema.sql @@ -0,0 +1,17 @@ +CREATE SCHEMA foo; + +CREATE TYPE point_type AS ( + x integer, + y integer +); + +CREATE TYPE foo.point_type AS ( + x integer, + y integer +); + +CREATE TABLE foo.paths ( + point_one point_type, + point_two foo.point_type +); + diff --git a/internal/endtoend/testdata/composite_type/pgx/v5/sqlc.json b/internal/endtoend/testdata/composite_type/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/composite_type/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/composite_type/stdlib/go/db.go b/internal/endtoend/testdata/composite_type/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/composite_type/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/composite_type/stdlib/go/models.go b/internal/endtoend/testdata/composite_type/stdlib/go/models.go new file mode 100644 index 0000000..6e0affb --- /dev/null +++ b/internal/endtoend/testdata/composite_type/stdlib/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type FooPath struct { + PointOne sql.NullString + PointTwo sql.NullString +} diff --git a/internal/endtoend/testdata/composite_type/stdlib/go/query.sql.go b/internal/endtoend/testdata/composite_type/stdlib/go/query.sql.go new file mode 100644 index 0000000..ae8a6b8 --- /dev/null +++ b/internal/endtoend/testdata/composite_type/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listPaths = `-- name: ListPaths :many +SELECT point_one, point_two FROM foo.paths +` + +func (q *Queries) ListPaths(ctx context.Context) ([]FooPath, error) { + rows, err := q.db.QueryContext(ctx, listPaths) + if err != nil { + return nil, err + } + defer rows.Close() + var items []FooPath + for rows.Next() { + var i FooPath + if err := rows.Scan(&i.PointOne, &i.PointTwo); 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/composite_type/stdlib/query.sql b/internal/endtoend/testdata/composite_type/stdlib/query.sql new file mode 100644 index 0000000..dc1cf9e --- /dev/null +++ b/internal/endtoend/testdata/composite_type/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: ListPaths :many +SELECT * FROM foo.paths; diff --git a/internal/endtoend/testdata/composite_type/stdlib/schema.sql b/internal/endtoend/testdata/composite_type/stdlib/schema.sql new file mode 100644 index 0000000..e2d26b7 --- /dev/null +++ b/internal/endtoend/testdata/composite_type/stdlib/schema.sql @@ -0,0 +1,17 @@ +CREATE SCHEMA foo; + +CREATE TYPE point_type AS ( + x integer, + y integer +); + +CREATE TYPE foo.point_type AS ( + x integer, + y integer +); + +CREATE TABLE foo.paths ( + point_one point_type, + point_two foo.point_type +); + diff --git a/internal/endtoend/testdata/composite_type/stdlib/sqlc.json b/internal/endtoend/testdata/composite_type/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/composite_type/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/conflicted_arg_name/postgresql/db/db.go b/internal/endtoend/testdata/conflicted_arg_name/postgresql/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/conflicted_arg_name/postgresql/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/conflicted_arg_name/postgresql/db/models.go b/internal/endtoend/testdata/conflicted_arg_name/postgresql/db/models.go new file mode 100644 index 0000000..f86649a --- /dev/null +++ b/internal/endtoend/testdata/conflicted_arg_name/postgresql/db/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "time" + + "github.com/google/uuid" +) + +type Foo struct { + Time time.Time + Time2 time.Time + Uuid uuid.UUID + Uuid2 uuid.UUID +} diff --git a/internal/endtoend/testdata/conflicted_arg_name/postgresql/db/query.sql.go b/internal/endtoend/testdata/conflicted_arg_name/postgresql/db/query.sql.go new file mode 100644 index 0000000..1861778 --- /dev/null +++ b/internal/endtoend/testdata/conflicted_arg_name/postgresql/db/query.sql.go @@ -0,0 +1,35 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" + "time" + + "github.com/google/uuid" +) + +const time2ByTime = `-- name: Time2ByTime :one +SELECT time2 FROM foo WHERE time=$1 +` + +func (q *Queries) Time2ByTime(ctx context.Context, argTime time.Time) (time.Time, error) { + row := q.db.QueryRowContext(ctx, time2ByTime, argTime) + var time2 time.Time + err := row.Scan(&time2) + return time2, err +} + +const uuid2ByUuid = `-- name: Uuid2ByUuid :one +SELECT uuid2 FROM foo WHERE uuid=$1 +` + +func (q *Queries) Uuid2ByUuid(ctx context.Context, argUuid uuid.UUID) (uuid.UUID, error) { + row := q.db.QueryRowContext(ctx, uuid2ByUuid, argUuid) + var uuid2 uuid.UUID + err := row.Scan(&uuid2) + return uuid2, err +} diff --git a/internal/endtoend/testdata/conflicted_arg_name/postgresql/query.sql b/internal/endtoend/testdata/conflicted_arg_name/postgresql/query.sql new file mode 100644 index 0000000..d9e4446 --- /dev/null +++ b/internal/endtoend/testdata/conflicted_arg_name/postgresql/query.sql @@ -0,0 +1,5 @@ +-- name: Time2ByTime :one +SELECT time2 FROM foo WHERE time=$1; + +-- name: Uuid2ByUuid :one +SELECT uuid2 FROM foo WHERE uuid=$1; diff --git a/internal/endtoend/testdata/conflicted_arg_name/postgresql/schema.sql b/internal/endtoend/testdata/conflicted_arg_name/postgresql/schema.sql new file mode 100644 index 0000000..2d3521f --- /dev/null +++ b/internal/endtoend/testdata/conflicted_arg_name/postgresql/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE foo ( + time date NOT NULL, + time2 date NOT NULL, + uuid uuid NOT NULL, + uuid2 uuid NOT NULL +); + diff --git a/internal/endtoend/testdata/conflicted_arg_name/postgresql/sqlc.json b/internal/endtoend/testdata/conflicted_arg_name/postgresql/sqlc.json new file mode 100644 index 0000000..2a46100 --- /dev/null +++ b/internal/endtoend/testdata/conflicted_arg_name/postgresql/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "db", + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/copyfrom/mysql/go/copyfrom.go b/internal/endtoend/testdata/copyfrom/mysql/go/copyfrom.go new file mode 100644 index 0000000..b5ce436 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom/mysql/go/copyfrom.go @@ -0,0 +1,88 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: copyfrom.go + +package querytest + +import ( + "context" + "database/sql" + "fmt" + "io" + "sync/atomic" + + "github.com/go-sql-driver/mysql" + "github.com/hexon/mysqltsv" +) + +var readerHandlerSequenceForInsertSingleValue uint32 = 1 + +func convertRowsForInsertSingleValue(w *io.PipeWriter, a []sql.NullString) { + e := mysqltsv.NewEncoder(w, 1, nil) + for _, row := range a { + e.AppendValue(row) + } + w.CloseWithError(e.Close()) +} + +// InsertSingleValue uses MySQL's LOAD DATA LOCAL INFILE and is not atomic. +// +// Errors and duplicate keys are treated as warnings and insertion will +// continue, even without an error for some cases. Use this in a transaction +// and use SHOW WARNINGS to check for any problems and roll back if you want to. +// +// Check the documentation for more information: +// https://dev.mysql.com/doc/refman/8.0/en/load-data.html#load-data-error-handling +func (q *Queries) InsertSingleValue(ctx context.Context, a []sql.NullString) (int64, error) { + pr, pw := io.Pipe() + defer pr.Close() + rh := fmt.Sprintf("InsertSingleValue_%d", atomic.AddUint32(&readerHandlerSequenceForInsertSingleValue, 1)) + mysql.RegisterReaderHandler(rh, func() io.Reader { return pr }) + defer mysql.DeregisterReaderHandler(rh) + go convertRowsForInsertSingleValue(pw, a) + // The string interpolation is necessary because LOAD DATA INFILE requires + // the file name to be given as a literal string. + result, err := q.db.ExecContext(ctx, fmt.Sprintf("LOAD DATA LOCAL INFILE '%s' INTO TABLE `foo` %s (a)", "Reader::"+rh, mysqltsv.Escaping)) + if err != nil { + return 0, err + } + return result.RowsAffected() +} + +var readerHandlerSequenceForInsertValues uint32 = 1 + +func convertRowsForInsertValues(w *io.PipeWriter, arg []InsertValuesParams) { + e := mysqltsv.NewEncoder(w, 4, nil) + for _, row := range arg { + e.AppendValue(row.A) + e.AppendValue(row.B) + e.AppendValue(row.C) + e.AppendValue(row.D) + } + w.CloseWithError(e.Close()) +} + +// InsertValues uses MySQL's LOAD DATA LOCAL INFILE and is not atomic. +// +// Errors and duplicate keys are treated as warnings and insertion will +// continue, even without an error for some cases. Use this in a transaction +// and use SHOW WARNINGS to check for any problems and roll back if you want to. +// +// Check the documentation for more information: +// https://dev.mysql.com/doc/refman/8.0/en/load-data.html#load-data-error-handling +func (q *Queries) InsertValues(ctx context.Context, arg []InsertValuesParams) (int64, error) { + pr, pw := io.Pipe() + defer pr.Close() + rh := fmt.Sprintf("InsertValues_%d", atomic.AddUint32(&readerHandlerSequenceForInsertValues, 1)) + mysql.RegisterReaderHandler(rh, func() io.Reader { return pr }) + defer mysql.DeregisterReaderHandler(rh) + go convertRowsForInsertValues(pw, arg) + // The string interpolation is necessary because LOAD DATA INFILE requires + // the file name to be given as a literal string. + result, err := q.db.ExecContext(ctx, fmt.Sprintf("LOAD DATA LOCAL INFILE '%s' INTO TABLE `foo` %s (a, b, c, d)", "Reader::"+rh, mysqltsv.Escaping)) + if err != nil { + return 0, err + } + return result.RowsAffected() +} diff --git a/internal/endtoend/testdata/copyfrom/mysql/go/db.go b/internal/endtoend/testdata/copyfrom/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/copyfrom/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/copyfrom/mysql/go/models.go b/internal/endtoend/testdata/copyfrom/mysql/go/models.go new file mode 100644 index 0000000..168ecce --- /dev/null +++ b/internal/endtoend/testdata/copyfrom/mysql/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString + B sql.NullInt32 + C sql.NullTime + D sql.NullTime +} diff --git a/internal/endtoend/testdata/copyfrom/mysql/go/query.sql.go b/internal/endtoend/testdata/copyfrom/mysql/go/query.sql.go new file mode 100644 index 0000000..91bd662 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom/mysql/go/query.sql.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "database/sql" +) + +const insertSingleValue = `-- name: InsertSingleValue :copyfrom +INSERT INTO foo (a) VALUES (?) +` + +const insertValues = `-- name: InsertValues :copyfrom +INSERT INTO foo (a, b, c, d) VALUES (?, ?, ?, ?) +` + +type InsertValuesParams struct { + A sql.NullString + B sql.NullInt32 + C sql.NullTime + D sql.NullTime +} diff --git a/internal/endtoend/testdata/copyfrom/mysql/query.sql b/internal/endtoend/testdata/copyfrom/mysql/query.sql new file mode 100644 index 0000000..4c5fd5f --- /dev/null +++ b/internal/endtoend/testdata/copyfrom/mysql/query.sql @@ -0,0 +1,5 @@ +-- name: InsertValues :copyfrom +INSERT INTO foo (a, b, c, d) VALUES (?, ?, ?, ?); + +-- name: InsertSingleValue :copyfrom +INSERT INTO foo (a) VALUES (?); diff --git a/internal/endtoend/testdata/copyfrom/mysql/schema.sql b/internal/endtoend/testdata/copyfrom/mysql/schema.sql new file mode 100644 index 0000000..e447086 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b integer, c DATETIME, d DATE); + diff --git a/internal/endtoend/testdata/copyfrom/mysql/sqlc.json b/internal/endtoend/testdata/copyfrom/mysql/sqlc.json new file mode 100644 index 0000000..7dabfee --- /dev/null +++ b/internal/endtoend/testdata/copyfrom/mysql/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "sql_package": "database/sql", + "sql_driver": "github.com/go-sql-driver/mysql", + "engine": "mysql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/go/copyfrom.go b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/go/copyfrom.go new file mode 100644 index 0000000..863180d --- /dev/null +++ b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/go/copyfrom.go @@ -0,0 +1,78 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: copyfrom.go + +package querytest + +import ( + "context" + "database/sql" +) + +// iteratorForInsertSingleValue implements pgx.CopyFromSource. +type iteratorForInsertSingleValue struct { + rows []sql.NullString + skippedFirstNextCall bool +} + +func (r *iteratorForInsertSingleValue) Next() bool { + if len(r.rows) == 0 { + return false + } + if !r.skippedFirstNextCall { + r.skippedFirstNextCall = true + return true + } + r.rows = r.rows[1:] + return len(r.rows) > 0 +} + +func (r iteratorForInsertSingleValue) Values() ([]any, error) { + return []any{ + r.rows[0], + }, nil +} + +func (r iteratorForInsertSingleValue) Err() error { + return nil +} + +// InsertSingleValue inserts a single value using copy. +func (q *Queries) InsertSingleValue(ctx context.Context, a []sql.NullString) (int64, error) { + return q.db.CopyFrom(ctx, []string{"myschema", "foo"}, []string{"a"}, &iteratorForInsertSingleValue{rows: a}) +} + +// iteratorForInsertValues implements pgx.CopyFromSource. +type iteratorForInsertValues struct { + rows []InsertValuesParams + skippedFirstNextCall bool +} + +func (r *iteratorForInsertValues) Next() bool { + if len(r.rows) == 0 { + return false + } + if !r.skippedFirstNextCall { + r.skippedFirstNextCall = true + return true + } + r.rows = r.rows[1:] + return len(r.rows) > 0 +} + +func (r iteratorForInsertValues) Values() ([]any, error) { + return []any{ + r.rows[0].A, + r.rows[0].B, + }, nil +} + +func (r iteratorForInsertValues) Err() error { + return nil +} + +// InsertValues inserts multiple values using copy. +func (q *Queries) InsertValues(ctx context.Context, arg []InsertValuesParams) (int64, error) { + return q.db.CopyFrom(ctx, []string{"myschema", "foo"}, []string{"a", "b"}, &iteratorForInsertValues{rows: arg}) +} diff --git a/internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..f9e0a2c --- /dev/null +++ b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/go/db.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row + CopyFrom(ctx context.Context, tableName pgx.Identifier, columnNames []string, rowSrc pgx.CopyFromSource) (int64, error) +} + +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/copyfrom/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..fa0d297 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type MyschemaFoo struct { + A sql.NullString + B sql.NullInt32 +} diff --git a/internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/go/querier.go b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/go/querier.go new file mode 100644 index 0000000..7a8768b --- /dev/null +++ b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/go/querier.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type Querier interface { + // InsertSingleValue inserts a single value using copy. + InsertSingleValue(ctx context.Context, a []sql.NullString) (int64, error) + // InsertValues inserts multiple values using copy. + InsertValues(ctx context.Context, arg []InsertValuesParams) (int64, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..73bde9d --- /dev/null +++ b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "database/sql" +) + +type InsertValuesParams struct { + A sql.NullString + B sql.NullInt32 +} diff --git a/internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..8c9aa00 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/query.sql @@ -0,0 +1,7 @@ +-- name: InsertValues :copyfrom +-- InsertValues inserts multiple values using copy. +INSERT INTO myschema.foo (a, b) VALUES ($1, $2); + +-- name: InsertSingleValue :copyfrom +-- InsertSingleValue inserts a single value using copy. +INSERT INTO myschema.foo (a) VALUES ($1); diff --git a/internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..e53abe5 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA myschema; +CREATE TABLE myschema.foo (a text, b integer); + diff --git a/internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..e0530db --- /dev/null +++ b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_interface": true + } + ] +} diff --git a/internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/go/copyfrom.go b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/go/copyfrom.go new file mode 100644 index 0000000..8e04f47 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/go/copyfrom.go @@ -0,0 +1,79 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: copyfrom.go + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +// iteratorForInsertSingleValue implements pgx.CopyFromSource. +type iteratorForInsertSingleValue struct { + rows []pgtype.Text + skippedFirstNextCall bool +} + +func (r *iteratorForInsertSingleValue) Next() bool { + if len(r.rows) == 0 { + return false + } + if !r.skippedFirstNextCall { + r.skippedFirstNextCall = true + return true + } + r.rows = r.rows[1:] + return len(r.rows) > 0 +} + +func (r iteratorForInsertSingleValue) Values() ([]any, error) { + return []any{ + r.rows[0], + }, nil +} + +func (r iteratorForInsertSingleValue) Err() error { + return nil +} + +// InsertSingleValue inserts a single value using copy. +func (q *Queries) InsertSingleValue(ctx context.Context, a []pgtype.Text) (int64, error) { + return q.db.CopyFrom(ctx, []string{"myschema", "foo"}, []string{"a"}, &iteratorForInsertSingleValue{rows: a}) +} + +// iteratorForInsertValues implements pgx.CopyFromSource. +type iteratorForInsertValues struct { + rows []InsertValuesParams + skippedFirstNextCall bool +} + +func (r *iteratorForInsertValues) Next() bool { + if len(r.rows) == 0 { + return false + } + if !r.skippedFirstNextCall { + r.skippedFirstNextCall = true + return true + } + r.rows = r.rows[1:] + return len(r.rows) > 0 +} + +func (r iteratorForInsertValues) Values() ([]any, error) { + return []any{ + r.rows[0].A, + r.rows[0].B, + }, nil +} + +func (r iteratorForInsertValues) Err() error { + return nil +} + +// InsertValues inserts multiple values using copy. +func (q *Queries) InsertValues(ctx context.Context, arg []InsertValuesParams) (int64, error) { + return q.db.CopyFrom(ctx, []string{"myschema", "foo"}, []string{"a", "b"}, &iteratorForInsertValues{rows: arg}) +} diff --git a/internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..d17ab27 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/go/db.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row + CopyFrom(ctx context.Context, tableName pgx.Identifier, columnNames []string, rowSrc pgx.CopyFromSource) (int64, error) +} + +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/copyfrom/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..80e1ef5 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type MyschemaFoo struct { + A pgtype.Text + B pgtype.Int4 +} diff --git a/internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/go/querier.go b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/go/querier.go new file mode 100644 index 0000000..6e081e7 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/go/querier.go @@ -0,0 +1,20 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +type Querier interface { + // InsertSingleValue inserts a single value using copy. + InsertSingleValue(ctx context.Context, a []pgtype.Text) (int64, error) + // InsertValues inserts multiple values using copy. + InsertValues(ctx context.Context, arg []InsertValuesParams) (int64, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..5f9743f --- /dev/null +++ b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type InsertValuesParams struct { + A pgtype.Text + B pgtype.Int4 +} diff --git a/internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..8c9aa00 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/query.sql @@ -0,0 +1,7 @@ +-- name: InsertValues :copyfrom +-- InsertValues inserts multiple values using copy. +INSERT INTO myschema.foo (a, b) VALUES ($1, $2); + +-- name: InsertSingleValue :copyfrom +-- InsertSingleValue inserts a single value using copy. +INSERT INTO myschema.foo (a) VALUES ($1); diff --git a/internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..e53abe5 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA myschema; +CREATE TABLE myschema.foo (a text, b integer); + diff --git a/internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..007fb85 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_interface": true + } + ] +} diff --git a/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/go/copyfrom.go b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/go/copyfrom.go new file mode 100644 index 0000000..1d56607 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/go/copyfrom.go @@ -0,0 +1,43 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: copyfrom.go + +package querytest + +import ( + "context" +) + +// iteratorForInsertValues implements pgx.CopyFromSource. +type iteratorForInsertValues struct { + rows []InsertValuesParams + skippedFirstNextCall bool +} + +func (r *iteratorForInsertValues) Next() bool { + if len(r.rows) == 0 { + return false + } + if !r.skippedFirstNextCall { + r.skippedFirstNextCall = true + return true + } + r.rows = r.rows[1:] + return len(r.rows) > 0 +} + +func (r iteratorForInsertValues) Values() ([]any, error) { + return []any{ + r.rows[0].A, + r.rows[0].B, + }, nil +} + +func (r iteratorForInsertValues) Err() error { + return nil +} + +func (q *Queries) InsertValues(ctx context.Context, arg []InsertValuesParams) (int64, error) { + return q.db.CopyFrom(ctx, []string{"myschema", "foo"}, []string{"a", "b"}, &iteratorForInsertValues{rows: arg}) +} diff --git a/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..f9e0a2c --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/go/db.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row + CopyFrom(ctx context.Context, tableName pgx.Identifier, columnNames []string, rowSrc pgx.CopyFromSource) (int64, error) +} + +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/copyfrom_imports/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..fa0d297 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type MyschemaFoo struct { + A sql.NullString + B sql.NullInt32 +} diff --git a/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..582785f --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,36 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" + + "github.com/jackc/pgconn" +) + +const deleteValues = `-- name: DeleteValues :execresult +DELETE +FROM myschema.foo +` + +func (q *Queries) DeleteValues(ctx context.Context) (pgconn.CommandTag, error) { + return q.db.Exec(ctx, deleteValues) +} + +const insertSingleValue = `-- name: InsertSingleValue :exec +INSERT INTO myschema.foo (a) VALUES ($1) +` + +func (q *Queries) InsertSingleValue(ctx context.Context, a sql.NullString) error { + _, err := q.db.Exec(ctx, insertSingleValue, a) + return err +} + +type InsertValuesParams struct { + A sql.NullString + B sql.NullInt32 +} diff --git a/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..7b7f2bb --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/query.sql @@ -0,0 +1,9 @@ +-- name: InsertValues :copyfrom +INSERT INTO myschema.foo (a, b) VALUES ($1, $2); + +-- name: InsertSingleValue :exec +INSERT INTO myschema.foo (a) VALUES ($1); + +-- name: DeleteValues :execresult +DELETE +FROM myschema.foo; diff --git a/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..e53abe5 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA myschema; +CREATE TABLE myschema.foo (a text, b integer); + diff --git a/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/go/copyfrom.go b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/go/copyfrom.go new file mode 100644 index 0000000..1d56607 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/go/copyfrom.go @@ -0,0 +1,43 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: copyfrom.go + +package querytest + +import ( + "context" +) + +// iteratorForInsertValues implements pgx.CopyFromSource. +type iteratorForInsertValues struct { + rows []InsertValuesParams + skippedFirstNextCall bool +} + +func (r *iteratorForInsertValues) Next() bool { + if len(r.rows) == 0 { + return false + } + if !r.skippedFirstNextCall { + r.skippedFirstNextCall = true + return true + } + r.rows = r.rows[1:] + return len(r.rows) > 0 +} + +func (r iteratorForInsertValues) Values() ([]any, error) { + return []any{ + r.rows[0].A, + r.rows[0].B, + }, nil +} + +func (r iteratorForInsertValues) Err() error { + return nil +} + +func (q *Queries) InsertValues(ctx context.Context, arg []InsertValuesParams) (int64, error) { + return q.db.CopyFrom(ctx, []string{"myschema", "foo"}, []string{"a", "b"}, &iteratorForInsertValues{rows: arg}) +} diff --git a/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..d17ab27 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/go/db.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row + CopyFrom(ctx context.Context, tableName pgx.Identifier, columnNames []string, rowSrc pgx.CopyFromSource) (int64, error) +} + +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/copyfrom_imports/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..80e1ef5 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type MyschemaFoo struct { + A pgtype.Text + B pgtype.Int4 +} diff --git a/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..5be522e --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,36 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgconn" + "github.com/jackc/pgx/v5/pgtype" +) + +const deleteValues = `-- name: DeleteValues :execresult +DELETE +FROM myschema.foo +` + +func (q *Queries) DeleteValues(ctx context.Context) (pgconn.CommandTag, error) { + return q.db.Exec(ctx, deleteValues) +} + +const insertSingleValue = `-- name: InsertSingleValue :exec +INSERT INTO myschema.foo (a) VALUES ($1) +` + +func (q *Queries) InsertSingleValue(ctx context.Context, a pgtype.Text) error { + _, err := q.db.Exec(ctx, insertSingleValue, a) + return err +} + +type InsertValuesParams struct { + A pgtype.Text + B pgtype.Int4 +} diff --git a/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..7b7f2bb --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/query.sql @@ -0,0 +1,9 @@ +-- name: InsertValues :copyfrom +INSERT INTO myschema.foo (a, b) VALUES ($1, $2); + +-- name: InsertSingleValue :exec +INSERT INTO myschema.foo (a) VALUES ($1); + +-- name: DeleteValues :execresult +DELETE +FROM myschema.foo; diff --git a/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..e53abe5 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA myschema; +CREATE TABLE myschema.foo (a text, b integer); + diff --git a/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_imports/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/go/copyfrom.go b/internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/go/copyfrom.go new file mode 100644 index 0000000..662d6e1 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/go/copyfrom.go @@ -0,0 +1,51 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: copyfrom.go + +package querytest + +import ( + "context" + "fmt" + "io" + "sync/atomic" + + "github.com/go-sql-driver/mysql" + "github.com/hexon/mysqltsv" +) + +var readerHandlerSequenceForInsertMultipleValues uint32 = 1 + +func convertRowsForInsertMultipleValues(w *io.PipeWriter, arg []InsertMultipleValuesParams) { + e := mysqltsv.NewEncoder(w, 2, nil) + for _, row := range arg { + e.AppendValue(row.A) + e.AppendValue(row.B) + } + w.CloseWithError(e.Close()) +} + +// InsertMultipleValues uses MySQL's LOAD DATA LOCAL INFILE and is not atomic. +// +// Errors and duplicate keys are treated as warnings and insertion will +// continue, even without an error for some cases. Use this in a transaction +// and use SHOW WARNINGS to check for any problems and roll back if you want to. +// +// Check the documentation for more information: +// https://dev.mysql.com/doc/refman/8.0/en/load-data.html#load-data-error-handling +func (q *Queries) InsertMultipleValues(ctx context.Context, arg []InsertMultipleValuesParams) (int64, error) { + pr, pw := io.Pipe() + defer pr.Close() + rh := fmt.Sprintf("InsertMultipleValues_%d", atomic.AddUint32(&readerHandlerSequenceForInsertMultipleValues, 1)) + mysql.RegisterReaderHandler(rh, func() io.Reader { return pr }) + defer mysql.DeregisterReaderHandler(rh) + go convertRowsForInsertMultipleValues(pw, arg) + // The string interpolation is necessary because LOAD DATA INFILE requires + // the file name to be given as a literal string. + result, err := q.db.ExecContext(ctx, fmt.Sprintf("LOAD DATA LOCAL INFILE '%s' INTO TABLE `foo` %s (a, b)", "Reader::"+rh, mysqltsv.Escaping)) + if err != nil { + return 0, err + } + return result.RowsAffected() +} diff --git a/internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/go/db.go b/internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/copyfrom_multicolumn_parameter_limit/mysql/go/models.go b/internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/go/models.go new file mode 100644 index 0000000..a26317d --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString + B sql.NullString +} diff --git a/internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/go/query.sql.go b/internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/go/query.sql.go new file mode 100644 index 0000000..83233f4 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "database/sql" +) + +const insertMultipleValues = `-- name: InsertMultipleValues :copyfrom +INSERT INTO foo (a, b) VALUES (?, ?) +` + +type InsertMultipleValuesParams struct { + A sql.NullString + B sql.NullString +} diff --git a/internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/query.sql b/internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/query.sql new file mode 100644 index 0000000..18a13f8 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: InsertMultipleValues :copyfrom +INSERT INTO foo (a, b) VALUES (?, ?); diff --git a/internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/schema.sql b/internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/schema.sql new file mode 100644 index 0000000..dd2f6b6 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (a text, b text); diff --git a/internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/sqlc.json b/internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/sqlc.json new file mode 100644 index 0000000..0990bc2 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_multicolumn_parameter_limit/mysql/sqlc.json @@ -0,0 +1,15 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "sql_package": "database/sql", + "sql_driver": "github.com/go-sql-driver/mysql", + "engine": "mysql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "query_parameter_limit": 4 + } + ] +} diff --git a/internal/endtoend/testdata/copyfrom_named_params/issue.md b/internal/endtoend/testdata/copyfrom_named_params/issue.md new file mode 100644 index 0000000..6d030f1 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_named_params/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/2833 diff --git a/internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/go/copyfrom.go b/internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/go/copyfrom.go new file mode 100644 index 0000000..531032b --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/go/copyfrom.go @@ -0,0 +1,43 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: copyfrom.go + +package querytest + +import ( + "context" +) + +// iteratorForStageUserData implements pgx.CopyFromSource. +type iteratorForStageUserData struct { + rows []StageUserDataParams + skippedFirstNextCall bool +} + +func (r *iteratorForStageUserData) Next() bool { + if len(r.rows) == 0 { + return false + } + if !r.skippedFirstNextCall { + r.skippedFirstNextCall = true + return true + } + r.rows = r.rows[1:] + return len(r.rows) > 0 +} + +func (r iteratorForStageUserData) Values() ([]any, error) { + return []any{ + r.rows[0].IDParam, + r.rows[0].UserParam, + }, nil +} + +func (r iteratorForStageUserData) Err() error { + return nil +} + +func (q *Queries) StageUserData(ctx context.Context, arg []StageUserDataParams) (int64, error) { + return q.db.CopyFrom(ctx, []string{"user_data"}, []string{"id", "user"}, &iteratorForStageUserData{rows: arg}) +} diff --git a/internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/go/db.go b/internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/go/db.go new file mode 100644 index 0000000..d17ab27 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/go/db.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row + CopyFrom(ctx context.Context, tableName pgx.Identifier, columnNames []string, rowSrc pgx.CopyFromSource) (int64, error) +} + +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/copyfrom_named_params/postgresql/pgx/go/models.go b/internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/go/models.go new file mode 100644 index 0000000..80f27cb --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type UserDatum struct { + ID string + User string +} diff --git a/internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..bd4515d --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/go/query.sql.go @@ -0,0 +1,11 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +type StageUserDataParams struct { + IDParam string + UserParam string +} diff --git a/internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/query.sql b/internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/query.sql new file mode 100644 index 0000000..0a2c750 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/query.sql @@ -0,0 +1,6 @@ +-- name: StageUserData :copyfrom +insert into "user_data" ("id", "user") +values ( + sqlc.arg('id_param'), + sqlc.arg('user_param') +); diff --git a/internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/schema.sql b/internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/schema.sql new file mode 100644 index 0000000..87d16b4 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/schema.sql @@ -0,0 +1,5 @@ +create table "user_data" ( + "id" varchar not null, + "user" varchar not null, + primary key ("id") +); diff --git a/internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_named_params/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/go/copyfrom.go b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/go/copyfrom.go new file mode 100644 index 0000000..e675323 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/go/copyfrom.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: copyfrom.go + +package querytest + +import ( + "context" +) + +// iteratorForCreateAuthors implements pgx.CopyFromSource. +type iteratorForCreateAuthors struct { + rows []int32 + skippedFirstNextCall bool +} + +func (r *iteratorForCreateAuthors) Next() bool { + if len(r.rows) == 0 { + return false + } + if !r.skippedFirstNextCall { + r.skippedFirstNextCall = true + return true + } + r.rows = r.rows[1:] + return len(r.rows) > 0 +} + +func (r iteratorForCreateAuthors) Values() ([]any, error) { + return []any{ + r.rows[0], + }, nil +} + +func (r iteratorForCreateAuthors) Err() error { + return nil +} + +func (q *Queries) CreateAuthors(ctx context.Context, authorID []int32) (int64, error) { + return q.db.CopyFrom(ctx, []string{"authors"}, []string{"author_id"}, &iteratorForCreateAuthors{rows: authorID}) +} diff --git a/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..f9e0a2c --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/go/db.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row + CopyFrom(ctx context.Context, tableName pgx.Identifier, columnNames []string, rowSrc pgx.CopyFromSource) (int64, error) +} + +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/copyfrom_singlecolumn/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..d2e63df --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Author struct { + AuthorID int32 +} diff --git a/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/go/querier.go b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/go/querier.go new file mode 100644 index 0000000..59b1100 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/go/querier.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" +) + +type Querier interface { + CreateAuthors(ctx context.Context, authorID []int32) (int64, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..aa95052 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,6 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest diff --git a/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..77f9980 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: CreateAuthors :copyfrom +INSERT INTO authors (author_id) VALUES ($1); diff --git a/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..634d492 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE authors ( + author_id SERIAL PRIMARY KEY +); + diff --git a/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..e0530db --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_interface": true + } + ] +} diff --git a/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/go/copyfrom.go b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/go/copyfrom.go new file mode 100644 index 0000000..e675323 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/go/copyfrom.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: copyfrom.go + +package querytest + +import ( + "context" +) + +// iteratorForCreateAuthors implements pgx.CopyFromSource. +type iteratorForCreateAuthors struct { + rows []int32 + skippedFirstNextCall bool +} + +func (r *iteratorForCreateAuthors) Next() bool { + if len(r.rows) == 0 { + return false + } + if !r.skippedFirstNextCall { + r.skippedFirstNextCall = true + return true + } + r.rows = r.rows[1:] + return len(r.rows) > 0 +} + +func (r iteratorForCreateAuthors) Values() ([]any, error) { + return []any{ + r.rows[0], + }, nil +} + +func (r iteratorForCreateAuthors) Err() error { + return nil +} + +func (q *Queries) CreateAuthors(ctx context.Context, authorID []int32) (int64, error) { + return q.db.CopyFrom(ctx, []string{"authors"}, []string{"author_id"}, &iteratorForCreateAuthors{rows: authorID}) +} diff --git a/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..d17ab27 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/go/db.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row + CopyFrom(ctx context.Context, tableName pgx.Identifier, columnNames []string, rowSrc pgx.CopyFromSource) (int64, error) +} + +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/copyfrom_singlecolumn/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..d2e63df --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Author struct { + AuthorID int32 +} diff --git a/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/go/querier.go b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/go/querier.go new file mode 100644 index 0000000..59b1100 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/go/querier.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" +) + +type Querier interface { + CreateAuthors(ctx context.Context, authorID []int32) (int64, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..aa95052 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,6 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest diff --git a/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..77f9980 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: CreateAuthors :copyfrom +INSERT INTO authors (author_id) VALUES ($1); diff --git a/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..634d492 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE authors ( + author_id SERIAL PRIMARY KEY +); + diff --git a/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..007fb85 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_singlecolumn/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_interface": true + } + ] +} diff --git a/internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/issue.md b/internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/issue.md new file mode 100644 index 0000000..4838ed7 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/3443 \ No newline at end of file diff --git a/internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/go/copyfrom.go b/internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/go/copyfrom.go new file mode 100644 index 0000000..59dab9b --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/go/copyfrom.go @@ -0,0 +1,50 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: copyfrom.go + +package querytest + +import ( + "context" + "fmt" + "io" + "sync/atomic" + + "github.com/go-sql-driver/mysql" + "github.com/hexon/mysqltsv" +) + +var readerHandlerSequenceForInsertSingleValue uint32 = 1 + +func convertRowsForInsertSingleValue(w *io.PipeWriter, arg []InsertSingleValueParams) { + e := mysqltsv.NewEncoder(w, 1, nil) + for _, row := range arg { + e.AppendValue(row.A) + } + w.CloseWithError(e.Close()) +} + +// InsertSingleValue uses MySQL's LOAD DATA LOCAL INFILE and is not atomic. +// +// Errors and duplicate keys are treated as warnings and insertion will +// continue, even without an error for some cases. Use this in a transaction +// and use SHOW WARNINGS to check for any problems and roll back if you want to. +// +// Check the documentation for more information: +// https://dev.mysql.com/doc/refman/8.0/en/load-data.html#load-data-error-handling +func (q *Queries) InsertSingleValue(ctx context.Context, arg []InsertSingleValueParams) (int64, error) { + pr, pw := io.Pipe() + defer pr.Close() + rh := fmt.Sprintf("InsertSingleValue_%d", atomic.AddUint32(&readerHandlerSequenceForInsertSingleValue, 1)) + mysql.RegisterReaderHandler(rh, func() io.Reader { return pr }) + defer mysql.DeregisterReaderHandler(rh) + go convertRowsForInsertSingleValue(pw, arg) + // The string interpolation is necessary because LOAD DATA INFILE requires + // the file name to be given as a literal string. + result, err := q.db.ExecContext(ctx, fmt.Sprintf("LOAD DATA LOCAL INFILE '%s' INTO TABLE `foo` %s (a)", "Reader::"+rh, mysqltsv.Escaping)) + if err != nil { + return 0, err + } + return result.RowsAffected() +} diff --git a/internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/go/db.go b/internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/copyfrom_singlecolumn_struct_only/mysql/go/models.go b/internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/go/models.go new file mode 100644 index 0000000..f05c6b5 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString +} diff --git a/internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/go/query.sql.go b/internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/go/query.sql.go new file mode 100644 index 0000000..68c76e9 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/go/query.sql.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "database/sql" +) + +const insertSingleValue = `-- name: InsertSingleValue :copyfrom +INSERT INTO foo (a) VALUES (?) +` + +type InsertSingleValueParams struct { + A sql.NullString +} diff --git a/internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/query.sql b/internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/query.sql new file mode 100644 index 0000000..091c903 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: InsertSingleValue :copyfrom +INSERT INTO foo (a) VALUES (?); diff --git a/internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/schema.sql b/internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/schema.sql new file mode 100644 index 0000000..022bbd6 --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (a text); diff --git a/internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/sqlc.json b/internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/sqlc.json new file mode 100644 index 0000000..4a4d43c --- /dev/null +++ b/internal/endtoend/testdata/copyfrom_singlecolumn_struct_only/mysql/sqlc.json @@ -0,0 +1,15 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "sql_package": "database/sql", + "sql_driver": "github.com/go-sql-driver/mysql", + "engine": "mysql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "query_parameter_limit": 0 + } + ] +} diff --git a/internal/endtoend/testdata/count_star/mysql/go/db.go b/internal/endtoend/testdata/count_star/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/count_star/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/count_star/mysql/go/models.go b/internal/endtoend/testdata/count_star/mysql/go/models.go new file mode 100644 index 0000000..9ac222a --- /dev/null +++ b/internal/endtoend/testdata/count_star/mysql/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID uint64 +} diff --git a/internal/endtoend/testdata/count_star/mysql/go/query.sql.go b/internal/endtoend/testdata/count_star/mysql/go/query.sql.go new file mode 100644 index 0000000..817ad88 --- /dev/null +++ b/internal/endtoend/testdata/count_star/mysql/go/query.sql.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const countStarLower = `-- name: CountStarLower :one +SELECT count(*) FROM bar +` + +func (q *Queries) CountStarLower(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, countStarLower) + var count int64 + err := row.Scan(&count) + return count, err +} + +const countStarUpper = `-- name: CountStarUpper :one +SELECT COUNT(*) FROM bar +` + +func (q *Queries) CountStarUpper(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, countStarUpper) + var count int64 + err := row.Scan(&count) + return count, err +} diff --git a/internal/endtoend/testdata/count_star/mysql/query.sql b/internal/endtoend/testdata/count_star/mysql/query.sql new file mode 100644 index 0000000..6cba436 --- /dev/null +++ b/internal/endtoend/testdata/count_star/mysql/query.sql @@ -0,0 +1,5 @@ +-- name: CountStarLower :one +SELECT count(*) FROM bar; + +-- name: CountStarUpper :one +SELECT COUNT(*) FROM bar; diff --git a/internal/endtoend/testdata/count_star/mysql/schema.sql b/internal/endtoend/testdata/count_star/mysql/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/count_star/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/count_star/mysql/sqlc.json b/internal/endtoend/testdata/count_star/mysql/sqlc.json new file mode 100644 index 0000000..b45b903 --- /dev/null +++ b/internal/endtoend/testdata/count_star/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "engine": "mysql", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/count_star/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/count_star/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/count_star/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/count_star/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/count_star/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/count_star/postgresql/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/count_star/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/count_star/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..b4498da --- /dev/null +++ b/internal/endtoend/testdata/count_star/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const countStarLower = `-- name: CountStarLower :one +SELECT count(*) FROM bar +` + +func (q *Queries) CountStarLower(ctx context.Context) (int64, error) { + row := q.db.QueryRow(ctx, countStarLower) + var count int64 + err := row.Scan(&count) + return count, err +} + +const countStarUpper = `-- name: CountStarUpper :one +SELECT COUNT(*) FROM bar +` + +func (q *Queries) CountStarUpper(ctx context.Context) (int64, error) { + row := q.db.QueryRow(ctx, countStarUpper) + var count int64 + err := row.Scan(&count) + return count, err +} diff --git a/internal/endtoend/testdata/count_star/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/count_star/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6cba436 --- /dev/null +++ b/internal/endtoend/testdata/count_star/postgresql/pgx/v4/query.sql @@ -0,0 +1,5 @@ +-- name: CountStarLower :one +SELECT count(*) FROM bar; + +-- name: CountStarUpper :one +SELECT COUNT(*) FROM bar; diff --git a/internal/endtoend/testdata/count_star/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/count_star/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/count_star/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/count_star/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/count_star/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..afdff35 --- /dev/null +++ b/internal/endtoend/testdata/count_star/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "engine": "postgresql", + "sql_package": "pgx/v4", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/count_star/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/count_star/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/count_star/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/count_star/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/count_star/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/count_star/postgresql/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/count_star/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/count_star/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..b4498da --- /dev/null +++ b/internal/endtoend/testdata/count_star/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const countStarLower = `-- name: CountStarLower :one +SELECT count(*) FROM bar +` + +func (q *Queries) CountStarLower(ctx context.Context) (int64, error) { + row := q.db.QueryRow(ctx, countStarLower) + var count int64 + err := row.Scan(&count) + return count, err +} + +const countStarUpper = `-- name: CountStarUpper :one +SELECT COUNT(*) FROM bar +` + +func (q *Queries) CountStarUpper(ctx context.Context) (int64, error) { + row := q.db.QueryRow(ctx, countStarUpper) + var count int64 + err := row.Scan(&count) + return count, err +} diff --git a/internal/endtoend/testdata/count_star/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/count_star/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6cba436 --- /dev/null +++ b/internal/endtoend/testdata/count_star/postgresql/pgx/v5/query.sql @@ -0,0 +1,5 @@ +-- name: CountStarLower :one +SELECT count(*) FROM bar; + +-- name: CountStarUpper :one +SELECT COUNT(*) FROM bar; diff --git a/internal/endtoend/testdata/count_star/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/count_star/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/count_star/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/count_star/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/count_star/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..a690d83 --- /dev/null +++ b/internal/endtoend/testdata/count_star/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "engine": "postgresql", + "sql_package": "pgx/v5", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/count_star/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/count_star/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/count_star/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/count_star/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/count_star/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/count_star/postgresql/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/count_star/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/count_star/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..817ad88 --- /dev/null +++ b/internal/endtoend/testdata/count_star/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const countStarLower = `-- name: CountStarLower :one +SELECT count(*) FROM bar +` + +func (q *Queries) CountStarLower(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, countStarLower) + var count int64 + err := row.Scan(&count) + return count, err +} + +const countStarUpper = `-- name: CountStarUpper :one +SELECT COUNT(*) FROM bar +` + +func (q *Queries) CountStarUpper(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, countStarUpper) + var count int64 + err := row.Scan(&count) + return count, err +} diff --git a/internal/endtoend/testdata/count_star/postgresql/stdlib/query.sql b/internal/endtoend/testdata/count_star/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6cba436 --- /dev/null +++ b/internal/endtoend/testdata/count_star/postgresql/stdlib/query.sql @@ -0,0 +1,5 @@ +-- name: CountStarLower :one +SELECT count(*) FROM bar; + +-- name: CountStarUpper :one +SELECT COUNT(*) FROM bar; diff --git a/internal/endtoend/testdata/count_star/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/count_star/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/count_star/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/count_star/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/count_star/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..3a3e2e5 --- /dev/null +++ b/internal/endtoend/testdata/count_star/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/count_star/sqlite/go/db.go b/internal/endtoend/testdata/count_star/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/count_star/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/count_star/sqlite/go/models.go b/internal/endtoend/testdata/count_star/sqlite/go/models.go new file mode 100644 index 0000000..bc354e0 --- /dev/null +++ b/internal/endtoend/testdata/count_star/sqlite/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int64 +} diff --git a/internal/endtoend/testdata/count_star/sqlite/go/query.sql.go b/internal/endtoend/testdata/count_star/sqlite/go/query.sql.go new file mode 100644 index 0000000..155bfc1 --- /dev/null +++ b/internal/endtoend/testdata/count_star/sqlite/go/query.sql.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const countStarLower = `-- name: CountStarLower :one +SELECT count(*) FROM bar +` + +func (q *Queries) CountStarLower(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, countStarLower) + var count int64 + err := row.Scan(&count) + return count, err +} + +const countStarUpper = `-- name: CountStarUpper :one +SELECT count(*) FROM bar +` + +func (q *Queries) CountStarUpper(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, countStarUpper) + var count int64 + err := row.Scan(&count) + return count, err +} diff --git a/internal/endtoend/testdata/count_star/sqlite/query.sql b/internal/endtoend/testdata/count_star/sqlite/query.sql new file mode 100644 index 0000000..4fbc659 --- /dev/null +++ b/internal/endtoend/testdata/count_star/sqlite/query.sql @@ -0,0 +1,5 @@ +-- name: CountStarLower :one +SELECT count(*) FROM bar; + +-- name: CountStarUpper :one +SELECT count(*) FROM bar; diff --git a/internal/endtoend/testdata/count_star/sqlite/schema.sql b/internal/endtoend/testdata/count_star/sqlite/schema.sql new file mode 100644 index 0000000..0fe4a93 --- /dev/null +++ b/internal/endtoend/testdata/count_star/sqlite/schema.sql @@ -0,0 +1 @@ +CREATE TABLE bar (id BIGINT not null); diff --git a/internal/endtoend/testdata/count_star/sqlite/sqlc.json b/internal/endtoend/testdata/count_star/sqlite/sqlc.json new file mode 100644 index 0000000..9655954 --- /dev/null +++ b/internal/endtoend/testdata/count_star/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "engine": "sqlite", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/create_materialized_view/postgresql/go/db.go b/internal/endtoend/testdata/create_materialized_view/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/create_materialized_view/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/create_materialized_view/postgresql/go/models.go b/internal/endtoend/testdata/create_materialized_view/postgresql/go/models.go new file mode 100644 index 0000000..e72052f --- /dev/null +++ b/internal/endtoend/testdata/create_materialized_view/postgresql/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Val string +} + +type MatFirstView struct { + Val string +} diff --git a/internal/endtoend/testdata/create_materialized_view/postgresql/go/query.sql.go b/internal/endtoend/testdata/create_materialized_view/postgresql/go/query.sql.go new file mode 100644 index 0000000..fab385a --- /dev/null +++ b/internal/endtoend/testdata/create_materialized_view/postgresql/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getFirst = `-- name: GetFirst :many +SELECT val FROM mat_first_view +` + +func (q *Queries) GetFirst(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, getFirst) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var val string + if err := rows.Scan(&val); err != nil { + return nil, err + } + items = append(items, val) + } + 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/create_materialized_view/postgresql/query.sql b/internal/endtoend/testdata/create_materialized_view/postgresql/query.sql new file mode 100644 index 0000000..0c86bfd --- /dev/null +++ b/internal/endtoend/testdata/create_materialized_view/postgresql/query.sql @@ -0,0 +1,3 @@ +-- name: GetFirst :many +SELECT * FROM mat_first_view; + diff --git a/internal/endtoend/testdata/create_materialized_view/postgresql/schema.sql b/internal/endtoend/testdata/create_materialized_view/postgresql/schema.sql new file mode 100644 index 0000000..fc0c213 --- /dev/null +++ b/internal/endtoend/testdata/create_materialized_view/postgresql/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (val text not null); + +CREATE MATERIALIZED VIEW mat_first_view AS SELECT * FROM foo; diff --git a/internal/endtoend/testdata/create_materialized_view/postgresql/sqlc.json b/internal/endtoend/testdata/create_materialized_view/postgresql/sqlc.json new file mode 100644 index 0000000..cd51867 --- /dev/null +++ b/internal/endtoend/testdata/create_materialized_view/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/create_table_as/postgresql/go/db.go b/internal/endtoend/testdata/create_table_as/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/create_table_as/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/create_table_as/postgresql/go/models.go b/internal/endtoend/testdata/create_table_as/postgresql/go/models.go new file mode 100644 index 0000000..500a1d1 --- /dev/null +++ b/internal/endtoend/testdata/create_table_as/postgresql/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Val string +} + +type SecondTable struct { + Val string +} diff --git a/internal/endtoend/testdata/create_table_as/postgresql/go/query.sql.go b/internal/endtoend/testdata/create_table_as/postgresql/go/query.sql.go new file mode 100644 index 0000000..40b8cbe --- /dev/null +++ b/internal/endtoend/testdata/create_table_as/postgresql/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getFirst = `-- name: GetFirst :many +SELECT val FROM second_table +` + +func (q *Queries) GetFirst(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, getFirst) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var val string + if err := rows.Scan(&val); err != nil { + return nil, err + } + items = append(items, val) + } + 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/create_table_as/postgresql/query.sql b/internal/endtoend/testdata/create_table_as/postgresql/query.sql new file mode 100644 index 0000000..c2861a6 --- /dev/null +++ b/internal/endtoend/testdata/create_table_as/postgresql/query.sql @@ -0,0 +1,3 @@ +-- name: GetFirst :many +SELECT * FROM second_table; + diff --git a/internal/endtoend/testdata/create_table_as/postgresql/schema.sql b/internal/endtoend/testdata/create_table_as/postgresql/schema.sql new file mode 100644 index 0000000..deace97 --- /dev/null +++ b/internal/endtoend/testdata/create_table_as/postgresql/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (val text not null); + +CREATE TABLE second_table AS SELECT * FROM foo; diff --git a/internal/endtoend/testdata/create_table_as/postgresql/sqlc.json b/internal/endtoend/testdata/create_table_as/postgresql/sqlc.json new file mode 100644 index 0000000..cd51867 --- /dev/null +++ b/internal/endtoend/testdata/create_table_as/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/create_table_like/mysql/go/db.go b/internal/endtoend/testdata/create_table_like/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/create_table_like/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/create_table_like/mysql/go/models.go b/internal/endtoend/testdata/create_table_like/mysql/go/models.go new file mode 100644 index 0000000..3de6994 --- /dev/null +++ b/internal/endtoend/testdata/create_table_like/mysql/go/models.go @@ -0,0 +1,22 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type SuperUser struct { + ID int32 + FirstName string + LastName sql.NullString + DateOfBirth sql.NullTime +} + +type User struct { + ID int32 + LastName sql.NullString + Age int32 +} diff --git a/internal/endtoend/testdata/create_table_like/mysql/go/query.sql.go b/internal/endtoend/testdata/create_table_like/mysql/go/query.sql.go new file mode 100644 index 0000000..d354d45 --- /dev/null +++ b/internal/endtoend/testdata/create_table_like/mysql/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, date_of_birth FROM super_users +` + +func (q *Queries) GetAll(ctx context.Context) ([]SuperUser, error) { + rows, err := q.db.QueryContext(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []SuperUser + for rows.Next() { + var i SuperUser + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.DateOfBirth, + ); 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/create_table_like/mysql/query.sql b/internal/endtoend/testdata/create_table_like/mysql/query.sql new file mode 100644 index 0000000..c503d78 --- /dev/null +++ b/internal/endtoend/testdata/create_table_like/mysql/query.sql @@ -0,0 +1,2 @@ +/* name: GetAll :many */ +SELECT * FROM super_users; diff --git a/internal/endtoend/testdata/create_table_like/mysql/schema.sql b/internal/endtoend/testdata/create_table_like/mysql/schema.sql new file mode 100644 index 0000000..11f9eba --- /dev/null +++ b/internal/endtoend/testdata/create_table_like/mysql/schema.sql @@ -0,0 +1,18 @@ +CREATE TABLE users ( + id integer NOT NULL AUTO_INCREMENT PRIMARY KEY, + first_name varchar(255) NOT NULL +); + +ALTER TABLE users + ADD COLUMN last_name varchar(255); + +CREATE TABLE super_users LIKE users; + +ALTER TABLE users + ADD COLUMN age integer NOT NULL; + +ALTER TABLE users + DROP COLUMN first_name; + +ALTER TABLE super_users + ADD COLUMN date_of_birth DATETIME(6); diff --git a/internal/endtoend/testdata/create_table_like/mysql/sqlc.json b/internal/endtoend/testdata/create_table_like/mysql/sqlc.json new file mode 100644 index 0000000..a9e7b05 --- /dev/null +++ b/internal/endtoend/testdata/create_table_like/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "schema.sql", + "queries": "query.sql", + "engine": "mysql" + } + ] +} diff --git a/internal/endtoend/testdata/create_table_like/postgresql/go/db.go b/internal/endtoend/testdata/create_table_like/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/create_table_like/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/create_table_like/postgresql/go/models.go b/internal/endtoend/testdata/create_table_like/postgresql/go/models.go new file mode 100644 index 0000000..3de6994 --- /dev/null +++ b/internal/endtoend/testdata/create_table_like/postgresql/go/models.go @@ -0,0 +1,22 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type SuperUser struct { + ID int32 + FirstName string + LastName sql.NullString + DateOfBirth sql.NullTime +} + +type User struct { + ID int32 + LastName sql.NullString + Age int32 +} diff --git a/internal/endtoend/testdata/create_table_like/postgresql/go/query.sql.go b/internal/endtoend/testdata/create_table_like/postgresql/go/query.sql.go new file mode 100644 index 0000000..d354d45 --- /dev/null +++ b/internal/endtoend/testdata/create_table_like/postgresql/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, date_of_birth FROM super_users +` + +func (q *Queries) GetAll(ctx context.Context) ([]SuperUser, error) { + rows, err := q.db.QueryContext(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []SuperUser + for rows.Next() { + var i SuperUser + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.DateOfBirth, + ); 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/create_table_like/postgresql/query.sql b/internal/endtoend/testdata/create_table_like/postgresql/query.sql new file mode 100644 index 0000000..c503d78 --- /dev/null +++ b/internal/endtoend/testdata/create_table_like/postgresql/query.sql @@ -0,0 +1,2 @@ +/* name: GetAll :many */ +SELECT * FROM super_users; diff --git a/internal/endtoend/testdata/create_table_like/postgresql/schema.sql b/internal/endtoend/testdata/create_table_like/postgresql/schema.sql new file mode 100644 index 0000000..131a309 --- /dev/null +++ b/internal/endtoend/testdata/create_table_like/postgresql/schema.sql @@ -0,0 +1,18 @@ +CREATE TABLE users ( + id serial NOT NULL PRIMARY KEY, + first_name varchar(255) NOT NULL +); + +ALTER TABLE users + ADD COLUMN last_name varchar(255); + +CREATE TABLE super_users ( LIKE users ); + +ALTER TABLE users + ADD COLUMN age integer NOT NULL; + +ALTER TABLE users + DROP COLUMN first_name; + +ALTER TABLE super_users + ADD COLUMN date_of_birth TIMESTAMP; diff --git a/internal/endtoend/testdata/create_table_like/postgresql/sqlc.json b/internal/endtoend/testdata/create_table_like/postgresql/sqlc.json new file mode 100644 index 0000000..f5a835c --- /dev/null +++ b/internal/endtoend/testdata/create_table_like/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql" + } + ] +} diff --git a/internal/endtoend/testdata/create_view/mysql/go/db.go b/internal/endtoend/testdata/create_view/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/create_view/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/create_view/mysql/go/models.go b/internal/endtoend/testdata/create_view/mysql/go/models.go new file mode 100644 index 0000000..a979a1a --- /dev/null +++ b/internal/endtoend/testdata/create_view/mysql/go/models.go @@ -0,0 +1,23 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type FirstView struct { + Val string +} + +type Foo struct { + Val string + Val2 sql.NullInt32 +} + +type SecondView struct { + Val string + Val2 sql.NullInt32 +} diff --git a/internal/endtoend/testdata/create_view/mysql/go/query.sql.go b/internal/endtoend/testdata/create_view/mysql/go/query.sql.go new file mode 100644 index 0000000..c959a71 --- /dev/null +++ b/internal/endtoend/testdata/create_view/mysql/go/query.sql.go @@ -0,0 +1,64 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getFirst = `-- name: GetFirst :many +SELECT val FROM first_view +` + +func (q *Queries) GetFirst(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, getFirst) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var val string + if err := rows.Scan(&val); err != nil { + return nil, err + } + items = append(items, val) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getSecond = `-- name: GetSecond :many +SELECT val, val2 FROM second_view WHERE val2 = $1 +` + +func (q *Queries) GetSecond(ctx context.Context) ([]SecondView, error) { + rows, err := q.db.QueryContext(ctx, getSecond) + if err != nil { + return nil, err + } + defer rows.Close() + var items []SecondView + for rows.Next() { + var i SecondView + if err := rows.Scan(&i.Val, &i.Val2); 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/create_view/mysql/query.sql b/internal/endtoend/testdata/create_view/mysql/query.sql new file mode 100644 index 0000000..1063db8 --- /dev/null +++ b/internal/endtoend/testdata/create_view/mysql/query.sql @@ -0,0 +1,5 @@ +-- name: GetFirst :many +SELECT * FROM first_view; + +-- name: GetSecond :many +SELECT * FROM second_view WHERE val2 = $1; diff --git a/internal/endtoend/testdata/create_view/mysql/schema.sql b/internal/endtoend/testdata/create_view/mysql/schema.sql new file mode 100644 index 0000000..3f94440 --- /dev/null +++ b/internal/endtoend/testdata/create_view/mysql/schema.sql @@ -0,0 +1,10 @@ +CREATE TABLE foo (val text not null); + +CREATE VIEW first_view AS SELECT * FROM foo; +CREATE VIEW second_view AS SELECT * FROM foo; +CREATE VIEW third_view AS SELECT * FROM foo; + +ALTER TABLE foo ADD COLUMN val2 integer; +CREATE OR REPLACE VIEW second_view AS SELECT * FROM foo; + +DROP VIEW third_view; diff --git a/internal/endtoend/testdata/create_view/mysql/sqlc.json b/internal/endtoend/testdata/create_view/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/create_view/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/create_view/postgresql/go/db.go b/internal/endtoend/testdata/create_view/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/create_view/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/create_view/postgresql/go/models.go b/internal/endtoend/testdata/create_view/postgresql/go/models.go new file mode 100644 index 0000000..a979a1a --- /dev/null +++ b/internal/endtoend/testdata/create_view/postgresql/go/models.go @@ -0,0 +1,23 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type FirstView struct { + Val string +} + +type Foo struct { + Val string + Val2 sql.NullInt32 +} + +type SecondView struct { + Val string + Val2 sql.NullInt32 +} diff --git a/internal/endtoend/testdata/create_view/postgresql/go/query.sql.go b/internal/endtoend/testdata/create_view/postgresql/go/query.sql.go new file mode 100644 index 0000000..08b6f2f --- /dev/null +++ b/internal/endtoend/testdata/create_view/postgresql/go/query.sql.go @@ -0,0 +1,65 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const getFirst = `-- name: GetFirst :many +SELECT val FROM first_view +` + +func (q *Queries) GetFirst(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, getFirst) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var val string + if err := rows.Scan(&val); err != nil { + return nil, err + } + items = append(items, val) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getSecond = `-- name: GetSecond :many +SELECT val, val2 FROM second_view WHERE val2 = $1 +` + +func (q *Queries) GetSecond(ctx context.Context, val2 sql.NullInt32) ([]SecondView, error) { + rows, err := q.db.QueryContext(ctx, getSecond, val2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []SecondView + for rows.Next() { + var i SecondView + if err := rows.Scan(&i.Val, &i.Val2); 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/create_view/postgresql/query.sql b/internal/endtoend/testdata/create_view/postgresql/query.sql new file mode 100644 index 0000000..1063db8 --- /dev/null +++ b/internal/endtoend/testdata/create_view/postgresql/query.sql @@ -0,0 +1,5 @@ +-- name: GetFirst :many +SELECT * FROM first_view; + +-- name: GetSecond :many +SELECT * FROM second_view WHERE val2 = $1; diff --git a/internal/endtoend/testdata/create_view/postgresql/schema.sql b/internal/endtoend/testdata/create_view/postgresql/schema.sql new file mode 100644 index 0000000..3f94440 --- /dev/null +++ b/internal/endtoend/testdata/create_view/postgresql/schema.sql @@ -0,0 +1,10 @@ +CREATE TABLE foo (val text not null); + +CREATE VIEW first_view AS SELECT * FROM foo; +CREATE VIEW second_view AS SELECT * FROM foo; +CREATE VIEW third_view AS SELECT * FROM foo; + +ALTER TABLE foo ADD COLUMN val2 integer; +CREATE OR REPLACE VIEW second_view AS SELECT * FROM foo; + +DROP VIEW third_view; diff --git a/internal/endtoend/testdata/create_view/postgresql/sqlc.json b/internal/endtoend/testdata/create_view/postgresql/sqlc.json new file mode 100644 index 0000000..cd51867 --- /dev/null +++ b/internal/endtoend/testdata/create_view/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/create_view/sqlite/go/db.go b/internal/endtoend/testdata/create_view/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/create_view/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/create_view/sqlite/go/models.go b/internal/endtoend/testdata/create_view/sqlite/go/models.go new file mode 100644 index 0000000..2f186df --- /dev/null +++ b/internal/endtoend/testdata/create_view/sqlite/go/models.go @@ -0,0 +1,23 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type FirstView struct { + Val string +} + +type Foo struct { + Val string + Val2 sql.NullInt64 +} + +type SecondView struct { + Val string + Val2 sql.NullInt64 +} diff --git a/internal/endtoend/testdata/create_view/sqlite/go/query.sql.go b/internal/endtoend/testdata/create_view/sqlite/go/query.sql.go new file mode 100644 index 0000000..0c88a41 --- /dev/null +++ b/internal/endtoend/testdata/create_view/sqlite/go/query.sql.go @@ -0,0 +1,65 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const getFirst = `-- name: GetFirst :many +SELECT val FROM first_view +` + +func (q *Queries) GetFirst(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, getFirst) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var val string + if err := rows.Scan(&val); err != nil { + return nil, err + } + items = append(items, val) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getSecond = `-- name: GetSecond :many +SELECT val, val2 FROM second_view WHERE val2 = ? +` + +func (q *Queries) GetSecond(ctx context.Context, val2 sql.NullInt64) ([]SecondView, error) { + rows, err := q.db.QueryContext(ctx, getSecond, val2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []SecondView + for rows.Next() { + var i SecondView + if err := rows.Scan(&i.Val, &i.Val2); 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/create_view/sqlite/query.sql b/internal/endtoend/testdata/create_view/sqlite/query.sql new file mode 100644 index 0000000..c94fc58 --- /dev/null +++ b/internal/endtoend/testdata/create_view/sqlite/query.sql @@ -0,0 +1,5 @@ +-- name: GetFirst :many +SELECT * FROM first_view; + +-- name: GetSecond :many +SELECT * FROM second_view WHERE val2 = ?; diff --git a/internal/endtoend/testdata/create_view/sqlite/schema.sql b/internal/endtoend/testdata/create_view/sqlite/schema.sql new file mode 100644 index 0000000..246f73e --- /dev/null +++ b/internal/endtoend/testdata/create_view/sqlite/schema.sql @@ -0,0 +1,11 @@ +CREATE TABLE foo (val text not null); + +CREATE VIEW first_view AS SELECT * FROM foo; +CREATE VIEW second_view AS SELECT * FROM foo; +CREATE VIEW third_view AS SELECT * FROM foo; + +ALTER TABLE foo ADD COLUMN val2 integer; +DROP VIEW second_view; +CREATE VIEW second_view AS SELECT * FROM foo; + +DROP VIEW third_view; diff --git a/internal/endtoend/testdata/create_view/sqlite/sqlc.json b/internal/endtoend/testdata/create_view/sqlite/sqlc.json new file mode 100644 index 0000000..f8e8051 --- /dev/null +++ b/internal/endtoend/testdata/create_view/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "sqlite", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/cte_count/mysql/go/db.go b/internal/endtoend/testdata/cte_count/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/cte_count/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/cte_count/mysql/go/models.go b/internal/endtoend/testdata/cte_count/mysql/go/models.go new file mode 100644 index 0000000..329a259 --- /dev/null +++ b/internal/endtoend/testdata/cte_count/mysql/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + Ready bool +} diff --git a/internal/endtoend/testdata/cte_count/mysql/go/query.sql.go b/internal/endtoend/testdata/cte_count/mysql/go/query.sql.go new file mode 100644 index 0000000..dbaccd8 --- /dev/null +++ b/internal/endtoend/testdata/cte_count/mysql/go/query.sql.go @@ -0,0 +1,48 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const cTECount = `-- name: CTECount :many +WITH all_count AS ( + SELECT count(*) FROM bar +), ready_count AS ( + SELECT count(*) FROM bar WHERE ready = true +) +SELECT all_count.count, ready_count.count +FROM all_count, ready_count +` + +type CTECountRow struct { + Count int64 + Count_2 int64 +} + +func (q *Queries) CTECount(ctx context.Context) ([]CTECountRow, error) { + rows, err := q.db.QueryContext(ctx, cTECount) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CTECountRow + for rows.Next() { + var i CTECountRow + if err := rows.Scan(&i.Count, &i.Count_2); 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/cte_count/mysql/query.sql b/internal/endtoend/testdata/cte_count/mysql/query.sql new file mode 100644 index 0000000..9afd2e4 --- /dev/null +++ b/internal/endtoend/testdata/cte_count/mysql/query.sql @@ -0,0 +1,8 @@ +-- name: CTECount :many +WITH all_count AS ( + SELECT count(*) FROM bar +), ready_count AS ( + SELECT count(*) FROM bar WHERE ready = true +) +SELECT all_count.count, ready_count.count +FROM all_count, ready_count; diff --git a/internal/endtoend/testdata/cte_count/mysql/schema.sql b/internal/endtoend/testdata/cte_count/mysql/schema.sql new file mode 100644 index 0000000..1a17eee --- /dev/null +++ b/internal/endtoend/testdata/cte_count/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (ready bool not null); + diff --git a/internal/endtoend/testdata/cte_count/mysql/sqlc.json b/internal/endtoend/testdata/cte_count/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/cte_count/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/cte_count/pgx/v4/go/db.go b/internal/endtoend/testdata/cte_count/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/cte_count/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/cte_count/pgx/v4/go/models.go b/internal/endtoend/testdata/cte_count/pgx/v4/go/models.go new file mode 100644 index 0000000..329a259 --- /dev/null +++ b/internal/endtoend/testdata/cte_count/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + Ready bool +} diff --git a/internal/endtoend/testdata/cte_count/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/cte_count/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8f46c91 --- /dev/null +++ b/internal/endtoend/testdata/cte_count/pgx/v4/go/query.sql.go @@ -0,0 +1,45 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const cTECount = `-- name: CTECount :many +WITH all_count AS ( + SELECT count(*) FROM bar +), ready_count AS ( + SELECT count(*) FROM bar WHERE ready = true +) +SELECT all_count.count, ready_count.count +FROM all_count, ready_count +` + +type CTECountRow struct { + Count int64 + Count_2 int64 +} + +func (q *Queries) CTECount(ctx context.Context) ([]CTECountRow, error) { + rows, err := q.db.Query(ctx, cTECount) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CTECountRow + for rows.Next() { + var i CTECountRow + if err := rows.Scan(&i.Count, &i.Count_2); 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/cte_count/pgx/v4/query.sql b/internal/endtoend/testdata/cte_count/pgx/v4/query.sql new file mode 100644 index 0000000..9afd2e4 --- /dev/null +++ b/internal/endtoend/testdata/cte_count/pgx/v4/query.sql @@ -0,0 +1,8 @@ +-- name: CTECount :many +WITH all_count AS ( + SELECT count(*) FROM bar +), ready_count AS ( + SELECT count(*) FROM bar WHERE ready = true +) +SELECT all_count.count, ready_count.count +FROM all_count, ready_count; diff --git a/internal/endtoend/testdata/cte_count/pgx/v4/schema.sql b/internal/endtoend/testdata/cte_count/pgx/v4/schema.sql new file mode 100644 index 0000000..1a17eee --- /dev/null +++ b/internal/endtoend/testdata/cte_count/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (ready bool not null); + diff --git a/internal/endtoend/testdata/cte_count/pgx/v4/sqlc.json b/internal/endtoend/testdata/cte_count/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/cte_count/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/cte_count/pgx/v5/go/db.go b/internal/endtoend/testdata/cte_count/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/cte_count/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/cte_count/pgx/v5/go/models.go b/internal/endtoend/testdata/cte_count/pgx/v5/go/models.go new file mode 100644 index 0000000..329a259 --- /dev/null +++ b/internal/endtoend/testdata/cte_count/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + Ready bool +} diff --git a/internal/endtoend/testdata/cte_count/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/cte_count/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8f46c91 --- /dev/null +++ b/internal/endtoend/testdata/cte_count/pgx/v5/go/query.sql.go @@ -0,0 +1,45 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const cTECount = `-- name: CTECount :many +WITH all_count AS ( + SELECT count(*) FROM bar +), ready_count AS ( + SELECT count(*) FROM bar WHERE ready = true +) +SELECT all_count.count, ready_count.count +FROM all_count, ready_count +` + +type CTECountRow struct { + Count int64 + Count_2 int64 +} + +func (q *Queries) CTECount(ctx context.Context) ([]CTECountRow, error) { + rows, err := q.db.Query(ctx, cTECount) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CTECountRow + for rows.Next() { + var i CTECountRow + if err := rows.Scan(&i.Count, &i.Count_2); 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/cte_count/pgx/v5/query.sql b/internal/endtoend/testdata/cte_count/pgx/v5/query.sql new file mode 100644 index 0000000..9afd2e4 --- /dev/null +++ b/internal/endtoend/testdata/cte_count/pgx/v5/query.sql @@ -0,0 +1,8 @@ +-- name: CTECount :many +WITH all_count AS ( + SELECT count(*) FROM bar +), ready_count AS ( + SELECT count(*) FROM bar WHERE ready = true +) +SELECT all_count.count, ready_count.count +FROM all_count, ready_count; diff --git a/internal/endtoend/testdata/cte_count/pgx/v5/schema.sql b/internal/endtoend/testdata/cte_count/pgx/v5/schema.sql new file mode 100644 index 0000000..1a17eee --- /dev/null +++ b/internal/endtoend/testdata/cte_count/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (ready bool not null); + diff --git a/internal/endtoend/testdata/cte_count/pgx/v5/sqlc.json b/internal/endtoend/testdata/cte_count/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/cte_count/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/cte_count/stdlib/go/db.go b/internal/endtoend/testdata/cte_count/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/cte_count/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/cte_count/stdlib/go/models.go b/internal/endtoend/testdata/cte_count/stdlib/go/models.go new file mode 100644 index 0000000..329a259 --- /dev/null +++ b/internal/endtoend/testdata/cte_count/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + Ready bool +} diff --git a/internal/endtoend/testdata/cte_count/stdlib/go/query.sql.go b/internal/endtoend/testdata/cte_count/stdlib/go/query.sql.go new file mode 100644 index 0000000..dbaccd8 --- /dev/null +++ b/internal/endtoend/testdata/cte_count/stdlib/go/query.sql.go @@ -0,0 +1,48 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const cTECount = `-- name: CTECount :many +WITH all_count AS ( + SELECT count(*) FROM bar +), ready_count AS ( + SELECT count(*) FROM bar WHERE ready = true +) +SELECT all_count.count, ready_count.count +FROM all_count, ready_count +` + +type CTECountRow struct { + Count int64 + Count_2 int64 +} + +func (q *Queries) CTECount(ctx context.Context) ([]CTECountRow, error) { + rows, err := q.db.QueryContext(ctx, cTECount) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CTECountRow + for rows.Next() { + var i CTECountRow + if err := rows.Scan(&i.Count, &i.Count_2); 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/cte_count/stdlib/query.sql b/internal/endtoend/testdata/cte_count/stdlib/query.sql new file mode 100644 index 0000000..9afd2e4 --- /dev/null +++ b/internal/endtoend/testdata/cte_count/stdlib/query.sql @@ -0,0 +1,8 @@ +-- name: CTECount :many +WITH all_count AS ( + SELECT count(*) FROM bar +), ready_count AS ( + SELECT count(*) FROM bar WHERE ready = true +) +SELECT all_count.count, ready_count.count +FROM all_count, ready_count; diff --git a/internal/endtoend/testdata/cte_count/stdlib/schema.sql b/internal/endtoend/testdata/cte_count/stdlib/schema.sql new file mode 100644 index 0000000..1a17eee --- /dev/null +++ b/internal/endtoend/testdata/cte_count/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (ready bool not null); + diff --git a/internal/endtoend/testdata/cte_count/stdlib/sqlc.json b/internal/endtoend/testdata/cte_count/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/cte_count/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/cte_filter/mysql/go/db.go b/internal/endtoend/testdata/cte_filter/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/cte_filter/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/cte_filter/mysql/go/models.go b/internal/endtoend/testdata/cte_filter/mysql/go/models.go new file mode 100644 index 0000000..329a259 --- /dev/null +++ b/internal/endtoend/testdata/cte_filter/mysql/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + Ready bool +} diff --git a/internal/endtoend/testdata/cte_filter/mysql/go/query.sql.go b/internal/endtoend/testdata/cte_filter/mysql/go/query.sql.go new file mode 100644 index 0000000..a3d9591 --- /dev/null +++ b/internal/endtoend/testdata/cte_filter/mysql/go/query.sql.go @@ -0,0 +1,41 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const cTEFilter = `-- name: CTEFilter :many +WITH filter_count AS ( + SELECT count(*) FROM bar WHERE ready = ? +) +SELECT filter_count.count +FROM filter_count +` + +func (q *Queries) CTEFilter(ctx context.Context, ready bool) ([]int64, error) { + rows, err := q.db.QueryContext(ctx, cTEFilter, ready) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var count int64 + if err := rows.Scan(&count); err != nil { + return nil, err + } + items = append(items, count) + } + 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/cte_filter/mysql/query.sql b/internal/endtoend/testdata/cte_filter/mysql/query.sql new file mode 100644 index 0000000..6fdc700 --- /dev/null +++ b/internal/endtoend/testdata/cte_filter/mysql/query.sql @@ -0,0 +1,6 @@ +-- name: CTEFilter :many +WITH filter_count AS ( + SELECT count(*) FROM bar WHERE ready = ? +) +SELECT filter_count.count +FROM filter_count; diff --git a/internal/endtoend/testdata/cte_filter/mysql/schema.sql b/internal/endtoend/testdata/cte_filter/mysql/schema.sql new file mode 100644 index 0000000..1a17eee --- /dev/null +++ b/internal/endtoend/testdata/cte_filter/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (ready bool not null); + diff --git a/internal/endtoend/testdata/cte_filter/mysql/sqlc.json b/internal/endtoend/testdata/cte_filter/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/cte_filter/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/cte_filter/pgx/v4/go/db.go b/internal/endtoend/testdata/cte_filter/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/cte_filter/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/cte_filter/pgx/v4/go/models.go b/internal/endtoend/testdata/cte_filter/pgx/v4/go/models.go new file mode 100644 index 0000000..329a259 --- /dev/null +++ b/internal/endtoend/testdata/cte_filter/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + Ready bool +} diff --git a/internal/endtoend/testdata/cte_filter/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/cte_filter/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..6f1d58c --- /dev/null +++ b/internal/endtoend/testdata/cte_filter/pgx/v4/go/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const cTEFilter = `-- name: CTEFilter :many +WITH filter_count AS ( + SELECT count(*) FROM bar WHERE ready = $1 +) +SELECT filter_count.count +FROM filter_count +` + +func (q *Queries) CTEFilter(ctx context.Context, ready bool) ([]int64, error) { + rows, err := q.db.Query(ctx, cTEFilter, ready) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var count int64 + if err := rows.Scan(&count); err != nil { + return nil, err + } + items = append(items, count) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/cte_filter/pgx/v4/query.sql b/internal/endtoend/testdata/cte_filter/pgx/v4/query.sql new file mode 100644 index 0000000..3965e43 --- /dev/null +++ b/internal/endtoend/testdata/cte_filter/pgx/v4/query.sql @@ -0,0 +1,6 @@ +-- name: CTEFilter :many +WITH filter_count AS ( + SELECT count(*) FROM bar WHERE ready = $1 +) +SELECT filter_count.count +FROM filter_count; diff --git a/internal/endtoend/testdata/cte_filter/pgx/v4/schema.sql b/internal/endtoend/testdata/cte_filter/pgx/v4/schema.sql new file mode 100644 index 0000000..1a17eee --- /dev/null +++ b/internal/endtoend/testdata/cte_filter/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (ready bool not null); + diff --git a/internal/endtoend/testdata/cte_filter/pgx/v4/sqlc.json b/internal/endtoend/testdata/cte_filter/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/cte_filter/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/cte_filter/pgx/v5/go/db.go b/internal/endtoend/testdata/cte_filter/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/cte_filter/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/cte_filter/pgx/v5/go/models.go b/internal/endtoend/testdata/cte_filter/pgx/v5/go/models.go new file mode 100644 index 0000000..329a259 --- /dev/null +++ b/internal/endtoend/testdata/cte_filter/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + Ready bool +} diff --git a/internal/endtoend/testdata/cte_filter/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/cte_filter/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..6f1d58c --- /dev/null +++ b/internal/endtoend/testdata/cte_filter/pgx/v5/go/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const cTEFilter = `-- name: CTEFilter :many +WITH filter_count AS ( + SELECT count(*) FROM bar WHERE ready = $1 +) +SELECT filter_count.count +FROM filter_count +` + +func (q *Queries) CTEFilter(ctx context.Context, ready bool) ([]int64, error) { + rows, err := q.db.Query(ctx, cTEFilter, ready) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var count int64 + if err := rows.Scan(&count); err != nil { + return nil, err + } + items = append(items, count) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/cte_filter/pgx/v5/query.sql b/internal/endtoend/testdata/cte_filter/pgx/v5/query.sql new file mode 100644 index 0000000..3965e43 --- /dev/null +++ b/internal/endtoend/testdata/cte_filter/pgx/v5/query.sql @@ -0,0 +1,6 @@ +-- name: CTEFilter :many +WITH filter_count AS ( + SELECT count(*) FROM bar WHERE ready = $1 +) +SELECT filter_count.count +FROM filter_count; diff --git a/internal/endtoend/testdata/cte_filter/pgx/v5/schema.sql b/internal/endtoend/testdata/cte_filter/pgx/v5/schema.sql new file mode 100644 index 0000000..1a17eee --- /dev/null +++ b/internal/endtoend/testdata/cte_filter/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (ready bool not null); + diff --git a/internal/endtoend/testdata/cte_filter/pgx/v5/sqlc.json b/internal/endtoend/testdata/cte_filter/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/cte_filter/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/cte_filter/stdlib/go/db.go b/internal/endtoend/testdata/cte_filter/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/cte_filter/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/cte_filter/stdlib/go/models.go b/internal/endtoend/testdata/cte_filter/stdlib/go/models.go new file mode 100644 index 0000000..329a259 --- /dev/null +++ b/internal/endtoend/testdata/cte_filter/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + Ready bool +} diff --git a/internal/endtoend/testdata/cte_filter/stdlib/go/query.sql.go b/internal/endtoend/testdata/cte_filter/stdlib/go/query.sql.go new file mode 100644 index 0000000..62294fe --- /dev/null +++ b/internal/endtoend/testdata/cte_filter/stdlib/go/query.sql.go @@ -0,0 +1,41 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const cTEFilter = `-- name: CTEFilter :many +WITH filter_count AS ( + SELECT count(*) FROM bar WHERE ready = $1 +) +SELECT filter_count.count +FROM filter_count +` + +func (q *Queries) CTEFilter(ctx context.Context, ready bool) ([]int64, error) { + rows, err := q.db.QueryContext(ctx, cTEFilter, ready) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var count int64 + if err := rows.Scan(&count); err != nil { + return nil, err + } + items = append(items, count) + } + 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/cte_filter/stdlib/query.sql b/internal/endtoend/testdata/cte_filter/stdlib/query.sql new file mode 100644 index 0000000..3965e43 --- /dev/null +++ b/internal/endtoend/testdata/cte_filter/stdlib/query.sql @@ -0,0 +1,6 @@ +-- name: CTEFilter :many +WITH filter_count AS ( + SELECT count(*) FROM bar WHERE ready = $1 +) +SELECT filter_count.count +FROM filter_count; diff --git a/internal/endtoend/testdata/cte_filter/stdlib/schema.sql b/internal/endtoend/testdata/cte_filter/stdlib/schema.sql new file mode 100644 index 0000000..1a17eee --- /dev/null +++ b/internal/endtoend/testdata/cte_filter/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (ready bool not null); + diff --git a/internal/endtoend/testdata/cte_filter/stdlib/sqlc.json b/internal/endtoend/testdata/cte_filter/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/cte_filter/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/cte_in_delete/mysql/go/db.go b/internal/endtoend/testdata/cte_in_delete/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/cte_in_delete/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/cte_in_delete/mysql/go/models.go b/internal/endtoend/testdata/cte_in_delete/mysql/go/models.go new file mode 100644 index 0000000..bdc60fa --- /dev/null +++ b/internal/endtoend/testdata/cte_in_delete/mysql/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 + Ready bool +} diff --git a/internal/endtoend/testdata/cte_in_delete/mysql/go/query.sql.go b/internal/endtoend/testdata/cte_in_delete/mysql/go/query.sql.go new file mode 100644 index 0000000..0fd419b --- /dev/null +++ b/internal/endtoend/testdata/cte_in_delete/mysql/go/query.sql.go @@ -0,0 +1,22 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const deleteReadyWithCTE = `-- name: DeleteReadyWithCTE :exec +WITH ready_ids AS ( + SELECT id FROM bar WHERE ready +) +DELETE FROM bar WHERE id IN (SELECT id FROM ready_ids) +` + +func (q *Queries) DeleteReadyWithCTE(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, deleteReadyWithCTE) + return err +} diff --git a/internal/endtoend/testdata/cte_in_delete/mysql/query.sql b/internal/endtoend/testdata/cte_in_delete/mysql/query.sql new file mode 100644 index 0000000..fd3db48 --- /dev/null +++ b/internal/endtoend/testdata/cte_in_delete/mysql/query.sql @@ -0,0 +1,5 @@ +-- name: DeleteReadyWithCTE :exec +WITH ready_ids AS ( + SELECT id FROM bar WHERE ready +) +DELETE FROM bar WHERE id IN (SELECT * FROM ready_ids); diff --git a/internal/endtoend/testdata/cte_in_delete/mysql/schema.sql b/internal/endtoend/testdata/cte_in_delete/mysql/schema.sql new file mode 100644 index 0000000..ba1fd0f --- /dev/null +++ b/internal/endtoend/testdata/cte_in_delete/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id integer NOT NULL AUTO_INCREMENT PRIMARY KEY, ready bool not null); + diff --git a/internal/endtoend/testdata/cte_in_delete/mysql/sqlc.json b/internal/endtoend/testdata/cte_in_delete/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/cte_in_delete/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/cte_in_delete/pgx/v4/go/db.go b/internal/endtoend/testdata/cte_in_delete/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/cte_in_delete/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/cte_in_delete/pgx/v4/go/models.go b/internal/endtoend/testdata/cte_in_delete/pgx/v4/go/models.go new file mode 100644 index 0000000..bdc60fa --- /dev/null +++ b/internal/endtoend/testdata/cte_in_delete/pgx/v4/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 + Ready bool +} diff --git a/internal/endtoend/testdata/cte_in_delete/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/cte_in_delete/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..31f9300 --- /dev/null +++ b/internal/endtoend/testdata/cte_in_delete/pgx/v4/go/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const deleteReadyWithCTE = `-- name: DeleteReadyWithCTE :many +WITH ready_ids AS ( + SELECT id FROM bar WHERE ready +) +DELETE FROM bar WHERE id IN (SELECT id FROM ready_ids) +RETURNING id +` + +func (q *Queries) DeleteReadyWithCTE(ctx context.Context) ([]int32, error) { + rows, err := q.db.Query(ctx, deleteReadyWithCTE) + 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 +} diff --git a/internal/endtoend/testdata/cte_in_delete/pgx/v4/query.sql b/internal/endtoend/testdata/cte_in_delete/pgx/v4/query.sql new file mode 100644 index 0000000..6a7a16d --- /dev/null +++ b/internal/endtoend/testdata/cte_in_delete/pgx/v4/query.sql @@ -0,0 +1,6 @@ +-- name: DeleteReadyWithCTE :many +WITH ready_ids AS ( + SELECT id FROM bar WHERE ready +) +DELETE FROM bar WHERE id IN (SELECT * FROM ready_ids) +RETURNING id; diff --git a/internal/endtoend/testdata/cte_in_delete/pgx/v4/schema.sql b/internal/endtoend/testdata/cte_in_delete/pgx/v4/schema.sql new file mode 100644 index 0000000..96e5fbb --- /dev/null +++ b/internal/endtoend/testdata/cte_in_delete/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial primary key not null, ready bool not null); + diff --git a/internal/endtoend/testdata/cte_in_delete/pgx/v4/sqlc.json b/internal/endtoend/testdata/cte_in_delete/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/cte_in_delete/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/cte_in_delete/pgx/v5/go/db.go b/internal/endtoend/testdata/cte_in_delete/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/cte_in_delete/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/cte_in_delete/pgx/v5/go/models.go b/internal/endtoend/testdata/cte_in_delete/pgx/v5/go/models.go new file mode 100644 index 0000000..bdc60fa --- /dev/null +++ b/internal/endtoend/testdata/cte_in_delete/pgx/v5/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 + Ready bool +} diff --git a/internal/endtoend/testdata/cte_in_delete/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/cte_in_delete/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..31f9300 --- /dev/null +++ b/internal/endtoend/testdata/cte_in_delete/pgx/v5/go/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const deleteReadyWithCTE = `-- name: DeleteReadyWithCTE :many +WITH ready_ids AS ( + SELECT id FROM bar WHERE ready +) +DELETE FROM bar WHERE id IN (SELECT id FROM ready_ids) +RETURNING id +` + +func (q *Queries) DeleteReadyWithCTE(ctx context.Context) ([]int32, error) { + rows, err := q.db.Query(ctx, deleteReadyWithCTE) + 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 +} diff --git a/internal/endtoend/testdata/cte_in_delete/pgx/v5/query.sql b/internal/endtoend/testdata/cte_in_delete/pgx/v5/query.sql new file mode 100644 index 0000000..6a7a16d --- /dev/null +++ b/internal/endtoend/testdata/cte_in_delete/pgx/v5/query.sql @@ -0,0 +1,6 @@ +-- name: DeleteReadyWithCTE :many +WITH ready_ids AS ( + SELECT id FROM bar WHERE ready +) +DELETE FROM bar WHERE id IN (SELECT * FROM ready_ids) +RETURNING id; diff --git a/internal/endtoend/testdata/cte_in_delete/pgx/v5/schema.sql b/internal/endtoend/testdata/cte_in_delete/pgx/v5/schema.sql new file mode 100644 index 0000000..96e5fbb --- /dev/null +++ b/internal/endtoend/testdata/cte_in_delete/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial primary key not null, ready bool not null); + diff --git a/internal/endtoend/testdata/cte_in_delete/pgx/v5/sqlc.json b/internal/endtoend/testdata/cte_in_delete/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/cte_in_delete/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/cte_in_delete/stdlib/go/db.go b/internal/endtoend/testdata/cte_in_delete/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/cte_in_delete/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/cte_in_delete/stdlib/go/models.go b/internal/endtoend/testdata/cte_in_delete/stdlib/go/models.go new file mode 100644 index 0000000..bdc60fa --- /dev/null +++ b/internal/endtoend/testdata/cte_in_delete/stdlib/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 + Ready bool +} diff --git a/internal/endtoend/testdata/cte_in_delete/stdlib/go/query.sql.go b/internal/endtoend/testdata/cte_in_delete/stdlib/go/query.sql.go new file mode 100644 index 0000000..fd4e4c3 --- /dev/null +++ b/internal/endtoend/testdata/cte_in_delete/stdlib/go/query.sql.go @@ -0,0 +1,41 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const deleteReadyWithCTE = `-- name: DeleteReadyWithCTE :many +WITH ready_ids AS ( + SELECT id FROM bar WHERE ready +) +DELETE FROM bar WHERE id IN (SELECT id FROM ready_ids) +RETURNING id +` + +func (q *Queries) DeleteReadyWithCTE(ctx context.Context) ([]int32, error) { + rows, err := q.db.QueryContext(ctx, deleteReadyWithCTE) + 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 +} diff --git a/internal/endtoend/testdata/cte_in_delete/stdlib/query.sql b/internal/endtoend/testdata/cte_in_delete/stdlib/query.sql new file mode 100644 index 0000000..6a7a16d --- /dev/null +++ b/internal/endtoend/testdata/cte_in_delete/stdlib/query.sql @@ -0,0 +1,6 @@ +-- name: DeleteReadyWithCTE :many +WITH ready_ids AS ( + SELECT id FROM bar WHERE ready +) +DELETE FROM bar WHERE id IN (SELECT * FROM ready_ids) +RETURNING id; diff --git a/internal/endtoend/testdata/cte_in_delete/stdlib/schema.sql b/internal/endtoend/testdata/cte_in_delete/stdlib/schema.sql new file mode 100644 index 0000000..96e5fbb --- /dev/null +++ b/internal/endtoend/testdata/cte_in_delete/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial primary key not null, ready bool not null); + diff --git a/internal/endtoend/testdata/cte_in_delete/stdlib/sqlc.json b/internal/endtoend/testdata/cte_in_delete/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/cte_in_delete/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/cte_join_self/issue.md b/internal/endtoend/testdata/cte_join_self/issue.md new file mode 100644 index 0000000..7dcb76b --- /dev/null +++ b/internal/endtoend/testdata/cte_join_self/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/2132 diff --git a/internal/endtoend/testdata/cte_join_self/postgresql/pgx/exec.json b/internal/endtoend/testdata/cte_join_self/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/cte_join_self/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/cte_join_self/postgresql/pgx/go/db.go b/internal/endtoend/testdata/cte_join_self/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/cte_join_self/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/cte_join_self/postgresql/pgx/go/models.go b/internal/endtoend/testdata/cte_join_self/postgresql/pgx/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/cte_join_self/postgresql/pgx/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/cte_join_self/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/cte_join_self/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..1238110 --- /dev/null +++ b/internal/endtoend/testdata/cte_join_self/postgresql/pgx/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listItems = `-- name: ListItems :one +WITH + items1 AS (SELECT 'id'::TEXT AS id, 'name'::TEXT AS name), + items2 AS (SELECT 'id'::TEXT AS id, 'name'::TEXT AS name) +SELECT + i1.id AS id1, + i2.id AS id2 +FROM + items1 i1 + JOIN items1 i2 ON 1 = 1 +` + +type ListItemsRow struct { + Id1 string + Id2 string +} + +func (q *Queries) ListItems(ctx context.Context) (ListItemsRow, error) { + row := q.db.QueryRow(ctx, listItems) + var i ListItemsRow + err := row.Scan(&i.Id1, &i.Id2) + return i, err +} diff --git a/internal/endtoend/testdata/cte_join_self/postgresql/pgx/query.sql b/internal/endtoend/testdata/cte_join_self/postgresql/pgx/query.sql new file mode 100644 index 0000000..972d8bf --- /dev/null +++ b/internal/endtoend/testdata/cte_join_self/postgresql/pgx/query.sql @@ -0,0 +1,10 @@ +-- name: ListItems :one +WITH + items1 AS (SELECT 'id'::TEXT AS id, 'name'::TEXT AS name), + items2 AS (SELECT 'id'::TEXT AS id, 'name'::TEXT AS name) +SELECT + i1.id AS id1, + i2.id AS id2 +FROM + items1 i1 + JOIN items1 i2 ON 1 = 1; diff --git a/internal/endtoend/testdata/cte_join_self/postgresql/pgx/schema.sql b/internal/endtoend/testdata/cte_join_self/postgresql/pgx/schema.sql new file mode 100644 index 0000000..af3b949 --- /dev/null +++ b/internal/endtoend/testdata/cte_join_self/postgresql/pgx/schema.sql @@ -0,0 +1 @@ +-- TODO \ No newline at end of file diff --git a/internal/endtoend/testdata/cte_join_self/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/cte_join_self/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/cte_join_self/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/cte_left_join/issue.md b/internal/endtoend/testdata/cte_left_join/issue.md new file mode 100644 index 0000000..6027f3c --- /dev/null +++ b/internal/endtoend/testdata/cte_left_join/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1236 \ No newline at end of file diff --git a/internal/endtoend/testdata/cte_left_join/postgresql/pgx/exec.json b/internal/endtoend/testdata/cte_left_join/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/cte_left_join/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/cte_left_join/postgresql/pgx/go/db.go b/internal/endtoend/testdata/cte_left_join/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/cte_left_join/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/cte_left_join/postgresql/pgx/go/models.go b/internal/endtoend/testdata/cte_left_join/postgresql/pgx/go/models.go new file mode 100644 index 0000000..3ed85c9 --- /dev/null +++ b/internal/endtoend/testdata/cte_left_join/postgresql/pgx/go/models.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Author struct { + ID int64 + Name string + Bio pgtype.Text +} + +type Fake struct { + ID int64 + Name string + Bio pgtype.Text +} diff --git a/internal/endtoend/testdata/cte_left_join/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/cte_left_join/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..64c2320 --- /dev/null +++ b/internal/endtoend/testdata/cte_left_join/postgresql/pgx/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const badQuery = `-- name: BadQuery :exec +WITH + q + AS ( + SELECT + authors.name, authors.bio + FROM + authors + LEFT JOIN fake ON authors.name = fake.name + ) +SELECT + name, bio +FROM + q AS c1 +WHERE c1.name = $1 +` + +func (q *Queries) BadQuery(ctx context.Context, dollar_1 pgtype.Text) error { + _, err := q.db.Exec(ctx, badQuery, dollar_1) + return err +} diff --git a/internal/endtoend/testdata/cte_left_join/postgresql/pgx/query.sql b/internal/endtoend/testdata/cte_left_join/postgresql/pgx/query.sql new file mode 100644 index 0000000..d201807 --- /dev/null +++ b/internal/endtoend/testdata/cte_left_join/postgresql/pgx/query.sql @@ -0,0 +1,15 @@ +-- name: BadQuery :exec +WITH + q + AS ( + SELECT + authors.name, authors.bio + FROM + authors + LEFT JOIN fake ON authors.name = fake.name + ) +SELECT + * +FROM + q AS c1 +WHERE c1.name = $1; \ No newline at end of file diff --git a/internal/endtoend/testdata/cte_left_join/postgresql/pgx/schema.sql b/internal/endtoend/testdata/cte_left_join/postgresql/pgx/schema.sql new file mode 100644 index 0000000..3d2f5be --- /dev/null +++ b/internal/endtoend/testdata/cte_left_join/postgresql/pgx/schema.sql @@ -0,0 +1,11 @@ +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); + +CREATE TABLE fake ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); \ No newline at end of file diff --git a/internal/endtoend/testdata/cte_left_join/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/cte_left_join/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..01489e0 --- /dev/null +++ b/internal/endtoend/testdata/cte_left_join/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" \ No newline at end of file diff --git a/internal/endtoend/testdata/cte_multiple_alias/issue.md b/internal/endtoend/testdata/cte_multiple_alias/issue.md new file mode 100644 index 0000000..5e4ec56 --- /dev/null +++ b/internal/endtoend/testdata/cte_multiple_alias/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1237 \ No newline at end of file diff --git a/internal/endtoend/testdata/cte_multiple_alias/postgresql/pgx/go/db.go b/internal/endtoend/testdata/cte_multiple_alias/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/cte_multiple_alias/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/cte_multiple_alias/postgresql/pgx/go/models.go b/internal/endtoend/testdata/cte_multiple_alias/postgresql/pgx/go/models.go new file mode 100644 index 0000000..3ed85c9 --- /dev/null +++ b/internal/endtoend/testdata/cte_multiple_alias/postgresql/pgx/go/models.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Author struct { + ID int64 + Name string + Bio pgtype.Text +} + +type Fake struct { + ID int64 + Name string + Bio pgtype.Text +} diff --git a/internal/endtoend/testdata/cte_multiple_alias/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/cte_multiple_alias/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..2b4b7f7 --- /dev/null +++ b/internal/endtoend/testdata/cte_multiple_alias/postgresql/pgx/go/query.sql.go @@ -0,0 +1,48 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const badQuery = `-- name: BadQuery :one +WITH + q + AS ( + SELECT + authors.name, authors.bio + FROM + authors + LEFT JOIN fake ON authors.name = fake.name + ) +SELECT + c1.name, c1.bio, c2.name, c2.bio +FROM + q AS c1, + q as c2 +` + +type BadQueryRow struct { + Name string + Bio pgtype.Text + Name_2 string + Bio_2 pgtype.Text +} + +func (q *Queries) BadQuery(ctx context.Context) (BadQueryRow, error) { + row := q.db.QueryRow(ctx, badQuery) + var i BadQueryRow + err := row.Scan( + &i.Name, + &i.Bio, + &i.Name_2, + &i.Bio_2, + ) + return i, err +} diff --git a/internal/endtoend/testdata/cte_multiple_alias/postgresql/pgx/query.sql b/internal/endtoend/testdata/cte_multiple_alias/postgresql/pgx/query.sql new file mode 100644 index 0000000..75d7705 --- /dev/null +++ b/internal/endtoend/testdata/cte_multiple_alias/postgresql/pgx/query.sql @@ -0,0 +1,15 @@ +-- name: BadQuery :one +WITH + q + AS ( + SELECT + authors.name, authors.bio + FROM + authors + LEFT JOIN fake ON authors.name = fake.name + ) +SELECT + * +FROM + q AS c1, + q as c2; \ No newline at end of file diff --git a/internal/endtoend/testdata/cte_multiple_alias/postgresql/pgx/schema.sql b/internal/endtoend/testdata/cte_multiple_alias/postgresql/pgx/schema.sql new file mode 100644 index 0000000..3d2f5be --- /dev/null +++ b/internal/endtoend/testdata/cte_multiple_alias/postgresql/pgx/schema.sql @@ -0,0 +1,11 @@ +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); + +CREATE TABLE fake ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); \ No newline at end of file diff --git a/internal/endtoend/testdata/cte_multiple_alias/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/cte_multiple_alias/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..01489e0 --- /dev/null +++ b/internal/endtoend/testdata/cte_multiple_alias/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" \ No newline at end of file diff --git a/internal/endtoend/testdata/cte_nested_with/issue.md b/internal/endtoend/testdata/cte_nested_with/issue.md new file mode 100644 index 0000000..40300c9 --- /dev/null +++ b/internal/endtoend/testdata/cte_nested_with/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/2226 diff --git a/internal/endtoend/testdata/cte_nested_with/postgresql/pgx/exec.json b/internal/endtoend/testdata/cte_nested_with/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/cte_nested_with/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/cte_nested_with/postgresql/pgx/go/db.go b/internal/endtoend/testdata/cte_nested_with/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/cte_nested_with/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/cte_nested_with/postgresql/pgx/go/models.go b/internal/endtoend/testdata/cte_nested_with/postgresql/pgx/go/models.go new file mode 100644 index 0000000..4e97f66 --- /dev/null +++ b/internal/endtoend/testdata/cte_nested_with/postgresql/pgx/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Author struct { + ID int64 + Name string + Bio pgtype.Text +} diff --git a/internal/endtoend/testdata/cte_nested_with/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/cte_nested_with/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..63c955b --- /dev/null +++ b/internal/endtoend/testdata/cte_nested_with/postgresql/pgx/go/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const getAuthor = `-- name: GetAuthor :one +WITH person AS( + WITH summary AS( + WITH mb AS( + select + id, name, bio + from authors + ) + SELECT + bio + FROM mb + ) + SELECT + count(*) as total + FROM summary +) +select total from person +` + +func (q *Queries) GetAuthor(ctx context.Context) (pgtype.Int8, error) { + row := q.db.QueryRow(ctx, getAuthor) + var total pgtype.Int8 + err := row.Scan(&total) + return total, err +} diff --git a/internal/endtoend/testdata/cte_nested_with/postgresql/pgx/query.sql b/internal/endtoend/testdata/cte_nested_with/postgresql/pgx/query.sql new file mode 100644 index 0000000..947cdc2 --- /dev/null +++ b/internal/endtoend/testdata/cte_nested_with/postgresql/pgx/query.sql @@ -0,0 +1,17 @@ +-- name: GetAuthor :one +WITH person AS( + WITH summary AS( + WITH mb AS( + select + id, name, bio + from authors + ) + SELECT + bio + FROM mb + ) + SELECT + count(*) as total + FROM summary +) +select total from person; diff --git a/internal/endtoend/testdata/cte_nested_with/postgresql/pgx/schema.sql b/internal/endtoend/testdata/cte_nested_with/postgresql/pgx/schema.sql new file mode 100644 index 0000000..69b607d --- /dev/null +++ b/internal/endtoend/testdata/cte_nested_with/postgresql/pgx/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/cte_nested_with/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/cte_nested_with/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/cte_nested_with/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/cte_recursive/mysql/go/db.go b/internal/endtoend/testdata/cte_recursive/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/cte_recursive/mysql/go/models.go b/internal/endtoend/testdata/cte_recursive/mysql/go/models.go new file mode 100644 index 0000000..b5270e9 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive/mysql/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ID int32 + ParentID sql.NullInt32 +} diff --git a/internal/endtoend/testdata/cte_recursive/mysql/go/query.sql.go b/internal/endtoend/testdata/cte_recursive/mysql/go/query.sql.go new file mode 100644 index 0000000..3fb405a --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive/mysql/go/query.sql.go @@ -0,0 +1,50 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const cTERecursive = `-- name: CTERecursive :many +WITH RECURSIVE cte AS ( + SELECT b.id, b.parent_id FROM bar AS b + WHERE b.id = ? + UNION ALL + SELECT b.id, b.parent_id + FROM bar AS b, cte AS c + WHERE b.parent_id = c.id +) SELECT id, parent_id FROM cte +` + +type CTERecursiveRow struct { + ID int32 + ParentID sql.NullInt32 +} + +func (q *Queries) CTERecursive(ctx context.Context, id int32) ([]CTERecursiveRow, error) { + rows, err := q.db.QueryContext(ctx, cTERecursive, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CTERecursiveRow + for rows.Next() { + var i CTERecursiveRow + if err := rows.Scan(&i.ID, &i.ParentID); 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/cte_recursive/mysql/query.sql b/internal/endtoend/testdata/cte_recursive/mysql/query.sql new file mode 100644 index 0000000..a2fa306 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive/mysql/query.sql @@ -0,0 +1,9 @@ +-- name: CTERecursive :many +WITH RECURSIVE cte AS ( + SELECT b.* FROM bar AS b + WHERE b.id = ? + UNION ALL + SELECT b.* + FROM bar AS b, cte AS c + WHERE b.parent_id = c.id +) SELECT * FROM cte; diff --git a/internal/endtoend/testdata/cte_recursive/mysql/schema.sql b/internal/endtoend/testdata/cte_recursive/mysql/schema.sql new file mode 100644 index 0000000..ccb09e1 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id INT NOT NULL, parent_id INT); + diff --git a/internal/endtoend/testdata/cte_recursive/mysql/sqlc.json b/internal/endtoend/testdata/cte_recursive/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/cte_recursive/pgx/v4/go/db.go b/internal/endtoend/testdata/cte_recursive/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/cte_recursive/pgx/v4/go/models.go b/internal/endtoend/testdata/cte_recursive/pgx/v4/go/models.go new file mode 100644 index 0000000..b5270e9 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive/pgx/v4/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ID int32 + ParentID sql.NullInt32 +} diff --git a/internal/endtoend/testdata/cte_recursive/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/cte_recursive/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..97d5c2c --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive/pgx/v4/go/query.sql.go @@ -0,0 +1,47 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const cTERecursive = `-- name: CTERecursive :many +WITH RECURSIVE cte AS ( + SELECT b.id, b.parent_id FROM bar AS b + WHERE b.id = $1 + UNION ALL + SELECT b.id, b.parent_id + FROM bar AS b, cte AS c + WHERE b.parent_id = c.id +) SELECT id, parent_id FROM cte +` + +type CTERecursiveRow struct { + ID int32 + ParentID sql.NullInt32 +} + +func (q *Queries) CTERecursive(ctx context.Context, id int32) ([]CTERecursiveRow, error) { + rows, err := q.db.Query(ctx, cTERecursive, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CTERecursiveRow + for rows.Next() { + var i CTERecursiveRow + if err := rows.Scan(&i.ID, &i.ParentID); 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/cte_recursive/pgx/v4/query.sql b/internal/endtoend/testdata/cte_recursive/pgx/v4/query.sql new file mode 100644 index 0000000..c18d216 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive/pgx/v4/query.sql @@ -0,0 +1,9 @@ +-- name: CTERecursive :many +WITH RECURSIVE cte AS ( + SELECT b.* FROM bar AS b + WHERE b.id = $1 + UNION ALL + SELECT b.* + FROM bar AS b, cte AS c + WHERE b.parent_id = c.id +) SELECT * FROM cte; diff --git a/internal/endtoend/testdata/cte_recursive/pgx/v4/schema.sql b/internal/endtoend/testdata/cte_recursive/pgx/v4/schema.sql new file mode 100644 index 0000000..ccb09e1 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id INT NOT NULL, parent_id INT); + diff --git a/internal/endtoend/testdata/cte_recursive/pgx/v4/sqlc.json b/internal/endtoend/testdata/cte_recursive/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/cte_recursive/pgx/v5/go/db.go b/internal/endtoend/testdata/cte_recursive/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/cte_recursive/pgx/v5/go/models.go b/internal/endtoend/testdata/cte_recursive/pgx/v5/go/models.go new file mode 100644 index 0000000..cbd9a4b --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Bar struct { + ID int32 + ParentID pgtype.Int4 +} diff --git a/internal/endtoend/testdata/cte_recursive/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/cte_recursive/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..515bac8 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive/pgx/v5/go/query.sql.go @@ -0,0 +1,48 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const cTERecursive = `-- name: CTERecursive :many +WITH RECURSIVE cte AS ( + SELECT b.id, b.parent_id FROM bar AS b + WHERE b.id = $1 + UNION ALL + SELECT b.id, b.parent_id + FROM bar AS b, cte AS c + WHERE b.parent_id = c.id +) SELECT id, parent_id FROM cte +` + +type CTERecursiveRow struct { + ID int32 + ParentID pgtype.Int4 +} + +func (q *Queries) CTERecursive(ctx context.Context, id int32) ([]CTERecursiveRow, error) { + rows, err := q.db.Query(ctx, cTERecursive, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CTERecursiveRow + for rows.Next() { + var i CTERecursiveRow + if err := rows.Scan(&i.ID, &i.ParentID); 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/cte_recursive/pgx/v5/query.sql b/internal/endtoend/testdata/cte_recursive/pgx/v5/query.sql new file mode 100644 index 0000000..c18d216 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive/pgx/v5/query.sql @@ -0,0 +1,9 @@ +-- name: CTERecursive :many +WITH RECURSIVE cte AS ( + SELECT b.* FROM bar AS b + WHERE b.id = $1 + UNION ALL + SELECT b.* + FROM bar AS b, cte AS c + WHERE b.parent_id = c.id +) SELECT * FROM cte; diff --git a/internal/endtoend/testdata/cte_recursive/pgx/v5/schema.sql b/internal/endtoend/testdata/cte_recursive/pgx/v5/schema.sql new file mode 100644 index 0000000..ccb09e1 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id INT NOT NULL, parent_id INT); + diff --git a/internal/endtoend/testdata/cte_recursive/pgx/v5/sqlc.json b/internal/endtoend/testdata/cte_recursive/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/cte_recursive/stdlib/go/db.go b/internal/endtoend/testdata/cte_recursive/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/cte_recursive/stdlib/go/models.go b/internal/endtoend/testdata/cte_recursive/stdlib/go/models.go new file mode 100644 index 0000000..b5270e9 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive/stdlib/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ID int32 + ParentID sql.NullInt32 +} diff --git a/internal/endtoend/testdata/cte_recursive/stdlib/go/query.sql.go b/internal/endtoend/testdata/cte_recursive/stdlib/go/query.sql.go new file mode 100644 index 0000000..12419a7 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive/stdlib/go/query.sql.go @@ -0,0 +1,50 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const cTERecursive = `-- name: CTERecursive :many +WITH RECURSIVE cte AS ( + SELECT b.id, b.parent_id FROM bar AS b + WHERE b.id = $1 + UNION ALL + SELECT b.id, b.parent_id + FROM bar AS b, cte AS c + WHERE b.parent_id = c.id +) SELECT id, parent_id FROM cte +` + +type CTERecursiveRow struct { + ID int32 + ParentID sql.NullInt32 +} + +func (q *Queries) CTERecursive(ctx context.Context, id int32) ([]CTERecursiveRow, error) { + rows, err := q.db.QueryContext(ctx, cTERecursive, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CTERecursiveRow + for rows.Next() { + var i CTERecursiveRow + if err := rows.Scan(&i.ID, &i.ParentID); 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/cte_recursive/stdlib/query.sql b/internal/endtoend/testdata/cte_recursive/stdlib/query.sql new file mode 100644 index 0000000..c18d216 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive/stdlib/query.sql @@ -0,0 +1,9 @@ +-- name: CTERecursive :many +WITH RECURSIVE cte AS ( + SELECT b.* FROM bar AS b + WHERE b.id = $1 + UNION ALL + SELECT b.* + FROM bar AS b, cte AS c + WHERE b.parent_id = c.id +) SELECT * FROM cte; diff --git a/internal/endtoend/testdata/cte_recursive/stdlib/schema.sql b/internal/endtoend/testdata/cte_recursive/stdlib/schema.sql new file mode 100644 index 0000000..ccb09e1 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id INT NOT NULL, parent_id INT); + diff --git a/internal/endtoend/testdata/cte_recursive/stdlib/sqlc.json b/internal/endtoend/testdata/cte_recursive/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/cte_recursive_employees/issue.md b/internal/endtoend/testdata/cte_recursive_employees/issue.md new file mode 100644 index 0000000..11f5771 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_employees/issue.md @@ -0,0 +1,2 @@ +https://github.com/sqlc-dev/sqlc/issues/1219 +https://github.com/sqlc-dev/sqlc/issues/1912 diff --git a/internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/exec.json b/internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/go/db.go b/internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/cte_recursive_employees/postgresql/pgx/go/models.go b/internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/go/models.go new file mode 100644 index 0000000..8859eaf --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Employee struct { + ID int64 + Name string + Manager pgtype.Text +} diff --git a/internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..9bb9598 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/go/query.sql.go @@ -0,0 +1,56 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const getSubordinates = `-- name: GetSubordinates :many +WITH RECURSIVE subordinates(name, manager) AS ( + SELECT + NULL, $1::TEXT + UNION + SELECT + s.manager, e.name + FROM + subordinates AS s + LEFT OUTER JOIN + employees AS e + ON + e.manager = s.manager + WHERE + s.manager IS NOT NULL +) +SELECT + s.name +FROM + subordinates AS s +WHERE + s.name != $1 +` + +func (q *Queries) GetSubordinates(ctx context.Context, name pgtype.Text) ([]pgtype.Text, error) { + rows, err := q.db.Query(ctx, getSubordinates, name) + if err != nil { + return nil, err + } + defer rows.Close() + var items []pgtype.Text + for rows.Next() { + var name pgtype.Text + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/query.sql b/internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/query.sql new file mode 100644 index 0000000..00d490a --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/query.sql @@ -0,0 +1,22 @@ +-- name: GetSubordinates :many +WITH RECURSIVE subordinates(name, manager) AS ( + SELECT + NULL, sqlc.arg(name)::TEXT + UNION + SELECT + s.manager, e.name + FROM + subordinates AS s + LEFT OUTER JOIN + employees AS e + ON + e.manager = s.manager + WHERE + s.manager IS NOT NULL +) +SELECT + s.name +FROM + subordinates AS s +WHERE + s.name != sqlc.arg(name); \ No newline at end of file diff --git a/internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/schema.sql b/internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/schema.sql new file mode 100644 index 0000000..b95effb --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE employees ( + id BIGSERIAL PRIMARY KEY, + name text UNIQUE NOT NULL, + manager text REFERENCES employees(name) +); \ No newline at end of file diff --git a/internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..01489e0 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_employees/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" \ No newline at end of file diff --git a/internal/endtoend/testdata/cte_recursive_star/issue.md b/internal/endtoend/testdata/cte_recursive_star/issue.md new file mode 100644 index 0000000..2bc0335 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_star/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1219 \ No newline at end of file diff --git a/internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/exec.json b/internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/go/db.go b/internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/cte_recursive_star/postgresql/pgx/go/models.go b/internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/go/models.go new file mode 100644 index 0000000..680b74c --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/go/models.go @@ -0,0 +1,27 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Dict struct { + ID string + AppID string + Code pgtype.Text + ParentCode string + Label string + Value pgtype.Text + Weight int32 + IsDefault bool + IsVirtual bool + Status int16 + CreateAt pgtype.Timestamptz + CreateBy string + UpdateAt pgtype.Timestamptz + UpdateBy pgtype.Text + IsDelete bool +} diff --git a/internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..6034af9 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/go/query.sql.go @@ -0,0 +1,59 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const getDictTree = `-- name: GetDictTree :many +with recursive dictTree(id, code, parent_code, label, value, path, depth) AS ( + select id, code, parent_code, label, value, ARRAY[COALESCE((select id from dict where code=''),'virtual_root'), id], 1 as depth from dict where app_id = '1' and parent_code = '' and is_delete=false + union + select d.id, d.code, d.parent_code, d.label, d.value, t.path || ARRAY[d.id], t.depth+1 as depth from dict d join dictTree t on d.parent_code = t.code and not d.id = ANY(t.path) and d.is_delete=false +) +select id, code, parent_code, label, value, path, depth from dictTree d order by depth, parent_code +` + +type GetDictTreeRow struct { + ID string + Code pgtype.Text + ParentCode string + Label string + Value pgtype.Text + Path []string + Depth int32 +} + +func (q *Queries) GetDictTree(ctx context.Context) ([]GetDictTreeRow, error) { + rows, err := q.db.Query(ctx, getDictTree) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetDictTreeRow + for rows.Next() { + var i GetDictTreeRow + if err := rows.Scan( + &i.ID, + &i.Code, + &i.ParentCode, + &i.Label, + &i.Value, + &i.Path, + &i.Depth, + ); 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/cte_recursive_star/postgresql/pgx/query.sql b/internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/query.sql new file mode 100644 index 0000000..a48253d --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/query.sql @@ -0,0 +1,7 @@ +-- name: GetDictTree :many +with recursive dictTree(id, code, parent_code, label, value, path, depth) AS ( + select id, code, parent_code, label, value, ARRAY[COALESCE((select id from dict where code=''),'virtual_root'), id], 1 as depth from dict where app_id = '1' and parent_code = '' and is_delete=false + union + select d.id, d.code, d.parent_code, d.label, d.value, t.path || ARRAY[d.id], t.depth+1 as depth from dict d join dictTree t on d.parent_code = t.code and not d.id = ANY(t.path) and d.is_delete=false +) +select * from dictTree d order by depth, parent_code; \ No newline at end of file diff --git a/internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/schema.sql b/internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/schema.sql new file mode 100644 index 0000000..c4257ab --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/schema.sql @@ -0,0 +1,17 @@ +create table dict( + id VARCHAR(36) PRIMARY KEY DEFAULT gen_random_uuid(), + app_id VARCHAR(36) NOT NULL, + code VARCHAR(64), + parent_code VARCHAR(64) NOT NULL, + label TEXT NOT NULL DEFAULT '', + value TEXT NULL, + weight INT NOT NULL DEFAULT 0, + is_default BOOLEAN NOT NULL DEFAULT false, + is_virtual BOOLEAN NOT NULL DEFAULT false, + status SMALLINT NOT NULL DEFAULT 1, + create_at TIMESTAMPTZ(0) NOT NULL DEFAULT now(), + create_by VARCHAR(36) NOT NULL DEFAULT '', + update_at TIMESTAMPTZ(0), + update_by VARCHAR(36), + is_delete BOOLEAN NOT NULL DEFAULT false +); diff --git a/internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..01489e0 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_star/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" \ No newline at end of file diff --git a/internal/endtoend/testdata/cte_recursive_subquery/issue.md b/internal/endtoend/testdata/cte_recursive_subquery/issue.md new file mode 100644 index 0000000..98c00da --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_subquery/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/2644 diff --git a/internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/exec.json b/internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/go/db.go b/internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/cte_recursive_subquery/postgresql/pgx/go/models.go b/internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/go/models.go new file mode 100644 index 0000000..9662cea --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Version struct { + ID int64 + Name pgtype.Text + PreviousVersionID int64 +} diff --git a/internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..60559a0 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/go/query.sql.go @@ -0,0 +1,60 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getLatestVersion = `-- name: GetLatestVersion :one +WITH RECURSIVE search_tree(id, chain_id, chain_counter) AS ( + SELECT base.id, base.id AS chain_id, 0 as chain_counter + FROM versions AS base + WHERE base.previous_version_id IS NULL + UNION ALL + SELECT v.id, search_tree.chain_id, search_tree.chain_counter + 1 + FROM versions AS v + INNER JOIN search_tree ON search_tree.id = v.previous_version_id +) +SELECT DISTINCT ON (search_tree.chain_id) + search_tree.id +FROM search_tree +ORDER BY search_tree.chain_id, chain_counter DESC +` + +func (q *Queries) GetLatestVersion(ctx context.Context) (int64, error) { + row := q.db.QueryRow(ctx, getLatestVersion) + var id int64 + err := row.Scan(&id) + return id, err +} + +const getLatestVersionWithSubquery = `-- name: GetLatestVersionWithSubquery :one +SELECT id +FROM versions +WHERE versions.id IN ( + WITH RECURSIVE search_tree(id, chain_id, chain_counter) AS ( + SELECT base.id, base.id AS chain_id, 0 as chain_counter + FROM versions AS base + WHERE versions.previous_version_id IS NULL + UNION ALL + SELECT v.id, search_tree.chain_id, search_tree.chain_counter + 1 + FROM versions AS v + INNER JOIN search_tree ON search_tree.id = v.previous_version_id + ) + SELECT DISTINCT ON (search_tree.chain_id) + search_tree.id + FROM search_tree + ORDER BY search_tree.chain_id, chain_counter DESC +) +` + +func (q *Queries) GetLatestVersionWithSubquery(ctx context.Context) (int64, error) { + row := q.db.QueryRow(ctx, getLatestVersionWithSubquery) + var id int64 + err := row.Scan(&id) + return id, err +} diff --git a/internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/query.sql b/internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/query.sql new file mode 100644 index 0000000..021d493 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/query.sql @@ -0,0 +1,33 @@ +-- name: GetLatestVersion :one +WITH RECURSIVE search_tree(id, chain_id, chain_counter) AS ( + SELECT base.id, base.id AS chain_id, 0 as chain_counter + FROM versions AS base + WHERE base.previous_version_id IS NULL + UNION ALL + SELECT v.id, search_tree.chain_id, search_tree.chain_counter + 1 + FROM versions AS v + INNER JOIN search_tree ON search_tree.id = v.previous_version_id +) +SELECT DISTINCT ON (search_tree.chain_id) + search_tree.id +FROM search_tree +ORDER BY search_tree.chain_id, chain_counter DESC; + +-- name: GetLatestVersionWithSubquery :one +SELECT id +FROM versions +WHERE versions.id IN ( + WITH RECURSIVE search_tree(id, chain_id, chain_counter) AS ( + SELECT base.id, base.id AS chain_id, 0 as chain_counter + FROM versions AS base + WHERE versions.previous_version_id IS NULL + UNION ALL + SELECT v.id, search_tree.chain_id, search_tree.chain_counter + 1 + FROM versions AS v + INNER JOIN search_tree ON search_tree.id = v.previous_version_id + ) + SELECT DISTINCT ON (search_tree.chain_id) + search_tree.id + FROM search_tree + ORDER BY search_tree.chain_id, chain_counter DESC +); diff --git a/internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/schema.sql b/internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/schema.sql new file mode 100644 index 0000000..766adb0 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE versions ( + id BIGSERIAL PRIMARY KEY, + name TEXT, + previous_version_id bigint NOT NULL +); diff --git a/internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..2f12715 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_subquery/postgresql/pgx/sqlc.yaml @@ -0,0 +1,14 @@ +version: "2" +cloud: + project: "01HAQMMECEYQYKFJN8MP16QC41" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" + database: + managed: true diff --git a/internal/endtoend/testdata/cte_recursive_union/issue.md b/internal/endtoend/testdata/cte_recursive_union/issue.md new file mode 100644 index 0000000..f87f5c1 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_union/issue.md @@ -0,0 +1 @@ +# TODO \ No newline at end of file diff --git a/internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/exec.json b/internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/go/db.go b/internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/cte_recursive_union/postgresql/pgx/go/models.go b/internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/go/models.go new file mode 100644 index 0000000..c0f1a21 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/go/models.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type CaseIntent struct { + ID int32 + CaseIntentString string + Description string + Author string +} + +type CaseIntentParentJoin struct { + CaseIntentID int64 + CaseIntentParentID int64 +} + +type CaseIntentVersion struct { + VersionID int32 + Reviewer string + CreatedAt pgtype.Timestamptz +} + +type CaseIntentVersionJoin struct { + CaseIntentID int64 + CaseIntentVersionID int32 +} diff --git a/internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..a60bc65 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/go/query.sql.go @@ -0,0 +1,57 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const listCaseIntentHistory = `-- name: ListCaseIntentHistory :many +WITH RECURSIVE descendants AS + ( SELECT case_intent_parent_id AS parent, case_intent_id AS child, 1 AS lvl + FROM case_intent_parent_join + UNION ALL + SELECT d.parent as parent, p.case_intent_id as child, d.lvl + 1 as lvl + FROM descendants d + JOIN case_intent_parent_join p + ON d.child = p.case_intent_parent_id + ) +select distinct child, 'child' group_ +from descendants +where parent = $1 +union +select distinct parent, 'parent' group_ +from descendants +where child = $1 +ORDER BY child +` + +type ListCaseIntentHistoryRow struct { + Child int64 + Group string +} + +func (q *Queries) ListCaseIntentHistory(ctx context.Context, caseIntentID pgtype.Int8) ([]ListCaseIntentHistoryRow, error) { + rows, err := q.db.Query(ctx, listCaseIntentHistory, caseIntentID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListCaseIntentHistoryRow + for rows.Next() { + var i ListCaseIntentHistoryRow + if err := rows.Scan(&i.Child, &i.Group); 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/cte_recursive_union/postgresql/pgx/query.sql b/internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/query.sql new file mode 100644 index 0000000..dce099d --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/query.sql @@ -0,0 +1,18 @@ +-- name: ListCaseIntentHistory :many +WITH RECURSIVE descendants AS + ( SELECT case_intent_parent_id AS parent, case_intent_id AS child, 1 AS lvl + FROM case_intent_parent_join + UNION ALL + SELECT d.parent as parent, p.case_intent_id as child, d.lvl + 1 as lvl + FROM descendants d + JOIN case_intent_parent_join p + ON d.child = p.case_intent_parent_id + ) +select distinct child, 'child' group_ +from descendants +where parent = @case_intent_id +union +select distinct parent, 'parent' group_ +from descendants +where child = @case_intent_id +ORDER BY child; diff --git a/internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/schema.sql b/internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/schema.sql new file mode 100644 index 0000000..a2c3a68 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/schema.sql @@ -0,0 +1,27 @@ +CREATE TABLE case_intent_version +( + version_id SERIAL NOT NULL PRIMARY KEY, + reviewer TEXT NOT NULL, + created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW() +); +CREATE TABLE case_intent +( + id SERIAL NOT NULL PRIMARY KEY, + case_intent_string TEXT NOT NULL, + description TEXT NOT NULL, + author TEXT NOT NULL +); +CREATE TABLE case_intent_parent_join +( + case_intent_id BIGINT NOT NULL, + case_intent_parent_id BIGINT NOT NULL, + constraint fk_case_intent_id foreign key (case_intent_id) references case_intent(id), + constraint fk_case_intent_parent_id foreign key (case_intent_parent_id) references case_intent(id) +); +CREATE TABLE case_intent_version_join +( + case_intent_id BIGINT NOT NULL, + case_intent_version_id INT NOT NULL, + constraint fk_case_intent_id foreign key (case_intent_id) references case_intent(id), + constraint fk_case_intent_version_id foreign key (case_intent_version_id) references case_intent_version(version_id) +); diff --git a/internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/cte_select_one/issue.md b/internal/endtoend/testdata/cte_select_one/issue.md new file mode 100644 index 0000000..f87f5c1 --- /dev/null +++ b/internal/endtoend/testdata/cte_select_one/issue.md @@ -0,0 +1 @@ +# TODO \ No newline at end of file diff --git a/internal/endtoend/testdata/cte_select_one/postgresql/pgx/go/db.go b/internal/endtoend/testdata/cte_select_one/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/cte_select_one/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/cte_select_one/postgresql/pgx/go/models.go b/internal/endtoend/testdata/cte_select_one/postgresql/pgx/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/cte_select_one/postgresql/pgx/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/cte_select_one/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/cte_select_one/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..463398c --- /dev/null +++ b/internal/endtoend/testdata/cte_select_one/postgresql/pgx/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const testRecursive = `-- name: TestRecursive :one +WITH t1 AS ( + select 1 as foo +) +SELECT foo FROM t1 +` + +func (q *Queries) TestRecursive(ctx context.Context) (int32, error) { + row := q.db.QueryRow(ctx, testRecursive) + var foo int32 + err := row.Scan(&foo) + return foo, err +} diff --git a/internal/endtoend/testdata/cte_select_one/postgresql/pgx/query.sql b/internal/endtoend/testdata/cte_select_one/postgresql/pgx/query.sql new file mode 100644 index 0000000..9f4fdf0 --- /dev/null +++ b/internal/endtoend/testdata/cte_select_one/postgresql/pgx/query.sql @@ -0,0 +1,5 @@ +-- name: TestRecursive :one +WITH t1 AS ( + select 1 as foo +) +SELECT * FROM t1; \ No newline at end of file diff --git a/internal/endtoend/testdata/cte_select_one/postgresql/pgx/schema.sql b/internal/endtoend/testdata/cte_select_one/postgresql/pgx/schema.sql new file mode 100644 index 0000000..af3b949 --- /dev/null +++ b/internal/endtoend/testdata/cte_select_one/postgresql/pgx/schema.sql @@ -0,0 +1 @@ +-- TODO \ No newline at end of file diff --git a/internal/endtoend/testdata/cte_select_one/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/cte_select_one/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..01489e0 --- /dev/null +++ b/internal/endtoend/testdata/cte_select_one/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" \ No newline at end of file diff --git a/internal/endtoend/testdata/cte_update/issue.md b/internal/endtoend/testdata/cte_update/issue.md new file mode 100644 index 0000000..5f1a592 --- /dev/null +++ b/internal/endtoend/testdata/cte_update/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1515 diff --git a/internal/endtoend/testdata/cte_update/postgresql/pgx/exec.json b/internal/endtoend/testdata/cte_update/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/cte_update/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/cte_update/postgresql/pgx/go/db.go b/internal/endtoend/testdata/cte_update/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/cte_update/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/cte_update/postgresql/pgx/go/models.go b/internal/endtoend/testdata/cte_update/postgresql/pgx/go/models.go new file mode 100644 index 0000000..f66a67c --- /dev/null +++ b/internal/endtoend/testdata/cte_update/postgresql/pgx/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Attribute struct { + ID int64 + Name string +} + +type AttributeValue struct { + ID int64 + Val string + Attribute int64 +} diff --git a/internal/endtoend/testdata/cte_update/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/cte_update/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..3d729de --- /dev/null +++ b/internal/endtoend/testdata/cte_update/postgresql/pgx/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const updateAttribute = `-- name: UpdateAttribute :one +with updated_attribute as (UPDATE attribute_value + SET + val = CASE WHEN $1::bool THEN $2 ELSE val END + WHERE attribute_value.id = $3 + RETURNING id,attribute,val) +select updated_attribute.id, val, name +from updated_attribute + left join attribute on updated_attribute.attribute = attribute.id +` + +type UpdateAttributeParams struct { + FilterValue pgtype.Bool + Value pgtype.Text + ID pgtype.Int8 +} + +type UpdateAttributeRow struct { + ID int64 + Val string + Name pgtype.Text +} + +func (q *Queries) UpdateAttribute(ctx context.Context, arg UpdateAttributeParams) (UpdateAttributeRow, error) { + row := q.db.QueryRow(ctx, updateAttribute, arg.FilterValue, arg.Value, arg.ID) + var i UpdateAttributeRow + err := row.Scan(&i.ID, &i.Val, &i.Name) + return i, err +} diff --git a/internal/endtoend/testdata/cte_update/postgresql/pgx/query.sql b/internal/endtoend/testdata/cte_update/postgresql/pgx/query.sql new file mode 100644 index 0000000..6ba9aa4 --- /dev/null +++ b/internal/endtoend/testdata/cte_update/postgresql/pgx/query.sql @@ -0,0 +1,9 @@ +-- name: UpdateAttribute :one +with updated_attribute as (UPDATE attribute_value + SET + val = CASE WHEN @filter_value::bool THEN @value ELSE val END + WHERE attribute_value.id = @id + RETURNING id,attribute,val) +select updated_attribute.id, val, name +from updated_attribute + left join attribute on updated_attribute.attribute = attribute.id; diff --git a/internal/endtoend/testdata/cte_update/postgresql/pgx/schema.sql b/internal/endtoend/testdata/cte_update/postgresql/pgx/schema.sql new file mode 100644 index 0000000..6273c9a --- /dev/null +++ b/internal/endtoend/testdata/cte_update/postgresql/pgx/schema.sql @@ -0,0 +1,12 @@ +create table attribute_value +( + id bigserial not null, + val text not null, + attribute bigint not null +); + +create table attribute +( + id bigserial not null, + name text not null +); diff --git a/internal/endtoend/testdata/cte_update/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/cte_update/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/cte_update/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/cte_update_multiple/issue.md b/internal/endtoend/testdata/cte_update_multiple/issue.md new file mode 100644 index 0000000..fc662de --- /dev/null +++ b/internal/endtoend/testdata/cte_update_multiple/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1916 diff --git a/internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/exec.json b/internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/go/db.go b/internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/cte_update_multiple/postgresql/pgx/go/models.go b/internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/go/models.go new file mode 100644 index 0000000..53e1984 --- /dev/null +++ b/internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/go/models.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Address struct { + ID int64 + AddressLine string + Region string + City string + CreatedAt pgtype.Timestamptz + UpdatedAt pgtype.Timestamptz +} + +type User struct { + ID int64 + Username string + Email string + Password string + Telephone int32 + DefaultPayment pgtype.Int8 + CreatedAt pgtype.Timestamptz + UpdatedAt pgtype.Timestamptz +} + +type UserAddress struct { + UserID int64 + AddressID int64 + DefaultAddress pgtype.Int8 + CreatedAt pgtype.Timestamptz + UpdatedAt pgtype.Timestamptz +} diff --git a/internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..b44b0a9 --- /dev/null +++ b/internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/go/query.sql.go @@ -0,0 +1,83 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const updateUserAddressWithAddress = `-- name: UpdateUserAddressWithAddress :one +WITH t1 AS ( + UPDATE "address" as a + SET + address_line = COALESCE($1,address_line), + region = COALESCE($2,region), + city= COALESCE($3,city) + WHERE id = COALESCE($4,id) + RETURNING a.id, a.address_line, a.region, a.city + ), + + t2 AS ( + UPDATE "user_address" + SET + default_address = COALESCE($5,default_address) + WHERE + user_id = COALESCE($6,user_id) + AND address_id = COALESCE($7,address_id) + RETURNING user_id, address_id, default_address + ) + +SELECT +user_id, +address_id, +default_address, +address_line, +region, +city From t1,t2 +` + +type UpdateUserAddressWithAddressParams struct { + AddressLine pgtype.Text + Region pgtype.Text + City pgtype.Text + ID pgtype.Int8 + DefaultAddress pgtype.Int8 + UserID pgtype.Int8 + AddressID pgtype.Int8 +} + +type UpdateUserAddressWithAddressRow struct { + UserID int64 + AddressID int64 + DefaultAddress pgtype.Int8 + AddressLine string + Region string + City string +} + +func (q *Queries) UpdateUserAddressWithAddress(ctx context.Context, arg UpdateUserAddressWithAddressParams) (UpdateUserAddressWithAddressRow, error) { + row := q.db.QueryRow(ctx, updateUserAddressWithAddress, + arg.AddressLine, + arg.Region, + arg.City, + arg.ID, + arg.DefaultAddress, + arg.UserID, + arg.AddressID, + ) + var i UpdateUserAddressWithAddressRow + err := row.Scan( + &i.UserID, + &i.AddressID, + &i.DefaultAddress, + &i.AddressLine, + &i.Region, + &i.City, + ) + return i, err +} diff --git a/internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/query.sql b/internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/query.sql new file mode 100644 index 0000000..9cb15e5 --- /dev/null +++ b/internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/query.sql @@ -0,0 +1,28 @@ +-- name: UpdateUserAddressWithAddress :one +WITH t1 AS ( + UPDATE "address" as a + SET + address_line = COALESCE(sqlc.narg(address_line),address_line), + region = COALESCE(sqlc.narg(region),region), + city= COALESCE(sqlc.narg(city),city) + WHERE id = COALESCE(sqlc.arg(id),id) + RETURNING a.id, a.address_line, a.region, a.city + ), + + t2 AS ( + UPDATE "user_address" + SET + default_address = COALESCE(sqlc.narg(default_address),default_address) + WHERE + user_id = COALESCE(sqlc.arg(user_id),user_id) + AND address_id = COALESCE(sqlc.arg(address_id),address_id) + RETURNING user_id, address_id, default_address + ) + +SELECT +user_id, +address_id, +default_address, +address_line, +region, +city From t1,t2; diff --git a/internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/schema.sql b/internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/schema.sql new file mode 100644 index 0000000..7ec7b1a --- /dev/null +++ b/internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/schema.sql @@ -0,0 +1,27 @@ +CREATE TABLE "user" ( + "id" bigserial PRIMARY KEY NOT NULL, + "username" varchar NOT NULL, + "email" varchar UNIQUE NOT NULL, + "password" varchar NOT NULL, + "telephone" int NOT NULL DEFAULT 0, + "default_payment" bigint, + "created_at" timestamptz NOT NULL DEFAULT (now()), + "updated_at" timestamptz NOT NULL DEFAULT '0001-01-01 00:00:00Z' +); + +CREATE TABLE "address" ( + "id" bigserial PRIMARY KEY NOT NULL, + "address_line" varchar NOT NULL, + "region" varchar NOT NULL, + "city" varchar NOT NULL, + "created_at" timestamptz NOT NULL DEFAULT (now()), + "updated_at" timestamptz NOT NULL DEFAULT '0001-01-01 00:00:00Z' +); + +CREATE TABLE "user_address" ( + "user_id" bigint NOT NULL, + "address_id" bigint UNIQUE NOT NULL, + "default_address" bigint, + "created_at" timestamptz NOT NULL DEFAULT (now()), + "updated_at" timestamptz NOT NULL DEFAULT '0001-01-01 00:00:00Z' +); diff --git a/internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/cte_update_multiple/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/cte_with_in/issue.md b/internal/endtoend/testdata/cte_with_in/issue.md new file mode 100644 index 0000000..34fccd5 --- /dev/null +++ b/internal/endtoend/testdata/cte_with_in/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/2153 diff --git a/internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/exec.json b/internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/go/db.go b/internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/cte_with_in/postgresql/pganalyze/go/models.go b/internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/go/models.go new file mode 100644 index 0000000..2eeae6b --- /dev/null +++ b/internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/go/models.go @@ -0,0 +1,20 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type L struct { + ID int64 + ParentID pgtype.Int4 +} + +type T struct { + ID int64 + LID pgtype.Int4 + F pgtype.Text +} diff --git a/internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/go/query.sql.go b/internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/go/query.sql.go new file mode 100644 index 0000000..8d9bdb7 --- /dev/null +++ b/internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/go/query.sql.go @@ -0,0 +1,164 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const getAll = `-- name: GetAll :many +SELECT id, parent_id FROM L +` + +func (q *Queries) GetAll(ctx context.Context) ([]L, error) { + rows, err := q.db.Query(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []L + for rows.Next() { + var i L + if err := rows.Scan(&i.ID, &i.ParentID); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getAll1 = `-- name: GetAll1 :many +with recursive cte as ( + select id, L_ID, F from T + union all + select c.id, c.L_ID, c.F from T as c where c.L_ID = $1 +) select id, l_id, f from cte +` + +type GetAll1Row struct { + ID int64 + LID pgtype.Int4 + F pgtype.Text +} + +func (q *Queries) GetAll1(ctx context.Context, lID pgtype.Int4) ([]GetAll1Row, error) { + rows, err := q.db.Query(ctx, getAll1, lID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetAll1Row + for rows.Next() { + var i GetAll1Row + if err := rows.Scan(&i.ID, &i.LID, &i.F); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getAll2 = `-- name: GetAll2 :many +with recursive cte as ( + select id, L_ID, F from T where T.ID=2 + union all + select c.id, c.L_ID, c.F from T as c where c.L_ID = $1 +) select id, l_id, f from cte +` + +type GetAll2Row struct { + ID int64 + LID pgtype.Int4 + F pgtype.Text +} + +func (q *Queries) GetAll2(ctx context.Context, lID pgtype.Int4) ([]GetAll2Row, error) { + rows, err := q.db.Query(ctx, getAll2, lID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetAll2Row + for rows.Next() { + var i GetAll2Row + if err := rows.Scan(&i.ID, &i.LID, &i.F); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getAll3 = `-- name: GetAll3 :many +select id from T where L_ID in( + with recursive cte as ( + select id, L_ID, F from T where T.ID =2 + union all + select c.id, c.L_ID, c.F from T as c where c.L_ID = $1 + ) select l_id from cte +) +` + +func (q *Queries) GetAll3(ctx context.Context, dollar_1 pgtype.Int4) ([]int64, error) { + rows, err := q.db.Query(ctx, getAll3, dollar_1) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var id int64 + 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 getAll4 = `-- name: GetAll4 :many +select id from T where L_ID in( + with recursive L as ( + select id, L_ID, F from T where T.ID =2 + union all + select c.id, c.L_ID, c.F from T as c where c.L_ID = $1 + ) select l_id from L +) +` + +func (q *Queries) GetAll4(ctx context.Context, lID pgtype.Int4) ([]int64, error) { + rows, err := q.db.Query(ctx, getAll4, lID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var id int64 + 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 +} diff --git a/internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/query.sql b/internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/query.sql new file mode 100644 index 0000000..4a27713 --- /dev/null +++ b/internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/query.sql @@ -0,0 +1,34 @@ +-- name: GetAll :many +SELECT * FROM L; + +-- name: GetAll1 :many +with recursive cte as ( + select id, L_ID, F from T + union all + select c.id, c.L_ID, c.F from T as c where c.L_ID = $1 +) select id, l_id, f from cte; + +-- name: GetAll2 :many +with recursive cte as ( + select id, L_ID, F from T where T.ID=2 + union all + select c.id, c.L_ID, c.F from T as c where c.L_ID = $1 +) select id, l_id, f from cte; + +-- name: GetAll4 :many +select id from T where L_ID in( + with recursive L as ( + select id, L_ID, F from T where T.ID =2 + union all + select c.id, c.L_ID, c.F from T as c where c.L_ID = $1 + ) select l_id from L +); + +-- name: GetAll3 :many +select id from T where L_ID in( + with recursive cte as ( + select id, L_ID, F from T where T.ID =2 + union all + select c.id, c.L_ID, c.F from T as c where c.L_ID = $1 + ) select l_id from cte +); diff --git a/internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/schema.sql b/internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/schema.sql new file mode 100644 index 0000000..cf970e3 --- /dev/null +++ b/internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/schema.sql @@ -0,0 +1,12 @@ +-- https://github.com/sqlc-dev/sqlc/issues/2153 + +CREATE TABLE L ( + id BIGSERIAL PRIMARY KEY, + parent_id int null +); + +CREATE TABLE T ( + id BIGSERIAL PRIMARY KEY, + L_ID int, + F varchar(256) +); diff --git a/internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/sqlc.json b/internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/sqlc.json new file mode 100644 index 0000000..4905a64 --- /dev/null +++ b/internal/endtoend/testdata/cte_with_in/postgresql/pganalyze/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "sql_package": "pgx/v5" + } + ] +} + diff --git a/internal/endtoend/testdata/data_type_boolean/mysql/db/db.go b/internal/endtoend/testdata/data_type_boolean/mysql/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/mysql/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/data_type_boolean/mysql/db/models.go b/internal/endtoend/testdata/data_type_boolean/mysql/db/models.go new file mode 100644 index 0000000..c9881be --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/mysql/db/models.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "database/sql" +) + +type Bar struct { + ColA sql.NullBool + ColB sql.NullBool + ColC sql.NullBool +} + +type Foo struct { + ColA bool + ColB bool + ColC bool +} diff --git a/internal/endtoend/testdata/data_type_boolean/mysql/db/query.sql.go b/internal/endtoend/testdata/data_type_boolean/mysql/db/query.sql.go new file mode 100644 index 0000000..3bf45fb --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/mysql/db/query.sql.go @@ -0,0 +1,64 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" +) + +const listBar = `-- name: ListBar :many +SELECT col_a, col_b, col_c FROM bar +` + +func (q *Queries) ListBar(ctx context.Context) ([]Bar, error) { + rows, err := q.db.QueryContext(ctx, listBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Bar + for rows.Next() { + var i Bar + if err := rows.Scan(&i.ColA, &i.ColB, &i.ColC); 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 listFoo = `-- name: ListFoo :many +SELECT col_a, col_b, col_c FROM foo +` + +func (q *Queries) ListFoo(ctx context.Context) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, listFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.ColA, &i.ColB, &i.ColC); 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/data_type_boolean/mysql/query.sql b/internal/endtoend/testdata/data_type_boolean/mysql/query.sql new file mode 100644 index 0000000..c0adc5c --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/mysql/query.sql @@ -0,0 +1,5 @@ +-- name: ListFoo :many +SELECT * FROM foo; + +-- name: ListBar :many +SELECT * FROM bar; diff --git a/internal/endtoend/testdata/data_type_boolean/mysql/schema.sql b/internal/endtoend/testdata/data_type_boolean/mysql/schema.sql new file mode 100644 index 0000000..8289125 --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/mysql/schema.sql @@ -0,0 +1,13 @@ +CREATE TABLE foo +( + col_a BOOL NOT NULL, + col_b BOOLEAN NOT NULL, + col_c TINYINT(1) NOT NULL +); + +CREATE TABLE bar +( + col_a BOOL, + col_b BOOLEAN, + col_c TINYINT(1) +); diff --git a/internal/endtoend/testdata/data_type_boolean/mysql/sqlc.json b/internal/endtoend/testdata/data_type_boolean/mysql/sqlc.json new file mode 100644 index 0000000..d98ee6f --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "db", + "engine": "mysql", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} + diff --git a/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/data_type_boolean/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..e58b7da --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v4/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ColA sql.NullBool + ColB sql.NullBool +} + +type Foo struct { + ColA bool + ColB bool +} diff --git a/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..cbe50cf --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,58 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listBar = `-- name: ListBar :many +SELECT col_a, col_b FROM bar +` + +func (q *Queries) ListBar(ctx context.Context) ([]Bar, error) { + rows, err := q.db.Query(ctx, listBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Bar + for rows.Next() { + var i Bar + if err := rows.Scan(&i.ColA, &i.ColB); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listFoo = `-- name: ListFoo :many +SELECT col_a, col_b FROM foo +` + +func (q *Queries) ListFoo(ctx context.Context) ([]Foo, error) { + rows, err := q.db.Query(ctx, listFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.ColA, &i.ColB); 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/data_type_boolean/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..c0adc5c --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v4/query.sql @@ -0,0 +1,5 @@ +-- name: ListFoo :many +SELECT * FROM foo; + +-- name: ListBar :many +SELECT * FROM bar; diff --git a/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..735b66f --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v4/schema.sql @@ -0,0 +1,11 @@ +CREATE TABLE foo +( + col_a BOOL NOT NULL, + col_b BOOLEAN NOT NULL +); + +CREATE TABLE bar +( + col_a BOOL, + col_b BOOLEAN +); diff --git a/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d5697fa --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} + diff --git a/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/data_type_boolean/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..3b11a26 --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v5/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Bar struct { + ColA pgtype.Bool + ColB pgtype.Bool +} + +type Foo struct { + ColA bool + ColB bool +} diff --git a/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..cbe50cf --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,58 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listBar = `-- name: ListBar :many +SELECT col_a, col_b FROM bar +` + +func (q *Queries) ListBar(ctx context.Context) ([]Bar, error) { + rows, err := q.db.Query(ctx, listBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Bar + for rows.Next() { + var i Bar + if err := rows.Scan(&i.ColA, &i.ColB); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listFoo = `-- name: ListFoo :many +SELECT col_a, col_b FROM foo +` + +func (q *Queries) ListFoo(ctx context.Context) ([]Foo, error) { + rows, err := q.db.Query(ctx, listFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.ColA, &i.ColB); 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/data_type_boolean/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..c0adc5c --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v5/query.sql @@ -0,0 +1,5 @@ +-- name: ListFoo :many +SELECT * FROM foo; + +-- name: ListBar :many +SELECT * FROM bar; diff --git a/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..735b66f --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v5/schema.sql @@ -0,0 +1,11 @@ +CREATE TABLE foo +( + col_a BOOL NOT NULL, + col_b BOOLEAN NOT NULL +); + +CREATE TABLE bar +( + col_a BOOL, + col_b BOOLEAN +); diff --git a/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..59a4822 --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} + diff --git a/internal/endtoend/testdata/data_type_boolean/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/data_type_boolean/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/data_type_boolean/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/data_type_boolean/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..e58b7da --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/postgresql/stdlib/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ColA sql.NullBool + ColB sql.NullBool +} + +type Foo struct { + ColA bool + ColB bool +} diff --git a/internal/endtoend/testdata/data_type_boolean/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/data_type_boolean/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..69b40a8 --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,64 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listBar = `-- name: ListBar :many +SELECT col_a, col_b FROM bar +` + +func (q *Queries) ListBar(ctx context.Context) ([]Bar, error) { + rows, err := q.db.QueryContext(ctx, listBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Bar + for rows.Next() { + var i Bar + if err := rows.Scan(&i.ColA, &i.ColB); 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 listFoo = `-- name: ListFoo :many +SELECT col_a, col_b FROM foo +` + +func (q *Queries) ListFoo(ctx context.Context) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, listFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.ColA, &i.ColB); 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/data_type_boolean/postgresql/stdlib/query.sql b/internal/endtoend/testdata/data_type_boolean/postgresql/stdlib/query.sql new file mode 100644 index 0000000..c0adc5c --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/postgresql/stdlib/query.sql @@ -0,0 +1,5 @@ +-- name: ListFoo :many +SELECT * FROM foo; + +-- name: ListBar :many +SELECT * FROM bar; diff --git a/internal/endtoend/testdata/data_type_boolean/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/data_type_boolean/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..735b66f --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/postgresql/stdlib/schema.sql @@ -0,0 +1,11 @@ +CREATE TABLE foo +( + col_a BOOL NOT NULL, + col_b BOOLEAN NOT NULL +); + +CREATE TABLE bar +( + col_a BOOL, + col_b BOOLEAN +); diff --git a/internal/endtoend/testdata/data_type_boolean/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/data_type_boolean/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..84cf1bb --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/postgresql/stdlib/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} + diff --git a/internal/endtoend/testdata/data_type_boolean/sqlite/db/db.go b/internal/endtoend/testdata/data_type_boolean/sqlite/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/sqlite/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/data_type_boolean/sqlite/db/models.go b/internal/endtoend/testdata/data_type_boolean/sqlite/db/models.go new file mode 100644 index 0000000..00e5da2 --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/sqlite/db/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "database/sql" +) + +type Bar struct { + ColA sql.NullBool + ColB sql.NullBool +} + +type Foo struct { + ColA bool + ColB bool +} diff --git a/internal/endtoend/testdata/data_type_boolean/sqlite/db/query.sql.go b/internal/endtoend/testdata/data_type_boolean/sqlite/db/query.sql.go new file mode 100644 index 0000000..247c171 --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/sqlite/db/query.sql.go @@ -0,0 +1,64 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" +) + +const listBar = `-- name: ListBar :many +SELECT col_a, col_b FROM bar +` + +func (q *Queries) ListBar(ctx context.Context) ([]Bar, error) { + rows, err := q.db.QueryContext(ctx, listBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Bar + for rows.Next() { + var i Bar + if err := rows.Scan(&i.ColA, &i.ColB); 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 listFoo = `-- name: ListFoo :many +SELECT col_a, col_b FROM foo +` + +func (q *Queries) ListFoo(ctx context.Context) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, listFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.ColA, &i.ColB); 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/data_type_boolean/sqlite/query.sql b/internal/endtoend/testdata/data_type_boolean/sqlite/query.sql new file mode 100644 index 0000000..c0adc5c --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/sqlite/query.sql @@ -0,0 +1,5 @@ +-- name: ListFoo :many +SELECT * FROM foo; + +-- name: ListBar :many +SELECT * FROM bar; diff --git a/internal/endtoend/testdata/data_type_boolean/sqlite/schema.sql b/internal/endtoend/testdata/data_type_boolean/sqlite/schema.sql new file mode 100644 index 0000000..735b66f --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/sqlite/schema.sql @@ -0,0 +1,11 @@ +CREATE TABLE foo +( + col_a BOOL NOT NULL, + col_b BOOLEAN NOT NULL +); + +CREATE TABLE bar +( + col_a BOOL, + col_b BOOLEAN +); diff --git a/internal/endtoend/testdata/data_type_boolean/sqlite/sqlc.json b/internal/endtoend/testdata/data_type_boolean/sqlite/sqlc.json new file mode 100644 index 0000000..8dc788d --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/sqlite/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "db", + "engine": "sqlite", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/datatype/mysql/go/db.go b/internal/endtoend/testdata/datatype/mysql/go/db.go new file mode 100644 index 0000000..31b1352 --- /dev/null +++ b/internal/endtoend/testdata/datatype/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package datatype + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/datatype/mysql/go/models.go b/internal/endtoend/testdata/datatype/mysql/go/models.go new file mode 100644 index 0000000..c0b51ba --- /dev/null +++ b/internal/endtoend/testdata/datatype/mysql/go/models.go @@ -0,0 +1,91 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package datatype + +import ( + "database/sql" + "time" +) + +type DtCharacter struct { + A sql.NullString + B sql.NullString + C sql.NullString + D sql.NullString + E sql.NullString + F sql.NullString + G sql.NullString + H sql.NullString + I sql.NullString + J sql.NullString + K sql.NullString + L sql.NullString +} + +type DtCharacterNotNull struct { + A string + B string + C string + D []byte + E []byte + F []byte + G string + H string + I string + J []byte + K string + L []byte +} + +type DtDatetime struct { + A sql.NullTime + B sql.NullTime + C sql.NullTime +} + +type DtDatetimeNotNull struct { + A time.Time + B time.Time + C time.Time +} + +type DtNumeric struct { + A sql.NullInt32 + B sql.NullInt32 + C sql.NullInt16 + D sql.NullInt16 + E sql.NullInt32 + F sql.NullInt64 + G any + H sql.NullString + I sql.NullString + J sql.NullFloat64 + K sql.NullFloat64 + L sql.NullFloat64 +} + +type DtNumericNotNull struct { + A int32 + B int32 + C int8 + D int16 + E int32 + F int64 + G any + H string + I string + J float64 + K float64 + L float64 +} + +type DtNumericUnsigned struct { + A sql.NullInt32 + B sql.NullInt32 + C sql.NullInt16 + D sql.NullInt16 + E sql.NullInt32 + F sql.NullInt64 +} diff --git a/internal/endtoend/testdata/datatype/mysql/go/query.sql.go b/internal/endtoend/testdata/datatype/mysql/go/query.sql.go new file mode 100644 index 0000000..96b4633 --- /dev/null +++ b/internal/endtoend/testdata/datatype/mysql/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package datatype + +import ( + "context" +) + +const test = `-- name: Test :one +SELECT 1 +` + +func (q *Queries) Test(ctx context.Context) (int32, error) { + row := q.db.QueryRowContext(ctx, test) + var column_1 int32 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/datatype/mysql/sql/character.sql b/internal/endtoend/testdata/datatype/mysql/sql/character.sql new file mode 100644 index 0000000..4213047 --- /dev/null +++ b/internal/endtoend/testdata/datatype/mysql/sql/character.sql @@ -0,0 +1,31 @@ +-- Character Types +-- https://dev.mysql.com/doc/refman/8.0/en/string-type-syntax.html +CREATE TABLE dt_character ( + a CHARACTER(32), + b VARCHAR(32), + c CHAR(32), + d BINARY(32), + e VARBINARY(32), + f TINYBLOB, + g TINYTEXT, + h TEXT, + i MEDIUMTEXT, + j MEDIUMBLOB, + k LONGTEXT, + l LONGBLOB +); + +CREATE TABLE dt_character_not_null ( + a CHARACTER(32) NOT NULL, + b VARCHAR(32) NOT NULL, + c CHAR(32) NOT NULL, + d BINARY(32) NOT NULL, + e VARBINARY(32) NOT NULL, + f TINYBLOB NOT NULL, + g TINYTEXT NOT NULL, + h TEXT NOT NULL, + i MEDIUMTEXT NOT NULL, + j MEDIUMBLOB NOT NULL, + k LONGTEXT NOT NULL, + l LONGBLOB NOT NULL +); diff --git a/internal/endtoend/testdata/datatype/mysql/sql/datetime.sql b/internal/endtoend/testdata/datatype/mysql/sql/datetime.sql new file mode 100644 index 0000000..6008cf6 --- /dev/null +++ b/internal/endtoend/testdata/datatype/mysql/sql/datetime.sql @@ -0,0 +1,13 @@ +-- Date/Time Types +-- https://www.sqlite.org/datatype3.html +CREATE TABLE dt_datetime ( + a DATE, + b DATETIME, + c TIMESTAMP +); + +CREATE TABLE dt_datetime_not_null ( + a DATE NOT NULL, + b DATETIME NOT NULL, + c TIMESTAMP NOT NULL +); diff --git a/internal/endtoend/testdata/datatype/mysql/sql/numeric.sql b/internal/endtoend/testdata/datatype/mysql/sql/numeric.sql new file mode 100644 index 0000000..ddc1573 --- /dev/null +++ b/internal/endtoend/testdata/datatype/mysql/sql/numeric.sql @@ -0,0 +1,40 @@ +-- Numeric Types +-- https://dev.mysql.com/doc/refman/8.0/en/numeric-type-syntax.html +CREATE TABLE dt_numeric ( + a INT, + b INTEGER, + c TINYINT, + d SMALLINT, + e MEDIUMINT, + f BIGINT, + g BIT, + h DECIMAL(10, 5), + i DEC(10, 5), + j FLOAT, + k DOUBLE, + l DOUBLE PRECISION +); + +CREATE TABLE dt_numeric_unsigned ( + a INT UNSIGNED, + b INTEGER UNSIGNED, + c TINYINT UNSIGNED, + d SMALLINT UNSIGNED, + e MEDIUMINT UNSIGNED, + f BIGINT UNSIGNED +); + +CREATE TABLE dt_numeric_not_null ( + a INT NOT NULL, + b INTEGER NOT NULL, + c TINYINT NOT NULL, + d SMALLINT NOT NULL, + e MEDIUMINT NOT NULL, + f BIGINT NOT NULL, + g BIT NOT NULL, + h DECIMAL(10, 5) NOT NULL, + i DEC(10, 5) NOT NULL, + j FLOAT NOT NULL, + k DOUBLE NOT NULL, + l DOUBLE PRECISION NOT NULL +); diff --git a/internal/endtoend/testdata/datatype/mysql/sql/query.sql b/internal/endtoend/testdata/datatype/mysql/sql/query.sql new file mode 100644 index 0000000..9da604b --- /dev/null +++ b/internal/endtoend/testdata/datatype/mysql/sql/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT 1; diff --git a/internal/endtoend/testdata/datatype/mysql/sqlc.json b/internal/endtoend/testdata/datatype/mysql/sqlc.json new file mode 100644 index 0000000..8bc2cb7 --- /dev/null +++ b/internal/endtoend/testdata/datatype/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "mysql", + "name": "datatype", + "schema": "sql/", + "queries": "sql/" + } + ] +} diff --git a/internal/endtoend/testdata/datatype/pgx/v4/go/db.go b/internal/endtoend/testdata/datatype/pgx/v4/go/db.go new file mode 100644 index 0000000..5cc19ed --- /dev/null +++ b/internal/endtoend/testdata/datatype/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package datatype + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/datatype/pgx/v4/go/models.go b/internal/endtoend/testdata/datatype/pgx/v4/go/models.go new file mode 100644 index 0000000..1408ef6 --- /dev/null +++ b/internal/endtoend/testdata/datatype/pgx/v4/go/models.go @@ -0,0 +1,112 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package datatype + +import ( + "database/sql" + "time" + + "github.com/jackc/pgtype" +) + +type DtCharacter struct { + A sql.NullString + B sql.NullString + C sql.NullString + D sql.NullString + E sql.NullString +} + +type DtCharacterNotNull struct { + A string + B string + C string + D string + E string +} + +type DtDatetime struct { + A sql.NullTime + B sql.NullTime + C sql.NullTime + D sql.NullTime + E sql.NullTime + F sql.NullTime + G sql.NullTime + H sql.NullTime +} + +type DtDatetimeNotNull struct { + A time.Time + B time.Time + C time.Time + D time.Time + E time.Time + F time.Time + G time.Time + H time.Time +} + +type DtNetType struct { + A pgtype.Inet + B pgtype.CIDR + C pgtype.Macaddr +} + +type DtNetTypesNotNull struct { + A pgtype.Inet + B pgtype.CIDR + C pgtype.Macaddr +} + +type DtNumeric struct { + A sql.NullInt16 + B sql.NullInt32 + C sql.NullInt64 + D pgtype.Numeric + E pgtype.Numeric + F sql.NullFloat64 + G sql.NullFloat64 + H sql.NullInt16 + I sql.NullInt32 + J sql.NullInt64 + K sql.NullInt16 + L sql.NullInt32 + M sql.NullInt64 +} + +type DtNumericNotNull struct { + A int16 + B int32 + C int64 + D pgtype.Numeric + E pgtype.Numeric + F float32 + G float64 + H int16 + I int32 + J int64 + K int16 + L int32 + M int64 +} + +type DtRange struct { + A pgtype.Int4range + B pgtype.Int8range + C pgtype.Numrange + D pgtype.Tsrange + E pgtype.Tstzrange + F pgtype.Daterange +} + +type DtRangeNotNull struct { + A pgtype.Int4range + B pgtype.Int8range + C pgtype.Numrange + D pgtype.Tsrange + E pgtype.Tstzrange + F pgtype.Daterange +} diff --git a/internal/endtoend/testdata/datatype/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/datatype/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..29ea3c7 --- /dev/null +++ b/internal/endtoend/testdata/datatype/pgx/v4/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package datatype + +import ( + "context" +) + +const test = `-- name: Test :one +SELECT 1 +` + +func (q *Queries) Test(ctx context.Context) (int32, error) { + row := q.db.QueryRow(ctx, test) + var column_1 int32 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/datatype/pgx/v4/sql/character.sql b/internal/endtoend/testdata/datatype/pgx/v4/sql/character.sql new file mode 100644 index 0000000..e3f41da --- /dev/null +++ b/internal/endtoend/testdata/datatype/pgx/v4/sql/character.sql @@ -0,0 +1,17 @@ +-- Character Types +-- https://www.postgresql.org/docs/current/datatype-character.html +CREATE TABLE dt_character ( + a text, + b character varying(32), + c varchar(32), + d character(32), + e char(32) +); + +CREATE TABLE dt_character_not_null ( + a text NOT NULL, + b character varying(32) NOT NULL, + c varchar(32) NOT NULL, + d character(32) NOT NULL, + e char(32) NOT NULL +); diff --git a/internal/endtoend/testdata/datatype/pgx/v4/sql/datetime.sql b/internal/endtoend/testdata/datatype/pgx/v4/sql/datetime.sql new file mode 100644 index 0000000..5e6bcf0 --- /dev/null +++ b/internal/endtoend/testdata/datatype/pgx/v4/sql/datetime.sql @@ -0,0 +1,23 @@ +-- Date/Time Types +-- https://www.postgresql.org/docs/current/datatype-datetime.html +CREATE TABLE dt_datetime ( + a DATE, + b TIME, + c TIME WITHOUT TIME ZONE, + d TIME WITH TIME ZONE, + e TIMESTAMP, + f TIMESTAMP WITHOUT TIME ZONE, + g TIMESTAMP WITH TIME ZONE, + h timestamptz +); + +CREATE TABLE dt_datetime_not_null ( + a DATE NOT NULL, + b TIME NOT NULL, + c TIME WITHOUT TIME ZONE NOT NULL, + d TIME WITH TIME ZONE NOT NULL, + e TIMESTAMP NOT NULL, + f TIMESTAMP WITHOUT TIME ZONE NOT NULL, + g TIMESTAMP WITH TIME ZONE NOT NULL, + h timestamptz NOT NULL +); diff --git a/internal/endtoend/testdata/datatype/pgx/v4/sql/net-types.sql b/internal/endtoend/testdata/datatype/pgx/v4/sql/net-types.sql new file mode 100644 index 0000000..6239b6f --- /dev/null +++ b/internal/endtoend/testdata/datatype/pgx/v4/sql/net-types.sql @@ -0,0 +1,13 @@ +-- Network Address Types +-- https://www.postgresql.org/docs/current/datatype-net-types.html +CREATE TABLE dt_net_types ( + a inet, + b cidr, + c macaddr +); + +CREATE TABLE dt_net_types_not_null ( + a inet NOT NULL, + b cidr NOT NULL, + c macaddr NOT NULL +); diff --git a/internal/endtoend/testdata/datatype/pgx/v4/sql/numeric.sql b/internal/endtoend/testdata/datatype/pgx/v4/sql/numeric.sql new file mode 100644 index 0000000..9df1494 --- /dev/null +++ b/internal/endtoend/testdata/datatype/pgx/v4/sql/numeric.sql @@ -0,0 +1,36 @@ +-- Numeric Types +-- https://www.postgresql.org/docs/current/datatype-numeric.html +CREATE TABLE dt_numeric ( + -- TODO: this maps incorrectly to int16, not NullInt16 + a smallint, + b integer, + c bigint, + d decimal, + e numeric, + f real, + g double precision, + -- TODO: this maps incorrectly to int16, not NullInt16 + h smallserial, + i serial, + j bigserial, + -- TODO: this maps incorrectly to int16, not NullInt16 + k int2, + l int4, + m int8 +); + +CREATE TABLE dt_numeric_not_null ( + a smallint NOT NULL, + b integer NOT NULL, + c bigint NOT NULL, + d decimal NOT NULL, + e numeric NOT NULL, + f real NOT NULL, + g double precision NOT NULL, + h smallserial NOT NULL, + i serial NOT NULL, + j bigserial NOT NULL, + k int2 NOT NULL, + l int4 NOT NULL, + m int8 NOT NULL +); diff --git a/internal/endtoend/testdata/datatype/pgx/v4/sql/query.sql b/internal/endtoend/testdata/datatype/pgx/v4/sql/query.sql new file mode 100644 index 0000000..9da604b --- /dev/null +++ b/internal/endtoend/testdata/datatype/pgx/v4/sql/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT 1; diff --git a/internal/endtoend/testdata/datatype/pgx/v4/sql/rangetypes.sql b/internal/endtoend/testdata/datatype/pgx/v4/sql/rangetypes.sql new file mode 100644 index 0000000..7e61b65 --- /dev/null +++ b/internal/endtoend/testdata/datatype/pgx/v4/sql/rangetypes.sql @@ -0,0 +1,19 @@ +-- Range Types +-- https://www.postgresql.org/docs/current/rangetypes.html +CREATE TABLE dt_range ( + a int4range, + b int8range, + c numrange, + d tsrange, + e tstzrange, + f daterange +); + +CREATE TABLE dt_range_not_null ( + a int4range NOT NULL, + b int8range NOT NULL, + c numrange NOT NULL, + d tsrange NOT NULL, + e tstzrange NOT NULL, + f daterange NOT NULL +); diff --git a/internal/endtoend/testdata/datatype/pgx/v4/sqlc.json b/internal/endtoend/testdata/datatype/pgx/v4/sqlc.json new file mode 100644 index 0000000..196e0d3 --- /dev/null +++ b/internal/endtoend/testdata/datatype/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "datatype", + "schema": "sql/", + "queries": "sql/" + } + ] +} diff --git a/internal/endtoend/testdata/datatype/pgx/v5/go/db.go b/internal/endtoend/testdata/datatype/pgx/v5/go/db.go new file mode 100644 index 0000000..b57247c --- /dev/null +++ b/internal/endtoend/testdata/datatype/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package datatype + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/datatype/pgx/v5/go/models.go b/internal/endtoend/testdata/datatype/pgx/v5/go/models.go new file mode 100644 index 0000000..26252be --- /dev/null +++ b/internal/endtoend/testdata/datatype/pgx/v5/go/models.go @@ -0,0 +1,114 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package datatype + +import ( + "database/sql" + "net" + "net/netip" + "time" + + "github.com/jackc/pgx/v5/pgtype" +) + +type DtCharacter struct { + A pgtype.Text + B pgtype.Text + C pgtype.Text + D pgtype.Text + E pgtype.Text +} + +type DtCharacterNotNull struct { + A string + B string + C string + D string + E string +} + +type DtDatetime struct { + A pgtype.Date + B pgtype.Time + C pgtype.Time + D sql.NullTime + E pgtype.Timestamp + F pgtype.Timestamp + G pgtype.Timestamptz + H pgtype.Timestamptz +} + +type DtDatetimeNotNull struct { + A pgtype.Date + B pgtype.Time + C pgtype.Time + D time.Time + E pgtype.Timestamp + F pgtype.Timestamp + G pgtype.Timestamptz + H pgtype.Timestamptz +} + +type DtNetType struct { + A *netip.Addr + B *netip.Prefix + C net.HardwareAddr +} + +type DtNetTypesNotNull struct { + A netip.Addr + B netip.Prefix + C net.HardwareAddr +} + +type DtNumeric struct { + A pgtype.Int2 + B pgtype.Int4 + C pgtype.Int8 + D pgtype.Numeric + E pgtype.Numeric + F pgtype.Float4 + G pgtype.Float8 + H pgtype.Int2 + I pgtype.Int4 + J pgtype.Int8 + K pgtype.Int2 + L pgtype.Int4 + M pgtype.Int8 +} + +type DtNumericNotNull struct { + A int16 + B int32 + C int64 + D pgtype.Numeric + E pgtype.Numeric + F float32 + G float64 + H int16 + I int32 + J int64 + K int16 + L int32 + M int64 +} + +type DtRange struct { + A pgtype.Range[pgtype.Int4] + B pgtype.Range[pgtype.Int8] + C pgtype.Range[pgtype.Numeric] + D pgtype.Range[pgtype.Timestamp] + E pgtype.Range[pgtype.Timestamptz] + F pgtype.Range[pgtype.Date] +} + +type DtRangeNotNull struct { + A pgtype.Range[pgtype.Int4] + B pgtype.Range[pgtype.Int8] + C pgtype.Range[pgtype.Numeric] + D pgtype.Range[pgtype.Timestamp] + E pgtype.Range[pgtype.Timestamptz] + F pgtype.Range[pgtype.Date] +} diff --git a/internal/endtoend/testdata/datatype/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/datatype/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..29ea3c7 --- /dev/null +++ b/internal/endtoend/testdata/datatype/pgx/v5/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package datatype + +import ( + "context" +) + +const test = `-- name: Test :one +SELECT 1 +` + +func (q *Queries) Test(ctx context.Context) (int32, error) { + row := q.db.QueryRow(ctx, test) + var column_1 int32 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/datatype/pgx/v5/sql/character.sql b/internal/endtoend/testdata/datatype/pgx/v5/sql/character.sql new file mode 100644 index 0000000..e3f41da --- /dev/null +++ b/internal/endtoend/testdata/datatype/pgx/v5/sql/character.sql @@ -0,0 +1,17 @@ +-- Character Types +-- https://www.postgresql.org/docs/current/datatype-character.html +CREATE TABLE dt_character ( + a text, + b character varying(32), + c varchar(32), + d character(32), + e char(32) +); + +CREATE TABLE dt_character_not_null ( + a text NOT NULL, + b character varying(32) NOT NULL, + c varchar(32) NOT NULL, + d character(32) NOT NULL, + e char(32) NOT NULL +); diff --git a/internal/endtoend/testdata/datatype/pgx/v5/sql/datetime.sql b/internal/endtoend/testdata/datatype/pgx/v5/sql/datetime.sql new file mode 100644 index 0000000..5e6bcf0 --- /dev/null +++ b/internal/endtoend/testdata/datatype/pgx/v5/sql/datetime.sql @@ -0,0 +1,23 @@ +-- Date/Time Types +-- https://www.postgresql.org/docs/current/datatype-datetime.html +CREATE TABLE dt_datetime ( + a DATE, + b TIME, + c TIME WITHOUT TIME ZONE, + d TIME WITH TIME ZONE, + e TIMESTAMP, + f TIMESTAMP WITHOUT TIME ZONE, + g TIMESTAMP WITH TIME ZONE, + h timestamptz +); + +CREATE TABLE dt_datetime_not_null ( + a DATE NOT NULL, + b TIME NOT NULL, + c TIME WITHOUT TIME ZONE NOT NULL, + d TIME WITH TIME ZONE NOT NULL, + e TIMESTAMP NOT NULL, + f TIMESTAMP WITHOUT TIME ZONE NOT NULL, + g TIMESTAMP WITH TIME ZONE NOT NULL, + h timestamptz NOT NULL +); diff --git a/internal/endtoend/testdata/datatype/pgx/v5/sql/net-types.sql b/internal/endtoend/testdata/datatype/pgx/v5/sql/net-types.sql new file mode 100644 index 0000000..6239b6f --- /dev/null +++ b/internal/endtoend/testdata/datatype/pgx/v5/sql/net-types.sql @@ -0,0 +1,13 @@ +-- Network Address Types +-- https://www.postgresql.org/docs/current/datatype-net-types.html +CREATE TABLE dt_net_types ( + a inet, + b cidr, + c macaddr +); + +CREATE TABLE dt_net_types_not_null ( + a inet NOT NULL, + b cidr NOT NULL, + c macaddr NOT NULL +); diff --git a/internal/endtoend/testdata/datatype/pgx/v5/sql/numeric.sql b/internal/endtoend/testdata/datatype/pgx/v5/sql/numeric.sql new file mode 100644 index 0000000..9df1494 --- /dev/null +++ b/internal/endtoend/testdata/datatype/pgx/v5/sql/numeric.sql @@ -0,0 +1,36 @@ +-- Numeric Types +-- https://www.postgresql.org/docs/current/datatype-numeric.html +CREATE TABLE dt_numeric ( + -- TODO: this maps incorrectly to int16, not NullInt16 + a smallint, + b integer, + c bigint, + d decimal, + e numeric, + f real, + g double precision, + -- TODO: this maps incorrectly to int16, not NullInt16 + h smallserial, + i serial, + j bigserial, + -- TODO: this maps incorrectly to int16, not NullInt16 + k int2, + l int4, + m int8 +); + +CREATE TABLE dt_numeric_not_null ( + a smallint NOT NULL, + b integer NOT NULL, + c bigint NOT NULL, + d decimal NOT NULL, + e numeric NOT NULL, + f real NOT NULL, + g double precision NOT NULL, + h smallserial NOT NULL, + i serial NOT NULL, + j bigserial NOT NULL, + k int2 NOT NULL, + l int4 NOT NULL, + m int8 NOT NULL +); diff --git a/internal/endtoend/testdata/datatype/pgx/v5/sql/query.sql b/internal/endtoend/testdata/datatype/pgx/v5/sql/query.sql new file mode 100644 index 0000000..9da604b --- /dev/null +++ b/internal/endtoend/testdata/datatype/pgx/v5/sql/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT 1; diff --git a/internal/endtoend/testdata/datatype/pgx/v5/sql/rangetypes.sql b/internal/endtoend/testdata/datatype/pgx/v5/sql/rangetypes.sql new file mode 100644 index 0000000..7e61b65 --- /dev/null +++ b/internal/endtoend/testdata/datatype/pgx/v5/sql/rangetypes.sql @@ -0,0 +1,19 @@ +-- Range Types +-- https://www.postgresql.org/docs/current/rangetypes.html +CREATE TABLE dt_range ( + a int4range, + b int8range, + c numrange, + d tsrange, + e tstzrange, + f daterange +); + +CREATE TABLE dt_range_not_null ( + a int4range NOT NULL, + b int8range NOT NULL, + c numrange NOT NULL, + d tsrange NOT NULL, + e tstzrange NOT NULL, + f daterange NOT NULL +); diff --git a/internal/endtoend/testdata/datatype/pgx/v5/sqlc.json b/internal/endtoend/testdata/datatype/pgx/v5/sqlc.json new file mode 100644 index 0000000..c4ad3be --- /dev/null +++ b/internal/endtoend/testdata/datatype/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "datatype", + "schema": "sql/", + "queries": "sql/" + } + ] +} diff --git a/internal/endtoend/testdata/datatype/sqlite/go/db.go b/internal/endtoend/testdata/datatype/sqlite/go/db.go new file mode 100644 index 0000000..31b1352 --- /dev/null +++ b/internal/endtoend/testdata/datatype/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package datatype + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/datatype/sqlite/go/models.go b/internal/endtoend/testdata/datatype/sqlite/go/models.go new file mode 100644 index 0000000..7354c7d --- /dev/null +++ b/internal/endtoend/testdata/datatype/sqlite/go/models.go @@ -0,0 +1,80 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package datatype + +import ( + "database/sql" + "time" +) + +type DtCharacter struct { + A sql.NullString + B sql.NullString + C sql.NullString + D sql.NullString + E sql.NullString + F sql.NullString + G sql.NullString + H sql.NullString +} + +type DtCharacterNotNull struct { + A string + B string + C string + D string + E string + F string + G string + H string +} + +type DtDatetime struct { + A sql.NullTime + B sql.NullTime + C sql.NullTime +} + +type DtDatetimeNotNull struct { + A time.Time + B time.Time + C time.Time +} + +type DtNumeric struct { + A sql.NullInt64 + B sql.NullInt64 + C sql.NullInt64 + D sql.NullInt64 + E sql.NullInt64 + F sql.NullInt64 + G sql.NullInt64 + H sql.NullInt64 + I sql.NullInt64 + J sql.NullFloat64 + K sql.NullFloat64 + L sql.NullFloat64 + M sql.NullFloat64 + N sql.NullFloat64 + O sql.NullFloat64 +} + +type DtNumericNotNull struct { + A int64 + B int64 + C int64 + D int64 + E int64 + F int64 + G int64 + H int64 + I int64 + J float64 + K float64 + L float64 + M float64 + N float64 + O float64 +} diff --git a/internal/endtoend/testdata/datatype/sqlite/go/query.sql.go b/internal/endtoend/testdata/datatype/sqlite/go/query.sql.go new file mode 100644 index 0000000..3023724 --- /dev/null +++ b/internal/endtoend/testdata/datatype/sqlite/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package datatype + +import ( + "context" +) + +const test = `-- name: Test :one +SELECT 1 +` + +func (q *Queries) Test(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, test) + var column_1 int64 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/datatype/sqlite/sql/character.sql b/internal/endtoend/testdata/datatype/sqlite/sql/character.sql new file mode 100644 index 0000000..8c5a6ea --- /dev/null +++ b/internal/endtoend/testdata/datatype/sqlite/sql/character.sql @@ -0,0 +1,23 @@ +-- Character Types +-- https://www.sqlite.org/datatype3.html +CREATE TABLE dt_character ( + a CHARACTER(32), + b VARCHAR(32), + c VARYING CHARACTER(32), + d NCHAR(32), + e NATIVE CHARACTER(32), + f NVARCHAR(32), + g TEXT, + h CLOB +); + +CREATE TABLE dt_character_not_null ( + a CHARACTER(32) NOT NULL, + b VARCHAR(32) NOT NULL, + c VARYING CHARACTER(32) NOT NULL, + d NCHAR(32) NOT NULL, + e NATIVE CHARACTER(32) NOT NULL, + f NVARCHAR(32) NOT NULL, + g TEXT NOT NULL, + h CLOB NOT NULL +); diff --git a/internal/endtoend/testdata/datatype/sqlite/sql/datetime.sql b/internal/endtoend/testdata/datatype/sqlite/sql/datetime.sql new file mode 100644 index 0000000..a1f91e5 --- /dev/null +++ b/internal/endtoend/testdata/datatype/sqlite/sql/datetime.sql @@ -0,0 +1,13 @@ +-- Date/Time Types +-- https://www.sqlite.org/datatype3.html +CREATE TABLE dt_datetime ( + a DATE, + b DATETIME, + c TIMESTAMP +); + +CREATE TABLE dt_datetime_not_null ( + a DATE NOT NULL, + b DATETIME NOT NULL, + c TIMESTAMP NOT NULL +); diff --git a/internal/endtoend/testdata/datatype/sqlite/sql/numeric.sql b/internal/endtoend/testdata/datatype/sqlite/sql/numeric.sql new file mode 100644 index 0000000..1662cb6 --- /dev/null +++ b/internal/endtoend/testdata/datatype/sqlite/sql/numeric.sql @@ -0,0 +1,37 @@ +-- Numeric Types +-- https://www.sqlite.org/datatype3.html +CREATE TABLE dt_numeric ( + a INT, + b INTEGER, + c TINYINT, + d SMALLINT, + e MEDIUMINT, + f BIGINT, + g UNSIGNED BIG INT, + h INT2, + i INT8, + j REAL, + k DOUBLE, + l DOUBLE PRECISION, + m FLOAT, + n NUMERIC, + o DECIMAL(10,5) +); + +CREATE TABLE dt_numeric_not_null ( + a INT NOT NULL, + b INTEGER NOT NULL, + c TINYINT NOT NULL, + d SMALLINT NOT NULL, + e MEDIUMINT NOT NULL, + f BIGINT NOT NULL, + g UNSIGNED BIG INT NOT NULL, + h INT2 NOT NULL, + i INT8 NOT NULL, + j REAL NOT NULL, + k DOUBLE NOT NULL, + l DOUBLE PRECISION NOT NULL, + m FLOAT NOT NULL, + n NUMERIC NOT NULL, + o DECIMAL(10,5) NOT NULL +); diff --git a/internal/endtoend/testdata/datatype/sqlite/sql/query.sql b/internal/endtoend/testdata/datatype/sqlite/sql/query.sql new file mode 100644 index 0000000..9da604b --- /dev/null +++ b/internal/endtoend/testdata/datatype/sqlite/sql/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT 1; diff --git a/internal/endtoend/testdata/datatype/sqlite/sqlc.json b/internal/endtoend/testdata/datatype/sqlite/sqlc.json new file mode 100644 index 0000000..768a85b --- /dev/null +++ b/internal/endtoend/testdata/datatype/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "datatype", + "schema": "sql/", + "queries": "sql/" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/datatype/stdlib/go/db.go b/internal/endtoend/testdata/datatype/stdlib/go/db.go new file mode 100644 index 0000000..31b1352 --- /dev/null +++ b/internal/endtoend/testdata/datatype/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package datatype + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/datatype/stdlib/go/models.go b/internal/endtoend/testdata/datatype/stdlib/go/models.go new file mode 100644 index 0000000..0dbaa9a --- /dev/null +++ b/internal/endtoend/testdata/datatype/stdlib/go/models.go @@ -0,0 +1,112 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package datatype + +import ( + "database/sql" + "time" + + "github.com/sqlc-dev/pqtype" +) + +type DtCharacter struct { + A sql.NullString + B sql.NullString + C sql.NullString + D sql.NullString + E sql.NullString +} + +type DtCharacterNotNull struct { + A string + B string + C string + D string + E string +} + +type DtDatetime struct { + A sql.NullTime + B sql.NullTime + C sql.NullTime + D sql.NullTime + E sql.NullTime + F sql.NullTime + G sql.NullTime + H sql.NullTime +} + +type DtDatetimeNotNull struct { + A time.Time + B time.Time + C time.Time + D time.Time + E time.Time + F time.Time + G time.Time + H time.Time +} + +type DtNetType struct { + A pqtype.Inet + B pqtype.CIDR + C pqtype.Macaddr +} + +type DtNetTypesNotNull struct { + A pqtype.Inet + B pqtype.CIDR + C pqtype.Macaddr +} + +type DtNumeric struct { + A sql.NullInt16 + B sql.NullInt32 + C sql.NullInt64 + D sql.NullString + E sql.NullString + F sql.NullFloat64 + G sql.NullFloat64 + H sql.NullInt16 + I sql.NullInt32 + J sql.NullInt64 + K sql.NullInt16 + L sql.NullInt32 + M sql.NullInt64 +} + +type DtNumericNotNull struct { + A int16 + B int32 + C int64 + D string + E string + F float32 + G float64 + H int16 + I int32 + J int64 + K int16 + L int32 + M int64 +} + +type DtRange struct { + A any + B any + C any + D any + E any + F any +} + +type DtRangeNotNull struct { + A any + B any + C any + D any + E any + F any +} diff --git a/internal/endtoend/testdata/datatype/stdlib/go/query.sql.go b/internal/endtoend/testdata/datatype/stdlib/go/query.sql.go new file mode 100644 index 0000000..96b4633 --- /dev/null +++ b/internal/endtoend/testdata/datatype/stdlib/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package datatype + +import ( + "context" +) + +const test = `-- name: Test :one +SELECT 1 +` + +func (q *Queries) Test(ctx context.Context) (int32, error) { + row := q.db.QueryRowContext(ctx, test) + var column_1 int32 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/datatype/stdlib/sql/character.sql b/internal/endtoend/testdata/datatype/stdlib/sql/character.sql new file mode 100644 index 0000000..e3f41da --- /dev/null +++ b/internal/endtoend/testdata/datatype/stdlib/sql/character.sql @@ -0,0 +1,17 @@ +-- Character Types +-- https://www.postgresql.org/docs/current/datatype-character.html +CREATE TABLE dt_character ( + a text, + b character varying(32), + c varchar(32), + d character(32), + e char(32) +); + +CREATE TABLE dt_character_not_null ( + a text NOT NULL, + b character varying(32) NOT NULL, + c varchar(32) NOT NULL, + d character(32) NOT NULL, + e char(32) NOT NULL +); diff --git a/internal/endtoend/testdata/datatype/stdlib/sql/datetime.sql b/internal/endtoend/testdata/datatype/stdlib/sql/datetime.sql new file mode 100644 index 0000000..5e6bcf0 --- /dev/null +++ b/internal/endtoend/testdata/datatype/stdlib/sql/datetime.sql @@ -0,0 +1,23 @@ +-- Date/Time Types +-- https://www.postgresql.org/docs/current/datatype-datetime.html +CREATE TABLE dt_datetime ( + a DATE, + b TIME, + c TIME WITHOUT TIME ZONE, + d TIME WITH TIME ZONE, + e TIMESTAMP, + f TIMESTAMP WITHOUT TIME ZONE, + g TIMESTAMP WITH TIME ZONE, + h timestamptz +); + +CREATE TABLE dt_datetime_not_null ( + a DATE NOT NULL, + b TIME NOT NULL, + c TIME WITHOUT TIME ZONE NOT NULL, + d TIME WITH TIME ZONE NOT NULL, + e TIMESTAMP NOT NULL, + f TIMESTAMP WITHOUT TIME ZONE NOT NULL, + g TIMESTAMP WITH TIME ZONE NOT NULL, + h timestamptz NOT NULL +); diff --git a/internal/endtoend/testdata/datatype/stdlib/sql/net-types.sql b/internal/endtoend/testdata/datatype/stdlib/sql/net-types.sql new file mode 100644 index 0000000..6239b6f --- /dev/null +++ b/internal/endtoend/testdata/datatype/stdlib/sql/net-types.sql @@ -0,0 +1,13 @@ +-- Network Address Types +-- https://www.postgresql.org/docs/current/datatype-net-types.html +CREATE TABLE dt_net_types ( + a inet, + b cidr, + c macaddr +); + +CREATE TABLE dt_net_types_not_null ( + a inet NOT NULL, + b cidr NOT NULL, + c macaddr NOT NULL +); diff --git a/internal/endtoend/testdata/datatype/stdlib/sql/numeric.sql b/internal/endtoend/testdata/datatype/stdlib/sql/numeric.sql new file mode 100644 index 0000000..9df1494 --- /dev/null +++ b/internal/endtoend/testdata/datatype/stdlib/sql/numeric.sql @@ -0,0 +1,36 @@ +-- Numeric Types +-- https://www.postgresql.org/docs/current/datatype-numeric.html +CREATE TABLE dt_numeric ( + -- TODO: this maps incorrectly to int16, not NullInt16 + a smallint, + b integer, + c bigint, + d decimal, + e numeric, + f real, + g double precision, + -- TODO: this maps incorrectly to int16, not NullInt16 + h smallserial, + i serial, + j bigserial, + -- TODO: this maps incorrectly to int16, not NullInt16 + k int2, + l int4, + m int8 +); + +CREATE TABLE dt_numeric_not_null ( + a smallint NOT NULL, + b integer NOT NULL, + c bigint NOT NULL, + d decimal NOT NULL, + e numeric NOT NULL, + f real NOT NULL, + g double precision NOT NULL, + h smallserial NOT NULL, + i serial NOT NULL, + j bigserial NOT NULL, + k int2 NOT NULL, + l int4 NOT NULL, + m int8 NOT NULL +); diff --git a/internal/endtoend/testdata/datatype/stdlib/sql/query.sql b/internal/endtoend/testdata/datatype/stdlib/sql/query.sql new file mode 100644 index 0000000..9da604b --- /dev/null +++ b/internal/endtoend/testdata/datatype/stdlib/sql/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT 1; diff --git a/internal/endtoend/testdata/datatype/stdlib/sql/rangetypes.sql b/internal/endtoend/testdata/datatype/stdlib/sql/rangetypes.sql new file mode 100644 index 0000000..7e61b65 --- /dev/null +++ b/internal/endtoend/testdata/datatype/stdlib/sql/rangetypes.sql @@ -0,0 +1,19 @@ +-- Range Types +-- https://www.postgresql.org/docs/current/rangetypes.html +CREATE TABLE dt_range ( + a int4range, + b int8range, + c numrange, + d tsrange, + e tstzrange, + f daterange +); + +CREATE TABLE dt_range_not_null ( + a int4range NOT NULL, + b int8range NOT NULL, + c numrange NOT NULL, + d tsrange NOT NULL, + e tstzrange NOT NULL, + f daterange NOT NULL +); diff --git a/internal/endtoend/testdata/datatype/stdlib/sqlc.json b/internal/endtoend/testdata/datatype/stdlib/sqlc.json new file mode 100644 index 0000000..3f30bc5 --- /dev/null +++ b/internal/endtoend/testdata/datatype/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "datatype", + "schema": "sql/", + "queries": "sql/" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/issue.md b/internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/issue.md new file mode 100644 index 0000000..c51bd7f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1519 diff --git a/internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/postgresql/pgx/go/db.go b/internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_materialized_views_set_schema/postgresql/pgx/go/models.go b/internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/postgresql/pgx/go/models.go new file mode 100644 index 0000000..c7ea43b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/postgresql/pgx/go/models.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type ComputedTablesSomething struct { + ID pgtype.Int4 + EventType string + CreatedAt pgtype.Timestamptz +} + +type Event struct { + ID pgtype.Int4 + EventType string + CreatedAt pgtype.Timestamptz +} diff --git a/internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..b916b59 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/postgresql/pgx/go/query.sql.go @@ -0,0 +1,36 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const someQuery = `-- name: SomeQuery :many +select id from "computed_tables"."something" +` + +func (q *Queries) SomeQuery(ctx context.Context) ([]pgtype.Int4, error) { + rows, err := q.db.Query(ctx, someQuery) + if err != nil { + return nil, err + } + defer rows.Close() + var items []pgtype.Int4 + for rows.Next() { + var id pgtype.Int4 + 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 +} diff --git a/internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/postgresql/pgx/query.sql b/internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/postgresql/pgx/query.sql new file mode 100644 index 0000000..24dafea --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/postgresql/pgx/query.sql @@ -0,0 +1,2 @@ +-- name: SomeQuery :many +select id from "computed_tables"."something"; diff --git a/internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/postgresql/pgx/schema.sql b/internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/postgresql/pgx/schema.sql new file mode 100644 index 0000000..2b788e0 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/postgresql/pgx/schema.sql @@ -0,0 +1,13 @@ +create table events ( + id int, + event_type text not null, + created_at timestamptz +); + +CREATE MATERIALIZED VIEW something AS +select * from events +where event_type = 'sale' +order by created_at desc; + +create schema computed_tables; +alter materialized view something set schema computed_tables; diff --git a/internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_materialized_views_set_schema/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/go/db.go b/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_add_column/mysql/go/models.go b/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/go/models.go new file mode 100644 index 0000000..97d9160 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar string + Baz sql.NullInt32 + Bio sql.NullInt32 +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/query.sql b/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/query.sql new file mode 100644 index 0000000..bb628f9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/query.sql @@ -0,0 +1,2 @@ +/* name: Placeholder :exec */ +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/schema.sql b/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/schema.sql new file mode 100644 index 0000000..0019a39 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (bar text NOT NULL); +ALTER TABLE foo ADD COLUMN baz integer; +ALTER TABLE foo ADD bio integer; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/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/ddl_alter_table_add_column/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_add_column/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..401bfd0 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v4/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar string + Baz sql.NullInt32 + Bio sql.NullInt32 + Foobar []int32 +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..a70d902 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v4/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE foo (bar text NOT NULL); +ALTER TABLE foo ADD COLUMN baz int; +ALTER TABLE foo ADD bio int; +ALTER TABLE foo ADD COLUMN foobar int[]; diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_add_column/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..782c4c5 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v5/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + Bar string + Baz pgtype.Int4 + Bio pgtype.Int4 + Foobar []int32 +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..a70d902 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v5/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE foo (bar text NOT NULL); +ALTER TABLE foo ADD COLUMN baz int; +ALTER TABLE foo ADD bio int; +ALTER TABLE foo ADD COLUMN foobar int[]; diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_add_column/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..401bfd0 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar string + Baz sql.NullInt32 + Bio sql.NullInt32 + Foobar []int32 +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..a70d902 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE foo (bar text NOT NULL); +ALTER TABLE foo ADD COLUMN baz int; +ALTER TABLE foo ADD bio int; +ALTER TABLE foo ADD COLUMN foobar int[]; diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/sqlite/go/db.go b/internal/endtoend/testdata/ddl_alter_table_add_column/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_add_column/sqlite/go/models.go b/internal/endtoend/testdata/ddl_alter_table_add_column/sqlite/go/models.go new file mode 100644 index 0000000..cfe57d4 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/sqlite/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Venue struct { + Name sql.NullString + Location sql.NullString + Size sql.NullInt64 +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/sqlite/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_add_column/sqlite/go/query.sql.go new file mode 100644 index 0000000..f6fb2a4 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/sqlite/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :many +SELECT name, location, size FROM venues +` + +func (q *Queries) Placeholder(ctx context.Context) ([]Venue, error) { + rows, err := q.db.QueryContext(ctx, placeholder) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Venue + for rows.Next() { + var i Venue + if err := rows.Scan(&i.Name, &i.Location, &i.Size); 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/ddl_alter_table_add_column/sqlite/query.sql b/internal/endtoend/testdata/ddl_alter_table_add_column/sqlite/query.sql new file mode 100644 index 0000000..c05c220 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/sqlite/query.sql @@ -0,0 +1,2 @@ +/* name: Placeholder :many */ +SELECT * FROM venues; diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/sqlite/schema.sql b/internal/endtoend/testdata/ddl_alter_table_add_column/sqlite/schema.sql new file mode 100644 index 0000000..8214519 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/sqlite/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE venues (name text); +ALTER TABLE venues ADD location text; +ALTER TABLE venues ADD COLUMN size integer; diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/sqlite/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_add_column/sqlite/sqlc.json new file mode 100644 index 0000000..cd66df0 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a172787 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v4/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar string + Baz string +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..2f54078 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text NOT NULL, baz text NOT NULL); +ALTER TABLE foo ADD COLUMN IF NOT EXISTS bar text; diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a172787 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v5/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar string + Baz string +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..6eb79f6 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text NOT NULL, baz text NOT NULL); +ALTER TABLE foo ADD COLUMN IF NOT EXISTS bar text; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_add_column_if_not_exists/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a172787 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/stdlib/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar string + Baz string +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..2f54078 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text NOT NULL, baz text NOT NULL); +ALTER TABLE foo ADD COLUMN IF NOT EXISTS bar text; diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column_if_not_exists/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/go/db.go b/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_alter_type/mysql/go/models.go b/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/go/models.go new file mode 100644 index 0000000..824f928 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullInt32 + Baz sql.NullInt32 +} diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/query.sql b/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/query.sql new file mode 100644 index 0000000..bb628f9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/query.sql @@ -0,0 +1,2 @@ +/* name: Placeholder :exec */ +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/schema.sql b/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/schema.sql new file mode 100644 index 0000000..a81bc00 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (bar text NOT NULL, baz text NOT NULL); +ALTER TABLE foo MODIFY COLUMN bar integer; +ALTER TABLE foo MODIFY baz integer; diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/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/ddl_alter_table_alter_type/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_alter_type/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..dce4e35 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar []string +} diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..26fa6c7 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar TEXT); +ALTER TABLE foo ALTER bar TYPE TEXT ARRAY USING bar::text[]; diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_alter_type/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..dce4e35 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar []string +} diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..26fa6c7 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar TEXT); +ALTER TABLE foo ALTER bar TYPE TEXT ARRAY USING bar::text[]; diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_alter_type/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..dce4e35 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar []string +} diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..26fa6c7 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar TEXT); +ALTER TABLE foo ALTER bar TYPE TEXT ARRAY USING bar::text[]; diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_case_sensitivity/sqlite/go/db.go b/internal/endtoend/testdata/ddl_alter_table_case_sensitivity/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_case_sensitivity/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_case_sensitivity/sqlite/go/models.go b/internal/endtoend/testdata/ddl_alter_table_case_sensitivity/sqlite/go/models.go new file mode 100644 index 0000000..4bda213 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_case_sensitivity/sqlite/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID int64 + FullName sql.NullString + EmailAddress sql.NullString + CreatedAt sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_alter_table_case_sensitivity/sqlite/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_case_sensitivity/sqlite/go/query.sql.go new file mode 100644 index 0000000..43e0007 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_case_sensitivity/sqlite/go/query.sql.go @@ -0,0 +1,60 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const insertUser = `-- name: InsertUser :exec +INSERT INTO users (full_name, "EmailAddress", created_at) +VALUES (?, ?, ?) +` + +type InsertUserParams struct { + FullName sql.NullString + EmailAddress sql.NullString + CreatedAt sql.NullString +} + +func (q *Queries) InsertUser(ctx context.Context, arg InsertUserParams) error { + _, err := q.db.ExecContext(ctx, insertUser, arg.FullName, arg.EmailAddress, arg.CreatedAt) + return err +} + +const selectUsers = `-- name: SelectUsers :many +SELECT id, full_name, "EmailAddress", created_at +FROM users +` + +func (q *Queries) SelectUsers(ctx context.Context) ([]User, error) { + rows, err := q.db.QueryContext(ctx, selectUsers) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FullName, + &i.EmailAddress, + &i.CreatedAt, + ); 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/ddl_alter_table_case_sensitivity/sqlite/query.sql b/internal/endtoend/testdata/ddl_alter_table_case_sensitivity/sqlite/query.sql new file mode 100644 index 0000000..d960ab1 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_case_sensitivity/sqlite/query.sql @@ -0,0 +1,7 @@ +-- name: InsertUser :exec +INSERT INTO users (full_name, "EmailAddress", created_at) +VALUES (?, ?, ?); + +-- name: SelectUsers :many +SELECT id, full_name, "EmailAddress", created_at +FROM users; diff --git a/internal/endtoend/testdata/ddl_alter_table_case_sensitivity/sqlite/schema.sql b/internal/endtoend/testdata/ddl_alter_table_case_sensitivity/sqlite/schema.sql new file mode 100644 index 0000000..5b8af0a --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_case_sensitivity/sqlite/schema.sql @@ -0,0 +1,10 @@ +-- Test ALTER TABLE operations with mixed case table and column names +-- Verifies consistent handling of case sensitivity in DDL operations +CREATE TABLE Users (id integer primary key, name text, "Email" text); + +-- Test renaming columns with different case formats +ALTER TABLE Users RENAME COLUMN name TO full_name; +ALTER TABLE Users RENAME COLUMN "Email" TO "EmailAddress"; + +-- Test adding a simple column +ALTER TABLE Users ADD COLUMN created_at text; diff --git a/internal/endtoend/testdata/ddl_alter_table_case_sensitivity/sqlite/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_case_sensitivity/sqlite/sqlc.json new file mode 100644 index 0000000..cd66df0 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_case_sensitivity/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/mysql/go/db.go b/internal/endtoend/testdata/ddl_alter_table_change_column/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_change_column/mysql/go/models.go b/internal/endtoend/testdata/ddl_alter_table_change_column/mysql/go/models.go new file mode 100644 index 0000000..1ef93ed --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/mysql/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Baz sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/mysql/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_change_column/mysql/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/mysql/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/mysql/query.sql b/internal/endtoend/testdata/ddl_alter_table_change_column/mysql/query.sql new file mode 100644 index 0000000..bb628f9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/mysql/query.sql @@ -0,0 +1,2 @@ +/* name: Placeholder :exec */ +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/mysql/schema.sql b/internal/endtoend/testdata/ddl_alter_table_change_column/mysql/schema.sql new file mode 100644 index 0000000..df60e48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text); +ALTER TABLE foo CHANGE COLUMN bar baz text; diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/mysql/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_change_column/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/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/ddl_alter_table_change_column/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_change_column/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..98c9fc4 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Baz string +} diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..501fc0c --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text NOT NULL); +ALTER TABLE foo RENAME COLUMN bar TO baz; diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_change_column/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..98c9fc4 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Baz string +} diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..501fc0c --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text NOT NULL); +ALTER TABLE foo RENAME COLUMN bar TO baz; diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_change_column/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..98c9fc4 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Baz string +} diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..501fc0c --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text NOT NULL); +ALTER TABLE foo RENAME COLUMN bar TO baz; diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/mysql/go/db.go b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_column_drop_not_null/mysql/go/models.go b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/mysql/go/models.go new file mode 100644 index 0000000..a61eef2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/mysql/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString + Baz sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/mysql/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/mysql/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/mysql/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/mysql/query.sql b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/mysql/query.sql new file mode 100644 index 0000000..bb628f9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/mysql/query.sql @@ -0,0 +1,2 @@ +/* name: Placeholder :exec */ +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/mysql/schema.sql b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/mysql/schema.sql new file mode 100644 index 0000000..079770e --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/mysql/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (bar text NOT NULL, baz text NOT NULL); +ALTER TABLE foo MODIFY COLUMN bar text; +ALTER TABLE foo MODIFY baz text; diff --git a/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/mysql/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/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/ddl_alter_table_column_drop_not_null/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_column_drop_not_null/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a61eef2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v4/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString + Baz sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..1d68afb --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (bar text NOT NULL, baz text NOT NULL); +ALTER TABLE foo ALTER COLUMN bar DROP NOT NULL; +ALTER TABLE foo ALTER baz DROP NOT NULL; diff --git a/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_column_drop_not_null/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..4f597ba --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + Bar pgtype.Text + Baz pgtype.Text +} diff --git a/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..1d68afb --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (bar text NOT NULL, baz text NOT NULL); +ALTER TABLE foo ALTER COLUMN bar DROP NOT NULL; +ALTER TABLE foo ALTER baz DROP NOT NULL; diff --git a/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_column_drop_not_null/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a61eef2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/stdlib/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString + Baz sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..1d68afb --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (bar text NOT NULL, baz text NOT NULL); +ALTER TABLE foo ALTER COLUMN bar DROP NOT NULL; +ALTER TABLE foo ALTER baz DROP NOT NULL; diff --git a/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_column_drop_not_null/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column/mysql/go/db.go b/internal/endtoend/testdata/ddl_alter_table_drop_column/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_drop_column/mysql/go/models.go b/internal/endtoend/testdata/ddl_alter_table_drop_column/mysql/go/models.go new file mode 100644 index 0000000..1ef93ed --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/mysql/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Baz sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column/mysql/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_drop_column/mysql/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/mysql/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column/mysql/query.sql b/internal/endtoend/testdata/ddl_alter_table_drop_column/mysql/query.sql new file mode 100644 index 0000000..bb628f9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/mysql/query.sql @@ -0,0 +1,2 @@ +/* name: Placeholder :exec */ +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column/mysql/schema.sql b/internal/endtoend/testdata/ddl_alter_table_drop_column/mysql/schema.sql new file mode 100644 index 0000000..ca13f22 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text, baz text); +ALTER TABLE foo DROP COLUMN bar; diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column/mysql/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_drop_column/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/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/ddl_alter_table_drop_column/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_drop_column/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..1ef93ed --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v4/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Baz sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..ca13f22 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text, baz text); +ALTER TABLE foo DROP COLUMN bar; diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_drop_column/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..8620cf6 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v5/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + Baz pgtype.Text +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..ca13f22 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text, baz text); +ALTER TABLE foo DROP COLUMN bar; diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_drop_column/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..1ef93ed --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/stdlib/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Baz sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..ca13f22 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text, baz text); +ALTER TABLE foo DROP COLUMN bar; diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column/sqlite/go/db.go b/internal/endtoend/testdata/ddl_alter_table_drop_column/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_drop_column/sqlite/go/models.go b/internal/endtoend/testdata/ddl_alter_table_drop_column/sqlite/go/models.go new file mode 100644 index 0000000..1ef93ed --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/sqlite/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Baz sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column/sqlite/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_drop_column/sqlite/go/query.sql.go new file mode 100644 index 0000000..a0b6155 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/sqlite/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT baz FROM foo +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column/sqlite/query.sql b/internal/endtoend/testdata/ddl_alter_table_drop_column/sqlite/query.sql new file mode 100644 index 0000000..92dc725 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column/sqlite/schema.sql b/internal/endtoend/testdata/ddl_alter_table_drop_column/sqlite/schema.sql new file mode 100644 index 0000000..ed3c451 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/sqlite/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text, baz text); +ALTER TABLE foo DROP COLUMN bar; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column/sqlite/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_drop_column/sqlite/sqlc.json new file mode 100644 index 0000000..cd66df0 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/exec.json b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/exec.json new file mode 100644 index 0000000..c85ca2d --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/exec.json @@ -0,0 +1,6 @@ +{ + "contexts": ["base"], + "meta": { + "invalid_schema": true + } +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/go/db.go b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_drop_column_if_exists/mysql/go/models.go b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/go/models.go new file mode 100644 index 0000000..a856c9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/go/models.go @@ -0,0 +1,8 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/query.sql b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/query.sql new file mode 100644 index 0000000..bb628f9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/query.sql @@ -0,0 +1,2 @@ +/* name: Placeholder :exec */ +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/schema.sql b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/schema.sql new file mode 100644 index 0000000..e36aaeb --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (bar text); +ALTER TABLE foo DROP COLUMN IF EXISTS bar; +ALTER TABLE foo DROP COLUMN IF EXISTS bar; diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/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/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a856c9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v4/go/models.go @@ -0,0 +1,8 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..e36aaeb --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (bar text); +ALTER TABLE foo DROP COLUMN IF EXISTS bar; +ALTER TABLE foo DROP COLUMN IF EXISTS bar; diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a856c9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v5/go/models.go @@ -0,0 +1,8 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..e36aaeb --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (bar text); +ALTER TABLE foo DROP COLUMN IF EXISTS bar; +ALTER TABLE foo DROP COLUMN IF EXISTS bar; diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_drop_column_if_exists/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a856c9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/stdlib/go/models.go @@ -0,0 +1,8 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..e36aaeb --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (bar text); +ALTER TABLE foo DROP COLUMN IF EXISTS bar; +ALTER TABLE foo DROP COLUMN IF EXISTS bar; diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_column_if_exists/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/exec.json b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/exec.json new file mode 100644 index 0000000..c85ca2d --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/exec.json @@ -0,0 +1,6 @@ +{ + "contexts": ["base"], + "meta": { + "invalid_schema": true + } +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/go/db.go b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_drop_constraint/mysql/go/models.go b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/go/models.go new file mode 100644 index 0000000..4b013d4 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Venue struct { + ID uint64 +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/query.sql b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/query.sql new file mode 100644 index 0000000..bb628f9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/query.sql @@ -0,0 +1,2 @@ +/* name: Placeholder :exec */ +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/schema.sql b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/schema.sql new file mode 100644 index 0000000..9477f00 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE venues (id SERIAL PRIMARY KEY); +ALTER TABLE venues DROP CONSTRAINT venues_id_pkey; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/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/ddl_alter_table_drop_constraint/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_drop_constraint/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..2feb3c3 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Venue struct { + ID int32 +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..1dbb844 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE venues (id SERIAL PRIMARY KEY); +ALTER TABLE venues DROP CONSTRAINT venues_pkey; diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_drop_constraint/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..2feb3c3 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Venue struct { + ID int32 +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..1dbb844 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE venues (id SERIAL PRIMARY KEY); +ALTER TABLE venues DROP CONSTRAINT venues_pkey; diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_drop_constraint/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..2feb3c3 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Venue struct { + ID int32 +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..1dbb844 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE venues (id SERIAL PRIMARY KEY); +ALTER TABLE venues DROP CONSTRAINT venues_pkey; diff --git a/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_drop_constraint/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_if_exists/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..43a3e75 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v4/schema.sql @@ -0,0 +1,7 @@ +ALTER TABLE IF EXISTS foo ADD COLUMN bar integer; +ALTER TABLE IF EXISTS bar RENAME COLUMN bar TO baz; +ALTER TABLE IF EXISTS bat RENAME CONSTRAINT bar TO baz; +ALTER TABLE IF EXISTS baz RENAME TO bar; +ALTER TABLE IF EXISTS goo SET SCHEMA bar; +ALTER TABLE IF EXISTS gob ATTACH PARTITION partition_name DEFAULT; +ALTER TABLE IF EXISTS doo DETACH PARTITION partition_name; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_if_exists/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..43a3e75 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v5/schema.sql @@ -0,0 +1,7 @@ +ALTER TABLE IF EXISTS foo ADD COLUMN bar integer; +ALTER TABLE IF EXISTS bar RENAME COLUMN bar TO baz; +ALTER TABLE IF EXISTS bat RENAME CONSTRAINT bar TO baz; +ALTER TABLE IF EXISTS baz RENAME TO bar; +ALTER TABLE IF EXISTS goo SET SCHEMA bar; +ALTER TABLE IF EXISTS gob ATTACH PARTITION partition_name DEFAULT; +ALTER TABLE IF EXISTS doo DETACH PARTITION partition_name; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_if_exists/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..43a3e75 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/stdlib/schema.sql @@ -0,0 +1,7 @@ +ALTER TABLE IF EXISTS foo ADD COLUMN bar integer; +ALTER TABLE IF EXISTS bar RENAME COLUMN bar TO baz; +ALTER TABLE IF EXISTS bat RENAME CONSTRAINT bar TO baz; +ALTER TABLE IF EXISTS baz RENAME TO bar; +ALTER TABLE IF EXISTS goo SET SCHEMA bar; +ALTER TABLE IF EXISTS gob ATTACH PARTITION partition_name DEFAULT; +ALTER TABLE IF EXISTS doo DETACH PARTITION partition_name; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_if_exists/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_index/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..dfc996b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v4/go/models.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + "time" +) + +type Measurement struct { + CityID int32 + Logdate time.Time + Peaktemp sql.NullInt32 + Unitsales sql.NullInt32 +} + +type MeasurementY2006m02 struct { + CityID int32 + Logdate time.Time + Peaktemp sql.NullInt32 + Unitsales sql.NullInt32 +} diff --git a/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..0fb8fb1 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v4/schema.sql @@ -0,0 +1,17 @@ +CREATE TABLE measurement ( + city_id int not null, + logdate date not null, + peaktemp int, + unitsales int +) PARTITION BY RANGE (logdate); + +CREATE TABLE measurement_y2006m02 PARTITION OF measurement + FOR VALUES FROM ('2006-02-01') TO ('2006-03-01'); + +CREATE INDEX measurement_usls_idx ON ONLY measurement (unitsales); + +CREATE INDEX measurement_usls_200602_idx + ON measurement_y2006m02 (unitsales); + +ALTER INDEX measurement_usls_idx + ATTACH PARTITION measurement_usls_200602_idx; diff --git a/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_index/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..6b1a915 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v5/go/models.go @@ -0,0 +1,23 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Measurement struct { + CityID int32 + Logdate pgtype.Date + Peaktemp pgtype.Int4 + Unitsales pgtype.Int4 +} + +type MeasurementY2006m02 struct { + CityID int32 + Logdate pgtype.Date + Peaktemp pgtype.Int4 + Unitsales pgtype.Int4 +} diff --git a/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..0fb8fb1 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v5/schema.sql @@ -0,0 +1,17 @@ +CREATE TABLE measurement ( + city_id int not null, + logdate date not null, + peaktemp int, + unitsales int +) PARTITION BY RANGE (logdate); + +CREATE TABLE measurement_y2006m02 PARTITION OF measurement + FOR VALUES FROM ('2006-02-01') TO ('2006-03-01'); + +CREATE INDEX measurement_usls_idx ON ONLY measurement (unitsales); + +CREATE INDEX measurement_usls_200602_idx + ON measurement_y2006m02 (unitsales); + +ALTER INDEX measurement_usls_idx + ATTACH PARTITION measurement_usls_200602_idx; diff --git a/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_index/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_index/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..dfc996b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/stdlib/go/models.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + "time" +) + +type Measurement struct { + CityID int32 + Logdate time.Time + Peaktemp sql.NullInt32 + Unitsales sql.NullInt32 +} + +type MeasurementY2006m02 struct { + CityID int32 + Logdate time.Time + Peaktemp sql.NullInt32 + Unitsales sql.NullInt32 +} diff --git a/internal/endtoend/testdata/ddl_alter_table_index/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_index/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_index/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..0fb8fb1 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/stdlib/schema.sql @@ -0,0 +1,17 @@ +CREATE TABLE measurement ( + city_id int not null, + logdate date not null, + peaktemp int, + unitsales int +) PARTITION BY RANGE (logdate); + +CREATE TABLE measurement_y2006m02 PARTITION OF measurement + FOR VALUES FROM ('2006-02-01') TO ('2006-03-01'); + +CREATE INDEX measurement_usls_idx ON ONLY measurement (unitsales); + +CREATE INDEX measurement_usls_200602_idx + ON measurement_y2006m02 (unitsales); + +ALTER INDEX measurement_usls_idx + ATTACH PARTITION measurement_usls_200602_idx; diff --git a/internal/endtoend/testdata/ddl_alter_table_index/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_index/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename/mysql/go/db.go b/internal/endtoend/testdata/ddl_alter_table_rename/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_rename/mysql/go/models.go b/internal/endtoend/testdata/ddl_alter_table_rename/mysql/go/models.go new file mode 100644 index 0000000..935e0b7 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/mysql/go/models.go @@ -0,0 +1,17 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Arena struct { + Name sql.NullString +} + +type Location struct { + Name sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename/mysql/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_rename/mysql/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/mysql/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename/mysql/query.sql b/internal/endtoend/testdata/ddl_alter_table_rename/mysql/query.sql new file mode 100644 index 0000000..bb628f9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/mysql/query.sql @@ -0,0 +1,2 @@ +/* name: Placeholder :exec */ +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_rename/mysql/schema.sql b/internal/endtoend/testdata/ddl_alter_table_rename/mysql/schema.sql new file mode 100644 index 0000000..a478cc9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/mysql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE venues (name text); +ALTER TABLE venues RENAME TO arenas; + +CREATE TABLE cities (name text); +RENAME TABLE cities TO locations; diff --git a/internal/endtoend/testdata/ddl_alter_table_rename/mysql/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_rename/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/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/ddl_alter_table_rename/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_rename/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..847b2c2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v4/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Arena struct { + Name sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..cdc12b8 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE venues (name text); +ALTER TABLE venues RENAME TO arenas; diff --git a/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_rename/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..bf0cad8 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v5/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Arena struct { + Name pgtype.Text +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..cdc12b8 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE venues (name text); +ALTER TABLE venues RENAME TO arenas; diff --git a/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_rename/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..847b2c2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/stdlib/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Arena struct { + Name sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..cdc12b8 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE venues (name text); +ALTER TABLE venues RENAME TO arenas; diff --git a/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename/sqlite/go/db.go b/internal/endtoend/testdata/ddl_alter_table_rename/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_rename/sqlite/go/models.go b/internal/endtoend/testdata/ddl_alter_table_rename/sqlite/go/models.go new file mode 100644 index 0000000..847b2c2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/sqlite/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Arena struct { + Name sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename/sqlite/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_rename/sqlite/go/query.sql.go new file mode 100644 index 0000000..e52ada4 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/sqlite/go/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const placeholder = `-- name: Placeholder :many +SELECT name FROM arenas +` + +func (q *Queries) Placeholder(ctx context.Context) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, placeholder) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var name sql.NullString + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + 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/ddl_alter_table_rename/sqlite/query.sql b/internal/endtoend/testdata/ddl_alter_table_rename/sqlite/query.sql new file mode 100644 index 0000000..bf777e0 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/sqlite/query.sql @@ -0,0 +1,2 @@ +/* name: Placeholder :many */ +SELECT * FROM arenas; diff --git a/internal/endtoend/testdata/ddl_alter_table_rename/sqlite/schema.sql b/internal/endtoend/testdata/ddl_alter_table_rename/sqlite/schema.sql new file mode 100644 index 0000000..8ab8f06 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/sqlite/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE venues (name text); +ALTER TABLE venues RENAME TO arenas; + diff --git a/internal/endtoend/testdata/ddl_alter_table_rename/sqlite/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_rename/sqlite/sqlc.json new file mode 100644 index 0000000..cd66df0 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename_column/mysql/go/db.go b/internal/endtoend/testdata/ddl_alter_table_rename_column/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_rename_column/mysql/go/models.go b/internal/endtoend/testdata/ddl_alter_table_rename_column/mysql/go/models.go new file mode 100644 index 0000000..1ef93ed --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/mysql/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Baz sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename_column/mysql/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_rename_column/mysql/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/mysql/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename_column/mysql/query.sql b/internal/endtoend/testdata/ddl_alter_table_rename_column/mysql/query.sql new file mode 100644 index 0000000..bb628f9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/mysql/query.sql @@ -0,0 +1,2 @@ +/* name: Placeholder :exec */ +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_rename_column/mysql/schema.sql b/internal/endtoend/testdata/ddl_alter_table_rename_column/mysql/schema.sql new file mode 100644 index 0000000..7a160ec --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text); +ALTER TABLE foo RENAME COLUMN bar TO baz; diff --git a/internal/endtoend/testdata/ddl_alter_table_rename_column/mysql/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_rename_column/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/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/ddl_alter_table_rename_column/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_rename_column/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..1ef93ed --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v4/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Baz sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..1848df2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text); +ALTER TABLE foo RENAME bar TO baz; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_rename_column/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..8620cf6 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v5/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + Baz pgtype.Text +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..1848df2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text); +ALTER TABLE foo RENAME bar TO baz; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_rename_column/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..1ef93ed --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/stdlib/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Baz sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..1848df2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text); +ALTER TABLE foo RENAME bar TO baz; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename_column/sqlite/go/db.go b/internal/endtoend/testdata/ddl_alter_table_rename_column/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_rename_column/sqlite/go/models.go b/internal/endtoend/testdata/ddl_alter_table_rename_column/sqlite/go/models.go new file mode 100644 index 0000000..38ba011 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/sqlite/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Boo sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_alter_table_rename_column/sqlite/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_rename_column/sqlite/go/query.sql.go new file mode 100644 index 0000000..d8317bd --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/sqlite/go/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const placeholder = `-- name: Placeholder :many +SELECT boo FROM foo +` + +func (q *Queries) Placeholder(ctx context.Context) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, placeholder) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var boo sql.NullString + if err := rows.Scan(&boo); err != nil { + return nil, err + } + items = append(items, boo) + } + 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/ddl_alter_table_rename_column/sqlite/query.sql b/internal/endtoend/testdata/ddl_alter_table_rename_column/sqlite/query.sql new file mode 100644 index 0000000..4b98a81 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/sqlite/query.sql @@ -0,0 +1,2 @@ +/* name: Placeholder :many */ +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/ddl_alter_table_rename_column/sqlite/schema.sql b/internal/endtoend/testdata/ddl_alter_table_rename_column/sqlite/schema.sql new file mode 100644 index 0000000..f173f17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/sqlite/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE foo (bar text); +ALTER TABLE foo RENAME COLUMN bar TO baz; + +ALTER TABLE foo RENAME baz TO boo; diff --git a/internal/endtoend/testdata/ddl_alter_table_rename_column/sqlite/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_rename_column/sqlite/sqlc.json new file mode 100644 index 0000000..cd66df0 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_rename_column/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_data_type/mysql/go/db.go b/internal/endtoend/testdata/ddl_alter_table_set_data_type/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_data_type/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_set_data_type/mysql/go/models.go b/internal/endtoend/testdata/ddl_alter_table_set_data_type/mysql/go/models.go new file mode 100644 index 0000000..a443e19 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_data_type/mysql/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullInt32 +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_data_type/mysql/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_set_data_type/mysql/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_data_type/mysql/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_data_type/mysql/query.sql b/internal/endtoend/testdata/ddl_alter_table_set_data_type/mysql/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_data_type/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_set_data_type/mysql/schema.sql b/internal/endtoend/testdata/ddl_alter_table_set_data_type/mysql/schema.sql new file mode 100644 index 0000000..e5128c6 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_data_type/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text); +ALTER TABLE foo MODIFY bar integer; diff --git a/internal/endtoend/testdata/ddl_alter_table_set_data_type/mysql/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_set_data_type/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_data_type/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/ddl_alter_table_set_data_type/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_set_data_type/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..eab07e1 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v4/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullBool +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..5ef5dc5 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text); +ALTER TABLE foo ALTER bar SET DATA TYPE bool USING bar::boolean; diff --git a/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_set_data_type/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..5e178ef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v5/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + Bar pgtype.Bool +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..5ef5dc5 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text); +ALTER TABLE foo ALTER bar SET DATA TYPE bool USING bar::boolean; diff --git a/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_set_data_type/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..eab07e1 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/stdlib/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullBool +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..5ef5dc5 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text); +ALTER TABLE foo ALTER bar SET DATA TYPE bool USING bar::boolean; diff --git a/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_data_type/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_not_null/mysql/go/db.go b/internal/endtoend/testdata/ddl_alter_table_set_not_null/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_not_null/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_set_not_null/mysql/go/models.go b/internal/endtoend/testdata/ddl_alter_table_set_not_null/mysql/go/models.go new file mode 100644 index 0000000..d324fe9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_not_null/mysql/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar string +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_not_null/mysql/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_set_not_null/mysql/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_not_null/mysql/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_not_null/mysql/query.sql b/internal/endtoend/testdata/ddl_alter_table_set_not_null/mysql/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_not_null/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_set_not_null/mysql/schema.sql b/internal/endtoend/testdata/ddl_alter_table_set_not_null/mysql/schema.sql new file mode 100644 index 0000000..0aac8fd --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_not_null/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text); +ALTER TABLE foo MODIFY bar text NOT NULL; diff --git a/internal/endtoend/testdata/ddl_alter_table_set_not_null/mysql/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_set_not_null/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_not_null/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/ddl_alter_table_set_not_null/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_set_not_null/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..d324fe9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar string +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..a5e129a --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text); +ALTER TABLE foo ALTER bar SET NOT NULL; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_set_not_null/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..d324fe9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar string +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..a5e129a --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text); +ALTER TABLE foo ALTER bar SET NOT NULL; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_set_not_null/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..d324fe9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar string +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..a5e129a --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text); +ALTER TABLE foo ALTER bar SET NOT NULL; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_not_null/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_schema/mysql/README.md b/internal/endtoend/testdata/ddl_alter_table_set_schema/mysql/README.md new file mode 100644 index 0000000..6b43b91 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_schema/mysql/README.md @@ -0,0 +1 @@ +MySQL does not implement `ALTER TABLE ... SET SCHEMA`. diff --git a/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_set_schema/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..ce6ac2a --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v4/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type FooBar struct { + Name sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..3f12a3b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,29 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const getFooBar = `-- name: GetFooBar :exec +SELECT name FROM foo.bar +` + +func (q *Queries) GetFooBar(ctx context.Context) error { + _, err := q.db.Exec(ctx, getFooBar) + return err +} + +const updateFooBar = `-- name: UpdateFooBar :exec +UPDATE foo.bar SET name = $1 +` + +func (q *Queries) UpdateFooBar(ctx context.Context, name sql.NullString) error { + _, err := q.db.Exec(ctx, updateFooBar, name) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..9d28274 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v4/query.sql @@ -0,0 +1,5 @@ +-- name: GetFooBar :exec +SELECT * FROM foo.bar; + +-- name: UpdateFooBar :exec +UPDATE foo.bar SET name = $1; diff --git a/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..ac617b3 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE bar (name text); +ALTER TABLE bar SET SCHEMA foo; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_table_set_schema/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a021d20 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v5/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type FooBar struct { + Name pgtype.Text +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..6f05e29 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,30 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const getFooBar = `-- name: GetFooBar :exec +SELECT name FROM foo.bar +` + +func (q *Queries) GetFooBar(ctx context.Context) error { + _, err := q.db.Exec(ctx, getFooBar) + return err +} + +const updateFooBar = `-- name: UpdateFooBar :exec +UPDATE foo.bar SET name = $1 +` + +func (q *Queries) UpdateFooBar(ctx context.Context, name pgtype.Text) error { + _, err := q.db.Exec(ctx, updateFooBar, name) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..9d28274 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v5/query.sql @@ -0,0 +1,5 @@ +-- name: GetFooBar :exec +SELECT * FROM foo.bar; + +-- name: UpdateFooBar :exec +UPDATE foo.bar SET name = $1; diff --git a/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..ac617b3 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE bar (name text); +ALTER TABLE bar SET SCHEMA foo; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_table_set_schema/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..ce6ac2a --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/stdlib/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type FooBar struct { + Name sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..880cfc6 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,29 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const getFooBar = `-- name: GetFooBar :exec +SELECT name FROM foo.bar +` + +func (q *Queries) GetFooBar(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, getFooBar) + return err +} + +const updateFooBar = `-- name: UpdateFooBar :exec +UPDATE foo.bar SET name = $1 +` + +func (q *Queries) UpdateFooBar(ctx context.Context, name sql.NullString) error { + _, err := q.db.ExecContext(ctx, updateFooBar, name) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/stdlib/query.sql new file mode 100644 index 0000000..9d28274 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/stdlib/query.sql @@ -0,0 +1,5 @@ +-- name: GetFooBar :exec +SELECT * FROM foo.bar; + +-- name: UpdateFooBar :exec +UPDATE foo.bar SET name = $1; diff --git a/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..ac617b3 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE bar (name text); +ALTER TABLE bar SET SCHEMA foo; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_set_schema/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_type_add_value/mysql/README.md b/internal/endtoend/testdata/ddl_alter_type_add_value/mysql/README.md new file mode 100644 index 0000000..bffc182 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_add_value/mysql/README.md @@ -0,0 +1,4 @@ +MySQL does not support `CREATE TYPE ... AS ENUM`. Instead, enumerations are +defined via the `ENUM` type directly in table columns. + +https://dev.mysql.com/doc/refman/8.0/en/enum.html diff --git a/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_type_add_value/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..5c53dc5 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v4/go/models.go @@ -0,0 +1,53 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type Status string + +const ( + StatusOpen Status = "open" + StatusClosed Status = "closed" + StatusUnknown Status = "unknown" +) + +func (e *Status) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = Status(s) + case string: + *e = Status(s) + default: + return fmt.Errorf("unsupported scan type for Status: %T", src) + } + return nil +} + +type NullStatus struct { + Status Status + Valid bool // Valid is true if Status is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullStatus) Scan(value any) error { + if value == nil { + ns.Status, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.Status.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullStatus) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.Status), nil +} diff --git a/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..4fede5d --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE TYPE status AS ENUM ('open', 'closed'); +ALTER TYPE status ADD VALUE 'unknown'; +ALTER TYPE status ADD VALUE IF NOT EXISTS 'unknown'; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_type_add_value/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..5c53dc5 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v5/go/models.go @@ -0,0 +1,53 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type Status string + +const ( + StatusOpen Status = "open" + StatusClosed Status = "closed" + StatusUnknown Status = "unknown" +) + +func (e *Status) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = Status(s) + case string: + *e = Status(s) + default: + return fmt.Errorf("unsupported scan type for Status: %T", src) + } + return nil +} + +type NullStatus struct { + Status Status + Valid bool // Valid is true if Status is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullStatus) Scan(value any) error { + if value == nil { + ns.Status, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.Status.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullStatus) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.Status), nil +} diff --git a/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..4fede5d --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE TYPE status AS ENUM ('open', 'closed'); +ALTER TYPE status ADD VALUE 'unknown'; +ALTER TYPE status ADD VALUE IF NOT EXISTS 'unknown'; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_type_add_value/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..5c53dc5 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/stdlib/go/models.go @@ -0,0 +1,53 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type Status string + +const ( + StatusOpen Status = "open" + StatusClosed Status = "closed" + StatusUnknown Status = "unknown" +) + +func (e *Status) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = Status(s) + case string: + *e = Status(s) + default: + return fmt.Errorf("unsupported scan type for Status: %T", src) + } + return nil +} + +type NullStatus struct { + Status Status + Valid bool // Valid is true if Status is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullStatus) Scan(value any) error { + if value == nil { + ns.Status, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.Status.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullStatus) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.Status), nil +} diff --git a/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..4fede5d --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE TYPE status AS ENUM ('open', 'closed'); +ALTER TYPE status ADD VALUE 'unknown'; +ALTER TYPE status ADD VALUE IF NOT EXISTS 'unknown'; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_add_value/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_type_rename/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..97a1bc3 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v4/go/models.go @@ -0,0 +1,57 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type NewEvent string + +const ( + NewEventSTART NewEvent = "START" + NewEventSTOP NewEvent = "STOP" +) + +func (e *NewEvent) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = NewEvent(s) + case string: + *e = NewEvent(s) + default: + return fmt.Errorf("unsupported scan type for NewEvent: %T", src) + } + return nil +} + +type NullNewEvent struct { + NewEvent NewEvent + Valid bool // Valid is true if NewEvent is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullNewEvent) Scan(value any) error { + if value == nil { + ns.NewEvent, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.NewEvent.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullNewEvent) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.NewEvent), nil +} + +type LogLine struct { + ID int64 + Status NewEvent +} diff --git a/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..7f56a7b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listAuthors = `-- name: ListAuthors :many +SELECT id, status FROM log_lines +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]LogLine, error) { + rows, err := q.db.Query(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []LogLine + for rows.Next() { + var i LogLine + if err := rows.Scan(&i.ID, &i.Status); 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/ddl_alter_type_rename/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..92575af --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: ListAuthors :many +SELECT * FROM log_lines; diff --git a/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..44a3b28 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v4/schema.sql @@ -0,0 +1,9 @@ +CREATE TYPE event AS enum ('START', 'STOP'); + +ALTER TYPE event RENAME TO "new_event"; + +CREATE TABLE log_lines ( + id BIGSERIAL PRIMARY KEY, + status "new_event" NOT NULL +); + diff --git a/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_type_rename/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..97a1bc3 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v5/go/models.go @@ -0,0 +1,57 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type NewEvent string + +const ( + NewEventSTART NewEvent = "START" + NewEventSTOP NewEvent = "STOP" +) + +func (e *NewEvent) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = NewEvent(s) + case string: + *e = NewEvent(s) + default: + return fmt.Errorf("unsupported scan type for NewEvent: %T", src) + } + return nil +} + +type NullNewEvent struct { + NewEvent NewEvent + Valid bool // Valid is true if NewEvent is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullNewEvent) Scan(value any) error { + if value == nil { + ns.NewEvent, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.NewEvent.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullNewEvent) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.NewEvent), nil +} + +type LogLine struct { + ID int64 + Status NewEvent +} diff --git a/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..7f56a7b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listAuthors = `-- name: ListAuthors :many +SELECT id, status FROM log_lines +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]LogLine, error) { + rows, err := q.db.Query(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []LogLine + for rows.Next() { + var i LogLine + if err := rows.Scan(&i.ID, &i.Status); 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/ddl_alter_type_rename/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..92575af --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: ListAuthors :many +SELECT * FROM log_lines; diff --git a/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..44a3b28 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v5/schema.sql @@ -0,0 +1,9 @@ +CREATE TYPE event AS enum ('START', 'STOP'); + +ALTER TYPE event RENAME TO "new_event"; + +CREATE TABLE log_lines ( + id BIGSERIAL PRIMARY KEY, + status "new_event" NOT NULL +); + diff --git a/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_type_rename/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..97a1bc3 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/stdlib/go/models.go @@ -0,0 +1,57 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type NewEvent string + +const ( + NewEventSTART NewEvent = "START" + NewEventSTOP NewEvent = "STOP" +) + +func (e *NewEvent) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = NewEvent(s) + case string: + *e = NewEvent(s) + default: + return fmt.Errorf("unsupported scan type for NewEvent: %T", src) + } + return nil +} + +type NullNewEvent struct { + NewEvent NewEvent + Valid bool // Valid is true if NewEvent is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullNewEvent) Scan(value any) error { + if value == nil { + ns.NewEvent, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.NewEvent.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullNewEvent) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.NewEvent), nil +} + +type LogLine struct { + ID int64 + Status NewEvent +} diff --git a/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..ac0f963 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listAuthors = `-- name: ListAuthors :many +SELECT id, status FROM log_lines +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]LogLine, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []LogLine + for rows.Next() { + var i LogLine + if err := rows.Scan(&i.ID, &i.Status); 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/ddl_alter_type_rename/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/stdlib/query.sql new file mode 100644 index 0000000..92575af --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: ListAuthors :many +SELECT * FROM log_lines; diff --git a/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..44a3b28 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/stdlib/schema.sql @@ -0,0 +1,9 @@ +CREATE TYPE event AS enum ('START', 'STOP'); + +ALTER TYPE event RENAME TO "new_event"; + +CREATE TABLE log_lines ( + id BIGSERIAL PRIMARY KEY, + status "new_event" NOT NULL +); + diff --git a/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..97a1bc3 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v4/go/models.go @@ -0,0 +1,57 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type NewEvent string + +const ( + NewEventSTART NewEvent = "START" + NewEventSTOP NewEvent = "STOP" +) + +func (e *NewEvent) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = NewEvent(s) + case string: + *e = NewEvent(s) + default: + return fmt.Errorf("unsupported scan type for NewEvent: %T", src) + } + return nil +} + +type NullNewEvent struct { + NewEvent NewEvent + Valid bool // Valid is true if NewEvent is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullNewEvent) Scan(value any) error { + if value == nil { + ns.NewEvent, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.NewEvent.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullNewEvent) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.NewEvent), nil +} + +type LogLine struct { + ID int64 + Status NewEvent +} diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..7f56a7b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listAuthors = `-- name: ListAuthors :many +SELECT id, status FROM log_lines +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]LogLine, error) { + rows, err := q.db.Query(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []LogLine + for rows.Next() { + var i LogLine + if err := rows.Scan(&i.ID, &i.Status); 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/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..92575af --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: ListAuthors :many +SELECT * FROM log_lines; diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..eb9ec7d --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v4/schema.sql @@ -0,0 +1,9 @@ +CREATE TYPE event AS enum ('START', 'STOP'); + +CREATE TABLE log_lines ( + id BIGSERIAL PRIMARY KEY, + status "event" NOT NULL +); + +ALTER TYPE event RENAME TO "new_event"; + diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..97a1bc3 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v5/go/models.go @@ -0,0 +1,57 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type NewEvent string + +const ( + NewEventSTART NewEvent = "START" + NewEventSTOP NewEvent = "STOP" +) + +func (e *NewEvent) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = NewEvent(s) + case string: + *e = NewEvent(s) + default: + return fmt.Errorf("unsupported scan type for NewEvent: %T", src) + } + return nil +} + +type NullNewEvent struct { + NewEvent NewEvent + Valid bool // Valid is true if NewEvent is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullNewEvent) Scan(value any) error { + if value == nil { + ns.NewEvent, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.NewEvent.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullNewEvent) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.NewEvent), nil +} + +type LogLine struct { + ID int64 + Status NewEvent +} diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..7f56a7b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listAuthors = `-- name: ListAuthors :many +SELECT id, status FROM log_lines +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]LogLine, error) { + rows, err := q.db.Query(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []LogLine + for rows.Next() { + var i LogLine + if err := rows.Scan(&i.ID, &i.Status); 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/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..92575af --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: ListAuthors :many +SELECT * FROM log_lines; diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..eb9ec7d --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v5/schema.sql @@ -0,0 +1,9 @@ +CREATE TYPE event AS enum ('START', 'STOP'); + +CREATE TABLE log_lines ( + id BIGSERIAL PRIMARY KEY, + status "event" NOT NULL +); + +ALTER TYPE event RENAME TO "new_event"; + diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_type_rename_and_update_columns/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..97a1bc3 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/stdlib/go/models.go @@ -0,0 +1,57 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type NewEvent string + +const ( + NewEventSTART NewEvent = "START" + NewEventSTOP NewEvent = "STOP" +) + +func (e *NewEvent) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = NewEvent(s) + case string: + *e = NewEvent(s) + default: + return fmt.Errorf("unsupported scan type for NewEvent: %T", src) + } + return nil +} + +type NullNewEvent struct { + NewEvent NewEvent + Valid bool // Valid is true if NewEvent is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullNewEvent) Scan(value any) error { + if value == nil { + ns.NewEvent, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.NewEvent.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullNewEvent) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.NewEvent), nil +} + +type LogLine struct { + ID int64 + Status NewEvent +} diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..ac0f963 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listAuthors = `-- name: ListAuthors :many +SELECT id, status FROM log_lines +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]LogLine, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []LogLine + for rows.Next() { + var i LogLine + if err := rows.Scan(&i.ID, &i.Status); 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/ddl_alter_type_rename_and_update_columns/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/stdlib/query.sql new file mode 100644 index 0000000..92575af --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: ListAuthors :many +SELECT * FROM log_lines; diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..eb9ec7d --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/stdlib/schema.sql @@ -0,0 +1,9 @@ +CREATE TYPE event AS enum ('START', 'STOP'); + +CREATE TABLE log_lines ( + id BIGSERIAL PRIMARY KEY, + status "event" NOT NULL +); + +ALTER TYPE event RENAME TO "new_event"; + diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_and_update_columns/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_value/mysql/README.md b/internal/endtoend/testdata/ddl_alter_type_rename_value/mysql/README.md new file mode 100644 index 0000000..bffc182 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_value/mysql/README.md @@ -0,0 +1,4 @@ +MySQL does not support `CREATE TYPE ... AS ENUM`. Instead, enumerations are +defined via the `ENUM` type directly in table columns. + +https://dev.mysql.com/doc/refman/8.0/en/enum.html diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_type_rename_value/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..2dae436 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v4/go/models.go @@ -0,0 +1,52 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type Status string + +const ( + StatusOpen Status = "open" + StatusShut Status = "shut" +) + +func (e *Status) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = Status(s) + case string: + *e = Status(s) + default: + return fmt.Errorf("unsupported scan type for Status: %T", src) + } + return nil +} + +type NullStatus struct { + Status Status + Valid bool // Valid is true if Status is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullStatus) Scan(value any) error { + if value == nil { + ns.Status, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.Status.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullStatus) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.Status), nil +} diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..8ba623d --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TYPE status AS ENUM ('open', 'closed'); +ALTER TYPE status RENAME VALUE 'closed' TO 'shut'; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_type_rename_value/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..2dae436 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v5/go/models.go @@ -0,0 +1,52 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type Status string + +const ( + StatusOpen Status = "open" + StatusShut Status = "shut" +) + +func (e *Status) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = Status(s) + case string: + *e = Status(s) + default: + return fmt.Errorf("unsupported scan type for Status: %T", src) + } + return nil +} + +type NullStatus struct { + Status Status + Valid bool // Valid is true if Status is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullStatus) Scan(value any) error { + if value == nil { + ns.Status, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.Status.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullStatus) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.Status), nil +} diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..8ba623d --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TYPE status AS ENUM ('open', 'closed'); +ALTER TYPE status RENAME VALUE 'closed' TO 'shut'; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_type_rename_value/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..2dae436 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/stdlib/go/models.go @@ -0,0 +1,52 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type Status string + +const ( + StatusOpen Status = "open" + StatusShut Status = "shut" +) + +func (e *Status) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = Status(s) + case string: + *e = Status(s) + default: + return fmt.Errorf("unsupported scan type for Status: %T", src) + } + return nil +} + +type NullStatus struct { + Status Status + Valid bool // Valid is true if Status is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullStatus) Scan(value any) error { + if value == nil { + ns.Status, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.Status.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullStatus) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.Status), nil +} diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..8ba623d --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TYPE status AS ENUM ('open', 'closed'); +ALTER TYPE status RENAME VALUE 'closed' TO 'shut'; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_rename_value/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_type_set_schema/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..c131129 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v4/go/models.go @@ -0,0 +1,103 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type Level string + +const ( + LevelDEBUG Level = "DEBUG" + LevelINFO Level = "INFO" + LevelWARN Level = "WARN" + LevelERROR Level = "ERROR" + LevelFATAL Level = "FATAL" +) + +func (e *Level) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = Level(s) + case string: + *e = Level(s) + default: + return fmt.Errorf("unsupported scan type for Level: %T", src) + } + return nil +} + +type NullLevel struct { + Level Level + Valid bool // Valid is true if Level is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullLevel) Scan(value any) error { + if value == nil { + ns.Level, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.Level.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullLevel) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.Level), nil +} + +type NewEvent string + +const ( + NewEventSTART NewEvent = "START" + NewEventSTOP NewEvent = "STOP" +) + +func (e *NewEvent) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = NewEvent(s) + case string: + *e = NewEvent(s) + default: + return fmt.Errorf("unsupported scan type for NewEvent: %T", src) + } + return nil +} + +type NullNewEvent struct { + NewEvent NewEvent + Valid bool // Valid is true if NewEvent is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullNewEvent) Scan(value any) error { + if value == nil { + ns.NewEvent, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.NewEvent.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullNewEvent) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.NewEvent), nil +} + +type LogLine struct { + ID int64 + Status NewEvent + Level Level +} diff --git a/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..22ba6e5 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listAuthors = `-- name: ListAuthors :many +SELECT id, status, level FROM log_lines +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]LogLine, error) { + rows, err := q.db.Query(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []LogLine + for rows.Next() { + var i LogLine + if err := rows.Scan(&i.ID, &i.Status, &i.Level); 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/ddl_alter_type_set_schema/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..92575af --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: ListAuthors :many +SELECT * FROM log_lines; diff --git a/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..c2f0eff --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v4/schema.sql @@ -0,0 +1,15 @@ +CREATE SCHEMA old; +CREATE SCHEMA new; + +CREATE TYPE event AS enum ('START', 'STOP'); +CREATE TYPE old.level AS enum ('DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL'); + +CREATE TABLE log_lines ( + id BIGSERIAL PRIMARY KEY, + status event NOT NULL, + level old.level NOT NULL +); + +ALTER TYPE event SET SCHEMA new; +ALTER TYPE old.level SET SCHEMA public; + diff --git a/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_alter_type_set_schema/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..c131129 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v5/go/models.go @@ -0,0 +1,103 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type Level string + +const ( + LevelDEBUG Level = "DEBUG" + LevelINFO Level = "INFO" + LevelWARN Level = "WARN" + LevelERROR Level = "ERROR" + LevelFATAL Level = "FATAL" +) + +func (e *Level) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = Level(s) + case string: + *e = Level(s) + default: + return fmt.Errorf("unsupported scan type for Level: %T", src) + } + return nil +} + +type NullLevel struct { + Level Level + Valid bool // Valid is true if Level is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullLevel) Scan(value any) error { + if value == nil { + ns.Level, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.Level.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullLevel) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.Level), nil +} + +type NewEvent string + +const ( + NewEventSTART NewEvent = "START" + NewEventSTOP NewEvent = "STOP" +) + +func (e *NewEvent) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = NewEvent(s) + case string: + *e = NewEvent(s) + default: + return fmt.Errorf("unsupported scan type for NewEvent: %T", src) + } + return nil +} + +type NullNewEvent struct { + NewEvent NewEvent + Valid bool // Valid is true if NewEvent is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullNewEvent) Scan(value any) error { + if value == nil { + ns.NewEvent, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.NewEvent.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullNewEvent) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.NewEvent), nil +} + +type LogLine struct { + ID int64 + Status NewEvent + Level Level +} diff --git a/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..22ba6e5 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listAuthors = `-- name: ListAuthors :many +SELECT id, status, level FROM log_lines +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]LogLine, error) { + rows, err := q.db.Query(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []LogLine + for rows.Next() { + var i LogLine + if err := rows.Scan(&i.ID, &i.Status, &i.Level); 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/ddl_alter_type_set_schema/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..92575af --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: ListAuthors :many +SELECT * FROM log_lines; diff --git a/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..c2f0eff --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v5/schema.sql @@ -0,0 +1,15 @@ +CREATE SCHEMA old; +CREATE SCHEMA new; + +CREATE TYPE event AS enum ('START', 'STOP'); +CREATE TYPE old.level AS enum ('DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL'); + +CREATE TABLE log_lines ( + id BIGSERIAL PRIMARY KEY, + status event NOT NULL, + level old.level NOT NULL +); + +ALTER TYPE event SET SCHEMA new; +ALTER TYPE old.level SET SCHEMA public; + diff --git a/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_alter_type_set_schema/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..c131129 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/stdlib/go/models.go @@ -0,0 +1,103 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type Level string + +const ( + LevelDEBUG Level = "DEBUG" + LevelINFO Level = "INFO" + LevelWARN Level = "WARN" + LevelERROR Level = "ERROR" + LevelFATAL Level = "FATAL" +) + +func (e *Level) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = Level(s) + case string: + *e = Level(s) + default: + return fmt.Errorf("unsupported scan type for Level: %T", src) + } + return nil +} + +type NullLevel struct { + Level Level + Valid bool // Valid is true if Level is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullLevel) Scan(value any) error { + if value == nil { + ns.Level, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.Level.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullLevel) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.Level), nil +} + +type NewEvent string + +const ( + NewEventSTART NewEvent = "START" + NewEventSTOP NewEvent = "STOP" +) + +func (e *NewEvent) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = NewEvent(s) + case string: + *e = NewEvent(s) + default: + return fmt.Errorf("unsupported scan type for NewEvent: %T", src) + } + return nil +} + +type NullNewEvent struct { + NewEvent NewEvent + Valid bool // Valid is true if NewEvent is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullNewEvent) Scan(value any) error { + if value == nil { + ns.NewEvent, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.NewEvent.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullNewEvent) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.NewEvent), nil +} + +type LogLine struct { + ID int64 + Status NewEvent + Level Level +} diff --git a/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..6b9793a --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listAuthors = `-- name: ListAuthors :many +SELECT id, status, level FROM log_lines +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]LogLine, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []LogLine + for rows.Next() { + var i LogLine + if err := rows.Scan(&i.ID, &i.Status, &i.Level); 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/ddl_alter_type_set_schema/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/stdlib/query.sql new file mode 100644 index 0000000..92575af --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: ListAuthors :many +SELECT * FROM log_lines; diff --git a/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..c2f0eff --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/stdlib/schema.sql @@ -0,0 +1,15 @@ +CREATE SCHEMA old; +CREATE SCHEMA new; + +CREATE TYPE event AS enum ('START', 'STOP'); +CREATE TYPE old.level AS enum ('DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL'); + +CREATE TABLE log_lines ( + id BIGSERIAL PRIMARY KEY, + status event NOT NULL, + level old.level NOT NULL +); + +ALTER TYPE event SET SCHEMA new; +ALTER TYPE old.level SET SCHEMA public; + diff --git a/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_type_set_schema/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_comment/mysql/README.md b/internal/endtoend/testdata/ddl_comment/mysql/README.md new file mode 100644 index 0000000..6cf9f93 --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/mysql/README.md @@ -0,0 +1,2 @@ +MySQL does not support the `COMMENT ON` statmement. Instead, comments can be +added to columns and tables at creation time. diff --git a/internal/endtoend/testdata/ddl_comment/mysql/go/db.go b/internal/endtoend/testdata/ddl_comment/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_comment/mysql/go/models.go b/internal/endtoend/testdata/ddl_comment/mysql/go/models.go new file mode 100644 index 0000000..5de5279 --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/mysql/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +// Table comment +type Bar struct { + // Column comment + Baz sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_comment/mysql/go/query.sql.go b/internal/endtoend/testdata/ddl_comment/mysql/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/mysql/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_comment/mysql/query.sql b/internal/endtoend/testdata/ddl_comment/mysql/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_comment/mysql/schema.sql b/internal/endtoend/testdata/ddl_comment/mysql/schema.sql new file mode 100644 index 0000000..bd25072 --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/mysql/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE bar ( + baz text COMMENT "Column comment" +) COMMENT="Table comment"; diff --git a/internal/endtoend/testdata/ddl_comment/mysql/sqlc.json b/internal/endtoend/testdata/ddl_comment/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/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/ddl_comment/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_comment/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..0ddf446 --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v4/go/models.go @@ -0,0 +1,59 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + "database/sql/driver" + "fmt" +) + +// Enum comment +type FooBat string + +const ( + FooBatBat FooBat = "bat" +) + +func (e *FooBat) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = FooBat(s) + case string: + *e = FooBat(s) + default: + return fmt.Errorf("unsupported scan type for FooBat: %T", src) + } + return nil +} + +type NullFooBat struct { + FooBat FooBat + Valid bool // Valid is true if FooBat is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullFooBat) Scan(value any) error { + if value == nil { + ns.FooBat, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.FooBat.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullFooBat) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.FooBat), nil +} + +// Table comment +type FooBar struct { + // Column comment + Baz sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..313e88c --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v4/schema.sql @@ -0,0 +1,7 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (baz text); +CREATE TYPE foo.bat AS ENUM ('bat'); +COMMENT ON SCHEMA foo IS 'Schema comment'; +COMMENT ON TABLE foo.bar IS 'Table comment'; +COMMENT ON COLUMN foo.bar.baz IS 'Column comment'; +COMMENT ON TYPE foo.bat IS 'Enum comment'; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_comment/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..56ac46a --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v5/go/models.go @@ -0,0 +1,60 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" + + "github.com/jackc/pgx/v5/pgtype" +) + +// Enum comment +type FooBat string + +const ( + FooBatBat FooBat = "bat" +) + +func (e *FooBat) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = FooBat(s) + case string: + *e = FooBat(s) + default: + return fmt.Errorf("unsupported scan type for FooBat: %T", src) + } + return nil +} + +type NullFooBat struct { + FooBat FooBat + Valid bool // Valid is true if FooBat is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullFooBat) Scan(value any) error { + if value == nil { + ns.FooBat, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.FooBat.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullFooBat) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.FooBat), nil +} + +// Table comment +type FooBar struct { + // Column comment + Baz pgtype.Text +} diff --git a/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..313e88c --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v5/schema.sql @@ -0,0 +1,7 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (baz text); +CREATE TYPE foo.bat AS ENUM ('bat'); +COMMENT ON SCHEMA foo IS 'Schema comment'; +COMMENT ON TABLE foo.bar IS 'Table comment'; +COMMENT ON COLUMN foo.bar.baz IS 'Column comment'; +COMMENT ON TYPE foo.bat IS 'Enum comment'; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_comment/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_comment/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_comment/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_comment/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..0ddf446 --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/postgresql/stdlib/go/models.go @@ -0,0 +1,59 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + "database/sql/driver" + "fmt" +) + +// Enum comment +type FooBat string + +const ( + FooBatBat FooBat = "bat" +) + +func (e *FooBat) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = FooBat(s) + case string: + *e = FooBat(s) + default: + return fmt.Errorf("unsupported scan type for FooBat: %T", src) + } + return nil +} + +type NullFooBat struct { + FooBat FooBat + Valid bool // Valid is true if FooBat is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullFooBat) Scan(value any) error { + if value == nil { + ns.FooBat, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.FooBat.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullFooBat) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.FooBat), nil +} + +// Table comment +type FooBar struct { + // Column comment + Baz sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_comment/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_comment/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_comment/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_comment/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_comment/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_comment/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..313e88c --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/postgresql/stdlib/schema.sql @@ -0,0 +1,7 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (baz text); +CREATE TYPE foo.bat AS ENUM ('bat'); +COMMENT ON SCHEMA foo IS 'Schema comment'; +COMMENT ON TABLE foo.bar IS 'Table comment'; +COMMENT ON COLUMN foo.bar.baz IS 'Column comment'; +COMMENT ON TYPE foo.bat IS 'Enum comment'; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_comment/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_comment/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_comment/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_enum/mysql/go/db.go b/internal/endtoend/testdata/ddl_create_enum/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_enum/mysql/go/models.go b/internal/endtoend/testdata/ddl_create_enum/mysql/go/models.go new file mode 100644 index 0000000..fe75a34 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/mysql/go/models.go @@ -0,0 +1,114 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type FooDigit string + +const ( + FooDigit0 FooDigit = "0" + FooDigit1 FooDigit = "1" + FooDigit2 FooDigit = "2" + FooDigit3 FooDigit = "3" + FooDigit4 FooDigit = "4" + FooDigit5 FooDigit = "5" + FooDigit6 FooDigit = "6" + FooDigit7 FooDigit = "7" + FooDigit8 FooDigit = "8" + FooDigit9 FooDigit = "9" + FooDigitValue10 FooDigit = "#" + FooDigitValue11 FooDigit = "*" +) + +func (e *FooDigit) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = FooDigit(s) + case string: + *e = FooDigit(s) + default: + return fmt.Errorf("unsupported scan type for FooDigit: %T", src) + } + return nil +} + +type NullFooDigit struct { + FooDigit FooDigit + Valid bool // Valid is true if FooDigit is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullFooDigit) Scan(value any) error { + if value == nil { + ns.FooDigit, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.FooDigit.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullFooDigit) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.FooDigit), nil +} + +type FooFoobar string + +const ( + FooFoobarFooA FooFoobar = "foo-a" + FooFoobarFooB FooFoobar = "foo_b" + FooFoobarFooC FooFoobar = "foo:c" + FooFoobarFooD FooFoobar = "foo/d" + FooFoobarFooe FooFoobar = "foo@e" + FooFoobarFoof FooFoobar = "foo+f" + FooFoobarFoog FooFoobar = "foo!g" +) + +func (e *FooFoobar) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = FooFoobar(s) + case string: + *e = FooFoobar(s) + default: + return fmt.Errorf("unsupported scan type for FooFoobar: %T", src) + } + return nil +} + +type NullFooFoobar struct { + FooFoobar FooFoobar + Valid bool // Valid is true if FooFoobar is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullFooFoobar) Scan(value any) error { + if value == nil { + ns.FooFoobar, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.FooFoobar.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullFooFoobar) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.FooFoobar), nil +} + +type Foo struct { + Foobar FooFoobar + Digit FooDigit +} diff --git a/internal/endtoend/testdata/ddl_create_enum/mysql/go/query.sql.go b/internal/endtoend/testdata/ddl_create_enum/mysql/go/query.sql.go new file mode 100644 index 0000000..1a5a732 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/mysql/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listFoo = `-- name: ListFoo :many +SELECT foobar, digit FROM foo +` + +func (q *Queries) ListFoo(ctx context.Context) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, listFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.Foobar, &i.Digit); 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/ddl_create_enum/mysql/query.sql b/internal/endtoend/testdata/ddl_create_enum/mysql/query.sql new file mode 100644 index 0000000..e120062 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/mysql/query.sql @@ -0,0 +1,2 @@ +/* name: ListFoo :many */ +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/ddl_create_enum/mysql/schema.sql b/internal/endtoend/testdata/ddl_create_enum/mysql/schema.sql new file mode 100644 index 0000000..da7818d --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/mysql/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE foo ( + foobar ENUM ('foo-a', 'foo_b', 'foo:c', 'foo/d', 'foo@e', 'foo+f', 'foo!g') NOT NULL, + digit ENUM ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '#', '*') NOT NULL +); diff --git a/internal/endtoend/testdata/ddl_create_enum/mysql/sqlc.json b/internal/endtoend/testdata/ddl_create_enum/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/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/ddl_create_enum/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_enum/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..55160bf --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v4/go/models.go @@ -0,0 +1,113 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type Digit string + +const ( + Digit0 Digit = "0" + Digit1 Digit = "1" + Digit2 Digit = "2" + Digit3 Digit = "3" + Digit4 Digit = "4" + Digit5 Digit = "5" + Digit6 Digit = "6" + Digit7 Digit = "7" + Digit8 Digit = "8" + Digit9 Digit = "9" + DigitValue10 Digit = "#" + DigitValue11 Digit = "*" +) + +func (e *Digit) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = Digit(s) + case string: + *e = Digit(s) + default: + return fmt.Errorf("unsupported scan type for Digit: %T", src) + } + return nil +} + +type NullDigit struct { + Digit Digit + Valid bool // Valid is true if Digit is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullDigit) Scan(value any) error { + if value == nil { + ns.Digit, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.Digit.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullDigit) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.Digit), nil +} + +type Foobar string + +const ( + FoobarFooA Foobar = "foo-a" + FoobarFooB Foobar = "foo_b" + FoobarFooC Foobar = "foo:c" + FoobarFooD Foobar = "foo/d" + FoobarFooe Foobar = "foo@e" + FoobarFoof Foobar = "foo+f" + FoobarFoog Foobar = "foo!g" +) + +func (e *Foobar) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = Foobar(s) + case string: + *e = Foobar(s) + default: + return fmt.Errorf("unsupported scan type for Foobar: %T", src) + } + return nil +} + +type NullFoobar struct { + Foobar Foobar + Valid bool // Valid is true if Foobar is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullFoobar) Scan(value any) error { + if value == nil { + ns.Foobar, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.Foobar.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullFoobar) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.Foobar), nil +} + +type Foo struct { + Val Foobar +} diff --git a/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..0b67822 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listFoo = `-- name: ListFoo :many +SELECT val FROM foo +` + +func (q *Queries) ListFoo(ctx context.Context) ([]Foobar, error) { + rows, err := q.db.Query(ctx, listFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foobar + for rows.Next() { + var val Foobar + if err := rows.Scan(&val); err != nil { + return nil, err + } + items = append(items, val) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..b475d29 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: ListFoo :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..0ba7f1a --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v4/schema.sql @@ -0,0 +1,28 @@ +CREATE TYPE foobar AS ENUM ( + -- Valid separators + 'foo-a', + 'foo_b', + 'foo:c', + 'foo/d', + -- Strip unknown characters + 'foo@e', + 'foo+f', + 'foo!g' +); + +CREATE TYPE "digit" AS ENUM ( + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '#', + '*' +); + +CREATE TABLE foo (val foobar NOT NULL); diff --git a/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_enum/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..55160bf --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v5/go/models.go @@ -0,0 +1,113 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type Digit string + +const ( + Digit0 Digit = "0" + Digit1 Digit = "1" + Digit2 Digit = "2" + Digit3 Digit = "3" + Digit4 Digit = "4" + Digit5 Digit = "5" + Digit6 Digit = "6" + Digit7 Digit = "7" + Digit8 Digit = "8" + Digit9 Digit = "9" + DigitValue10 Digit = "#" + DigitValue11 Digit = "*" +) + +func (e *Digit) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = Digit(s) + case string: + *e = Digit(s) + default: + return fmt.Errorf("unsupported scan type for Digit: %T", src) + } + return nil +} + +type NullDigit struct { + Digit Digit + Valid bool // Valid is true if Digit is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullDigit) Scan(value any) error { + if value == nil { + ns.Digit, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.Digit.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullDigit) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.Digit), nil +} + +type Foobar string + +const ( + FoobarFooA Foobar = "foo-a" + FoobarFooB Foobar = "foo_b" + FoobarFooC Foobar = "foo:c" + FoobarFooD Foobar = "foo/d" + FoobarFooe Foobar = "foo@e" + FoobarFoof Foobar = "foo+f" + FoobarFoog Foobar = "foo!g" +) + +func (e *Foobar) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = Foobar(s) + case string: + *e = Foobar(s) + default: + return fmt.Errorf("unsupported scan type for Foobar: %T", src) + } + return nil +} + +type NullFoobar struct { + Foobar Foobar + Valid bool // Valid is true if Foobar is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullFoobar) Scan(value any) error { + if value == nil { + ns.Foobar, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.Foobar.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullFoobar) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.Foobar), nil +} + +type Foo struct { + Val Foobar +} diff --git a/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..0b67822 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listFoo = `-- name: ListFoo :many +SELECT val FROM foo +` + +func (q *Queries) ListFoo(ctx context.Context) ([]Foobar, error) { + rows, err := q.db.Query(ctx, listFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foobar + for rows.Next() { + var val Foobar + if err := rows.Scan(&val); err != nil { + return nil, err + } + items = append(items, val) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..b475d29 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: ListFoo :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..0ba7f1a --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v5/schema.sql @@ -0,0 +1,28 @@ +CREATE TYPE foobar AS ENUM ( + -- Valid separators + 'foo-a', + 'foo_b', + 'foo:c', + 'foo/d', + -- Strip unknown characters + 'foo@e', + 'foo+f', + 'foo!g' +); + +CREATE TYPE "digit" AS ENUM ( + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '#', + '*' +); + +CREATE TABLE foo (val foobar NOT NULL); diff --git a/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_enum/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_create_enum/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_enum/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_create_enum/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..55160bf --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/postgresql/stdlib/go/models.go @@ -0,0 +1,113 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type Digit string + +const ( + Digit0 Digit = "0" + Digit1 Digit = "1" + Digit2 Digit = "2" + Digit3 Digit = "3" + Digit4 Digit = "4" + Digit5 Digit = "5" + Digit6 Digit = "6" + Digit7 Digit = "7" + Digit8 Digit = "8" + Digit9 Digit = "9" + DigitValue10 Digit = "#" + DigitValue11 Digit = "*" +) + +func (e *Digit) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = Digit(s) + case string: + *e = Digit(s) + default: + return fmt.Errorf("unsupported scan type for Digit: %T", src) + } + return nil +} + +type NullDigit struct { + Digit Digit + Valid bool // Valid is true if Digit is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullDigit) Scan(value any) error { + if value == nil { + ns.Digit, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.Digit.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullDigit) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.Digit), nil +} + +type Foobar string + +const ( + FoobarFooA Foobar = "foo-a" + FoobarFooB Foobar = "foo_b" + FoobarFooC Foobar = "foo:c" + FoobarFooD Foobar = "foo/d" + FoobarFooe Foobar = "foo@e" + FoobarFoof Foobar = "foo+f" + FoobarFoog Foobar = "foo!g" +) + +func (e *Foobar) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = Foobar(s) + case string: + *e = Foobar(s) + default: + return fmt.Errorf("unsupported scan type for Foobar: %T", src) + } + return nil +} + +type NullFoobar struct { + Foobar Foobar + Valid bool // Valid is true if Foobar is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullFoobar) Scan(value any) error { + if value == nil { + ns.Foobar, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.Foobar.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullFoobar) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.Foobar), nil +} + +type Foo struct { + Val Foobar +} diff --git a/internal/endtoend/testdata/ddl_create_enum/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_create_enum/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..7c474a5 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listFoo = `-- name: ListFoo :many +SELECT val FROM foo +` + +func (q *Queries) ListFoo(ctx context.Context) ([]Foobar, error) { + rows, err := q.db.QueryContext(ctx, listFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foobar + for rows.Next() { + var val Foobar + if err := rows.Scan(&val); err != nil { + return nil, err + } + items = append(items, val) + } + 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/ddl_create_enum/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_create_enum/postgresql/stdlib/query.sql new file mode 100644 index 0000000..b475d29 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: ListFoo :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/ddl_create_enum/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_create_enum/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..0ba7f1a --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/postgresql/stdlib/schema.sql @@ -0,0 +1,28 @@ +CREATE TYPE foobar AS ENUM ( + -- Valid separators + 'foo-a', + 'foo_b', + 'foo:c', + 'foo/d', + -- Strip unknown characters + 'foo@e', + 'foo+f', + 'foo!g' +); + +CREATE TYPE "digit" AS ENUM ( + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '#', + '*' +); + +CREATE TABLE foo (val foobar NOT NULL); diff --git a/internal/endtoend/testdata/ddl_create_enum/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_create_enum/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_func_exists/exec.json b/internal/endtoend/testdata/ddl_create_func_exists/exec.json new file mode 100644 index 0000000..c85ca2d --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_func_exists/exec.json @@ -0,0 +1,6 @@ +{ + "contexts": ["base"], + "meta": { + "invalid_schema": true + } +} diff --git a/internal/endtoend/testdata/ddl_create_func_exists/mysql/README.md b/internal/endtoend/testdata/ddl_create_func_exists/mysql/README.md new file mode 100644 index 0000000..5fa2c9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_func_exists/mysql/README.md @@ -0,0 +1,2 @@ +The MySQL parser currently does not support user-defined functions. See +https://github.com/pingcap/parser/issues/988. diff --git a/internal/endtoend/testdata/ddl_create_func_exists/query.sql b/internal/endtoend/testdata/ddl_create_func_exists/query.sql new file mode 100644 index 0000000..d4d665e --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_func_exists/query.sql @@ -0,0 +1,5 @@ +CREATE FUNCTION f(x TIMESTAMPTZ) RETURNS void AS '' LANGUAGE sql; +CREATE FUNCTION f(x timestamp with time zone) RETURNS void AS '' LANGUAGE sql; + +-- name: F :one +SELECT f(1); diff --git a/internal/endtoend/testdata/ddl_create_func_exists/sqlc.json b/internal/endtoend/testdata/ddl_create_func_exists/sqlc.json new file mode 100644 index 0000000..ac7c2ed --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_func_exists/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_func_exists/stderr.txt b/internal/endtoend/testdata/ddl_create_func_exists/stderr.txt new file mode 100644 index 0000000..43aaefe --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_func_exists/stderr.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:1:1: relation "f" already exists diff --git a/internal/endtoend/testdata/ddl_create_function/mysql/README.md b/internal/endtoend/testdata/ddl_create_function/mysql/README.md new file mode 100644 index 0000000..5fa2c9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function/mysql/README.md @@ -0,0 +1,2 @@ +The MySQL parser currently does not support user-defined functions. See +https://github.com/pingcap/parser/issues/988. diff --git a/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_function/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..8caad3e --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v4/schema.sql @@ -0,0 +1 @@ +CREATE FUNCTION foo(TEXT) RETURNS bool AS $$ SELECT true $$ LANGUAGE sql; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_function/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..8caad3e --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v5/schema.sql @@ -0,0 +1 @@ +CREATE FUNCTION foo(TEXT) RETURNS bool AS $$ SELECT true $$ LANGUAGE sql; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_function/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_create_function/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_function/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_create_function/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_create_function/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_create_function/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_function/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_create_function/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_function/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_create_function/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..8caad3e --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function/postgresql/stdlib/schema.sql @@ -0,0 +1 @@ +CREATE FUNCTION foo(TEXT) RETURNS bool AS $$ SELECT true $$ LANGUAGE sql; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_create_function/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_create_function/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_function_args/mysql/README.md b/internal/endtoend/testdata/ddl_create_function_args/mysql/README.md new file mode 100644 index 0000000..5fa2c9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_args/mysql/README.md @@ -0,0 +1,2 @@ +The MySQL parser currently does not support user-defined functions. See +https://github.com/pingcap/parser/issues/988. diff --git a/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_function_args/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..55b0403 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE FUNCTION foo(bar TEXT) RETURNS bool AS $$ SELECT true $$ LANGUAGE sql; +CREATE FUNCTION foo(bar TEXT, baz TEXT) RETURNS TEXT AS $$ SELECT "baz" $$ LANGUAGE sql; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_function_args/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..55b0403 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE FUNCTION foo(bar TEXT) RETURNS bool AS $$ SELECT true $$ LANGUAGE sql; +CREATE FUNCTION foo(bar TEXT, baz TEXT) RETURNS TEXT AS $$ SELECT "baz" $$ LANGUAGE sql; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_args/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_function_args/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_create_function_args/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_args/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_function_args/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_create_function_args/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_args/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_create_function_args/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_create_function_args/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_args/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_function_args/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_create_function_args/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_args/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_function_args/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_create_function_args/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..55b0403 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_args/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE FUNCTION foo(bar TEXT) RETURNS bool AS $$ SELECT true $$ LANGUAGE sql; +CREATE FUNCTION foo(bar TEXT, baz TEXT) RETURNS TEXT AS $$ SELECT "baz" $$ LANGUAGE sql; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_create_function_args/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_create_function_args/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_args/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_function_return/mysql/README.md b/internal/endtoend/testdata/ddl_create_function_return/mysql/README.md new file mode 100644 index 0000000..5fa2c9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_return/mysql/README.md @@ -0,0 +1,2 @@ +The MySQL parser currently does not support user-defined functions. See +https://github.com/pingcap/parser/issues/988. diff --git a/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_function_return/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..4b98ce9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v4/schema.sql @@ -0,0 +1 @@ +CREATE FUNCTION foo(bar TEXT, baz TEXT='baz') RETURNS bool AS $$ SELECT true $$ LANGUAGE sql; diff --git a/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_function_return/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..4b98ce9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v5/schema.sql @@ -0,0 +1 @@ +CREATE FUNCTION foo(bar TEXT, baz TEXT='baz') RETURNS bool AS $$ SELECT true $$ LANGUAGE sql; diff --git a/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_return/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_function_return/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_create_function_return/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_return/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_function_return/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_create_function_return/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_return/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_create_function_return/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_create_function_return/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_return/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_function_return/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_create_function_return/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_return/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_function_return/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_create_function_return/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..4b98ce9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_return/postgresql/stdlib/schema.sql @@ -0,0 +1 @@ +CREATE FUNCTION foo(bar TEXT, baz TEXT='baz') RETURNS bool AS $$ SELECT true $$ LANGUAGE sql; diff --git a/internal/endtoend/testdata/ddl_create_function_return/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_create_function_return/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_return/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_function_types/mysql/README.md b/internal/endtoend/testdata/ddl_create_function_types/mysql/README.md new file mode 100644 index 0000000..5fa2c9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_types/mysql/README.md @@ -0,0 +1,2 @@ +The MySQL parser currently does not support user-defined functions. See +https://github.com/pingcap/parser/issues/988. diff --git a/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_function_types/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..876d0f8 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE FUNCTION foo(bar TEXT) RETURNS bool AS $$ SELECT true $$ LANGUAGE sql; +CREATE FUNCTION foo(bar INTEGER) RETURNS TEXT AS $$ SELECT 'baz' $$ LANGUAGE sql; diff --git a/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_function_types/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..876d0f8 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE FUNCTION foo(bar TEXT) RETURNS bool AS $$ SELECT true $$ LANGUAGE sql; +CREATE FUNCTION foo(bar INTEGER) RETURNS TEXT AS $$ SELECT 'baz' $$ LANGUAGE sql; diff --git a/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_types/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_function_types/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_create_function_types/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_types/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_function_types/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_create_function_types/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_types/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_create_function_types/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_create_function_types/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_types/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_function_types/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_create_function_types/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_types/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_function_types/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_create_function_types/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..876d0f8 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_types/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE FUNCTION foo(bar TEXT) RETURNS bool AS $$ SELECT true $$ LANGUAGE sql; +CREATE FUNCTION foo(bar INTEGER) RETURNS TEXT AS $$ SELECT 'baz' $$ LANGUAGE sql; diff --git a/internal/endtoend/testdata/ddl_create_function_types/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_create_function_types/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_function_types/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.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 0000000..32faa9f --- /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.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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 0000000..131b306 --- /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.31.1 + +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 0000000..60db046 --- /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.31.1 +// 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 0000000..ff9bbad --- /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 0000000..e3f2d0a --- /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 0000000..e41c39e --- /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/ddl_create_procedure/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_procedure/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..131b306 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v4/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Tbl struct { + Value sql.NullInt32 +} diff --git a/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..65ec531 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,61 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const callInsertData = `-- name: CallInsertData :exec +CALL insert_data($1, $2) +` + +type CallInsertDataParams struct { + A int32 + B int32 +} + +func (q *Queries) CallInsertData(ctx context.Context, arg CallInsertDataParams) error { + _, err := q.db.Exec(ctx, callInsertData, arg.A, arg.B) + return err +} + +const callInsertDataNamed = `-- name: CallInsertDataNamed :exec +CALL insert_data(b => $1, a => $2) +` + +type CallInsertDataNamedParams struct { + B int32 + A int32 +} + +func (q *Queries) CallInsertDataNamed(ctx context.Context, arg CallInsertDataNamedParams) error { + _, err := q.db.Exec(ctx, callInsertDataNamed, arg.B, arg.A) + return err +} + +const callInsertDataNoArgs = `-- name: CallInsertDataNoArgs :exec +CALL insert_data(1, 2) +` + +func (q *Queries) CallInsertDataNoArgs(ctx context.Context) error { + _, err := q.db.Exec(ctx, callInsertDataNoArgs) + return err +} + +const callInsertDataSqlcArgs = `-- name: CallInsertDataSqlcArgs :exec +CALL insert_data($1, $2) +` + +type CallInsertDataSqlcArgsParams struct { + Foo int32 + Bar int32 +} + +func (q *Queries) CallInsertDataSqlcArgs(ctx context.Context, arg CallInsertDataSqlcArgsParams) error { + _, err := q.db.Exec(ctx, callInsertDataSqlcArgs, arg.Foo, arg.Bar) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..2d8d86a --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v4/query.sql @@ -0,0 +1,11 @@ +-- name: CallInsertData :exec +CALL insert_data($1, $2); + +-- name: CallInsertDataNoArgs :exec +CALL insert_data(1, 2); + +-- name: CallInsertDataNamed :exec +CALL insert_data(b => $1, a => $2); + +-- name: CallInsertDataSqlcArgs :exec +CALL insert_data(sqlc.arg('foo'), sqlc.arg('bar')); diff --git a/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..55a9a2e --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v4/schema.sql @@ -0,0 +1,11 @@ +CREATE TABLE tbl ( + value integer +); + +-- https://www.postgresql.org/docs/current/sql-createprocedure.html +CREATE PROCEDURE insert_data(a integer, b integer) +LANGUAGE SQL +AS $$ +INSERT INTO tbl VALUES (a); +INSERT INTO tbl VALUES (b); +$$; diff --git a/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_procedure/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..8ed71f6 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v5/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Tbl struct { + Value pgtype.Int4 +} diff --git a/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..65ec531 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,61 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const callInsertData = `-- name: CallInsertData :exec +CALL insert_data($1, $2) +` + +type CallInsertDataParams struct { + A int32 + B int32 +} + +func (q *Queries) CallInsertData(ctx context.Context, arg CallInsertDataParams) error { + _, err := q.db.Exec(ctx, callInsertData, arg.A, arg.B) + return err +} + +const callInsertDataNamed = `-- name: CallInsertDataNamed :exec +CALL insert_data(b => $1, a => $2) +` + +type CallInsertDataNamedParams struct { + B int32 + A int32 +} + +func (q *Queries) CallInsertDataNamed(ctx context.Context, arg CallInsertDataNamedParams) error { + _, err := q.db.Exec(ctx, callInsertDataNamed, arg.B, arg.A) + return err +} + +const callInsertDataNoArgs = `-- name: CallInsertDataNoArgs :exec +CALL insert_data(1, 2) +` + +func (q *Queries) CallInsertDataNoArgs(ctx context.Context) error { + _, err := q.db.Exec(ctx, callInsertDataNoArgs) + return err +} + +const callInsertDataSqlcArgs = `-- name: CallInsertDataSqlcArgs :exec +CALL insert_data($1, $2) +` + +type CallInsertDataSqlcArgsParams struct { + Foo int32 + Bar int32 +} + +func (q *Queries) CallInsertDataSqlcArgs(ctx context.Context, arg CallInsertDataSqlcArgsParams) error { + _, err := q.db.Exec(ctx, callInsertDataSqlcArgs, arg.Foo, arg.Bar) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..2d8d86a --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v5/query.sql @@ -0,0 +1,11 @@ +-- name: CallInsertData :exec +CALL insert_data($1, $2); + +-- name: CallInsertDataNoArgs :exec +CALL insert_data(1, 2); + +-- name: CallInsertDataNamed :exec +CALL insert_data(b => $1, a => $2); + +-- name: CallInsertDataSqlcArgs :exec +CALL insert_data(sqlc.arg('foo'), sqlc.arg('bar')); diff --git a/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..55a9a2e --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v5/schema.sql @@ -0,0 +1,11 @@ +CREATE TABLE tbl ( + value integer +); + +-- https://www.postgresql.org/docs/current/sql-createprocedure.html +CREATE PROCEDURE insert_data(a integer, b integer) +LANGUAGE SQL +AS $$ +INSERT INTO tbl VALUES (a); +INSERT INTO tbl VALUES (b); +$$; diff --git a/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_procedure/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_procedure/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_create_procedure/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_procedure/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_create_procedure/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..131b306 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_procedure/postgresql/stdlib/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Tbl struct { + Value sql.NullInt32 +} diff --git a/internal/endtoend/testdata/ddl_create_procedure/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_create_procedure/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..8a4bc9a --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_procedure/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,61 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const callInsertData = `-- name: CallInsertData :exec +CALL insert_data($1, $2) +` + +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 callInsertDataNamed = `-- name: CallInsertDataNamed :exec +CALL insert_data(b => $1, a => $2) +` + +type CallInsertDataNamedParams struct { + B int32 + A int32 +} + +func (q *Queries) CallInsertDataNamed(ctx context.Context, arg CallInsertDataNamedParams) error { + _, err := q.db.ExecContext(ctx, callInsertDataNamed, arg.B, arg.A) + 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($1, $2) +` + +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/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_create_procedure/postgresql/stdlib/query.sql new file mode 100644 index 0000000..2d8d86a --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_procedure/postgresql/stdlib/query.sql @@ -0,0 +1,11 @@ +-- name: CallInsertData :exec +CALL insert_data($1, $2); + +-- name: CallInsertDataNoArgs :exec +CALL insert_data(1, 2); + +-- name: CallInsertDataNamed :exec +CALL insert_data(b => $1, a => $2); + +-- name: CallInsertDataSqlcArgs :exec +CALL insert_data(sqlc.arg('foo'), sqlc.arg('bar')); diff --git a/internal/endtoend/testdata/ddl_create_procedure/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_create_procedure/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..55a9a2e --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_procedure/postgresql/stdlib/schema.sql @@ -0,0 +1,11 @@ +CREATE TABLE tbl ( + value integer +); + +-- https://www.postgresql.org/docs/current/sql-createprocedure.html +CREATE PROCEDURE insert_data(a integer, b integer) +LANGUAGE SQL +AS $$ +INSERT INTO tbl VALUES (a); +INSERT INTO tbl VALUES (b); +$$; diff --git a/internal/endtoend/testdata/ddl_create_procedure/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_create_procedure/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_procedure/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_table/mysql/go/db.go b/internal/endtoend/testdata/ddl_create_table/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_table/mysql/go/models.go b/internal/endtoend/testdata/ddl_create_table/mysql/go/models.go new file mode 100644 index 0000000..a2d2dc1 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/mysql/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Venue struct { + Name sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_create_table/mysql/go/query.sql.go b/internal/endtoend/testdata/ddl_create_table/mysql/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/mysql/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_table/mysql/query.sql b/internal/endtoend/testdata/ddl_create_table/mysql/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_table/mysql/schema.sql b/internal/endtoend/testdata/ddl_create_table/mysql/schema.sql new file mode 100644 index 0000000..78e89cb --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/mysql/schema.sql @@ -0,0 +1 @@ +CREATE TABLE venues (name text); diff --git a/internal/endtoend/testdata/ddl_create_table/mysql/sqlc.json b/internal/endtoend/testdata/ddl_create_table/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/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/ddl_create_table/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_table/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a2d2dc1 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v4/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Venue struct { + Name sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..78e89cb --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v4/schema.sql @@ -0,0 +1 @@ +CREATE TABLE venues (name text); diff --git a/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_table/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..bea173d --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v5/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Venue struct { + Name pgtype.Text +} diff --git a/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..78e89cb --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v5/schema.sql @@ -0,0 +1 @@ +CREATE TABLE venues (name text); diff --git a/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_table/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_create_table/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_table/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_create_table/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a2d2dc1 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/postgresql/stdlib/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Venue struct { + Name sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_create_table/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_create_table/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_table/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_create_table/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_table/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_create_table/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..78e89cb --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/postgresql/stdlib/schema.sql @@ -0,0 +1 @@ +CREATE TABLE venues (name text); diff --git a/internal/endtoend/testdata/ddl_create_table/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_create_table/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_table/sqlite/go/db.go b/internal/endtoend/testdata/ddl_create_table/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_table/sqlite/go/models.go b/internal/endtoend/testdata/ddl_create_table/sqlite/go/models.go new file mode 100644 index 0000000..a2d2dc1 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/sqlite/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Venue struct { + Name sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_create_table/sqlite/go/query.sql.go b/internal/endtoend/testdata/ddl_create_table/sqlite/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/sqlite/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_table/sqlite/query.sql b/internal/endtoend/testdata/ddl_create_table/sqlite/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_table/sqlite/schema.sql b/internal/endtoend/testdata/ddl_create_table/sqlite/schema.sql new file mode 100644 index 0000000..6bcf8ce --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/sqlite/schema.sql @@ -0,0 +1 @@ +CREATE TABLE venues (name text); \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_create_table/sqlite/sqlc.json b/internal/endtoend/testdata/ddl_create_table/sqlite/sqlc.json new file mode 100644 index 0000000..cd66df0 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_table_include/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..9822696 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v4/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A int32 + B int32 + C sql.NullInt32 +} diff --git a/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..db08b9d --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v4/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE foo ( + PRIMARY KEY (a, b) INCLUDE (c), + a integer, + b integer, + c integer +); diff --git a/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_table_include/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a911deb --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v5/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + A int32 + B int32 + C pgtype.Int4 +} diff --git a/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..db08b9d --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v5/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE foo ( + PRIMARY KEY (a, b) INCLUDE (c), + a integer, + b integer, + c integer +); diff --git a/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_include/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_table_include/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_create_table_include/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_include/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_table_include/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_create_table_include/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..9822696 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_include/postgresql/stdlib/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A int32 + B int32 + C sql.NullInt32 +} diff --git a/internal/endtoend/testdata/ddl_create_table_include/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_create_table_include/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_include/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_table_include/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_create_table_include/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_include/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_table_include/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_create_table_include/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..db08b9d --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_include/postgresql/stdlib/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE foo ( + PRIMARY KEY (a, b) INCLUDE (c), + a integer, + b integer, + c integer +); diff --git a/internal/endtoend/testdata/ddl_create_table_include/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_create_table_include/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_include/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_table_inherits/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..5b533a6 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/go/models.go @@ -0,0 +1,36 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + + "github.com/google/uuid" +) + +type Llc struct { + PartyID uuid.UUID + Name string + LegalName string + IncorporationDate sql.NullTime +} + +type Organisation struct { + PartyID uuid.UUID + Name string + LegalName string +} + +type Party struct { + PartyID uuid.UUID + Name string +} + +type Person struct { + PartyID uuid.UUID + Name string + FirstName string + LastName string +} diff --git a/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..4e956ff --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,87 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAllOrganisations = `-- name: GetAllOrganisations :many +SELECT party_id, name, legal_name FROM organisation +` + +func (q *Queries) GetAllOrganisations(ctx context.Context) ([]Organisation, error) { + rows, err := q.db.Query(ctx, getAllOrganisations) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Organisation + for rows.Next() { + var i Organisation + if err := rows.Scan(&i.PartyID, &i.Name, &i.LegalName); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getAllParties = `-- name: GetAllParties :many +SELECT party_id, name FROM party +` + +func (q *Queries) GetAllParties(ctx context.Context) ([]Party, error) { + rows, err := q.db.Query(ctx, getAllParties) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Party + for rows.Next() { + var i Party + if err := rows.Scan(&i.PartyID, &i.Name); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getAllPeople = `-- name: GetAllPeople :many +SELECT party_id, name, first_name, last_name FROM person +` + +func (q *Queries) GetAllPeople(ctx context.Context) ([]Person, error) { + rows, err := q.db.Query(ctx, getAllPeople) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Person + for rows.Next() { + var i Person + if err := rows.Scan( + &i.PartyID, + &i.Name, + &i.FirstName, + &i.LastName, + ); 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/ddl_create_table_inherits/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..30adbd9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/query.sql @@ -0,0 +1,8 @@ +-- name: GetAllParties :many +SELECT * FROM party; + +-- name: GetAllPeople :many +SELECT * FROM person; + +-- name: GetAllOrganisations :many +SELECT * FROM organisation; diff --git a/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..2da6749 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/schema.sql @@ -0,0 +1,18 @@ +CREATE TABLE party ( + party_id uuid PRIMARY KEY, + name text NOT NULL +); + +CREATE TABLE person ( + first_name text NOT NULL, + last_name text NOT NULL +) INHERITS (party); + +CREATE TABLE organisation ( + legal_name text +) INHERITS (party); + +CREATE TABLE llc ( + incorporation_date timestamp, + legal_name text NOT NULL +) INHERITS (organisation); \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_table_inherits/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..dd50ec4 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/go/models.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Llc struct { + PartyID pgtype.UUID + Name string + LegalName string + IncorporationDate pgtype.Timestamp +} + +type Organisation struct { + PartyID pgtype.UUID + Name string + LegalName string +} + +type Party struct { + PartyID pgtype.UUID + Name string +} + +type Person struct { + PartyID pgtype.UUID + Name string + FirstName string + LastName string +} diff --git a/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..4e956ff --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,87 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAllOrganisations = `-- name: GetAllOrganisations :many +SELECT party_id, name, legal_name FROM organisation +` + +func (q *Queries) GetAllOrganisations(ctx context.Context) ([]Organisation, error) { + rows, err := q.db.Query(ctx, getAllOrganisations) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Organisation + for rows.Next() { + var i Organisation + if err := rows.Scan(&i.PartyID, &i.Name, &i.LegalName); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getAllParties = `-- name: GetAllParties :many +SELECT party_id, name FROM party +` + +func (q *Queries) GetAllParties(ctx context.Context) ([]Party, error) { + rows, err := q.db.Query(ctx, getAllParties) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Party + for rows.Next() { + var i Party + if err := rows.Scan(&i.PartyID, &i.Name); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getAllPeople = `-- name: GetAllPeople :many +SELECT party_id, name, first_name, last_name FROM person +` + +func (q *Queries) GetAllPeople(ctx context.Context) ([]Person, error) { + rows, err := q.db.Query(ctx, getAllPeople) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Person + for rows.Next() { + var i Person + if err := rows.Scan( + &i.PartyID, + &i.Name, + &i.FirstName, + &i.LastName, + ); 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/ddl_create_table_inherits/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..30adbd9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/query.sql @@ -0,0 +1,8 @@ +-- name: GetAllParties :many +SELECT * FROM party; + +-- name: GetAllPeople :many +SELECT * FROM person; + +-- name: GetAllOrganisations :many +SELECT * FROM organisation; diff --git a/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..2da6749 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/schema.sql @@ -0,0 +1,18 @@ +CREATE TABLE party ( + party_id uuid PRIMARY KEY, + name text NOT NULL +); + +CREATE TABLE person ( + first_name text NOT NULL, + last_name text NOT NULL +) INHERITS (party); + +CREATE TABLE organisation ( + legal_name text +) INHERITS (party); + +CREATE TABLE llc ( + incorporation_date timestamp, + legal_name text NOT NULL +) INHERITS (organisation); \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_table_inherits/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..5b533a6 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/go/models.go @@ -0,0 +1,36 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + + "github.com/google/uuid" +) + +type Llc struct { + PartyID uuid.UUID + Name string + LegalName string + IncorporationDate sql.NullTime +} + +type Organisation struct { + PartyID uuid.UUID + Name string + LegalName string +} + +type Party struct { + PartyID uuid.UUID + Name string +} + +type Person struct { + PartyID uuid.UUID + Name string + FirstName string + LastName string +} diff --git a/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..797e41c --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,96 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAllOrganisations = `-- name: GetAllOrganisations :many +SELECT party_id, name, legal_name FROM organisation +` + +func (q *Queries) GetAllOrganisations(ctx context.Context) ([]Organisation, error) { + rows, err := q.db.QueryContext(ctx, getAllOrganisations) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Organisation + for rows.Next() { + var i Organisation + if err := rows.Scan(&i.PartyID, &i.Name, &i.LegalName); 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 getAllParties = `-- name: GetAllParties :many +SELECT party_id, name FROM party +` + +func (q *Queries) GetAllParties(ctx context.Context) ([]Party, error) { + rows, err := q.db.QueryContext(ctx, getAllParties) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Party + for rows.Next() { + var i Party + if err := rows.Scan(&i.PartyID, &i.Name); 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 getAllPeople = `-- name: GetAllPeople :many +SELECT party_id, name, first_name, last_name FROM person +` + +func (q *Queries) GetAllPeople(ctx context.Context) ([]Person, error) { + rows, err := q.db.QueryContext(ctx, getAllPeople) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Person + for rows.Next() { + var i Person + if err := rows.Scan( + &i.PartyID, + &i.Name, + &i.FirstName, + &i.LastName, + ); 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/ddl_create_table_inherits/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/query.sql new file mode 100644 index 0000000..30adbd9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/query.sql @@ -0,0 +1,8 @@ +-- name: GetAllParties :many +SELECT * FROM party; + +-- name: GetAllPeople :many +SELECT * FROM person; + +-- name: GetAllOrganisations :many +SELECT * FROM organisation; diff --git a/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..2da6749 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/schema.sql @@ -0,0 +1,18 @@ +CREATE TABLE party ( + party_id uuid PRIMARY KEY, + name text NOT NULL +); + +CREATE TABLE person ( + first_name text NOT NULL, + last_name text NOT NULL +) INHERITS (party); + +CREATE TABLE organisation ( + legal_name text +) INHERITS (party); + +CREATE TABLE llc ( + incorporation_date timestamp, + legal_name text NOT NULL +) INHERITS (organisation); \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_table_invalid_inherits/postgresql/stdlib/exec.json b/internal/endtoend/testdata/ddl_create_table_invalid_inherits/postgresql/stdlib/exec.json new file mode 100644 index 0000000..c85ca2d --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_invalid_inherits/postgresql/stdlib/exec.json @@ -0,0 +1,6 @@ +{ + "contexts": ["base"], + "meta": { + "invalid_schema": true + } +} diff --git a/internal/endtoend/testdata/ddl_create_table_invalid_inherits/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_create_table_invalid_inherits/postgresql/stdlib/query.sql new file mode 100644 index 0000000..c7d9d23 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_invalid_inherits/postgresql/stdlib/query.sql @@ -0,0 +1,5 @@ +-- name: GetAllParties :many +SELECT * FROM party; + +-- name: GetAllOrganisations :many +SELECT * FROM organisation; diff --git a/internal/endtoend/testdata/ddl_create_table_invalid_inherits/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_create_table_invalid_inherits/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..4df1c04 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_invalid_inherits/postgresql/stdlib/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE party ( + name text NOT NULL +); + +CREATE TABLE organisation ( + name integer NOT NULL +) INHERITS (party); diff --git a/internal/endtoend/testdata/ddl_create_table_invalid_inherits/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_create_table_invalid_inherits/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_invalid_inherits/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_table_invalid_inherits/postgresql/stdlib/stderr.txt b/internal/endtoend/testdata/ddl_create_table_invalid_inherits/postgresql/stdlib/stderr.txt new file mode 100644 index 0000000..2e95325 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_invalid_inherits/postgresql/stdlib/stderr.txt @@ -0,0 +1,2 @@ +# package querytest +schema.sql:1:1: column "name" has a type conflict diff --git a/internal/endtoend/testdata/ddl_create_table_like/issue.md b/internal/endtoend/testdata/ddl_create_table_like/issue.md new file mode 100644 index 0000000..371a255 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_like/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/481 diff --git a/internal/endtoend/testdata/ddl_create_table_like/postgresql/pgx/go/db.go b/internal/endtoend/testdata/ddl_create_table_like/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_like/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_table_like/postgresql/pgx/go/models.go b/internal/endtoend/testdata/ddl_create_table_like/postgresql/pgx/go/models.go new file mode 100644 index 0000000..5c416bd --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_like/postgresql/pgx/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Change struct { + Ranked int32 +} + +type ChangesRanked struct { + Ranked int32 + RankByEffectSize int32 + RankByAbsPercentChange int32 +} diff --git a/internal/endtoend/testdata/ddl_create_table_like/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/ddl_create_table_like/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..c399414 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_like/postgresql/pgx/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const allRanked = `-- name: AllRanked :many +SELECT ranked, rank_by_effect_size, rank_by_abs_percent_change FROM changes_ranked +` + +func (q *Queries) AllRanked(ctx context.Context) ([]ChangesRanked, error) { + rows, err := q.db.Query(ctx, allRanked) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ChangesRanked + for rows.Next() { + var i ChangesRanked + if err := rows.Scan(&i.Ranked, &i.RankByEffectSize, &i.RankByAbsPercentChange); 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/ddl_create_table_like/postgresql/pgx/query.sql b/internal/endtoend/testdata/ddl_create_table_like/postgresql/pgx/query.sql new file mode 100644 index 0000000..759ef86 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_like/postgresql/pgx/query.sql @@ -0,0 +1,2 @@ +-- name: AllRanked :many +SELECT * FROM changes_ranked; diff --git a/internal/endtoend/testdata/ddl_create_table_like/postgresql/pgx/schema.sql b/internal/endtoend/testdata/ddl_create_table_like/postgresql/pgx/schema.sql new file mode 100644 index 0000000..7365737 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_like/postgresql/pgx/schema.sql @@ -0,0 +1,9 @@ +CREATE TABLE changes ( + ranked INT NOT NULL +); + +CREATE TABLE changes_ranked ( + LIKE changes INCLUDING ALL, + rank_by_effect_size INT NOT NULL, + rank_by_abs_percent_change INT NOT NULL +); diff --git a/internal/endtoend/testdata/ddl_create_table_like/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/ddl_create_table_like/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_like/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_table_partition/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a484580 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v4/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/google/uuid" +) + +type Foo struct { + ID uuid.UUID + OtherID uuid.UUID +} + +type Foo1 struct { + ID uuid.UUID + OtherID uuid.UUID +} diff --git a/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..928b130 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v4/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE foo ( + id uuid NOT NULL, + other_id uuid NOT NULL +) PARTITION BY HASH (other_id); + +CREATE TABLE foo_1 PARTITION OF foo FOR VALUES WITH (MODULUS 10, REMAINDER 0); diff --git a/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_table_partition/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..802b921 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v5/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + ID pgtype.UUID + OtherID pgtype.UUID +} + +type Foo1 struct { + ID pgtype.UUID + OtherID pgtype.UUID +} diff --git a/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..928b130 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v5/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE foo ( + id uuid NOT NULL, + other_id uuid NOT NULL +) PARTITION BY HASH (other_id); + +CREATE TABLE foo_1 PARTITION OF foo FOR VALUES WITH (MODULUS 10, REMAINDER 0); diff --git a/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_table_partition/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_table_partition/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a484580 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/stdlib/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/google/uuid" +) + +type Foo struct { + ID uuid.UUID + OtherID uuid.UUID +} + +type Foo1 struct { + ID uuid.UUID + OtherID uuid.UUID +} diff --git a/internal/endtoend/testdata/ddl_create_table_partition/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_table_partition/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_table_partition/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..928b130 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/stdlib/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE foo ( + id uuid NOT NULL, + other_id uuid NOT NULL +) PARTITION BY HASH (other_id); + +CREATE TABLE foo_1 PARTITION OF foo FOR VALUES WITH (MODULUS 10, REMAINDER 0); diff --git a/internal/endtoend/testdata/ddl_create_table_partition/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_partition/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_table_reserved/mysql/go/db.go b/internal/endtoend/testdata/ddl_create_table_reserved/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_reserved/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_table_reserved/mysql/go/models.go b/internal/endtoend/testdata/ddl_create_table_reserved/mysql/go/models.go new file mode 100644 index 0000000..7fce81d --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_reserved/mysql/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type XVenue struct { + Name sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_create_table_reserved/mysql/go/query.sql.go b/internal/endtoend/testdata/ddl_create_table_reserved/mysql/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_reserved/mysql/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_table_reserved/mysql/query.sql b/internal/endtoend/testdata/ddl_create_table_reserved/mysql/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_reserved/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_table_reserved/mysql/schema.sql b/internal/endtoend/testdata/ddl_create_table_reserved/mysql/schema.sql new file mode 100644 index 0000000..a7b4398 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_reserved/mysql/schema.sql @@ -0,0 +1 @@ +CREATE TABLE `x-venues` (name text); diff --git a/internal/endtoend/testdata/ddl_create_table_reserved/mysql/sqlc.json b/internal/endtoend/testdata/ddl_create_table_reserved/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_reserved/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/ddl_create_table_reserved/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_table_reserved/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..7fce81d --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v4/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type XVenue struct { + Name sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..28fff49 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v4/schema.sql @@ -0,0 +1 @@ +CREATE TABLE "x-venues" (name text); diff --git a/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_table_reserved/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..f11f67a --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v5/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type XVenue struct { + Name pgtype.Text +} diff --git a/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..28fff49 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v5/schema.sql @@ -0,0 +1 @@ +CREATE TABLE "x-venues" (name text); diff --git a/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_table_reserved/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..7fce81d --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/stdlib/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type XVenue struct { + Name sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..28fff49 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/stdlib/schema.sql @@ -0,0 +1 @@ +CREATE TABLE "x-venues" (name text); diff --git a/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_reserved/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_table_strict/sqlite/go/db.go b/internal/endtoend/testdata/ddl_create_table_strict/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_strict/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_table_strict/sqlite/go/models.go b/internal/endtoend/testdata/ddl_create_table_strict/sqlite/go/models.go new file mode 100644 index 0000000..a2d2dc1 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_strict/sqlite/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Venue struct { + Name sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_create_table_strict/sqlite/go/query.sql.go b/internal/endtoend/testdata/ddl_create_table_strict/sqlite/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_strict/sqlite/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_table_strict/sqlite/query.sql b/internal/endtoend/testdata/ddl_create_table_strict/sqlite/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_strict/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_table_strict/sqlite/schema.sql b/internal/endtoend/testdata/ddl_create_table_strict/sqlite/schema.sql new file mode 100644 index 0000000..368491e --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_strict/sqlite/schema.sql @@ -0,0 +1 @@ +CREATE TABLE venues (name text) STRICT; diff --git a/internal/endtoend/testdata/ddl_create_table_strict/sqlite/sqlc.json b/internal/endtoend/testdata/ddl_create_table_strict/sqlite/sqlc.json new file mode 100644 index 0000000..cd66df0 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_strict/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_table_unknown_type/issue.md b/internal/endtoend/testdata/ddl_create_table_unknown_type/issue.md new file mode 100644 index 0000000..39b617c --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_unknown_type/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1917 diff --git a/internal/endtoend/testdata/ddl_create_table_unknown_type/postgresql/pgx/exec.json b/internal/endtoend/testdata/ddl_create_table_unknown_type/postgresql/pgx/exec.json new file mode 100644 index 0000000..abd3ab5 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_unknown_type/postgresql/pgx/exec.json @@ -0,0 +1,6 @@ +{ + "contexts": ["unknown"], + "meta": { + "invalid_schema": true + } +} diff --git a/internal/endtoend/testdata/ddl_create_table_unknown_type/postgresql/pgx/query.sql b/internal/endtoend/testdata/ddl_create_table_unknown_type/postgresql/pgx/query.sql new file mode 100644 index 0000000..299eb45 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_unknown_type/postgresql/pgx/query.sql @@ -0,0 +1,2 @@ +-- name: SelectOne :one +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_table_unknown_type/postgresql/pgx/schema.sql b/internal/endtoend/testdata/ddl_create_table_unknown_type/postgresql/pgx/schema.sql new file mode 100644 index 0000000..70cd3cf --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_unknown_type/postgresql/pgx/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE test_table ( + id STRING +); diff --git a/internal/endtoend/testdata/ddl_create_table_unknown_type/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/ddl_create_table_unknown_type/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_unknown_type/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/ddl_create_table_unknown_type/postgresql/pgx/stderr.txt b/internal/endtoend/testdata/ddl_create_table_unknown_type/postgresql/pgx/stderr.txt new file mode 100644 index 0000000..2cfd3ba --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_unknown_type/postgresql/pgx/stderr.txt @@ -0,0 +1,5 @@ +# package querytest +query.sql:1:1: rpc error: code = FailedPrecondition desc = type "string" does not exist (42704) +CREATE TABLE test_table ( + id STRING +); diff --git a/internal/endtoend/testdata/ddl_create_table_without_rowid/sqlite/go/db.go b/internal/endtoend/testdata/ddl_create_table_without_rowid/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_without_rowid/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_table_without_rowid/sqlite/go/models.go b/internal/endtoend/testdata/ddl_create_table_without_rowid/sqlite/go/models.go new file mode 100644 index 0000000..2dff895 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_without_rowid/sqlite/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Arena struct { + Name string + Location sql.NullString + Size int64 +} diff --git a/internal/endtoend/testdata/ddl_create_table_without_rowid/sqlite/go/query.sql.go b/internal/endtoend/testdata/ddl_create_table_without_rowid/sqlite/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_without_rowid/sqlite/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_table_without_rowid/sqlite/query.sql b/internal/endtoend/testdata/ddl_create_table_without_rowid/sqlite/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_without_rowid/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_table_without_rowid/sqlite/schema.sql b/internal/endtoend/testdata/ddl_create_table_without_rowid/sqlite/schema.sql new file mode 100644 index 0000000..4a8bff7 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_without_rowid/sqlite/schema.sql @@ -0,0 +1 @@ +CREATE TABLE IF NOT EXISTS arenas (name text PRIMARY KEY, location text, size int NOT NULL) WITHOUT ROWID; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_create_table_without_rowid/sqlite/sqlc.json b/internal/endtoend/testdata/ddl_create_table_without_rowid/sqlite/sqlc.json new file mode 100644 index 0000000..cd66df0 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_table_without_rowid/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_trigger/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..198cfdf --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v4/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "time" + + "github.com/google/uuid" +) + +type TddTest struct { + TestID uuid.UUID + Title string + Descr string + TsCreated time.Time + TsUpdated time.Time +} diff --git a/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..d218ce9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v4/schema.sql @@ -0,0 +1,24 @@ +CREATE SCHEMA tdd; + +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; +CREATE EXTENSION IF NOT EXISTS pgcrypto + SCHEMA public + VERSION "1.3"; + +CREATE FUNCTION tdd.trigger_set_timestamp() RETURNS trigger +LANGUAGE plpgsql +AS $$BEGIN + NEW.ts_updated = NOW(); + RETURN NEW; +END; +$$; + +CREATE TABLE tdd.tests ( + test_id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, + title text DEFAULT ''::text NOT NULL, + descr text DEFAULT ''::text NOT NULL, + ts_created timestamp with time zone DEFAULT now() NOT NULL, + ts_updated timestamp with time zone DEFAULT now() NOT NULL +); + +CREATE TRIGGER set_timestamp BEFORE UPDATE ON tdd.tests FOR EACH ROW EXECUTE FUNCTION tdd.trigger_set_timestamp(); diff --git a/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_create_trigger/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..39e8dc7 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v5/go/models.go @@ -0,0 +1,17 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type TddTest struct { + TestID pgtype.UUID + Title string + Descr string + TsCreated pgtype.Timestamptz + TsUpdated pgtype.Timestamptz +} diff --git a/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..d218ce9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v5/schema.sql @@ -0,0 +1,24 @@ +CREATE SCHEMA tdd; + +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; +CREATE EXTENSION IF NOT EXISTS pgcrypto + SCHEMA public + VERSION "1.3"; + +CREATE FUNCTION tdd.trigger_set_timestamp() RETURNS trigger +LANGUAGE plpgsql +AS $$BEGIN + NEW.ts_updated = NOW(); + RETURN NEW; +END; +$$; + +CREATE TABLE tdd.tests ( + test_id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, + title text DEFAULT ''::text NOT NULL, + descr text DEFAULT ''::text NOT NULL, + ts_created timestamp with time zone DEFAULT now() NOT NULL, + ts_updated timestamp with time zone DEFAULT now() NOT NULL +); + +CREATE TRIGGER set_timestamp BEFORE UPDATE ON tdd.tests FOR EACH ROW EXECUTE FUNCTION tdd.trigger_set_timestamp(); diff --git a/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_trigger/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_trigger/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_create_trigger/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_trigger/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_trigger/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_create_trigger/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..198cfdf --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_trigger/postgresql/stdlib/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "time" + + "github.com/google/uuid" +) + +type TddTest struct { + TestID uuid.UUID + Title string + Descr string + TsCreated time.Time + TsUpdated time.Time +} diff --git a/internal/endtoend/testdata/ddl_create_trigger/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_create_trigger/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_trigger/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_trigger/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_create_trigger/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_trigger/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_trigger/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_create_trigger/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..d218ce9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_trigger/postgresql/stdlib/schema.sql @@ -0,0 +1,24 @@ +CREATE SCHEMA tdd; + +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; +CREATE EXTENSION IF NOT EXISTS pgcrypto + SCHEMA public + VERSION "1.3"; + +CREATE FUNCTION tdd.trigger_set_timestamp() RETURNS trigger +LANGUAGE plpgsql +AS $$BEGIN + NEW.ts_updated = NOW(); + RETURN NEW; +END; +$$; + +CREATE TABLE tdd.tests ( + test_id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, + title text DEFAULT ''::text NOT NULL, + descr text DEFAULT ''::text NOT NULL, + ts_created timestamp with time zone DEFAULT now() NOT NULL, + ts_updated timestamp with time zone DEFAULT now() NOT NULL +); + +CREATE TRIGGER set_timestamp BEFORE UPDATE ON tdd.tests FOR EACH ROW EXECUTE FUNCTION tdd.trigger_set_timestamp(); diff --git a/internal/endtoend/testdata/ddl_create_trigger/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_create_trigger/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_trigger/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_trigger/sqlite/go/db.go b/internal/endtoend/testdata/ddl_create_trigger/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_trigger/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_trigger/sqlite/go/models.go b/internal/endtoend/testdata/ddl_create_trigger/sqlite/go/models.go new file mode 100644 index 0000000..55be7fc --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_trigger/sqlite/go/models.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Customer struct { + CustID int64 + CustName sql.NullString + CustAddr sql.NullString +} + +type CustomerAddress struct { + CustID int64 + CustAddr sql.NullString +} + +type TriggerCustomer struct { + Name string + Address sql.NullString +} + +type TriggerOrder struct { + ID int64 + CustomerName sql.NullString + Address sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_create_trigger/sqlite/go/query.sql.go b/internal/endtoend/testdata/ddl_create_trigger/sqlite/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_trigger/sqlite/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_create_trigger/sqlite/query.sql b/internal/endtoend/testdata/ddl_create_trigger/sqlite/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_trigger/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_create_trigger/sqlite/schema.sql b/internal/endtoend/testdata/ddl_create_trigger/sqlite/schema.sql new file mode 100644 index 0000000..59df748 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_trigger/sqlite/schema.sql @@ -0,0 +1,32 @@ +/* examples copied from https://www.sqlite.org/lang_createtrigger.html + only expectation in sqlc is that they parse, codegen is unaffected */ + +CREATE TABLE trigger_customers ( + name TEXT PRIMARY KEY, + address TEXT +); + +CREATE TABLE trigger_orders ( + id INTEGER PRIMARY KEY, + customer_name TEXT, + address TEXT +); + +CREATE TRIGGER update_customer_address UPDATE OF address ON trigger_customers +BEGIN + UPDATE trigger_orders SET address = new.address WHERE customer_name = old.name; +END; + +CREATE TABLE customer( + cust_id INTEGER PRIMARY KEY, + cust_name TEXT, + cust_addr TEXT +); +CREATE VIEW customer_address AS +SELECT cust_id, cust_addr FROM customer; +CREATE TRIGGER cust_addr_chng + INSTEAD OF UPDATE OF cust_addr ON customer_address +BEGIN + UPDATE customer SET cust_addr=NEW.cust_addr + WHERE cust_id=NEW.cust_id; +END; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_create_trigger/sqlite/sqlc.json b/internal/endtoend/testdata/ddl_create_trigger/sqlite/sqlc.json new file mode 100644 index 0000000..cd66df0 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_trigger/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_function/mysql/README.md b/internal/endtoend/testdata/ddl_drop_function/mysql/README.md new file mode 100644 index 0000000..5fa2c9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function/mysql/README.md @@ -0,0 +1,2 @@ +The MySQL parser currently does not support user-defined functions. See +https://github.com/pingcap/parser/issues/988. diff --git a/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_drop_function/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..e88ec85 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE FUNCTION foo(bar text) RETURNS bool AS $$ SELECT true $$ LANGUAGE sql; +DROP FUNCTION foo; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_drop_function/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..e88ec85 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE FUNCTION foo(bar text) RETURNS bool AS $$ SELECT true $$ LANGUAGE sql; +DROP FUNCTION foo; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_function/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_drop_function/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_drop_function/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_drop_function/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_function/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_function/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_function/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_drop_function/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_function/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_drop_function/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..e88ec85 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE FUNCTION foo(bar text) RETURNS bool AS $$ SELECT true $$ LANGUAGE sql; +DROP FUNCTION foo; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_function/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_drop_function/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_function_args/mysql/README.md b/internal/endtoend/testdata/ddl_drop_function_args/mysql/README.md new file mode 100644 index 0000000..5fa2c9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_args/mysql/README.md @@ -0,0 +1,2 @@ +The MySQL parser currently does not support user-defined functions. See +https://github.com/pingcap/parser/issues/988. diff --git a/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_drop_function_args/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..7150d3d --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE FUNCTION foo(bar text) RETURNS bool AS $$ SELECT true $$ LANGUAGE sql; +DROP FUNCTION foo(text); \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_drop_function_args/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..7150d3d --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE FUNCTION foo(bar text) RETURNS bool AS $$ SELECT true $$ LANGUAGE sql; +DROP FUNCTION foo(text); \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_function_args/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_drop_function_args/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_function_args/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_function_args/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_function_args/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..7150d3d --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE FUNCTION foo(bar text) RETURNS bool AS $$ SELECT true $$ LANGUAGE sql; +DROP FUNCTION foo(text); \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_function_args/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_args/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_function_if_exists/mysql/README.md b/internal/endtoend/testdata/ddl_drop_function_if_exists/mysql/README.md new file mode 100644 index 0000000..5fa2c9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_if_exists/mysql/README.md @@ -0,0 +1,2 @@ +The MySQL parser currently does not support user-defined functions. See +https://github.com/pingcap/parser/issues/988. diff --git a/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_drop_function_if_exists/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..1265430 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +DROP FUNCTION IF EXISTS bar; +DROP FUNCTION IF EXISTS bar(); \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_drop_function_if_exists/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..1265430 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +DROP FUNCTION IF EXISTS bar; +DROP FUNCTION IF EXISTS bar(); \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_drop_function_if_exists/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..1265430 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +DROP FUNCTION IF EXISTS bar; +DROP FUNCTION IF EXISTS bar(); \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_function_if_exists/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_schema/mysql/exec.json b/internal/endtoend/testdata/ddl_drop_schema/mysql/exec.json new file mode 100644 index 0000000..c85ca2d --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/mysql/exec.json @@ -0,0 +1,6 @@ +{ + "contexts": ["base"], + "meta": { + "invalid_schema": true + } +} diff --git a/internal/endtoend/testdata/ddl_drop_schema/mysql/go/db.go b/internal/endtoend/testdata/ddl_drop_schema/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_drop_schema/mysql/go/models.go b/internal/endtoend/testdata/ddl_drop_schema/mysql/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/mysql/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_schema/mysql/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_schema/mysql/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/mysql/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_schema/mysql/query.sql b/internal/endtoend/testdata/ddl_drop_schema/mysql/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_schema/mysql/schema.sql b/internal/endtoend/testdata/ddl_drop_schema/mysql/schema.sql new file mode 100644 index 0000000..8553bb9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/mysql/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (baz text); +DROP SCHEMA foo; diff --git a/internal/endtoend/testdata/ddl_drop_schema/mysql/sqlc.json b/internal/endtoend/testdata/ddl_drop_schema/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/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/ddl_drop_schema/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_drop_schema/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..0b9d918 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (baz text); +DROP SCHEMA foo CASCADE; diff --git a/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_drop_schema/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..0b9d918 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (baz text); +DROP SCHEMA foo CASCADE; diff --git a/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_schema/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_drop_schema/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_drop_schema/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_drop_schema/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_schema/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_schema/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_schema/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_drop_schema/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_schema/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_drop_schema/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..0b9d918 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/postgresql/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (baz text); +DROP SCHEMA foo CASCADE; diff --git a/internal/endtoend/testdata/ddl_drop_schema/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_drop_schema/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_drop_schema_if_exists/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..f39997e --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v4/schema.sql @@ -0,0 +1 @@ +DROP SCHEMA IF EXISTS foo; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_drop_schema_if_exists/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..f39997e --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v5/schema.sql @@ -0,0 +1 @@ +DROP SCHEMA IF EXISTS foo; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_drop_schema_if_exists/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..f39997e --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/stdlib/schema.sql @@ -0,0 +1 @@ +DROP SCHEMA IF EXISTS foo; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_schema_if_exists/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_drop_table/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..4b50366 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE venues (); +DROP TABLE venues; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_drop_table/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..4b50366 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE venues (); +DROP TABLE venues; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_table/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_drop_table/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_drop_table/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_drop_table/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_table/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_table/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_table/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_drop_table/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_table/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_drop_table/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..4b50366 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE venues (); +DROP TABLE venues; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_table/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_drop_table/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_table/sqlite/go/db.go b/internal/endtoend/testdata/ddl_drop_table/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_drop_table/sqlite/go/models.go b/internal/endtoend/testdata/ddl_drop_table/sqlite/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table/sqlite/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_table/sqlite/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_table/sqlite/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table/sqlite/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_table/sqlite/query.sql b/internal/endtoend/testdata/ddl_drop_table/sqlite/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_table/sqlite/schema.sql b/internal/endtoend/testdata/ddl_drop_table/sqlite/schema.sql new file mode 100644 index 0000000..c0b8f00 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table/sqlite/schema.sql @@ -0,0 +1,8 @@ +CREATE TABLE venues (hi text); +DROP TABLE venues; + +CREATE TABLE Authors (id integer); +DROP TABLE Authors; + +CREATE TABLE "Books" (id integer); +DROP TABLE "Books"; diff --git a/internal/endtoend/testdata/ddl_drop_table/sqlite/sqlc.json b/internal/endtoend/testdata/ddl_drop_table/sqlite/sqlc.json new file mode 100644 index 0000000..cd66df0 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_drop_table_if_exists/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..ecaee7d --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE venues (); +DROP TABLE IF EXISTS venues; +DROP TABLE IF EXISTS venues; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_drop_table_if_exists/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..ecaee7d --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE venues (); +DROP TABLE IF EXISTS venues; +DROP TABLE IF EXISTS venues; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_drop_table_if_exists/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..ecaee7d --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE venues (); +DROP TABLE IF EXISTS venues; +DROP TABLE IF EXISTS venues; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_if_exists/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_table_if_exists/sqlite/go/db.go b/internal/endtoend/testdata/ddl_drop_table_if_exists/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_if_exists/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_drop_table_if_exists/sqlite/go/models.go b/internal/endtoend/testdata/ddl_drop_table_if_exists/sqlite/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_if_exists/sqlite/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_table_if_exists/sqlite/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_table_if_exists/sqlite/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_if_exists/sqlite/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_table_if_exists/sqlite/query.sql b/internal/endtoend/testdata/ddl_drop_table_if_exists/sqlite/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_if_exists/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_table_if_exists/sqlite/schema.sql b/internal/endtoend/testdata/ddl_drop_table_if_exists/sqlite/schema.sql new file mode 100644 index 0000000..3233bad --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_if_exists/sqlite/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE venues (hi text); +DROP TABLE IF EXISTS venues; +DROP TABLE IF EXISTS venues; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_table_if_exists/sqlite/sqlc.json b/internal/endtoend/testdata/ddl_drop_table_if_exists/sqlite/sqlc.json new file mode 100644 index 0000000..cd66df0 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_if_exists/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_drop_table_in_schema/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..7567dfb --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE venues (); +DROP TABLE public.venues; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_drop_table_in_schema/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..7567dfb --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE venues (); +DROP TABLE public.venues; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_drop_table_in_schema/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..7567dfb --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE venues (); +DROP TABLE public.venues; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_table_in_schema/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_drop_type/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..437084d --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TYPE status AS ENUM ('open', 'closed'); +DROP TYPE status; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_drop_type/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..437084d --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TYPE status AS ENUM ('open', 'closed'); +DROP TYPE status; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_type/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_drop_type/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_drop_type/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_drop_type/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_type/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_type/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_type/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_drop_type/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_type/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_drop_type/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..437084d --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TYPE status AS ENUM ('open', 'closed'); +DROP TYPE status; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_type/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_drop_type/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_drop_type_if_exists/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..8910499 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE TYPE status AS ENUM ('open', 'closed'); +DROP TYPE IF EXISTS status; +DROP TYPE IF EXISTS status; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_drop_type_if_exists/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..8910499 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE TYPE status AS ENUM ('open', 'closed'); +DROP TYPE IF EXISTS status; +DROP TYPE IF EXISTS status; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_drop_type_if_exists/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..8910499 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE TYPE status AS ENUM ('open', 'closed'); +DROP TYPE IF EXISTS status; +DROP TYPE IF EXISTS status; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_if_exists/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_drop_type_in_schema/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..902406e --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TYPE status AS ENUM ('open', 'closed'); +DROP TYPE public.status; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_drop_type_in_schema/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..902406e --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TYPE status AS ENUM ('open', 'closed'); +DROP TYPE public.status; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_drop_type_in_schema/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..902406e --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TYPE status AS ENUM ('open', 'closed'); +DROP TYPE public.status; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_drop_type_in_schema/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_generated_columns/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..7dda389 --- /dev/null +++ b/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v4/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Description struct { + ID string + Txt sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..8df3af6 --- /dev/null +++ b/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v4/schema.sql @@ -0,0 +1,5 @@ +create table descriptions ( + id varchar(32) GENERATED ALWAYS AS (MD5(txt)) STORED, + txt text, + primary key (id) +); diff --git a/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_generated_columns/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..dde43ee --- /dev/null +++ b/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Description struct { + ID string + Txt pgtype.Text +} diff --git a/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..8df3af6 --- /dev/null +++ b/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v5/schema.sql @@ -0,0 +1,5 @@ +create table descriptions ( + id varchar(32) GENERATED ALWAYS AS (MD5(txt)) STORED, + txt text, + primary key (id) +); diff --git a/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_generated_columns/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_generated_columns/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_generated_columns/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_generated_columns/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_generated_columns/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_generated_columns/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..7dda389 --- /dev/null +++ b/internal/endtoend/testdata/ddl_generated_columns/postgresql/stdlib/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Description struct { + ID string + Txt sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_generated_columns/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_generated_columns/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_generated_columns/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_generated_columns/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_generated_columns/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_generated_columns/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_generated_columns/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_generated_columns/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..8df3af6 --- /dev/null +++ b/internal/endtoend/testdata/ddl_generated_columns/postgresql/stdlib/schema.sql @@ -0,0 +1,5 @@ +create table descriptions ( + id varchar(32) GENERATED ALWAYS AS (MD5(txt)) STORED, + txt text, + primary key (id) +); diff --git a/internal/endtoend/testdata/ddl_generated_columns/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_generated_columns/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_generated_columns/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_materialized_views_invalid/issue.md b/internal/endtoend/testdata/ddl_materialized_views_invalid/issue.md new file mode 100644 index 0000000..21df2f0 --- /dev/null +++ b/internal/endtoend/testdata/ddl_materialized_views_invalid/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1545 diff --git a/internal/endtoend/testdata/ddl_materialized_views_invalid/postgresql/pgx/exec.json b/internal/endtoend/testdata/ddl_materialized_views_invalid/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/ddl_materialized_views_invalid/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/ddl_materialized_views_invalid/postgresql/pgx/query.sql b/internal/endtoend/testdata/ddl_materialized_views_invalid/postgresql/pgx/query.sql new file mode 100644 index 0000000..b9fa4a4 --- /dev/null +++ b/internal/endtoend/testdata/ddl_materialized_views_invalid/postgresql/pgx/query.sql @@ -0,0 +1,4 @@ +-- name: GetTotalEarned :one +SELECT COALESCE(SUM(earned), 0) as total_earned +FROM grouped_kpis +WHERE day = @day; diff --git a/internal/endtoend/testdata/ddl_materialized_views_invalid/postgresql/pgx/schema.sql b/internal/endtoend/testdata/ddl_materialized_views_invalid/postgresql/pgx/schema.sql new file mode 100644 index 0000000..d95036a --- /dev/null +++ b/internal/endtoend/testdata/ddl_materialized_views_invalid/postgresql/pgx/schema.sql @@ -0,0 +1,9 @@ +CREATE TABLE kpis ( + ts TIMESTAMPTZ, + event_id TEXT NOT NULL +); + +CREATE MATERIALIZED VIEW IF NOT EXISTS grouped_kpis AS +SELECT date_trunc('1 day', ts) as day, COUNT(*) +FROM kpis +GROUP BY 1; diff --git a/internal/endtoend/testdata/ddl_materialized_views_invalid/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/ddl_materialized_views_invalid/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/ddl_materialized_views_invalid/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/ddl_materialized_views_invalid/postgresql/pgx/stderr.txt b/internal/endtoend/testdata/ddl_materialized_views_invalid/postgresql/pgx/stderr.txt new file mode 100644 index 0000000..e796764 --- /dev/null +++ b/internal/endtoend/testdata/ddl_materialized_views_invalid/postgresql/pgx/stderr.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:2:21: column "earned" does not exist diff --git a/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_pg_temp/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..db5ec04 --- /dev/null +++ b/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v4/go/models.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type NewTable struct { + Val sql.NullInt32 +} + +type OldTable struct { + Val sql.NullInt32 +} + +type PgTempMigrate struct { + Val sql.NullInt32 +} diff --git a/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..c02d6df --- /dev/null +++ b/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v4/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE old_table (val SERIAL); +CREATE TABLE new_table (val SERIAL); +CREATE TABLE pg_temp.migrate (val SERIAL); +INSERT INTO pg_temp.migrate (val) SELECT val FROM old_table; +INSERT INTO new_table (val) SELECT val FROM pg_temp.migrate; diff --git a/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_pg_temp/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..146125b --- /dev/null +++ b/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v5/go/models.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type NewTable struct { + Val pgtype.Int4 +} + +type OldTable struct { + Val pgtype.Int4 +} + +type PgTempMigrate struct { + Val pgtype.Int4 +} diff --git a/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8a2db17 --- /dev/null +++ b/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..c02d6df --- /dev/null +++ b/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v5/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE old_table (val SERIAL); +CREATE TABLE new_table (val SERIAL); +CREATE TABLE pg_temp.migrate (val SERIAL); +INSERT INTO pg_temp.migrate (val) SELECT val FROM old_table; +INSERT INTO new_table (val) SELECT val FROM pg_temp.migrate; diff --git a/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ddl_pg_temp/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_pg_temp/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_pg_temp/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/ddl_pg_temp/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_pg_temp/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_pg_temp/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..db5ec04 --- /dev/null +++ b/internal/endtoend/testdata/ddl_pg_temp/postgresql/stdlib/go/models.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type NewTable struct { + Val sql.NullInt32 +} + +type OldTable struct { + Val sql.NullInt32 +} + +type PgTempMigrate struct { + Val sql.NullInt32 +} diff --git a/internal/endtoend/testdata/ddl_pg_temp/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_pg_temp/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/ddl_pg_temp/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_pg_temp/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_pg_temp/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/ddl_pg_temp/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_pg_temp/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_pg_temp/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..c02d6df --- /dev/null +++ b/internal/endtoend/testdata/ddl_pg_temp/postgresql/stdlib/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE old_table (val SERIAL); +CREATE TABLE new_table (val SERIAL); +CREATE TABLE pg_temp.migrate (val SERIAL); +INSERT INTO pg_temp.migrate (val) SELECT val FROM old_table; +INSERT INTO new_table (val) SELECT val FROM pg_temp.migrate; diff --git a/internal/endtoend/testdata/ddl_pg_temp/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_pg_temp/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_pg_temp/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_rename_drop_materialized_views/issue.md b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/issue.md new file mode 100644 index 0000000..6b8f89e --- /dev/null +++ b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/3371 \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/exec.json b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_rename_drop_materialized_views/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..508afef --- /dev/null +++ b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/go/models.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} + +type AuthorsMv struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..cb67855 --- /dev/null +++ b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,22 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAuthorMv = `-- name: GetAuthorMv :one +SELECT id, name, bio FROM authors_mv +WHERE id = $1 LIMIT 1 +` + +func (q *Queries) GetAuthorMv(ctx context.Context, id int64) (AuthorsMv, error) { + row := q.db.QueryRow(ctx, getAuthorMv, id) + var i AuthorsMv + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} diff --git a/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..752a6f4 --- /dev/null +++ b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/query.sql @@ -0,0 +1,3 @@ +-- name: GetAuthorMv :one +SELECT * FROM authors_mv +WHERE id = $1 LIMIT 1; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..3f88871 --- /dev/null +++ b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/schema.sql @@ -0,0 +1,18 @@ +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); + +CREATE MATERIALIZED VIEW authors_mv AS ( + SELECT * FROM authors +); + +CREATE MATERIALIZED VIEW authors_mv_new AS ( + SELECT * FROM authors +); + +ALTER MATERIALIZED VIEW authors_mv RENAME TO authors_mv_old; +ALTER MATERIALIZED VIEW authors_mv_new RENAME TO authors_mv; + +DROP MATERIALIZED VIEW authors_mv_old; diff --git a/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/sqlc.yaml b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/sqlc.yaml new file mode 100644 index 0000000..3440c3f --- /dev/null +++ b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v4/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v4" diff --git a/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/exec.json b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ddl_rename_drop_materialized_views/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..4340770 --- /dev/null +++ b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/go/models.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Author struct { + ID int64 + Name string + Bio pgtype.Text +} + +type AuthorsMv struct { + ID int64 + Name string + Bio pgtype.Text +} diff --git a/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..cb67855 --- /dev/null +++ b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,22 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAuthorMv = `-- name: GetAuthorMv :one +SELECT id, name, bio FROM authors_mv +WHERE id = $1 LIMIT 1 +` + +func (q *Queries) GetAuthorMv(ctx context.Context, id int64) (AuthorsMv, error) { + row := q.db.QueryRow(ctx, getAuthorMv, id) + var i AuthorsMv + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} diff --git a/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..752a6f4 --- /dev/null +++ b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/query.sql @@ -0,0 +1,3 @@ +-- name: GetAuthorMv :one +SELECT * FROM authors_mv +WHERE id = $1 LIMIT 1; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..3f88871 --- /dev/null +++ b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/schema.sql @@ -0,0 +1,18 @@ +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); + +CREATE MATERIALIZED VIEW authors_mv AS ( + SELECT * FROM authors +); + +CREATE MATERIALIZED VIEW authors_mv_new AS ( + SELECT * FROM authors +); + +ALTER MATERIALIZED VIEW authors_mv RENAME TO authors_mv_old; +ALTER MATERIALIZED VIEW authors_mv_new RENAME TO authors_mv; + +DROP MATERIALIZED VIEW authors_mv_old; diff --git a/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/sqlc.yaml b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/ddl_rename_drop_materialized_views/postgresql/pgx/v5/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/delete_from/mysql/go/db.go b/internal/endtoend/testdata/delete_from/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/delete_from/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/delete_from/mysql/go/models.go b/internal/endtoend/testdata/delete_from/mysql/go/models.go new file mode 100644 index 0000000..e954fe1 --- /dev/null +++ b/internal/endtoend/testdata/delete_from/mysql/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + ID string +} diff --git a/internal/endtoend/testdata/delete_from/mysql/go/query.sql.go b/internal/endtoend/testdata/delete_from/mysql/go/query.sql.go new file mode 100644 index 0000000..a314078 --- /dev/null +++ b/internal/endtoend/testdata/delete_from/mysql/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const deleteFrom = `-- name: DeleteFrom :exec +DELETE FROM foo WHERE id = ? +` + +func (q *Queries) DeleteFrom(ctx context.Context, id string) error { + _, err := q.db.ExecContext(ctx, deleteFrom, id) + return err +} diff --git a/internal/endtoend/testdata/delete_from/mysql/query.sql b/internal/endtoend/testdata/delete_from/mysql/query.sql new file mode 100644 index 0000000..b47bfc4 --- /dev/null +++ b/internal/endtoend/testdata/delete_from/mysql/query.sql @@ -0,0 +1,2 @@ +/* name: DeleteFrom :exec */ +DELETE FROM foo WHERE id = ?; diff --git a/internal/endtoend/testdata/delete_from/mysql/schema.sql b/internal/endtoend/testdata/delete_from/mysql/schema.sql new file mode 100644 index 0000000..1576c81 --- /dev/null +++ b/internal/endtoend/testdata/delete_from/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (id text not null); + diff --git a/internal/endtoend/testdata/delete_from/mysql/sqlc.json b/internal/endtoend/testdata/delete_from/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/delete_from/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/delete_from/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/delete_from/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/delete_from/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/delete_from/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/delete_from/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..e954fe1 --- /dev/null +++ b/internal/endtoend/testdata/delete_from/postgresql/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + ID string +} diff --git a/internal/endtoend/testdata/delete_from/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/delete_from/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..e23a77b --- /dev/null +++ b/internal/endtoend/testdata/delete_from/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const deleteFrom = `-- name: DeleteFrom :exec +DELETE FROM foo WHERE id = $1 +` + +func (q *Queries) DeleteFrom(ctx context.Context, id string) error { + _, err := q.db.Exec(ctx, deleteFrom, id) + return err +} diff --git a/internal/endtoend/testdata/delete_from/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/delete_from/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..ed305f4 --- /dev/null +++ b/internal/endtoend/testdata/delete_from/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: DeleteFrom :exec +DELETE FROM foo WHERE id = $1; diff --git a/internal/endtoend/testdata/delete_from/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/delete_from/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..1576c81 --- /dev/null +++ b/internal/endtoend/testdata/delete_from/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (id text not null); + diff --git a/internal/endtoend/testdata/delete_from/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/delete_from/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/delete_from/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/delete_from/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/delete_from/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/delete_from/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/delete_from/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/delete_from/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..e954fe1 --- /dev/null +++ b/internal/endtoend/testdata/delete_from/postgresql/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + ID string +} diff --git a/internal/endtoend/testdata/delete_from/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/delete_from/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..e23a77b --- /dev/null +++ b/internal/endtoend/testdata/delete_from/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const deleteFrom = `-- name: DeleteFrom :exec +DELETE FROM foo WHERE id = $1 +` + +func (q *Queries) DeleteFrom(ctx context.Context, id string) error { + _, err := q.db.Exec(ctx, deleteFrom, id) + return err +} diff --git a/internal/endtoend/testdata/delete_from/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/delete_from/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..ed305f4 --- /dev/null +++ b/internal/endtoend/testdata/delete_from/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: DeleteFrom :exec +DELETE FROM foo WHERE id = $1; diff --git a/internal/endtoend/testdata/delete_from/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/delete_from/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..1576c81 --- /dev/null +++ b/internal/endtoend/testdata/delete_from/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (id text not null); + diff --git a/internal/endtoend/testdata/delete_from/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/delete_from/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/delete_from/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/delete_from/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/delete_from/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/delete_from/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/delete_from/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/delete_from/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..e954fe1 --- /dev/null +++ b/internal/endtoend/testdata/delete_from/postgresql/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + ID string +} diff --git a/internal/endtoend/testdata/delete_from/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/delete_from/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..f489dfe --- /dev/null +++ b/internal/endtoend/testdata/delete_from/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const deleteFrom = `-- name: DeleteFrom :exec +DELETE FROM foo WHERE id = $1 +` + +func (q *Queries) DeleteFrom(ctx context.Context, id string) error { + _, err := q.db.ExecContext(ctx, deleteFrom, id) + return err +} diff --git a/internal/endtoend/testdata/delete_from/postgresql/stdlib/query.sql b/internal/endtoend/testdata/delete_from/postgresql/stdlib/query.sql new file mode 100644 index 0000000..ed305f4 --- /dev/null +++ b/internal/endtoend/testdata/delete_from/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: DeleteFrom :exec +DELETE FROM foo WHERE id = $1; diff --git a/internal/endtoend/testdata/delete_from/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/delete_from/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..1576c81 --- /dev/null +++ b/internal/endtoend/testdata/delete_from/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (id text not null); + diff --git a/internal/endtoend/testdata/delete_from/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/delete_from/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..cd51867 --- /dev/null +++ b/internal/endtoend/testdata/delete_from/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/delete_from/sqlite/go/db.go b/internal/endtoend/testdata/delete_from/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/delete_from/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/delete_from/sqlite/go/models.go b/internal/endtoend/testdata/delete_from/sqlite/go/models.go new file mode 100644 index 0000000..e954fe1 --- /dev/null +++ b/internal/endtoend/testdata/delete_from/sqlite/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + ID string +} diff --git a/internal/endtoend/testdata/delete_from/sqlite/go/query.sql.go b/internal/endtoend/testdata/delete_from/sqlite/go/query.sql.go new file mode 100644 index 0000000..a314078 --- /dev/null +++ b/internal/endtoend/testdata/delete_from/sqlite/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const deleteFrom = `-- name: DeleteFrom :exec +DELETE FROM foo WHERE id = ? +` + +func (q *Queries) DeleteFrom(ctx context.Context, id string) error { + _, err := q.db.ExecContext(ctx, deleteFrom, id) + return err +} diff --git a/internal/endtoend/testdata/delete_from/sqlite/query.sql b/internal/endtoend/testdata/delete_from/sqlite/query.sql new file mode 100644 index 0000000..c222adb --- /dev/null +++ b/internal/endtoend/testdata/delete_from/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: DeleteFrom :exec +DELETE FROM foo WHERE id = ?; diff --git a/internal/endtoend/testdata/delete_from/sqlite/schema.sql b/internal/endtoend/testdata/delete_from/sqlite/schema.sql new file mode 100644 index 0000000..15fe209 --- /dev/null +++ b/internal/endtoend/testdata/delete_from/sqlite/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (id text not null); diff --git a/internal/endtoend/testdata/delete_from/sqlite/sqlc.json b/internal/endtoend/testdata/delete_from/sqlite/sqlc.json new file mode 100644 index 0000000..1f9d43d --- /dev/null +++ b/internal/endtoend/testdata/delete_from/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "sqlite", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/delete_inner_join/mysql/go/db.go b/internal/endtoend/testdata/delete_inner_join/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/delete_inner_join/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/delete_inner_join/mysql/go/models.go b/internal/endtoend/testdata/delete_inner_join/mysql/go/models.go new file mode 100644 index 0000000..71cdddc --- /dev/null +++ b/internal/endtoend/testdata/delete_inner_join/mysql/go/models.go @@ -0,0 +1,20 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Author struct { + ID uint32 + Name string +} + +type AuthorBook struct { + AuthorID uint32 + BookID uint32 +} + +type Book struct { + ID uint32 + Title string +} diff --git a/internal/endtoend/testdata/delete_inner_join/mysql/go/query.sql.go b/internal/endtoend/testdata/delete_inner_join/mysql/go/query.sql.go new file mode 100644 index 0000000..9755fc0 --- /dev/null +++ b/internal/endtoend/testdata/delete_inner_join/mysql/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const removeAllAuthorsFromTheGreatGatsby = `-- name: RemoveAllAuthorsFromTheGreatGatsby :exec +DELETE author_book +FROM + author_book + INNER JOIN book ON book.id = author_book.book_id +WHERE + book.title = 'The Great Gatsby' +` + +func (q *Queries) RemoveAllAuthorsFromTheGreatGatsby(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, removeAllAuthorsFromTheGreatGatsby) + return err +} diff --git a/internal/endtoend/testdata/delete_inner_join/mysql/query.sql b/internal/endtoend/testdata/delete_inner_join/mysql/query.sql new file mode 100644 index 0000000..58f2747 --- /dev/null +++ b/internal/endtoend/testdata/delete_inner_join/mysql/query.sql @@ -0,0 +1,7 @@ +/* name: RemoveAllAuthorsFromTheGreatGatsby :exec */ +DELETE author_book +FROM + author_book + INNER JOIN book ON book.id = author_book.book_id +WHERE + book.title = 'The Great Gatsby'; \ No newline at end of file diff --git a/internal/endtoend/testdata/delete_inner_join/mysql/schema.sql b/internal/endtoend/testdata/delete_inner_join/mysql/schema.sql new file mode 100644 index 0000000..61c646b --- /dev/null +++ b/internal/endtoend/testdata/delete_inner_join/mysql/schema.sql @@ -0,0 +1,18 @@ +CREATE TABLE author ( + id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL +); + +CREATE TABLE book ( + id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + title VARCHAR(255) NOT NULL +); + +CREATE TABLE author_book ( + author_id INT UNSIGNED NOT NULL, + book_id INT UNSIGNED NOT NULL, + CONSTRAINT `pk-author_book` PRIMARY KEY (author_id, book_id), + CONSTRAINT `fk-author_book-author-id` FOREIGN KEY (author_id) REFERENCES author (id), + CONSTRAINT `fk-author_book-book-id` FOREIGN KEY (book_id) REFERENCES book (id) +); + diff --git a/internal/endtoend/testdata/delete_inner_join/mysql/sqlc.json b/internal/endtoend/testdata/delete_inner_join/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/delete_inner_join/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/delete_join/mysql/db/db.go b/internal/endtoend/testdata/delete_join/mysql/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/delete_join/mysql/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/delete_join/mysql/db/models.go b/internal/endtoend/testdata/delete_join/mysql/db/models.go new file mode 100644 index 0000000..73ac86f --- /dev/null +++ b/internal/endtoend/testdata/delete_join/mysql/db/models.go @@ -0,0 +1,17 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +type JoinTable struct { + ID uint64 + PrimaryTableID uint64 + OtherTableID uint64 + IsActive bool +} + +type PrimaryTable struct { + ID uint64 + UserID uint64 +} diff --git a/internal/endtoend/testdata/delete_join/mysql/db/query.sql.go b/internal/endtoend/testdata/delete_join/mysql/db/query.sql.go new file mode 100644 index 0000000..8af3119 --- /dev/null +++ b/internal/endtoend/testdata/delete_join/mysql/db/query.sql.go @@ -0,0 +1,84 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" +) + +const deleteJoin = `-- name: DeleteJoin :exec +DELETE jt.*, +pt.* +FROM + join_table as jt + JOIN primary_table as pt ON jt.primary_table_id = pt.id +WHERE + jt.id = ? + AND pt.user_id = ? +` + +type DeleteJoinParams struct { + ID uint64 + UserID uint64 +} + +func (q *Queries) DeleteJoin(ctx context.Context, arg DeleteJoinParams) error { + _, err := q.db.ExecContext(ctx, deleteJoin, arg.ID, arg.UserID) + return err +} + +const deleteJoinWithSubquery = `-- name: DeleteJoinWithSubquery :exec +DELETE pt +FROM primary_table pt +JOIN (SELECT 1 as id) jt ON pt.id = jt.id +` + +func (q *Queries) DeleteJoinWithSubquery(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, deleteJoinWithSubquery) + return err +} + +const deleteLeftJoin = `-- name: DeleteLeftJoin :exec +DELETE jt.*, +pt.* +FROM + join_table as jt + LEFT JOIN primary_table as pt ON jt.primary_table_id = pt.id +WHERE + jt.id = ? + AND pt.user_id = ? +` + +type DeleteLeftJoinParams struct { + ID uint64 + UserID uint64 +} + +func (q *Queries) DeleteLeftJoin(ctx context.Context, arg DeleteLeftJoinParams) error { + _, err := q.db.ExecContext(ctx, deleteLeftJoin, arg.ID, arg.UserID) + return err +} + +const deleteRightJoin = `-- name: DeleteRightJoin :exec +DELETE jt.*, +pt.* +FROM + join_table as jt + RIGHT JOIN primary_table as pt ON jt.primary_table_id = pt.id +WHERE + jt.id = ? + AND pt.user_id = ? +` + +type DeleteRightJoinParams struct { + ID uint64 + UserID uint64 +} + +func (q *Queries) DeleteRightJoin(ctx context.Context, arg DeleteRightJoinParams) error { + _, err := q.db.ExecContext(ctx, deleteRightJoin, arg.ID, arg.UserID) + return err +} diff --git a/internal/endtoend/testdata/delete_join/mysql/query.sql b/internal/endtoend/testdata/delete_join/mysql/query.sql new file mode 100644 index 0000000..d29062f --- /dev/null +++ b/internal/endtoend/testdata/delete_join/mysql/query.sql @@ -0,0 +1,34 @@ +-- name: DeleteJoin :exec +DELETE jt.*, +pt.* +FROM + join_table as jt + JOIN primary_table as pt ON jt.primary_table_id = pt.id +WHERE + jt.id = ? + AND pt.user_id = ?; + +-- name: DeleteLeftJoin :exec +DELETE jt.*, +pt.* +FROM + join_table as jt + LEFT JOIN primary_table as pt ON jt.primary_table_id = pt.id +WHERE + jt.id = ? + AND pt.user_id = ?; + +-- name: DeleteRightJoin :exec +DELETE jt.*, +pt.* +FROM + join_table as jt + RIGHT JOIN primary_table as pt ON jt.primary_table_id = pt.id +WHERE + jt.id = ? + AND pt.user_id = ?; + +-- name: DeleteJoinWithSubquery :exec +DELETE pt +FROM primary_table pt +JOIN (SELECT 1 as id) jt ON pt.id = jt.id; diff --git a/internal/endtoend/testdata/delete_join/mysql/schema.sql b/internal/endtoend/testdata/delete_join/mysql/schema.sql new file mode 100644 index 0000000..d0ec352 --- /dev/null +++ b/internal/endtoend/testdata/delete_join/mysql/schema.sql @@ -0,0 +1,14 @@ +CREATE TABLE primary_table ( + id bigint(20) unsigned NOT NULL AUTO_INCREMENT, + user_id bigint(20) unsigned NOT NULL, + PRIMARY KEY (id) +); + +CREATE TABLE join_table ( + id bigint(20) unsigned NOT NULL AUTO_INCREMENT, + primary_table_id bigint(20) unsigned NOT NULL, + other_table_id bigint(20) unsigned NOT NULL, + is_active tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (id) +); + diff --git a/internal/endtoend/testdata/delete_join/mysql/sqlc.json b/internal/endtoend/testdata/delete_join/mysql/sqlc.json new file mode 100644 index 0000000..4217706 --- /dev/null +++ b/internal/endtoend/testdata/delete_join/mysql/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "db", + "engine": "mysql", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/delete_using/issue.md b/internal/endtoend/testdata/delete_using/issue.md new file mode 100644 index 0000000..c3fc394 --- /dev/null +++ b/internal/endtoend/testdata/delete_using/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1714 diff --git a/internal/endtoend/testdata/delete_using/postgresql/pgx/exec.json b/internal/endtoend/testdata/delete_using/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/delete_using/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/delete_using/postgresql/pgx/go/db.go b/internal/endtoend/testdata/delete_using/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/delete_using/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/delete_using/postgresql/pgx/go/models.go b/internal/endtoend/testdata/delete_using/postgresql/pgx/go/models.go new file mode 100644 index 0000000..a0041d0 --- /dev/null +++ b/internal/endtoend/testdata/delete_using/postgresql/pgx/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type A struct { + AID pgtype.Text + BIDFk pgtype.Text +} + +type B struct { + BID pgtype.Text +} diff --git a/internal/endtoend/testdata/delete_using/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/delete_using/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..0e5ca9c --- /dev/null +++ b/internal/endtoend/testdata/delete_using/postgresql/pgx/go/query.sql.go @@ -0,0 +1,39 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const getSomeDeletedNotOk = `-- name: GetSomeDeletedNotOk :many +DELETE FROM a +USING b +WHERE a.b_id_fk = b.b_id +RETURNING b.b_id +` + +func (q *Queries) GetSomeDeletedNotOk(ctx context.Context) ([]pgtype.Text, error) { + rows, err := q.db.Query(ctx, getSomeDeletedNotOk) + if err != nil { + return nil, err + } + defer rows.Close() + var items []pgtype.Text + for rows.Next() { + var b_id pgtype.Text + if err := rows.Scan(&b_id); err != nil { + return nil, err + } + items = append(items, b_id) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/delete_using/postgresql/pgx/query.sql b/internal/endtoend/testdata/delete_using/postgresql/pgx/query.sql new file mode 100644 index 0000000..f660aaf --- /dev/null +++ b/internal/endtoend/testdata/delete_using/postgresql/pgx/query.sql @@ -0,0 +1,5 @@ +-- name: GetSomeDeletedNotOk :many +DELETE FROM a +USING b +WHERE a.b_id_fk = b.b_id +RETURNING b.b_id; -- column "b_id" does not exist diff --git a/internal/endtoend/testdata/delete_using/postgresql/pgx/schema.sql b/internal/endtoend/testdata/delete_using/postgresql/pgx/schema.sql new file mode 100644 index 0000000..d6380b7 --- /dev/null +++ b/internal/endtoend/testdata/delete_using/postgresql/pgx/schema.sql @@ -0,0 +1,9 @@ +CREATE TABLE a +( + a_id TEXT, + b_id_fk TEXT +); +CREATE TABLE b +( + b_id TEXT +); diff --git a/internal/endtoend/testdata/delete_using/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/delete_using/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/delete_using/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/diff_no_output/exec.json b/internal/endtoend/testdata/diff_no_output/exec.json new file mode 100644 index 0000000..699e10b --- /dev/null +++ b/internal/endtoend/testdata/diff_no_output/exec.json @@ -0,0 +1,3 @@ +{ + "command": "diff" +} diff --git a/internal/endtoend/testdata/diff_no_output/go/db.go b/internal/endtoend/testdata/diff_no_output/go/db.go new file mode 100644 index 0000000..32f660c --- /dev/null +++ b/internal/endtoend/testdata/diff_no_output/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package authors + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/diff_no_output/go/models.go b/internal/endtoend/testdata/diff_no_output/go/models.go new file mode 100644 index 0000000..806d699 --- /dev/null +++ b/internal/endtoend/testdata/diff_no_output/go/models.go @@ -0,0 +1,20 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package authors + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} + +type Book struct { + ID int64 + Title string +} diff --git a/internal/endtoend/testdata/diff_no_output/go/query.sql.go b/internal/endtoend/testdata/diff_no_output/go/query.sql.go new file mode 100644 index 0000000..0618853 --- /dev/null +++ b/internal/endtoend/testdata/diff_no_output/go/query.sql.go @@ -0,0 +1,83 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package authors + +import ( + "context" + "database/sql" +) + +const createAuthor = `-- name: CreateAuthor :one +INSERT INTO authors ( + name, bio +) VALUES ( + $1, $2 +) +RETURNING id, name, bio +` + +type CreateAuthorParams struct { + Name string + Bio sql.NullString +} + +func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (Author, error) { + row := q.db.QueryRowContext(ctx, createAuthor, arg.Name, arg.Bio) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, bio FROM authors +WHERE id = $1 LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name, bio FROM authors +ORDER BY bio +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); 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 selectOne = `-- name: SelectOne :one +SELECT 1 +` + +func (q *Queries) SelectOne(ctx context.Context) (int32, error) { + row := q.db.QueryRowContext(ctx, selectOne) + var column_1 int32 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/diff_no_output/query.sql b/internal/endtoend/testdata/diff_no_output/query.sql new file mode 100644 index 0000000..cc98eae --- /dev/null +++ b/internal/endtoend/testdata/diff_no_output/query.sql @@ -0,0 +1,18 @@ +-- name: GetAuthor :one +SELECT * FROM authors +WHERE id = $1 LIMIT 1; + +-- name: ListAuthors :many +SELECT * FROM authors +ORDER BY bio; + +-- name: SelectOne :one +SELECT 1; + +-- name: CreateAuthor :one +INSERT INTO authors ( + name, bio +) VALUES ( + $1, $2 +) +RETURNING *; diff --git a/internal/endtoend/testdata/diff_no_output/schema.sql b/internal/endtoend/testdata/diff_no_output/schema.sql new file mode 100644 index 0000000..baed2e0 --- /dev/null +++ b/internal/endtoend/testdata/diff_no_output/schema.sql @@ -0,0 +1,11 @@ +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); + +CREATE TABLE books ( + id BIGSERIAL PRIMARY KEY, + title text NOT NULL +); + diff --git a/internal/endtoend/testdata/diff_no_output/sqlc.json b/internal/endtoend/testdata/diff_no_output/sqlc.json new file mode 100644 index 0000000..3576609 --- /dev/null +++ b/internal/endtoend/testdata/diff_no_output/sqlc.json @@ -0,0 +1,16 @@ +{ + "version": "2", + "sql": [ + { + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql", + "gen": { + "go": { + "package": "authors", + "out": "go" + } + } + } + ] +} diff --git a/internal/endtoend/testdata/diff_output/exec.json b/internal/endtoend/testdata/diff_output/exec.json new file mode 100644 index 0000000..699e10b --- /dev/null +++ b/internal/endtoend/testdata/diff_output/exec.json @@ -0,0 +1,3 @@ +{ + "command": "diff" +} diff --git a/internal/endtoend/testdata/diff_output/go/db.go b/internal/endtoend/testdata/diff_output/go/db.go new file mode 100644 index 0000000..32f660c --- /dev/null +++ b/internal/endtoend/testdata/diff_output/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package authors + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/diff_output/go/models.go b/internal/endtoend/testdata/diff_output/go/models.go new file mode 100644 index 0000000..62bacd8 --- /dev/null +++ b/internal/endtoend/testdata/diff_output/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package authors + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/diff_output/go/query.sql.go b/internal/endtoend/testdata/diff_output/go/query.sql.go new file mode 100644 index 0000000..3024509 --- /dev/null +++ b/internal/endtoend/testdata/diff_output/go/query.sql.go @@ -0,0 +1,82 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package authors + +import ( + "context" + "database/sql" +) + +const createAuthor = `-- name: CreateAuthor :one +INSERT INTO authors ( + name, bio +) VALUES ( + $1, $2 +) +RETURNING id, name, bio +` + +type CreateAuthorParams struct { + Name string + Bio sql.NullString +} + +func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (Author, error) { + row := q.db.QueryRowContext(ctx, createAuthor, arg.Name, arg.Bio) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const deleteAuthor = `-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = $1 +` + +func (q *Queries) DeleteAuthor(ctx context.Context, id int64) error { + _, err := q.db.ExecContext(ctx, deleteAuthor, id) + return err +} + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, bio FROM authors +WHERE id = $1 LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name, bio FROM authors +ORDER BY name +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); 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/diff_output/query.sql b/internal/endtoend/testdata/diff_output/query.sql new file mode 100644 index 0000000..cc98eae --- /dev/null +++ b/internal/endtoend/testdata/diff_output/query.sql @@ -0,0 +1,18 @@ +-- name: GetAuthor :one +SELECT * FROM authors +WHERE id = $1 LIMIT 1; + +-- name: ListAuthors :many +SELECT * FROM authors +ORDER BY bio; + +-- name: SelectOne :one +SELECT 1; + +-- name: CreateAuthor :one +INSERT INTO authors ( + name, bio +) VALUES ( + $1, $2 +) +RETURNING *; diff --git a/internal/endtoend/testdata/diff_output/schema.sql b/internal/endtoend/testdata/diff_output/schema.sql new file mode 100644 index 0000000..baed2e0 --- /dev/null +++ b/internal/endtoend/testdata/diff_output/schema.sql @@ -0,0 +1,11 @@ +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); + +CREATE TABLE books ( + id BIGSERIAL PRIMARY KEY, + title text NOT NULL +); + diff --git a/internal/endtoend/testdata/diff_output/sqlc.json b/internal/endtoend/testdata/diff_output/sqlc.json new file mode 100644 index 0000000..3576609 --- /dev/null +++ b/internal/endtoend/testdata/diff_output/sqlc.json @@ -0,0 +1,16 @@ +{ + "version": "2", + "sql": [ + { + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql", + "gen": { + "go": { + "package": "authors", + "out": "go" + } + } + } + ] +} diff --git a/internal/endtoend/testdata/diff_output/stderr.txt b/internal/endtoend/testdata/diff_output/stderr.txt new file mode 100644 index 0000000..e7e4554 --- /dev/null +++ b/internal/endtoend/testdata/diff_output/stderr.txt @@ -0,0 +1,55 @@ +--- a/go/models.go ++++ b/go/models.go +@@ -13,3 +13,8 @@ + Name string + Bio sql.NullString + } ++ ++type Book struct { ++ ID int64 ++ Title string ++} +--- a/go/query.sql.go ++++ b/go/query.sql.go +@@ -31,16 +31,6 @@ + return i, err + } + +-const deleteAuthor = `-- name: DeleteAuthor :exec +-DELETE FROM authors +-WHERE id = $1 +-` +- +-func (q *Queries) DeleteAuthor(ctx context.Context, id int64) error { +- _, err := q.db.ExecContext(ctx, deleteAuthor, id) +- return err +-} +- + const getAuthor = `-- name: GetAuthor :one + SELECT id, name, bio FROM authors + WHERE id = $1 LIMIT 1 +@@ -55,7 +45,7 @@ + + const listAuthors = `-- name: ListAuthors :many + SELECT id, name, bio FROM authors ++ORDER BY bio +-ORDER BY name + ` + + func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { +@@ -80,3 +70,14 @@ + } + return items, nil + } ++ ++const selectOne = `-- name: SelectOne :one ++SELECT 1 ++` ++ ++func (q *Queries) SelectOne(ctx context.Context) (int32, error) { ++ row := q.db.QueryRowContext(ctx, selectOne) ++ var column_1 int32 ++ err := row.Scan(&column_1) ++ return column_1, err ++} + diff --git a/internal/endtoend/testdata/do/postgresql/pgx/db/db.go b/internal/endtoend/testdata/do/postgresql/pgx/db/db.go new file mode 100644 index 0000000..42578b7 --- /dev/null +++ b/internal/endtoend/testdata/do/postgresql/pgx/db/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/do/postgresql/pgx/db/models.go b/internal/endtoend/testdata/do/postgresql/pgx/db/models.go new file mode 100644 index 0000000..761ab0c --- /dev/null +++ b/internal/endtoend/testdata/do/postgresql/pgx/db/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Author struct { + ID int64 + Name string + Bio pgtype.Text +} diff --git a/internal/endtoend/testdata/do/postgresql/pgx/db/query.sql.go b/internal/endtoend/testdata/do/postgresql/pgx/db/query.sql.go new file mode 100644 index 0000000..06e1c1e --- /dev/null +++ b/internal/endtoend/testdata/do/postgresql/pgx/db/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" +) + +const doStuff = `-- name: DoStuff :exec +DO $$ + BEGIN + ALTER TABLE authors + ADD COLUMN marked_for_processing bool; + END +$$ +` + +func (q *Queries) DoStuff(ctx context.Context) error { + _, err := q.db.Exec(ctx, doStuff) + return err +} diff --git a/internal/endtoend/testdata/do/postgresql/pgx/query.sql b/internal/endtoend/testdata/do/postgresql/pgx/query.sql new file mode 100644 index 0000000..26a790d --- /dev/null +++ b/internal/endtoend/testdata/do/postgresql/pgx/query.sql @@ -0,0 +1,7 @@ +-- name: DoStuff :exec +DO $$ + BEGIN + ALTER TABLE authors + ADD COLUMN marked_for_processing bool; + END +$$; diff --git a/internal/endtoend/testdata/do/postgresql/pgx/schema.sql b/internal/endtoend/testdata/do/postgresql/pgx/schema.sql new file mode 100644 index 0000000..69b607d --- /dev/null +++ b/internal/endtoend/testdata/do/postgresql/pgx/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/do/postgresql/pgx/sqlc.json b/internal/endtoend/testdata/do/postgresql/pgx/sqlc.json new file mode 100644 index 0000000..b74a2ef --- /dev/null +++ b/internal/endtoend/testdata/do/postgresql/pgx/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "db", + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "sql_package": "pgx/v5" + } + ] +} diff --git a/internal/endtoend/testdata/do/postgresql/pq/db/db.go b/internal/endtoend/testdata/do/postgresql/pq/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/do/postgresql/pq/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/do/postgresql/pq/db/models.go b/internal/endtoend/testdata/do/postgresql/pq/db/models.go new file mode 100644 index 0000000..56c9d4a --- /dev/null +++ b/internal/endtoend/testdata/do/postgresql/pq/db/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/do/postgresql/pq/db/query.sql.go b/internal/endtoend/testdata/do/postgresql/pq/db/query.sql.go new file mode 100644 index 0000000..5d7824c --- /dev/null +++ b/internal/endtoend/testdata/do/postgresql/pq/db/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" +) + +const doStuff = `-- name: DoStuff :exec +DO $$ + BEGIN + ALTER TABLE authors + ADD COLUMN marked_for_processing bool; + END +$$ +` + +func (q *Queries) DoStuff(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, doStuff) + return err +} diff --git a/internal/endtoend/testdata/do/postgresql/pq/query.sql b/internal/endtoend/testdata/do/postgresql/pq/query.sql new file mode 100644 index 0000000..26a790d --- /dev/null +++ b/internal/endtoend/testdata/do/postgresql/pq/query.sql @@ -0,0 +1,7 @@ +-- name: DoStuff :exec +DO $$ + BEGIN + ALTER TABLE authors + ADD COLUMN marked_for_processing bool; + END +$$; diff --git a/internal/endtoend/testdata/do/postgresql/pq/schema.sql b/internal/endtoend/testdata/do/postgresql/pq/schema.sql new file mode 100644 index 0000000..69b607d --- /dev/null +++ b/internal/endtoend/testdata/do/postgresql/pq/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/do/postgresql/pq/sqlc.json b/internal/endtoend/testdata/do/postgresql/pq/sqlc.json new file mode 100644 index 0000000..2a46100 --- /dev/null +++ b/internal/endtoend/testdata/do/postgresql/pq/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "db", + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/duplicate_go_names/enum/query.sql b/internal/endtoend/testdata/duplicate_go_names/enum/query.sql new file mode 100644 index 0000000..760e825 --- /dev/null +++ b/internal/endtoend/testdata/duplicate_go_names/enum/query.sql @@ -0,0 +1,2 @@ +-- name: GetFoos :many +SELECT * FROM foos; \ No newline at end of file diff --git a/internal/endtoend/testdata/duplicate_go_names/enum/schema.sql b/internal/endtoend/testdata/duplicate_go_names/enum/schema.sql new file mode 100644 index 0000000..d0ac445 --- /dev/null +++ b/internal/endtoend/testdata/duplicate_go_names/enum/schema.sql @@ -0,0 +1,3 @@ +CREATE TYPE foo AS ENUM (); + +CREATE TABLE foos (); \ No newline at end of file diff --git a/internal/endtoend/testdata/duplicate_go_names/enum/sqlc.yaml b/internal/endtoend/testdata/duplicate_go_names/enum/sqlc.yaml new file mode 100644 index 0000000..48946b0 --- /dev/null +++ b/internal/endtoend/testdata/duplicate_go_names/enum/sqlc.yaml @@ -0,0 +1,8 @@ +version: "2" +sql: +- schema: "schema.sql" + queries: "query.sql" + engine: "postgresql" + gen: + go: + out: "db" diff --git a/internal/endtoend/testdata/duplicate_go_names/enum/stderr.txt b/internal/endtoend/testdata/duplicate_go_names/enum/stderr.txt new file mode 100644 index 0000000..e6d206b --- /dev/null +++ b/internal/endtoend/testdata/duplicate_go_names/enum/stderr.txt @@ -0,0 +1,2 @@ +# package +error generating code: struct name conflicts with enum name: Foo diff --git a/internal/endtoend/testdata/duplicate_go_names/null_enum/query.sql b/internal/endtoend/testdata/duplicate_go_names/null_enum/query.sql new file mode 100644 index 0000000..fcb2e75 --- /dev/null +++ b/internal/endtoend/testdata/duplicate_go_names/null_enum/query.sql @@ -0,0 +1,2 @@ +-- name: GetFoos :many +SELECT * FROM null_foos; \ No newline at end of file diff --git a/internal/endtoend/testdata/duplicate_go_names/null_enum/schema.sql b/internal/endtoend/testdata/duplicate_go_names/null_enum/schema.sql new file mode 100644 index 0000000..46fe734 --- /dev/null +++ b/internal/endtoend/testdata/duplicate_go_names/null_enum/schema.sql @@ -0,0 +1,3 @@ +CREATE TYPE foo AS ENUM (); + +CREATE TABLE null_foos (); \ No newline at end of file diff --git a/internal/endtoend/testdata/duplicate_go_names/null_enum/sqlc.yaml b/internal/endtoend/testdata/duplicate_go_names/null_enum/sqlc.yaml new file mode 100644 index 0000000..48946b0 --- /dev/null +++ b/internal/endtoend/testdata/duplicate_go_names/null_enum/sqlc.yaml @@ -0,0 +1,8 @@ +version: "2" +sql: +- schema: "schema.sql" + queries: "query.sql" + engine: "postgresql" + gen: + go: + out: "db" diff --git a/internal/endtoend/testdata/duplicate_go_names/null_enum/stderr.txt b/internal/endtoend/testdata/duplicate_go_names/null_enum/stderr.txt new file mode 100644 index 0000000..16321a0 --- /dev/null +++ b/internal/endtoend/testdata/duplicate_go_names/null_enum/stderr.txt @@ -0,0 +1,2 @@ +# package +error generating code: struct name conflicts with enum name: NullFoo diff --git a/internal/endtoend/testdata/duplicate_go_names/query_constant/query.sql b/internal/endtoend/testdata/duplicate_go_names/query_constant/query.sql new file mode 100644 index 0000000..fc3436d --- /dev/null +++ b/internal/endtoend/testdata/duplicate_go_names/query_constant/query.sql @@ -0,0 +1,2 @@ +-- name: Foo :one +SELECT 1; \ No newline at end of file diff --git a/internal/endtoend/testdata/duplicate_go_names/query_constant/schema.sql b/internal/endtoend/testdata/duplicate_go_names/query_constant/schema.sql new file mode 100644 index 0000000..a0ed9c3 --- /dev/null +++ b/internal/endtoend/testdata/duplicate_go_names/query_constant/schema.sql @@ -0,0 +1 @@ +CREATE TYPE foo AS ENUM (); diff --git a/internal/endtoend/testdata/duplicate_go_names/query_constant/sqlc.yaml b/internal/endtoend/testdata/duplicate_go_names/query_constant/sqlc.yaml new file mode 100644 index 0000000..e631428 --- /dev/null +++ b/internal/endtoend/testdata/duplicate_go_names/query_constant/sqlc.yaml @@ -0,0 +1,9 @@ +version: "2" +sql: +- schema: "schema.sql" + queries: "query.sql" + engine: "postgresql" + gen: + go: + out: "db" + emit_exported_queries: true diff --git a/internal/endtoend/testdata/duplicate_go_names/query_constant/stderr.txt b/internal/endtoend/testdata/duplicate_go_names/query_constant/stderr.txt new file mode 100644 index 0000000..1a9b5f8 --- /dev/null +++ b/internal/endtoend/testdata/duplicate_go_names/query_constant/stderr.txt @@ -0,0 +1,2 @@ +# package +error generating code: query constant name conflicts with enum name: Foo diff --git a/internal/endtoend/testdata/emit_db_and_json_tags/mysql/go/db.go b/internal/endtoend/testdata/emit_db_and_json_tags/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/emit_db_and_json_tags/mysql/go/models.go b/internal/endtoend/testdata/emit_db_and_json_tags/mysql/go/models.go new file mode 100644 index 0000000..e6bbb97 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/mysql/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID int32 `db:"id" json:"id"` + FirstName string `db:"first_name" json:"first_name"` + LastName sql.NullString `db:"last_name" json:"last_name"` + Age int32 `db:"age" json:"age"` +} diff --git a/internal/endtoend/testdata/emit_db_and_json_tags/mysql/go/query.sql.go b/internal/endtoend/testdata/emit_db_and_json_tags/mysql/go/query.sql.go new file mode 100644 index 0000000..f589654 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/mysql/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]User, error) { + rows, err := q.db.QueryContext(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + ); 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/emit_db_and_json_tags/mysql/query.sql b/internal/endtoend/testdata/emit_db_and_json_tags/mysql/query.sql new file mode 100644 index 0000000..e2f85e2 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/mysql/query.sql @@ -0,0 +1,2 @@ +/* name: GetAll :many */ +SELECT * FROM users; diff --git a/internal/endtoend/testdata/emit_db_and_json_tags/mysql/schema.sql b/internal/endtoend/testdata/emit_db_and_json_tags/mysql/schema.sql new file mode 100644 index 0000000..3e36d6c --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/mysql/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + id integer NOT NULL AUTO_INCREMENT PRIMARY KEY, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL +); diff --git a/internal/endtoend/testdata/emit_db_and_json_tags/mysql/sqlc.json b/internal/endtoend/testdata/emit_db_and_json_tags/mysql/sqlc.json new file mode 100644 index 0000000..5eba7ce --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/mysql/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "schema.sql", + "queries": "query.sql", + "engine": "mysql", + "emit_json_tags": true, + "emit_db_tags": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/emit_db_and_json_tags/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..e6bbb97 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v4/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID int32 `db:"id" json:"id"` + FirstName string `db:"first_name" json:"first_name"` + LastName sql.NullString `db:"last_name" json:"last_name"` + Age int32 `db:"age" json:"age"` +} diff --git a/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..aa7c5c0 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,39 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]User, error) { + rows, err := q.db.Query(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + ); 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/emit_db_and_json_tags/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..237b201 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: GetAll :many +SELECT * FROM users; diff --git a/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..ae8e46e --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v4/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + id integer NOT NULL GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL +); diff --git a/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..c74e245 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,15 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_json_tags": true, + "emit_db_tags": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/emit_db_and_json_tags/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..7272c08 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v5/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type User struct { + ID int32 `db:"id" json:"id"` + FirstName string `db:"first_name" json:"first_name"` + LastName pgtype.Text `db:"last_name" json:"last_name"` + Age int32 `db:"age" json:"age"` +} diff --git a/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..aa7c5c0 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,39 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]User, error) { + rows, err := q.db.Query(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + ); 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/emit_db_and_json_tags/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..237b201 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: GetAll :many +SELECT * FROM users; diff --git a/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..ae8e46e --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v5/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + id integer NOT NULL GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL +); diff --git a/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..22dee5d --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,15 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_json_tags": true, + "emit_db_tags": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/emit_db_and_json_tags/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..e6bbb97 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/stdlib/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID int32 `db:"id" json:"id"` + FirstName string `db:"first_name" json:"first_name"` + LastName sql.NullString `db:"last_name" json:"last_name"` + Age int32 `db:"age" json:"age"` +} diff --git a/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..f589654 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]User, error) { + rows, err := q.db.QueryContext(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + ); 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/emit_db_and_json_tags/postgresql/stdlib/query.sql b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/stdlib/query.sql new file mode 100644 index 0000000..237b201 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: GetAll :many +SELECT * FROM users; diff --git a/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..ae8e46e --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/stdlib/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + id integer NOT NULL GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL +); diff --git a/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..45dbdc4 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/postgresql/stdlib/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_json_tags": true, + "emit_db_tags": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_db_and_json_tags/sqlite/go/db.go b/internal/endtoend/testdata/emit_db_and_json_tags/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/emit_db_and_json_tags/sqlite/go/models.go b/internal/endtoend/testdata/emit_db_and_json_tags/sqlite/go/models.go new file mode 100644 index 0000000..7d1ef96 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/sqlite/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID int64 `db:"id" json:"id"` + FirstName string `db:"first_name" json:"first_name"` + LastName sql.NullString `db:"last_name" json:"last_name"` + Age int64 `db:"age" json:"age"` +} diff --git a/internal/endtoend/testdata/emit_db_and_json_tags/sqlite/go/query.sql.go b/internal/endtoend/testdata/emit_db_and_json_tags/sqlite/go/query.sql.go new file mode 100644 index 0000000..f589654 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/sqlite/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]User, error) { + rows, err := q.db.QueryContext(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + ); 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/emit_db_and_json_tags/sqlite/query.sql b/internal/endtoend/testdata/emit_db_and_json_tags/sqlite/query.sql new file mode 100644 index 0000000..e2f85e2 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/sqlite/query.sql @@ -0,0 +1,2 @@ +/* name: GetAll :many */ +SELECT * FROM users; diff --git a/internal/endtoend/testdata/emit_db_and_json_tags/sqlite/schema.sql b/internal/endtoend/testdata/emit_db_and_json_tags/sqlite/schema.sql new file mode 100644 index 0000000..86b83a3 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/sqlite/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + id integer NOT NULL PRIMARY KEY, + first_name varchar NOT NULL, + last_name varchar, + age integer NOT NULL +); diff --git a/internal/endtoend/testdata/emit_db_and_json_tags/sqlite/sqlc.json b/internal/endtoend/testdata/emit_db_and_json_tags/sqlite/sqlc.json new file mode 100644 index 0000000..83a15e2 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_and_json_tags/sqlite/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "schema.sql", + "queries": "query.sql", + "engine": "sqlite", + "emit_json_tags": true, + "emit_db_tags": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_db_tags/mysql/go/db.go b/internal/endtoend/testdata/emit_db_tags/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/emit_db_tags/mysql/go/models.go b/internal/endtoend/testdata/emit_db_tags/mysql/go/models.go new file mode 100644 index 0000000..6485f84 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/mysql/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID int32 `db:"id"` + FirstName string `db:"first_name"` + LastName sql.NullString `db:"last_name"` + Age int32 `db:"age"` +} diff --git a/internal/endtoend/testdata/emit_db_tags/mysql/go/query.sql.go b/internal/endtoend/testdata/emit_db_tags/mysql/go/query.sql.go new file mode 100644 index 0000000..f589654 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/mysql/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]User, error) { + rows, err := q.db.QueryContext(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + ); 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/emit_db_tags/mysql/query.sql b/internal/endtoend/testdata/emit_db_tags/mysql/query.sql new file mode 100644 index 0000000..e2f85e2 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/mysql/query.sql @@ -0,0 +1,2 @@ +/* name: GetAll :many */ +SELECT * FROM users; diff --git a/internal/endtoend/testdata/emit_db_tags/mysql/schema.sql b/internal/endtoend/testdata/emit_db_tags/mysql/schema.sql new file mode 100644 index 0000000..3e36d6c --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/mysql/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + id integer NOT NULL AUTO_INCREMENT PRIMARY KEY, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL +); diff --git a/internal/endtoend/testdata/emit_db_tags/mysql/sqlc.json b/internal/endtoend/testdata/emit_db_tags/mysql/sqlc.json new file mode 100644 index 0000000..bf24f26 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/mysql/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "schema.sql", + "queries": "query.sql", + "engine": "mysql", + "emit_db_tags": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/emit_db_tags/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..6485f84 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v4/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID int32 `db:"id"` + FirstName string `db:"first_name"` + LastName sql.NullString `db:"last_name"` + Age int32 `db:"age"` +} diff --git a/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..aa7c5c0 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,39 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]User, error) { + rows, err := q.db.Query(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + ); 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/emit_db_tags/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..237b201 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: GetAll :many +SELECT * FROM users; diff --git a/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..ae8e46e --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v4/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + id integer NOT NULL GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL +); diff --git a/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..a96cd6d --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_db_tags": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/emit_db_tags/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..80b0b6d --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v5/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type User struct { + ID int32 `db:"id"` + FirstName string `db:"first_name"` + LastName pgtype.Text `db:"last_name"` + Age int32 `db:"age"` +} diff --git a/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..aa7c5c0 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,39 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]User, error) { + rows, err := q.db.Query(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + ); 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/emit_db_tags/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..237b201 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: GetAll :many +SELECT * FROM users; diff --git a/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..ae8e46e --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v5/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + id integer NOT NULL GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL +); diff --git a/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..c24ba08 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_db_tags": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_db_tags/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/emit_db_tags/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/emit_db_tags/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/emit_db_tags/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..6485f84 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/postgresql/stdlib/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID int32 `db:"id"` + FirstName string `db:"first_name"` + LastName sql.NullString `db:"last_name"` + Age int32 `db:"age"` +} diff --git a/internal/endtoend/testdata/emit_db_tags/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/emit_db_tags/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..f589654 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]User, error) { + rows, err := q.db.QueryContext(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + ); 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/emit_db_tags/postgresql/stdlib/query.sql b/internal/endtoend/testdata/emit_db_tags/postgresql/stdlib/query.sql new file mode 100644 index 0000000..237b201 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: GetAll :many +SELECT * FROM users; diff --git a/internal/endtoend/testdata/emit_db_tags/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/emit_db_tags/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..ae8e46e --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/postgresql/stdlib/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + id integer NOT NULL GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL +); diff --git a/internal/endtoend/testdata/emit_db_tags/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/emit_db_tags/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..98122fb --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/postgresql/stdlib/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_db_tags": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_db_tags/sqlite/go/db.go b/internal/endtoend/testdata/emit_db_tags/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/emit_db_tags/sqlite/go/models.go b/internal/endtoend/testdata/emit_db_tags/sqlite/go/models.go new file mode 100644 index 0000000..983baf7 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/sqlite/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID int64 `db:"id"` + FirstName string `db:"first_name"` + LastName sql.NullString `db:"last_name"` + Age int64 `db:"age"` +} diff --git a/internal/endtoend/testdata/emit_db_tags/sqlite/go/query.sql.go b/internal/endtoend/testdata/emit_db_tags/sqlite/go/query.sql.go new file mode 100644 index 0000000..f589654 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/sqlite/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]User, error) { + rows, err := q.db.QueryContext(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + ); 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/emit_db_tags/sqlite/query.sql b/internal/endtoend/testdata/emit_db_tags/sqlite/query.sql new file mode 100644 index 0000000..e2f85e2 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/sqlite/query.sql @@ -0,0 +1,2 @@ +/* name: GetAll :many */ +SELECT * FROM users; diff --git a/internal/endtoend/testdata/emit_db_tags/sqlite/schema.sql b/internal/endtoend/testdata/emit_db_tags/sqlite/schema.sql new file mode 100644 index 0000000..86b83a3 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/sqlite/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + id integer NOT NULL PRIMARY KEY, + first_name varchar NOT NULL, + last_name varchar, + age integer NOT NULL +); diff --git a/internal/endtoend/testdata/emit_db_tags/sqlite/sqlc.json b/internal/endtoend/testdata/emit_db_tags/sqlite/sqlc.json new file mode 100644 index 0000000..7e2ee44 --- /dev/null +++ b/internal/endtoend/testdata/emit_db_tags/sqlite/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "schema.sql", + "queries": "query.sql", + "engine": "sqlite", + "emit_db_tags": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_empty_slices/pgx/v4/go/db.go b/internal/endtoend/testdata/emit_empty_slices/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/emit_empty_slices/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/emit_empty_slices/pgx/v4/go/models.go b/internal/endtoend/testdata/emit_empty_slices/pgx/v4/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/emit_empty_slices/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/emit_empty_slices/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/emit_empty_slices/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..0ba10be --- /dev/null +++ b/internal/endtoend/testdata/emit_empty_slices/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listBar = `-- name: ListBar :many +SELECT id FROM bar +` + +func (q *Queries) ListBar(ctx context.Context) ([]int32, error) { + rows, err := q.db.Query(ctx, listBar) + if err != nil { + return nil, err + } + defer rows.Close() + 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 +} diff --git a/internal/endtoend/testdata/emit_empty_slices/pgx/v4/query.sql b/internal/endtoend/testdata/emit_empty_slices/pgx/v4/query.sql new file mode 100644 index 0000000..af1f130 --- /dev/null +++ b/internal/endtoend/testdata/emit_empty_slices/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: ListBar :many +SELECT * FROM bar; diff --git a/internal/endtoend/testdata/emit_empty_slices/pgx/v4/schema.sql b/internal/endtoend/testdata/emit_empty_slices/pgx/v4/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/emit_empty_slices/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/emit_empty_slices/pgx/v4/sqlc.json b/internal/endtoend/testdata/emit_empty_slices/pgx/v4/sqlc.json new file mode 100644 index 0000000..d3e0569 --- /dev/null +++ b/internal/endtoend/testdata/emit_empty_slices/pgx/v4/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_empty_slices": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_empty_slices/pgx/v5/go/db.go b/internal/endtoend/testdata/emit_empty_slices/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/emit_empty_slices/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/emit_empty_slices/pgx/v5/go/models.go b/internal/endtoend/testdata/emit_empty_slices/pgx/v5/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/emit_empty_slices/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/emit_empty_slices/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/emit_empty_slices/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..0ba10be --- /dev/null +++ b/internal/endtoend/testdata/emit_empty_slices/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listBar = `-- name: ListBar :many +SELECT id FROM bar +` + +func (q *Queries) ListBar(ctx context.Context) ([]int32, error) { + rows, err := q.db.Query(ctx, listBar) + if err != nil { + return nil, err + } + defer rows.Close() + 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 +} diff --git a/internal/endtoend/testdata/emit_empty_slices/pgx/v5/query.sql b/internal/endtoend/testdata/emit_empty_slices/pgx/v5/query.sql new file mode 100644 index 0000000..af1f130 --- /dev/null +++ b/internal/endtoend/testdata/emit_empty_slices/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: ListBar :many +SELECT * FROM bar; diff --git a/internal/endtoend/testdata/emit_empty_slices/pgx/v5/schema.sql b/internal/endtoend/testdata/emit_empty_slices/pgx/v5/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/emit_empty_slices/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/emit_empty_slices/pgx/v5/sqlc.json b/internal/endtoend/testdata/emit_empty_slices/pgx/v5/sqlc.json new file mode 100644 index 0000000..ed890d3 --- /dev/null +++ b/internal/endtoend/testdata/emit_empty_slices/pgx/v5/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_empty_slices": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_empty_slices/stdlib/go/db.go b/internal/endtoend/testdata/emit_empty_slices/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/emit_empty_slices/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/emit_empty_slices/stdlib/go/models.go b/internal/endtoend/testdata/emit_empty_slices/stdlib/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/emit_empty_slices/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/emit_empty_slices/stdlib/go/query.sql.go b/internal/endtoend/testdata/emit_empty_slices/stdlib/go/query.sql.go new file mode 100644 index 0000000..5d4efe1 --- /dev/null +++ b/internal/endtoend/testdata/emit_empty_slices/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listBar = `-- name: ListBar :many +SELECT id FROM bar +` + +func (q *Queries) ListBar(ctx context.Context) ([]int32, error) { + rows, err := q.db.QueryContext(ctx, listBar) + if err != nil { + return nil, err + } + defer rows.Close() + 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 +} diff --git a/internal/endtoend/testdata/emit_empty_slices/stdlib/query.sql b/internal/endtoend/testdata/emit_empty_slices/stdlib/query.sql new file mode 100644 index 0000000..af1f130 --- /dev/null +++ b/internal/endtoend/testdata/emit_empty_slices/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: ListBar :many +SELECT * FROM bar; diff --git a/internal/endtoend/testdata/emit_empty_slices/stdlib/schema.sql b/internal/endtoend/testdata/emit_empty_slices/stdlib/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/emit_empty_slices/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/emit_empty_slices/stdlib/sqlc.json b/internal/endtoend/testdata/emit_empty_slices/stdlib/sqlc.json new file mode 100644 index 0000000..b496f6a --- /dev/null +++ b/internal/endtoend/testdata/emit_empty_slices/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_empty_slices": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_enum_valid_and_values/go/db.go b/internal/endtoend/testdata/emit_enum_valid_and_values/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/emit_enum_valid_and_values/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/emit_enum_valid_and_values/go/models.go b/internal/endtoend/testdata/emit_enum_valid_and_values/go/models.go new file mode 100644 index 0000000..8d1878b --- /dev/null +++ b/internal/endtoend/testdata/emit_enum_valid_and_values/go/models.go @@ -0,0 +1,76 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type IPProtocol string + +const ( + IPProtocolTCP IPProtocol = "tcp" + IpProtocolIp IPProtocol = "ip" + IpProtocolIcmp IPProtocol = "icmp" +) + +func (e *IPProtocol) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = IPProtocol(s) + case string: + *e = IPProtocol(s) + default: + return fmt.Errorf("unsupported scan type for IPProtocol: %T", src) + } + return nil +} + +type NullIPProtocol struct { + IPProtocol IPProtocol + Valid bool // Valid is true if IPProtocol is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullIPProtocol) Scan(value any) error { + if value == nil { + ns.IPProtocol, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.IPProtocol.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullIPProtocol) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.IPProtocol), nil +} + +func (e IPProtocol) Valid() bool { + switch e { + case IPProtocolTCP, + IpProtocolIp, + IpProtocolIcmp: + return true + } + return false +} + +func AllIPProtocolValues() []IPProtocol { + return []IPProtocol{ + IPProtocolTCP, + IpProtocolIp, + IpProtocolIcmp, + } +} + +type BarNew struct { + IDNew int32 + IpOld IPProtocol +} diff --git a/internal/endtoend/testdata/emit_enum_valid_and_values/go/query.sql.go b/internal/endtoend/testdata/emit_enum_valid_and_values/go/query.sql.go new file mode 100644 index 0000000..98787cd --- /dev/null +++ b/internal/endtoend/testdata/emit_enum_valid_and_values/go/query.sql.go @@ -0,0 +1,70 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listBar = `-- name: ListBar :many +SELECT id_old, ip_old FROM bar_old +` + +func (q *Queries) ListBar(ctx context.Context) ([]BarNew, error) { + rows, err := q.db.Query(ctx, listBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []BarNew + for rows.Next() { + var i BarNew + if err := rows.Scan(&i.IDNew, &i.IpOld); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listFoo = `-- name: ListFoo :many +SELECT id_old as foo_old, id_old as baz_old +FROM bar_old +WHERE ip_old = $1 AND id_old = $2 +` + +type ListFooParams struct { + IpOld IPProtocol + IDNew int32 +} + +type ListFooRow struct { + FooNew int32 + BazOld int32 +} + +func (q *Queries) ListFoo(ctx context.Context, arg ListFooParams) ([]ListFooRow, error) { + rows, err := q.db.Query(ctx, listFoo, arg.IpOld, arg.IDNew) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListFooRow + for rows.Next() { + var i ListFooRow + if err := rows.Scan(&i.FooNew, &i.BazOld); 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/emit_enum_valid_and_values/query.sql b/internal/endtoend/testdata/emit_enum_valid_and_values/query.sql new file mode 100644 index 0000000..a8211d0 --- /dev/null +++ b/internal/endtoend/testdata/emit_enum_valid_and_values/query.sql @@ -0,0 +1,8 @@ +-- name: ListFoo :many +SELECT id_old as foo_old, id_old as baz_old +FROM bar_old +WHERE ip_old = $1 AND id_old = $2; + +-- name: ListBar :many +SELECT * FROM bar_old; + diff --git a/internal/endtoend/testdata/emit_enum_valid_and_values/schema.sql b/internal/endtoend/testdata/emit_enum_valid_and_values/schema.sql new file mode 100644 index 0000000..85cb7d3 --- /dev/null +++ b/internal/endtoend/testdata/emit_enum_valid_and_values/schema.sql @@ -0,0 +1,4 @@ +CREATE TYPE ip_protocol AS enum ('tcp', 'ip', 'icmp'); + +CREATE TABLE bar_old (id_old serial not null, ip_old ip_protocol NOT NULL); + diff --git a/internal/endtoend/testdata/emit_enum_valid_and_values/sqlc.json b/internal/endtoend/testdata/emit_enum_valid_and_values/sqlc.json new file mode 100644 index 0000000..ffa7377 --- /dev/null +++ b/internal/endtoend/testdata/emit_enum_valid_and_values/sqlc.json @@ -0,0 +1,22 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_enum_valid_method": true, + "emit_all_enum_values": true + } + ], + "rename": { + "id_old": "IDNew", + "bar_old": "BarNew", + "foo_old": "FooNew", + "ip_protocol": "IPProtocol", + "ip_protocol_tcp": "IPProtocolTCP" + } +} diff --git a/internal/endtoend/testdata/emit_exported_queries/pgx/v4/go/db.go b/internal/endtoend/testdata/emit_exported_queries/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/emit_exported_queries/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/emit_exported_queries/pgx/v4/go/models.go b/internal/endtoend/testdata/emit_exported_queries/pgx/v4/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/emit_exported_queries/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/emit_exported_queries/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/emit_exported_queries/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..6992864 --- /dev/null +++ b/internal/endtoend/testdata/emit_exported_queries/pgx/v4/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const UpdateBarID = `-- name: UpdateBarID :exec +UPDATE bar SET id = $1 WHERE id = $2 +` + +type UpdateBarIDParams struct { + ID int32 + ID_2 int32 +} + +func (q *Queries) UpdateBarID(ctx context.Context, arg UpdateBarIDParams) error { + _, err := q.db.Exec(ctx, UpdateBarID, arg.ID, arg.ID_2) + return err +} diff --git a/internal/endtoend/testdata/emit_exported_queries/pgx/v4/query.sql b/internal/endtoend/testdata/emit_exported_queries/pgx/v4/query.sql new file mode 100644 index 0000000..7591d3b --- /dev/null +++ b/internal/endtoend/testdata/emit_exported_queries/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: UpdateBarID :exec +UPDATE bar SET id = $1 WHERE id = $2; diff --git a/internal/endtoend/testdata/emit_exported_queries/pgx/v4/schema.sql b/internal/endtoend/testdata/emit_exported_queries/pgx/v4/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/emit_exported_queries/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/emit_exported_queries/pgx/v4/sqlc.json b/internal/endtoend/testdata/emit_exported_queries/pgx/v4/sqlc.json new file mode 100644 index 0000000..d000213 --- /dev/null +++ b/internal/endtoend/testdata/emit_exported_queries/pgx/v4/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_exported_queries": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_exported_queries/pgx/v5/go/db.go b/internal/endtoend/testdata/emit_exported_queries/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/emit_exported_queries/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/emit_exported_queries/pgx/v5/go/models.go b/internal/endtoend/testdata/emit_exported_queries/pgx/v5/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/emit_exported_queries/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/emit_exported_queries/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/emit_exported_queries/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..6992864 --- /dev/null +++ b/internal/endtoend/testdata/emit_exported_queries/pgx/v5/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const UpdateBarID = `-- name: UpdateBarID :exec +UPDATE bar SET id = $1 WHERE id = $2 +` + +type UpdateBarIDParams struct { + ID int32 + ID_2 int32 +} + +func (q *Queries) UpdateBarID(ctx context.Context, arg UpdateBarIDParams) error { + _, err := q.db.Exec(ctx, UpdateBarID, arg.ID, arg.ID_2) + return err +} diff --git a/internal/endtoend/testdata/emit_exported_queries/pgx/v5/query.sql b/internal/endtoend/testdata/emit_exported_queries/pgx/v5/query.sql new file mode 100644 index 0000000..7591d3b --- /dev/null +++ b/internal/endtoend/testdata/emit_exported_queries/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: UpdateBarID :exec +UPDATE bar SET id = $1 WHERE id = $2; diff --git a/internal/endtoend/testdata/emit_exported_queries/pgx/v5/schema.sql b/internal/endtoend/testdata/emit_exported_queries/pgx/v5/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/emit_exported_queries/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/emit_exported_queries/pgx/v5/sqlc.json b/internal/endtoend/testdata/emit_exported_queries/pgx/v5/sqlc.json new file mode 100644 index 0000000..22064cf --- /dev/null +++ b/internal/endtoend/testdata/emit_exported_queries/pgx/v5/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_exported_queries": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_exported_queries/stdlib/go/db.go b/internal/endtoend/testdata/emit_exported_queries/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/emit_exported_queries/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/emit_exported_queries/stdlib/go/models.go b/internal/endtoend/testdata/emit_exported_queries/stdlib/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/emit_exported_queries/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/emit_exported_queries/stdlib/go/query.sql.go b/internal/endtoend/testdata/emit_exported_queries/stdlib/go/query.sql.go new file mode 100644 index 0000000..3863b2b --- /dev/null +++ b/internal/endtoend/testdata/emit_exported_queries/stdlib/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const UpdateBarID = `-- name: UpdateBarID :exec +UPDATE bar SET id = $1 WHERE id = $2 +` + +type UpdateBarIDParams struct { + ID int32 + ID_2 int32 +} + +func (q *Queries) UpdateBarID(ctx context.Context, arg UpdateBarIDParams) error { + _, err := q.db.ExecContext(ctx, UpdateBarID, arg.ID, arg.ID_2) + return err +} diff --git a/internal/endtoend/testdata/emit_exported_queries/stdlib/query.sql b/internal/endtoend/testdata/emit_exported_queries/stdlib/query.sql new file mode 100644 index 0000000..7591d3b --- /dev/null +++ b/internal/endtoend/testdata/emit_exported_queries/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: UpdateBarID :exec +UPDATE bar SET id = $1 WHERE id = $2; diff --git a/internal/endtoend/testdata/emit_exported_queries/stdlib/schema.sql b/internal/endtoend/testdata/emit_exported_queries/stdlib/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/emit_exported_queries/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/emit_exported_queries/stdlib/sqlc.json b/internal/endtoend/testdata/emit_exported_queries/stdlib/sqlc.json new file mode 100644 index 0000000..24db62e --- /dev/null +++ b/internal/endtoend/testdata/emit_exported_queries/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_exported_queries": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/mysql/go/db.go b/internal/endtoend/testdata/emit_methods_with_db_argument/mysql/go/db.go new file mode 100644 index 0000000..fb46486 --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/mysql/go/db.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *sql.Row +} + +func New() *Queries { + return &Queries{} +} + +type Queries struct { +} diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/mysql/go/models.go b/internal/endtoend/testdata/emit_methods_with_db_argument/mysql/go/models.go new file mode 100644 index 0000000..643ee29 --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/mysql/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID int32 + FirstName string + LastName sql.NullString + Age int32 +} diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/mysql/go/query.sql.go b/internal/endtoend/testdata/emit_methods_with_db_argument/mysql/go/query.sql.go new file mode 100644 index 0000000..4dc2b1c --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/mysql/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context, db DBTX) ([]User, error) { + rows, err := db.QueryContext(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + ); 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/emit_methods_with_db_argument/mysql/query.sql b/internal/endtoend/testdata/emit_methods_with_db_argument/mysql/query.sql new file mode 100644 index 0000000..e2f85e2 --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/mysql/query.sql @@ -0,0 +1,2 @@ +/* name: GetAll :many */ +SELECT * FROM users; diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/mysql/schema.sql b/internal/endtoend/testdata/emit_methods_with_db_argument/mysql/schema.sql new file mode 100644 index 0000000..3e36d6c --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/mysql/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + id integer NOT NULL AUTO_INCREMENT PRIMARY KEY, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL +); diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/mysql/sqlc.json b/internal/endtoend/testdata/emit_methods_with_db_argument/mysql/sqlc.json new file mode 100644 index 0000000..f27ded3 --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/mysql/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "schema.sql", + "queries": "query.sql", + "engine": "mysql", + "emit_methods_with_db_argument": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..abdbd0d --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v4/go/db.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row +} + +func New() *Queries { + return &Queries{} +} + +type Queries struct { +} diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..643ee29 --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v4/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID int32 + FirstName string + LastName sql.NullString + Age int32 +} diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..6972686 --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,39 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context, db DBTX) ([]User, error) { + rows, err := db.Query(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + ); 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/emit_methods_with_db_argument/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..237b201 --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: GetAll :many +SELECT * FROM users; diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..ae8e46e --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v4/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + id integer NOT NULL GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL +); diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..069e8bc --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_methods_with_db_argument": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..0a95f19 --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v5/go/db.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row +} + +func New() *Queries { + return &Queries{} +} + +type Queries struct { +} diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..116ee8f --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v5/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type User struct { + ID int32 + FirstName string + LastName pgtype.Text + Age int32 +} diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..6972686 --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,39 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context, db DBTX) ([]User, error) { + rows, err := db.Query(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + ); 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/emit_methods_with_db_argument/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..237b201 --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: GetAll :many +SELECT * FROM users; diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..ae8e46e --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v5/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + id integer NOT NULL GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL +); diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..558a107 --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_methods_with_db_argument": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..fb46486 --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/stdlib/go/db.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *sql.Row +} + +func New() *Queries { + return &Queries{} +} + +type Queries struct { +} diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..643ee29 --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/stdlib/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID int32 + FirstName string + LastName sql.NullString + Age int32 +} diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..4dc2b1c --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context, db DBTX) ([]User, error) { + rows, err := db.QueryContext(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + ); 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/emit_methods_with_db_argument/postgresql/stdlib/query.sql b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/stdlib/query.sql new file mode 100644 index 0000000..237b201 --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: GetAll :many +SELECT * FROM users; diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..ae8e46e --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/stdlib/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + id integer NOT NULL GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL +); diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..6acde89 --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/postgresql/stdlib/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_methods_with_db_argument": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/sqlite/go/db.go b/internal/endtoend/testdata/emit_methods_with_db_argument/sqlite/go/db.go new file mode 100644 index 0000000..fb46486 --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/sqlite/go/db.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *sql.Row +} + +func New() *Queries { + return &Queries{} +} + +type Queries struct { +} diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/sqlite/go/models.go b/internal/endtoend/testdata/emit_methods_with_db_argument/sqlite/go/models.go new file mode 100644 index 0000000..deb1559 --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/sqlite/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID int64 + FirstName string + LastName sql.NullString + Age int64 +} diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/sqlite/go/query.sql.go b/internal/endtoend/testdata/emit_methods_with_db_argument/sqlite/go/query.sql.go new file mode 100644 index 0000000..4dc2b1c --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/sqlite/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context, db DBTX) ([]User, error) { + rows, err := db.QueryContext(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + ); 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/emit_methods_with_db_argument/sqlite/query.sql b/internal/endtoend/testdata/emit_methods_with_db_argument/sqlite/query.sql new file mode 100644 index 0000000..e2f85e2 --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/sqlite/query.sql @@ -0,0 +1,2 @@ +/* name: GetAll :many */ +SELECT * FROM users; diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/sqlite/schema.sql b/internal/endtoend/testdata/emit_methods_with_db_argument/sqlite/schema.sql new file mode 100644 index 0000000..86b83a3 --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/sqlite/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + id integer NOT NULL PRIMARY KEY, + first_name varchar NOT NULL, + last_name varchar, + age integer NOT NULL +); diff --git a/internal/endtoend/testdata/emit_methods_with_db_argument/sqlite/sqlc.json b/internal/endtoend/testdata/emit_methods_with_db_argument/sqlite/sqlc.json new file mode 100644 index 0000000..c0107e0 --- /dev/null +++ b/internal/endtoend/testdata/emit_methods_with_db_argument/sqlite/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "schema.sql", + "queries": "query.sql", + "engine": "sqlite", + "emit_methods_with_db_argument": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optin/pgx/v5/go/db.go b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optin/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optin/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/emit_pointers_for_null_enum_types/optin/pgx/v5/go/models.go b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optin/pgx/v5/go/models.go new file mode 100644 index 0000000..cc23a28 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optin/pgx/v5/go/models.go @@ -0,0 +1,60 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" + + "github.com/jackc/pgx/v5/pgtype" +) + +type UserRole string + +const ( + UserRoleAdmin UserRole = "admin" + UserRoleUser UserRole = "user" +) + +func (e *UserRole) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = UserRole(s) + case string: + *e = UserRole(s) + default: + return fmt.Errorf("unsupported scan type for UserRole: %T", src) + } + return nil +} + +type NullUserRole struct { + UserRole UserRole + Valid bool // Valid is true if UserRole is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullUserRole) Scan(value any) error { + if value == nil { + ns.UserRole, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.UserRole.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullUserRole) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.UserRole), nil +} + +type User struct { + Role *UserRole + RequiredRole UserRole + Name pgtype.Text +} diff --git a/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optin/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optin/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..c3459e4 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optin/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listUsersByRole = `-- name: ListUsersByRole :many +SELECT role, required_role, name FROM users WHERE role = $1 +` + +func (q *Queries) ListUsersByRole(ctx context.Context, role *UserRole) ([]User, error) { + rows, err := q.db.Query(ctx, listUsersByRole, role) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan(&i.Role, &i.RequiredRole, &i.Name); 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/emit_pointers_for_null_enum_types/optin/pgx/v5/query.sql b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optin/pgx/v5/query.sql new file mode 100644 index 0000000..5497d0e --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optin/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: ListUsersByRole :many +SELECT * FROM users WHERE role = $1; diff --git a/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optin/pgx/v5/schema.sql b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optin/pgx/v5/schema.sql new file mode 100644 index 0000000..1bf15e4 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optin/pgx/v5/schema.sql @@ -0,0 +1,7 @@ +CREATE TYPE user_role AS ENUM ('admin', 'user'); + +CREATE TABLE users ( + role user_role, + required_role user_role NOT NULL, + name text +); diff --git a/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optin/pgx/v5/sqlc.json b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optin/pgx/v5/sqlc.json new file mode 100644 index 0000000..220daad --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optin/pgx/v5/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_pointers_for_null_enum_types": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optout/pgx/v5/go/db.go b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optout/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optout/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/emit_pointers_for_null_enum_types/optout/pgx/v5/go/models.go b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optout/pgx/v5/go/models.go new file mode 100644 index 0000000..404fd3e --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optout/pgx/v5/go/models.go @@ -0,0 +1,57 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type UserRole string + +const ( + UserRoleAdmin UserRole = "admin" + UserRoleUser UserRole = "user" +) + +func (e *UserRole) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = UserRole(s) + case string: + *e = UserRole(s) + default: + return fmt.Errorf("unsupported scan type for UserRole: %T", src) + } + return nil +} + +type NullUserRole struct { + UserRole UserRole + Valid bool // Valid is true if UserRole is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullUserRole) Scan(value any) error { + if value == nil { + ns.UserRole, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.UserRole.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullUserRole) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.UserRole), nil +} + +type User struct { + Role NullUserRole + RequiredRole UserRole +} diff --git a/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optout/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optout/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..c8928aa --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optout/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listUsersByRole = `-- name: ListUsersByRole :many +SELECT role, required_role FROM users WHERE role = $1 +` + +func (q *Queries) ListUsersByRole(ctx context.Context, role NullUserRole) ([]User, error) { + rows, err := q.db.Query(ctx, listUsersByRole, role) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan(&i.Role, &i.RequiredRole); 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/emit_pointers_for_null_enum_types/optout/pgx/v5/query.sql b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optout/pgx/v5/query.sql new file mode 100644 index 0000000..5497d0e --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optout/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: ListUsersByRole :many +SELECT * FROM users WHERE role = $1; diff --git a/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optout/pgx/v5/schema.sql b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optout/pgx/v5/schema.sql new file mode 100644 index 0000000..f7d05db --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optout/pgx/v5/schema.sql @@ -0,0 +1,6 @@ +CREATE TYPE user_role AS ENUM ('admin', 'user'); + +CREATE TABLE users ( + role user_role, + required_role user_role NOT NULL +); diff --git a/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optout/pgx/v5/sqlc.json b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optout/pgx/v5/sqlc.json new file mode 100644 index 0000000..0798ec2 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/optout/pgx/v5/sqlc.json @@ -0,0 +1,15 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_pointers_for_null_types": true, + "emit_pointers_for_null_enum_types": false + } + ] +} diff --git a/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v4/go/db.go b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/emit_pointers_for_null_enum_types/pgx/v4/go/models.go b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v4/go/models.go new file mode 100644 index 0000000..650782a --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v4/go/models.go @@ -0,0 +1,57 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type UserRole string + +const ( + UserRoleAdmin UserRole = "admin" + UserRoleUser UserRole = "user" +) + +func (e *UserRole) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = UserRole(s) + case string: + *e = UserRole(s) + default: + return fmt.Errorf("unsupported scan type for UserRole: %T", src) + } + return nil +} + +type NullUserRole struct { + UserRole UserRole + Valid bool // Valid is true if UserRole is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullUserRole) Scan(value any) error { + if value == nil { + ns.UserRole, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.UserRole.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullUserRole) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.UserRole), nil +} + +type User struct { + Role *UserRole + RequiredRole UserRole +} diff --git a/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..0ba72bc --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listUsersByRole = `-- name: ListUsersByRole :many +SELECT role, required_role FROM users WHERE role = $1 +` + +func (q *Queries) ListUsersByRole(ctx context.Context, role *UserRole) ([]User, error) { + rows, err := q.db.Query(ctx, listUsersByRole, role) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan(&i.Role, &i.RequiredRole); 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/emit_pointers_for_null_enum_types/pgx/v4/query.sql b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v4/query.sql new file mode 100644 index 0000000..5497d0e --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: ListUsersByRole :many +SELECT * FROM users WHERE role = $1; diff --git a/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v4/schema.sql b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v4/schema.sql new file mode 100644 index 0000000..f7d05db --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v4/schema.sql @@ -0,0 +1,6 @@ +CREATE TYPE user_role AS ENUM ('admin', 'user'); + +CREATE TABLE users ( + role user_role, + required_role user_role NOT NULL +); diff --git a/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v4/sqlc.json b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v4/sqlc.json new file mode 100644 index 0000000..2f4be0f --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v4/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_pointers_for_null_types": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v5/go/db.go b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/emit_pointers_for_null_enum_types/pgx/v5/go/models.go b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v5/go/models.go new file mode 100644 index 0000000..5f1efc0 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v5/go/models.go @@ -0,0 +1,100 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type FooStatus string + +const ( + FooStatusActive FooStatus = "active" + FooStatusInactive FooStatus = "inactive" +) + +func (e *FooStatus) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = FooStatus(s) + case string: + *e = FooStatus(s) + default: + return fmt.Errorf("unsupported scan type for FooStatus: %T", src) + } + return nil +} + +type NullFooStatus struct { + FooStatus FooStatus + Valid bool // Valid is true if FooStatus is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullFooStatus) Scan(value any) error { + if value == nil { + ns.FooStatus, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.FooStatus.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullFooStatus) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.FooStatus), nil +} + +type UserRole string + +const ( + UserRoleAdmin UserRole = "admin" + UserRoleUser UserRole = "user" +) + +func (e *UserRole) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = UserRole(s) + case string: + *e = UserRole(s) + default: + return fmt.Errorf("unsupported scan type for UserRole: %T", src) + } + return nil +} + +type NullUserRole struct { + UserRole UserRole + Valid bool // Valid is true if UserRole is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullUserRole) Scan(value any) error { + if value == nil { + ns.UserRole, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.UserRole.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullUserRole) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.UserRole), nil +} + +type User struct { + Role *UserRole + RequiredRole UserRole + Status *FooStatus +} diff --git a/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..72afc38 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v5/go/query.sql.go @@ -0,0 +1,49 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const createUser = `-- name: CreateUser :exec +INSERT INTO users (role, required_role, status) VALUES ($1, $2, $3) +` + +type CreateUserParams struct { + Role *UserRole + RequiredRole UserRole + Status *FooStatus +} + +func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) error { + _, err := q.db.Exec(ctx, createUser, arg.Role, arg.RequiredRole, arg.Status) + return err +} + +const listUsersByRole = `-- name: ListUsersByRole :many +SELECT role, required_role, status FROM users WHERE role = $1 +` + +func (q *Queries) ListUsersByRole(ctx context.Context, role *UserRole) ([]User, error) { + rows, err := q.db.Query(ctx, listUsersByRole, role) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan(&i.Role, &i.RequiredRole, &i.Status); 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/emit_pointers_for_null_enum_types/pgx/v5/query.sql b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v5/query.sql new file mode 100644 index 0000000..3df4ef7 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v5/query.sql @@ -0,0 +1,5 @@ +-- name: ListUsersByRole :many +SELECT * FROM users WHERE role = $1; + +-- name: CreateUser :exec +INSERT INTO users (role, required_role, status) VALUES ($1, $2, $3); diff --git a/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v5/schema.sql b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v5/schema.sql new file mode 100644 index 0000000..20258bd --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v5/schema.sql @@ -0,0 +1,11 @@ +CREATE TYPE user_role AS ENUM ('admin', 'user'); + +CREATE SCHEMA foo; + +CREATE TYPE foo.status AS ENUM ('active', 'inactive'); + +CREATE TABLE users ( + role user_role, + required_role user_role NOT NULL, + status foo.status +); diff --git a/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v5/sqlc.json b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v5/sqlc.json new file mode 100644 index 0000000..9b919df --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_enum_types/pgx/v5/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_pointers_for_null_types": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/go/db.go b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/go/db.go new file mode 100644 index 0000000..5cc19ed --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package datatype + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/emit_pointers_for_null_types/pgx/v4/go/models.go b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/go/models.go new file mode 100644 index 0000000..8501ec7 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/go/models.go @@ -0,0 +1,111 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package datatype + +import ( + "time" + + "github.com/jackc/pgtype" +) + +type DtCharacter struct { + A *string + B *string + C *string + D *string + E *string +} + +type DtCharacterNotNull struct { + A string + B string + C string + D string + E string +} + +type DtDatetime struct { + A *time.Time + B *time.Time + C *time.Time + D *time.Time + E *time.Time + F *time.Time + G *time.Time + H *time.Time +} + +type DtDatetimeNotNull struct { + A time.Time + B time.Time + C time.Time + D time.Time + E time.Time + F time.Time + G time.Time + H time.Time +} + +type DtNetType struct { + A pgtype.Inet + B pgtype.CIDR + C pgtype.Macaddr +} + +type DtNetTypesNotNull struct { + A pgtype.Inet + B pgtype.CIDR + C pgtype.Macaddr +} + +type DtNumeric struct { + A *int16 + B *int32 + C *int64 + D pgtype.Numeric + E pgtype.Numeric + F *float32 + G *float64 + H *int16 + I *int32 + J *int64 + K *int16 + L *int32 + M *int64 +} + +type DtNumericNotNull struct { + A int16 + B int32 + C int64 + D pgtype.Numeric + E pgtype.Numeric + F float32 + G float64 + H int16 + I int32 + J int64 + K int16 + L int32 + M int64 +} + +type DtRange struct { + A pgtype.Int4range + B pgtype.Int8range + C pgtype.Numrange + D pgtype.Tsrange + E pgtype.Tstzrange + F pgtype.Daterange +} + +type DtRangeNotNull struct { + A pgtype.Int4range + B pgtype.Int8range + C pgtype.Numrange + D pgtype.Tsrange + E pgtype.Tstzrange + F pgtype.Daterange +} diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..29ea3c7 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package datatype + +import ( + "context" +) + +const test = `-- name: Test :one +SELECT 1 +` + +func (q *Queries) Test(ctx context.Context) (int32, error) { + row := q.db.QueryRow(ctx, test) + var column_1 int32 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sql/character.sql b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sql/character.sql new file mode 100644 index 0000000..e3f41da --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sql/character.sql @@ -0,0 +1,17 @@ +-- Character Types +-- https://www.postgresql.org/docs/current/datatype-character.html +CREATE TABLE dt_character ( + a text, + b character varying(32), + c varchar(32), + d character(32), + e char(32) +); + +CREATE TABLE dt_character_not_null ( + a text NOT NULL, + b character varying(32) NOT NULL, + c varchar(32) NOT NULL, + d character(32) NOT NULL, + e char(32) NOT NULL +); diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sql/datetime.sql b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sql/datetime.sql new file mode 100644 index 0000000..5e6bcf0 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sql/datetime.sql @@ -0,0 +1,23 @@ +-- Date/Time Types +-- https://www.postgresql.org/docs/current/datatype-datetime.html +CREATE TABLE dt_datetime ( + a DATE, + b TIME, + c TIME WITHOUT TIME ZONE, + d TIME WITH TIME ZONE, + e TIMESTAMP, + f TIMESTAMP WITHOUT TIME ZONE, + g TIMESTAMP WITH TIME ZONE, + h timestamptz +); + +CREATE TABLE dt_datetime_not_null ( + a DATE NOT NULL, + b TIME NOT NULL, + c TIME WITHOUT TIME ZONE NOT NULL, + d TIME WITH TIME ZONE NOT NULL, + e TIMESTAMP NOT NULL, + f TIMESTAMP WITHOUT TIME ZONE NOT NULL, + g TIMESTAMP WITH TIME ZONE NOT NULL, + h timestamptz NOT NULL +); diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sql/net-types.sql b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sql/net-types.sql new file mode 100644 index 0000000..6239b6f --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sql/net-types.sql @@ -0,0 +1,13 @@ +-- Network Address Types +-- https://www.postgresql.org/docs/current/datatype-net-types.html +CREATE TABLE dt_net_types ( + a inet, + b cidr, + c macaddr +); + +CREATE TABLE dt_net_types_not_null ( + a inet NOT NULL, + b cidr NOT NULL, + c macaddr NOT NULL +); diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sql/numeric.sql b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sql/numeric.sql new file mode 100644 index 0000000..9df1494 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sql/numeric.sql @@ -0,0 +1,36 @@ +-- Numeric Types +-- https://www.postgresql.org/docs/current/datatype-numeric.html +CREATE TABLE dt_numeric ( + -- TODO: this maps incorrectly to int16, not NullInt16 + a smallint, + b integer, + c bigint, + d decimal, + e numeric, + f real, + g double precision, + -- TODO: this maps incorrectly to int16, not NullInt16 + h smallserial, + i serial, + j bigserial, + -- TODO: this maps incorrectly to int16, not NullInt16 + k int2, + l int4, + m int8 +); + +CREATE TABLE dt_numeric_not_null ( + a smallint NOT NULL, + b integer NOT NULL, + c bigint NOT NULL, + d decimal NOT NULL, + e numeric NOT NULL, + f real NOT NULL, + g double precision NOT NULL, + h smallserial NOT NULL, + i serial NOT NULL, + j bigserial NOT NULL, + k int2 NOT NULL, + l int4 NOT NULL, + m int8 NOT NULL +); diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sql/query.sql b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sql/query.sql new file mode 100644 index 0000000..9da604b --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sql/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT 1; diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sql/rangetypes.sql b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sql/rangetypes.sql new file mode 100644 index 0000000..7e61b65 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sql/rangetypes.sql @@ -0,0 +1,19 @@ +-- Range Types +-- https://www.postgresql.org/docs/current/rangetypes.html +CREATE TABLE dt_range ( + a int4range, + b int8range, + c numrange, + d tsrange, + e tstzrange, + f daterange +); + +CREATE TABLE dt_range_not_null ( + a int4range NOT NULL, + b int8range NOT NULL, + c numrange NOT NULL, + d tsrange NOT NULL, + e tstzrange NOT NULL, + f daterange NOT NULL +); diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sqlc.json b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sqlc.json new file mode 100644 index 0000000..6fd3f73 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v4/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "datatype", + "schema": "sql/", + "queries": "sql/", + "emit_pointers_for_null_types": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/go/db.go b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/go/db.go new file mode 100644 index 0000000..b57247c --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package datatype + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/emit_pointers_for_null_types/pgx/v5/go/models.go b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/go/models.go new file mode 100644 index 0000000..23a0399 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/go/models.go @@ -0,0 +1,113 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package datatype + +import ( + "net" + "net/netip" + "time" + + "github.com/jackc/pgx/v5/pgtype" +) + +type DtCharacter struct { + A *string + B *string + C *string + D *string + E *string +} + +type DtCharacterNotNull struct { + A string + B string + C string + D string + E string +} + +type DtDatetime struct { + A pgtype.Date + B pgtype.Time + C pgtype.Time + D *time.Time + E pgtype.Timestamp + F pgtype.Timestamp + G pgtype.Timestamptz + H pgtype.Timestamptz +} + +type DtDatetimeNotNull struct { + A pgtype.Date + B pgtype.Time + C pgtype.Time + D time.Time + E pgtype.Timestamp + F pgtype.Timestamp + G pgtype.Timestamptz + H pgtype.Timestamptz +} + +type DtNetType struct { + A *netip.Addr + B *netip.Prefix + C net.HardwareAddr +} + +type DtNetTypesNotNull struct { + A netip.Addr + B netip.Prefix + C net.HardwareAddr +} + +type DtNumeric struct { + A *int16 + B *int32 + C *int64 + D pgtype.Numeric + E pgtype.Numeric + F *float32 + G *float64 + H *int16 + I *int32 + J *int64 + K *int16 + L *int32 + M *int64 +} + +type DtNumericNotNull struct { + A int16 + B int32 + C int64 + D pgtype.Numeric + E pgtype.Numeric + F float32 + G float64 + H int16 + I int32 + J int64 + K int16 + L int32 + M int64 +} + +type DtRange struct { + A pgtype.Range[pgtype.Int4] + B pgtype.Range[pgtype.Int8] + C pgtype.Range[pgtype.Numeric] + D pgtype.Range[pgtype.Timestamp] + E pgtype.Range[pgtype.Timestamptz] + F pgtype.Range[pgtype.Date] +} + +type DtRangeNotNull struct { + A pgtype.Range[pgtype.Int4] + B pgtype.Range[pgtype.Int8] + C pgtype.Range[pgtype.Numeric] + D pgtype.Range[pgtype.Timestamp] + E pgtype.Range[pgtype.Timestamptz] + F pgtype.Range[pgtype.Date] +} diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..29ea3c7 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package datatype + +import ( + "context" +) + +const test = `-- name: Test :one +SELECT 1 +` + +func (q *Queries) Test(ctx context.Context) (int32, error) { + row := q.db.QueryRow(ctx, test) + var column_1 int32 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sql/character.sql b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sql/character.sql new file mode 100644 index 0000000..e3f41da --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sql/character.sql @@ -0,0 +1,17 @@ +-- Character Types +-- https://www.postgresql.org/docs/current/datatype-character.html +CREATE TABLE dt_character ( + a text, + b character varying(32), + c varchar(32), + d character(32), + e char(32) +); + +CREATE TABLE dt_character_not_null ( + a text NOT NULL, + b character varying(32) NOT NULL, + c varchar(32) NOT NULL, + d character(32) NOT NULL, + e char(32) NOT NULL +); diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sql/datetime.sql b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sql/datetime.sql new file mode 100644 index 0000000..5e6bcf0 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sql/datetime.sql @@ -0,0 +1,23 @@ +-- Date/Time Types +-- https://www.postgresql.org/docs/current/datatype-datetime.html +CREATE TABLE dt_datetime ( + a DATE, + b TIME, + c TIME WITHOUT TIME ZONE, + d TIME WITH TIME ZONE, + e TIMESTAMP, + f TIMESTAMP WITHOUT TIME ZONE, + g TIMESTAMP WITH TIME ZONE, + h timestamptz +); + +CREATE TABLE dt_datetime_not_null ( + a DATE NOT NULL, + b TIME NOT NULL, + c TIME WITHOUT TIME ZONE NOT NULL, + d TIME WITH TIME ZONE NOT NULL, + e TIMESTAMP NOT NULL, + f TIMESTAMP WITHOUT TIME ZONE NOT NULL, + g TIMESTAMP WITH TIME ZONE NOT NULL, + h timestamptz NOT NULL +); diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sql/net-types.sql b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sql/net-types.sql new file mode 100644 index 0000000..6239b6f --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sql/net-types.sql @@ -0,0 +1,13 @@ +-- Network Address Types +-- https://www.postgresql.org/docs/current/datatype-net-types.html +CREATE TABLE dt_net_types ( + a inet, + b cidr, + c macaddr +); + +CREATE TABLE dt_net_types_not_null ( + a inet NOT NULL, + b cidr NOT NULL, + c macaddr NOT NULL +); diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sql/numeric.sql b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sql/numeric.sql new file mode 100644 index 0000000..9df1494 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sql/numeric.sql @@ -0,0 +1,36 @@ +-- Numeric Types +-- https://www.postgresql.org/docs/current/datatype-numeric.html +CREATE TABLE dt_numeric ( + -- TODO: this maps incorrectly to int16, not NullInt16 + a smallint, + b integer, + c bigint, + d decimal, + e numeric, + f real, + g double precision, + -- TODO: this maps incorrectly to int16, not NullInt16 + h smallserial, + i serial, + j bigserial, + -- TODO: this maps incorrectly to int16, not NullInt16 + k int2, + l int4, + m int8 +); + +CREATE TABLE dt_numeric_not_null ( + a smallint NOT NULL, + b integer NOT NULL, + c bigint NOT NULL, + d decimal NOT NULL, + e numeric NOT NULL, + f real NOT NULL, + g double precision NOT NULL, + h smallserial NOT NULL, + i serial NOT NULL, + j bigserial NOT NULL, + k int2 NOT NULL, + l int4 NOT NULL, + m int8 NOT NULL +); diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sql/query.sql b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sql/query.sql new file mode 100644 index 0000000..9da604b --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sql/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT 1; diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sql/rangetypes.sql b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sql/rangetypes.sql new file mode 100644 index 0000000..7e61b65 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sql/rangetypes.sql @@ -0,0 +1,19 @@ +-- Range Types +-- https://www.postgresql.org/docs/current/rangetypes.html +CREATE TABLE dt_range ( + a int4range, + b int8range, + c numrange, + d tsrange, + e tstzrange, + f daterange +); + +CREATE TABLE dt_range_not_null ( + a int4range NOT NULL, + b int8range NOT NULL, + c numrange NOT NULL, + d tsrange NOT NULL, + e tstzrange NOT NULL, + f daterange NOT NULL +); diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sqlc.json b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sqlc.json new file mode 100644 index 0000000..1073b51 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/pgx/v5/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "datatype", + "schema": "sql/", + "queries": "sql/", + "emit_pointers_for_null_types": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/sqlite/go/db.go b/internal/endtoend/testdata/emit_pointers_for_null_types/sqlite/go/db.go new file mode 100644 index 0000000..31b1352 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package datatype + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/emit_pointers_for_null_types/sqlite/go/models.go b/internal/endtoend/testdata/emit_pointers_for_null_types/sqlite/go/models.go new file mode 100644 index 0000000..1f4dda4 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/sqlite/go/models.go @@ -0,0 +1,27 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package datatype + +import ( + "time" +) + +type DtType struct { + A *int64 + B *float64 + C *bool + D *time.Time + E *string + F *float64 +} + +type DtTypesNotNull struct { + A int64 + B float64 + C bool + D time.Time + E string + F float64 +} diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/sqlite/go/query.sql.go b/internal/endtoend/testdata/emit_pointers_for_null_types/sqlite/go/query.sql.go new file mode 100644 index 0000000..b8250f9 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/sqlite/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package datatype + +import ( + "context" +) + +const noop = `-- name: Noop :one +SELECT 1 +` + +func (q *Queries) Noop(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, noop) + var column_1 int64 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/sqlite/sql/query.sql b/internal/endtoend/testdata/emit_pointers_for_null_types/sqlite/sql/query.sql new file mode 100644 index 0000000..d32220c --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/sqlite/sql/query.sql @@ -0,0 +1,2 @@ +-- name: Noop :one +SELECT 1; diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/sqlite/sql/types.sql b/internal/endtoend/testdata/emit_pointers_for_null_types/sqlite/sql/types.sql new file mode 100644 index 0000000..eb55c80 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/sqlite/sql/types.sql @@ -0,0 +1,18 @@ + +CREATE TABLE dt_types ( + a int, + b real, + c bool, + d date, + e text, + f numeric +); + +CREATE TABLE dt_types_not_null ( + a int NOT NULL, + b real NOT NULL, + c bool NOT NULL, + d date NOT NULL, + e text NOT NULL, + f numeric NOT NULL +); diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/sqlite/sqlc.json b/internal/endtoend/testdata/emit_pointers_for_null_types/sqlite/sqlc.json new file mode 100644 index 0000000..9b8d769 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/sqlite/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "datatype", + "schema": "sql/types.sql", + "queries": "sql/query.sql", + "emit_pointers_for_null_types": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/go/db.go b/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/go/db.go new file mode 100644 index 0000000..31b1352 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package datatype + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/emit_pointers_for_null_types/stdlib/go/models.go b/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/go/models.go new file mode 100644 index 0000000..0dbaa9a --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/go/models.go @@ -0,0 +1,112 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package datatype + +import ( + "database/sql" + "time" + + "github.com/sqlc-dev/pqtype" +) + +type DtCharacter struct { + A sql.NullString + B sql.NullString + C sql.NullString + D sql.NullString + E sql.NullString +} + +type DtCharacterNotNull struct { + A string + B string + C string + D string + E string +} + +type DtDatetime struct { + A sql.NullTime + B sql.NullTime + C sql.NullTime + D sql.NullTime + E sql.NullTime + F sql.NullTime + G sql.NullTime + H sql.NullTime +} + +type DtDatetimeNotNull struct { + A time.Time + B time.Time + C time.Time + D time.Time + E time.Time + F time.Time + G time.Time + H time.Time +} + +type DtNetType struct { + A pqtype.Inet + B pqtype.CIDR + C pqtype.Macaddr +} + +type DtNetTypesNotNull struct { + A pqtype.Inet + B pqtype.CIDR + C pqtype.Macaddr +} + +type DtNumeric struct { + A sql.NullInt16 + B sql.NullInt32 + C sql.NullInt64 + D sql.NullString + E sql.NullString + F sql.NullFloat64 + G sql.NullFloat64 + H sql.NullInt16 + I sql.NullInt32 + J sql.NullInt64 + K sql.NullInt16 + L sql.NullInt32 + M sql.NullInt64 +} + +type DtNumericNotNull struct { + A int16 + B int32 + C int64 + D string + E string + F float32 + G float64 + H int16 + I int32 + J int64 + K int16 + L int32 + M int64 +} + +type DtRange struct { + A any + B any + C any + D any + E any + F any +} + +type DtRangeNotNull struct { + A any + B any + C any + D any + E any + F any +} diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/go/query.sql.go b/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/go/query.sql.go new file mode 100644 index 0000000..96b4633 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package datatype + +import ( + "context" +) + +const test = `-- name: Test :one +SELECT 1 +` + +func (q *Queries) Test(ctx context.Context) (int32, error) { + row := q.db.QueryRowContext(ctx, test) + var column_1 int32 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sql/character.sql b/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sql/character.sql new file mode 100644 index 0000000..e3f41da --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sql/character.sql @@ -0,0 +1,17 @@ +-- Character Types +-- https://www.postgresql.org/docs/current/datatype-character.html +CREATE TABLE dt_character ( + a text, + b character varying(32), + c varchar(32), + d character(32), + e char(32) +); + +CREATE TABLE dt_character_not_null ( + a text NOT NULL, + b character varying(32) NOT NULL, + c varchar(32) NOT NULL, + d character(32) NOT NULL, + e char(32) NOT NULL +); diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sql/datetime.sql b/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sql/datetime.sql new file mode 100644 index 0000000..5e6bcf0 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sql/datetime.sql @@ -0,0 +1,23 @@ +-- Date/Time Types +-- https://www.postgresql.org/docs/current/datatype-datetime.html +CREATE TABLE dt_datetime ( + a DATE, + b TIME, + c TIME WITHOUT TIME ZONE, + d TIME WITH TIME ZONE, + e TIMESTAMP, + f TIMESTAMP WITHOUT TIME ZONE, + g TIMESTAMP WITH TIME ZONE, + h timestamptz +); + +CREATE TABLE dt_datetime_not_null ( + a DATE NOT NULL, + b TIME NOT NULL, + c TIME WITHOUT TIME ZONE NOT NULL, + d TIME WITH TIME ZONE NOT NULL, + e TIMESTAMP NOT NULL, + f TIMESTAMP WITHOUT TIME ZONE NOT NULL, + g TIMESTAMP WITH TIME ZONE NOT NULL, + h timestamptz NOT NULL +); diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sql/net-types.sql b/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sql/net-types.sql new file mode 100644 index 0000000..6239b6f --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sql/net-types.sql @@ -0,0 +1,13 @@ +-- Network Address Types +-- https://www.postgresql.org/docs/current/datatype-net-types.html +CREATE TABLE dt_net_types ( + a inet, + b cidr, + c macaddr +); + +CREATE TABLE dt_net_types_not_null ( + a inet NOT NULL, + b cidr NOT NULL, + c macaddr NOT NULL +); diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sql/numeric.sql b/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sql/numeric.sql new file mode 100644 index 0000000..9df1494 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sql/numeric.sql @@ -0,0 +1,36 @@ +-- Numeric Types +-- https://www.postgresql.org/docs/current/datatype-numeric.html +CREATE TABLE dt_numeric ( + -- TODO: this maps incorrectly to int16, not NullInt16 + a smallint, + b integer, + c bigint, + d decimal, + e numeric, + f real, + g double precision, + -- TODO: this maps incorrectly to int16, not NullInt16 + h smallserial, + i serial, + j bigserial, + -- TODO: this maps incorrectly to int16, not NullInt16 + k int2, + l int4, + m int8 +); + +CREATE TABLE dt_numeric_not_null ( + a smallint NOT NULL, + b integer NOT NULL, + c bigint NOT NULL, + d decimal NOT NULL, + e numeric NOT NULL, + f real NOT NULL, + g double precision NOT NULL, + h smallserial NOT NULL, + i serial NOT NULL, + j bigserial NOT NULL, + k int2 NOT NULL, + l int4 NOT NULL, + m int8 NOT NULL +); diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sql/query.sql b/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sql/query.sql new file mode 100644 index 0000000..9da604b --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sql/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT 1; diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sql/rangetypes.sql b/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sql/rangetypes.sql new file mode 100644 index 0000000..7e61b65 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sql/rangetypes.sql @@ -0,0 +1,19 @@ +-- Range Types +-- https://www.postgresql.org/docs/current/rangetypes.html +CREATE TABLE dt_range ( + a int4range, + b int8range, + c numrange, + d tsrange, + e tstzrange, + f daterange +); + +CREATE TABLE dt_range_not_null ( + a int4range NOT NULL, + b int8range NOT NULL, + c numrange NOT NULL, + d tsrange NOT NULL, + e tstzrange NOT NULL, + f daterange NOT NULL +); diff --git a/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sqlc.json b/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sqlc.json new file mode 100644 index 0000000..be5e301 --- /dev/null +++ b/internal/endtoend/testdata/emit_pointers_for_null_types/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "datatype", + "schema": "sql/", + "queries": "sql/", + "emit_pointers_for_null_types": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/go/db.go b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/emit_result_and_params_struct_pointers/mysql/go/models.go b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/go/models.go new file mode 100644 index 0000000..a3b713f --- /dev/null +++ b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullInt32 + B sql.NullInt32 +} diff --git a/internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/go/querier.go b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/go/querier.go new file mode 100644 index 0000000..041c039 --- /dev/null +++ b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/go/querier.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type Querier interface { + GetAll(ctx context.Context) ([]*Foo, error) + GetAllAByB(ctx context.Context, b sql.NullInt32) ([]sql.NullInt32, error) + GetOne(ctx context.Context, arg *GetOneParams) (*Foo, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/go/query.sql.go b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/go/query.sql.go new file mode 100644 index 0000000..e36af84 --- /dev/null +++ b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/go/query.sql.go @@ -0,0 +1,81 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const getAll = `-- name: GetAll :many +SELECT a, b FROM foo +` + +func (q *Queries) GetAll(ctx context.Context) ([]*Foo, error) { + rows, err := q.db.QueryContext(ctx, getAll) + 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 getAllAByB = `-- name: GetAllAByB :many +SELECT a FROM foo WHERE b = ? +` + +func (q *Queries) GetAllAByB(ctx context.Context, b sql.NullInt32) ([]sql.NullInt32, error) { + rows, err := q.db.QueryContext(ctx, getAllAByB, b) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullInt32 + for rows.Next() { + var a sql.NullInt32 + if err := rows.Scan(&a); err != nil { + return nil, err + } + items = append(items, a) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getOne = `-- name: GetOne :one +SELECT a, b FROM foo WHERE a = ? AND b = ? LIMIT 1 +` + +type GetOneParams struct { + A sql.NullInt32 + B sql.NullInt32 +} + +func (q *Queries) GetOne(ctx context.Context, arg *GetOneParams) (*Foo, error) { + row := q.db.QueryRowContext(ctx, getOne, arg.A, arg.B) + var i Foo + err := row.Scan(&i.A, &i.B) + return &i, err +} diff --git a/internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/query.sql b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/query.sql new file mode 100644 index 0000000..06d3554 --- /dev/null +++ b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/query.sql @@ -0,0 +1,8 @@ +/* name: GetOne :one */ +SELECT * FROM foo WHERE a = ? AND b = ? LIMIT 1; + +/* name: GetAll :many */ +SELECT * FROM foo; + +/* name: GetAllAByB :many */ +SELECT a FROM foo WHERE b = ?; diff --git a/internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/schema.sql b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/schema.sql new file mode 100644 index 0000000..f9244aa --- /dev/null +++ b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a integer, b integer); + diff --git a/internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/sqlc.json b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/sqlc.json new file mode 100644 index 0000000..be5b7dd --- /dev/null +++ b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/mysql/sqlc.json @@ -0,0 +1,15 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "schema.sql", + "queries": "query.sql", + "engine": "mysql", + "emit_interface": true, + "emit_result_struct_pointers": true, + "emit_params_struct_pointers": true + } + ] +} diff --git a/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/go/batch.go b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/go/batch.go new file mode 100644 index 0000000..90195fa --- /dev/null +++ b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/go/batch.go @@ -0,0 +1,72 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: batch.go + +package querytest + +import ( + "context" + "database/sql" + "errors" + + "github.com/jackc/pgx/v4" +) + +var ( + ErrBatchAlreadyClosed = errors.New("batch already closed") +) + +const insertValues = `-- name: InsertValues :batchone +INSERT INTO foo (a, b) +VALUES ($1, $2) +ON CONFLICT DO NOTHING +RETURNING a, b +` + +type InsertValuesBatchResults struct { + br pgx.BatchResults + tot int + closed bool +} + +type InsertValuesParams struct { + A sql.NullInt32 + B sql.NullInt32 +} + +func (q *Queries) InsertValues(ctx context.Context, arg []*InsertValuesParams) *InsertValuesBatchResults { + batch := &pgx.Batch{} + for _, a := range arg { + vals := []any{ + a.A, + a.B, + } + batch.Queue(insertValues, vals...) + } + br := q.db.SendBatch(ctx, batch) + return &InsertValuesBatchResults{br, len(arg), false} +} + +func (b *InsertValuesBatchResults) QueryRow(f func(int, *Foo, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + var i Foo + if b.closed { + if f != nil { + f(t, nil, ErrBatchAlreadyClosed) + } + continue + } + row := b.br.QueryRow() + err := row.Scan(&i.A, &i.B) + if f != nil { + f(t, &i, err) + } + } +} + +func (b *InsertValuesBatchResults) Close() error { + b.closed = true + return b.br.Close() +} diff --git a/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..49b7e30 --- /dev/null +++ b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/go/db.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row + SendBatch(context.Context, *pgx.Batch) pgx.BatchResults +} + +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/emit_result_and_params_struct_pointers/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a3b713f --- /dev/null +++ b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullInt32 + B sql.NullInt32 +} diff --git a/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..63eca2a --- /dev/null +++ b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,75 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const getAll = `-- name: GetAll :many +SELECT a, b FROM foo +` + +func (q *Queries) GetAll(ctx context.Context) ([]*Foo, error) { + rows, err := q.db.Query(ctx, getAll) + 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 getAllAByB = `-- name: GetAllAByB :many +SELECT a FROM foo WHERE b = $1 +` + +func (q *Queries) GetAllAByB(ctx context.Context, b sql.NullInt32) ([]sql.NullInt32, error) { + rows, err := q.db.Query(ctx, getAllAByB, b) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullInt32 + for rows.Next() { + var a sql.NullInt32 + if err := rows.Scan(&a); err != nil { + return nil, err + } + items = append(items, a) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getOne = `-- name: GetOne :one +SELECT a, b FROM foo WHERE a = $1 AND b = $2 LIMIT 1 +` + +type GetOneParams struct { + A sql.NullInt32 + B sql.NullInt32 +} + +func (q *Queries) GetOne(ctx context.Context, arg *GetOneParams) (*Foo, error) { + row := q.db.QueryRow(ctx, getOne, arg.A, arg.B) + var i Foo + err := row.Scan(&i.A, &i.B) + return &i, err +} diff --git a/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..e6321bb --- /dev/null +++ b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/query.sql @@ -0,0 +1,14 @@ +-- name: InsertValues :batchone +INSERT INTO foo (a, b) +VALUES ($1, $2) +ON CONFLICT DO NOTHING +RETURNING *; + +-- name: GetOne :one +SELECT * FROM foo WHERE a = $1 AND b = $2 LIMIT 1; + +-- name: GetAll :many +SELECT * FROM foo; + +-- name: GetAllAByB :many +SELECT a FROM foo WHERE b = $1; diff --git a/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..f9244aa --- /dev/null +++ b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a integer, b integer); + diff --git a/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..2289f94 --- /dev/null +++ b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,19 @@ +{ + "version": "2", + "sql": [ + { + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "gen": { + "go": { + "package": "querytest", + "sql_package": "pgx/v4", + "out": "go", + "emit_result_struct_pointers": true, + "emit_params_struct_pointers": true + } + } + } + ] +} diff --git a/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/go/batch.go b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/go/batch.go new file mode 100644 index 0000000..8f9c369 --- /dev/null +++ b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/go/batch.go @@ -0,0 +1,72 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: batch.go + +package querytest + +import ( + "context" + "errors" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgtype" +) + +var ( + ErrBatchAlreadyClosed = errors.New("batch already closed") +) + +const insertValues = `-- name: InsertValues :batchone +INSERT INTO foo (a, b) +VALUES ($1, $2) +ON CONFLICT DO NOTHING +RETURNING a, b +` + +type InsertValuesBatchResults struct { + br pgx.BatchResults + tot int + closed bool +} + +type InsertValuesParams struct { + A pgtype.Int4 + B pgtype.Int4 +} + +func (q *Queries) InsertValues(ctx context.Context, arg []*InsertValuesParams) *InsertValuesBatchResults { + batch := &pgx.Batch{} + for _, a := range arg { + vals := []any{ + a.A, + a.B, + } + batch.Queue(insertValues, vals...) + } + br := q.db.SendBatch(ctx, batch) + return &InsertValuesBatchResults{br, len(arg), false} +} + +func (b *InsertValuesBatchResults) QueryRow(f func(int, *Foo, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + var i Foo + if b.closed { + if f != nil { + f(t, nil, ErrBatchAlreadyClosed) + } + continue + } + row := b.br.QueryRow() + err := row.Scan(&i.A, &i.B) + if f != nil { + f(t, &i, err) + } + } +} + +func (b *InsertValuesBatchResults) Close() error { + b.closed = true + return b.br.Close() +} diff --git a/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..1f79ce6 --- /dev/null +++ b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/go/db.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row + SendBatch(context.Context, *pgx.Batch) pgx.BatchResults +} + +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/emit_result_and_params_struct_pointers/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..baf8c54 --- /dev/null +++ b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + A pgtype.Int4 + B pgtype.Int4 +} diff --git a/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..4b927ee --- /dev/null +++ b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,76 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const getAll = `-- name: GetAll :many +SELECT a, b FROM foo +` + +func (q *Queries) GetAll(ctx context.Context) ([]*Foo, error) { + rows, err := q.db.Query(ctx, getAll) + 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 getAllAByB = `-- name: GetAllAByB :many +SELECT a FROM foo WHERE b = $1 +` + +func (q *Queries) GetAllAByB(ctx context.Context, b pgtype.Int4) ([]pgtype.Int4, error) { + rows, err := q.db.Query(ctx, getAllAByB, b) + if err != nil { + return nil, err + } + defer rows.Close() + var items []pgtype.Int4 + for rows.Next() { + var a pgtype.Int4 + if err := rows.Scan(&a); err != nil { + return nil, err + } + items = append(items, a) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getOne = `-- name: GetOne :one +SELECT a, b FROM foo WHERE a = $1 AND b = $2 LIMIT 1 +` + +type GetOneParams struct { + A pgtype.Int4 + B pgtype.Int4 +} + +func (q *Queries) GetOne(ctx context.Context, arg *GetOneParams) (*Foo, error) { + row := q.db.QueryRow(ctx, getOne, arg.A, arg.B) + var i Foo + err := row.Scan(&i.A, &i.B) + return &i, err +} diff --git a/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..e6321bb --- /dev/null +++ b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/query.sql @@ -0,0 +1,14 @@ +-- name: InsertValues :batchone +INSERT INTO foo (a, b) +VALUES ($1, $2) +ON CONFLICT DO NOTHING +RETURNING *; + +-- name: GetOne :one +SELECT * FROM foo WHERE a = $1 AND b = $2 LIMIT 1; + +-- name: GetAll :many +SELECT * FROM foo; + +-- name: GetAllAByB :many +SELECT a FROM foo WHERE b = $1; diff --git a/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..f9244aa --- /dev/null +++ b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a integer, b integer); + diff --git a/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..eac0177 --- /dev/null +++ b/internal/endtoend/testdata/emit_result_and_params_struct_pointers/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,19 @@ +{ + "version": "2", + "sql": [ + { + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "gen": { + "go": { + "package": "querytest", + "sql_package": "pgx/v5", + "out": "go", + "emit_result_struct_pointers": true, + "emit_params_struct_pointers": true + } + } + } + ] +} diff --git a/internal/endtoend/testdata/emit_sql_as_comment/stdlib/exec.json b/internal/endtoend/testdata/emit_sql_as_comment/stdlib/exec.json new file mode 100644 index 0000000..9f208fb --- /dev/null +++ b/internal/endtoend/testdata/emit_sql_as_comment/stdlib/exec.json @@ -0,0 +1,3 @@ +{ + "os": ["darwin", "linux"] +} diff --git a/internal/endtoend/testdata/emit_sql_as_comment/stdlib/go/db.go b/internal/endtoend/testdata/emit_sql_as_comment/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/emit_sql_as_comment/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/emit_sql_as_comment/stdlib/go/models.go b/internal/endtoend/testdata/emit_sql_as_comment/stdlib/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/emit_sql_as_comment/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/emit_sql_as_comment/stdlib/go/query.sql.go b/internal/endtoend/testdata/emit_sql_as_comment/stdlib/go/query.sql.go new file mode 100644 index 0000000..b3da6e1 --- /dev/null +++ b/internal/endtoend/testdata/emit_sql_as_comment/stdlib/go/query.sql.go @@ -0,0 +1,56 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listBar = `-- name: ListBar :many +SELECT id FROM ( + SELECT id FROM bar +) bar +` + +// Lists all bars +// +// SELECT id FROM ( +// SELECT id FROM bar +// ) bar +func (q *Queries) ListBar(ctx context.Context) ([]int32, error) { + rows, err := q.db.QueryContext(ctx, listBar) + 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 removeBar = `-- name: RemoveBar :exec +DELETE FROM bar WHERE id = $1 +` + +// RemoveBar +// +// DELETE FROM bar WHERE id = $1 +func (q *Queries) RemoveBar(ctx context.Context, id int32) error { + _, err := q.db.ExecContext(ctx, removeBar, id) + return err +} diff --git a/internal/endtoend/testdata/emit_sql_as_comment/stdlib/query.sql b/internal/endtoend/testdata/emit_sql_as_comment/stdlib/query.sql new file mode 100644 index 0000000..e355189 --- /dev/null +++ b/internal/endtoend/testdata/emit_sql_as_comment/stdlib/query.sql @@ -0,0 +1,8 @@ +-- name: ListBar :many +-- Lists all bars +SELECT id FROM ( + SELECT * FROM bar +) bar; + +-- name: RemoveBar :exec +DELETE FROM bar WHERE id = $1; diff --git a/internal/endtoend/testdata/emit_sql_as_comment/stdlib/schema.sql b/internal/endtoend/testdata/emit_sql_as_comment/stdlib/schema.sql new file mode 100644 index 0000000..682614c --- /dev/null +++ b/internal/endtoend/testdata/emit_sql_as_comment/stdlib/schema.sql @@ -0,0 +1 @@ +CREATE TABLE bar (id serial not null); diff --git a/internal/endtoend/testdata/emit_sql_as_comment/stdlib/sqlc.json b/internal/endtoend/testdata/emit_sql_as_comment/stdlib/sqlc.json new file mode 100644 index 0000000..9464b72 --- /dev/null +++ b/internal/endtoend/testdata/emit_sql_as_comment/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_sql_as_comment": true + } + ] +} diff --git a/internal/endtoend/testdata/enum/mysql/go/db.go b/internal/endtoend/testdata/enum/mysql/go/db.go new file mode 100644 index 0000000..fb46486 --- /dev/null +++ b/internal/endtoend/testdata/enum/mysql/go/db.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *sql.Row +} + +func New() *Queries { + return &Queries{} +} + +type Queries struct { +} diff --git a/internal/endtoend/testdata/enum/mysql/go/models.go b/internal/endtoend/testdata/enum/mysql/go/models.go new file mode 100644 index 0000000..0f3d666 --- /dev/null +++ b/internal/endtoend/testdata/enum/mysql/go/models.go @@ -0,0 +1,110 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + "database/sql/driver" + "fmt" +) + +type UsersShirtSize string + +const ( + UsersShirtSizeXSmall UsersShirtSize = "x-small" + UsersShirtSizeSmall UsersShirtSize = "small" + UsersShirtSizeMedium UsersShirtSize = "medium" + UsersShirtSizeLarge UsersShirtSize = "large" + UsersShirtSizeXLarge UsersShirtSize = "x-large" +) + +func (e *UsersShirtSize) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = UsersShirtSize(s) + case string: + *e = UsersShirtSize(s) + default: + return fmt.Errorf("unsupported scan type for UsersShirtSize: %T", src) + } + return nil +} + +type NullUsersShirtSize struct { + UsersShirtSize UsersShirtSize + Valid bool // Valid is true if UsersShirtSize is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullUsersShirtSize) Scan(value any) error { + if value == nil { + ns.UsersShirtSize, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.UsersShirtSize.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullUsersShirtSize) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.UsersShirtSize), nil +} + +type UsersShoeSize string + +const ( + UsersShoeSizeXSmall UsersShoeSize = "x-small" + UsersShoeSizeSmall UsersShoeSize = "small" + UsersShoeSizeMedium UsersShoeSize = "medium" + UsersShoeSizeLarge UsersShoeSize = "large" + UsersShoeSizeXLarge UsersShoeSize = "x-large" +) + +func (e *UsersShoeSize) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = UsersShoeSize(s) + case string: + *e = UsersShoeSize(s) + default: + return fmt.Errorf("unsupported scan type for UsersShoeSize: %T", src) + } + return nil +} + +type NullUsersShoeSize struct { + UsersShoeSize UsersShoeSize + Valid bool // Valid is true if UsersShoeSize is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullUsersShoeSize) Scan(value any) error { + if value == nil { + ns.UsersShoeSize, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.UsersShoeSize.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullUsersShoeSize) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.UsersShoeSize), nil +} + +type User struct { + ID int32 + FirstName string + LastName sql.NullString + Age int32 + ShoeSize UsersShoeSize + ShirtSize NullUsersShirtSize +} diff --git a/internal/endtoend/testdata/enum/mysql/go/query.sql.go b/internal/endtoend/testdata/enum/mysql/go/query.sql.go new file mode 100644 index 0000000..8285426 --- /dev/null +++ b/internal/endtoend/testdata/enum/mysql/go/query.sql.go @@ -0,0 +1,110 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const deleteBySize = `-- name: DeleteBySize :exec +DELETE FROM users +WHERE shoe_size = ? AND shirt_size = ? +` + +type DeleteBySizeParams struct { + ShoeSize UsersShoeSize + ShirtSize NullUsersShirtSize +} + +func (q *Queries) DeleteBySize(ctx context.Context, db DBTX, arg DeleteBySizeParams) error { + _, err := db.ExecContext(ctx, deleteBySize, arg.ShoeSize, arg.ShirtSize) + return err +} + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, age, shoe_size, shirt_size FROM users +` + +func (q *Queries) GetAll(ctx context.Context, db DBTX) ([]User, error) { + rows, err := db.QueryContext(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + &i.ShoeSize, + &i.ShirtSize, + ); 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 newUser = `-- name: NewUser :exec +INSERT INTO users ( + id, + first_name, + last_name, + age, + shoe_size, + shirt_size +) VALUES +(?, ?, ?, ?, ?, ?) +` + +type NewUserParams struct { + ID int32 + FirstName string + LastName sql.NullString + Age int32 + ShoeSize UsersShoeSize + ShirtSize NullUsersShirtSize +} + +func (q *Queries) NewUser(ctx context.Context, db DBTX, arg NewUserParams) error { + _, err := db.ExecContext(ctx, newUser, + arg.ID, + arg.FirstName, + arg.LastName, + arg.Age, + arg.ShoeSize, + arg.ShirtSize, + ) + return err +} + +const updateSizes = `-- name: UpdateSizes :exec +UPDATE users +SET shoe_size = ?, shirt_size = ? +WHERE id = ? +` + +type UpdateSizesParams struct { + ShoeSize UsersShoeSize + ShirtSize NullUsersShirtSize + ID int32 +} + +func (q *Queries) UpdateSizes(ctx context.Context, db DBTX, arg UpdateSizesParams) error { + _, err := db.ExecContext(ctx, updateSizes, arg.ShoeSize, arg.ShirtSize, arg.ID) + return err +} diff --git a/internal/endtoend/testdata/enum/mysql/query.sql b/internal/endtoend/testdata/enum/mysql/query.sql new file mode 100644 index 0000000..dfc427d --- /dev/null +++ b/internal/endtoend/testdata/enum/mysql/query.sql @@ -0,0 +1,22 @@ +/* name: GetAll :many */ +SELECT * FROM users; + +-- name: NewUser :exec +INSERT INTO users ( + id, + first_name, + last_name, + age, + shoe_size, + shirt_size +) VALUES +(?, ?, ?, ?, ?, ?); + +-- name: UpdateSizes :exec +UPDATE users +SET shoe_size = ?, shirt_size = ? +WHERE id = ?; + +-- name: DeleteBySize :exec +DELETE FROM users +WHERE shoe_size = ? AND shirt_size = ?; diff --git a/internal/endtoend/testdata/enum/mysql/schema.sql b/internal/endtoend/testdata/enum/mysql/schema.sql new file mode 100644 index 0000000..ee7b6ea --- /dev/null +++ b/internal/endtoend/testdata/enum/mysql/schema.sql @@ -0,0 +1,8 @@ +CREATE TABLE users ( + id integer NOT NULL AUTO_INCREMENT PRIMARY KEY, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL, + shoe_size ENUM('x-small', 'small', 'medium', 'large', 'x-large') NOT NULL, + shirt_size ENUM('x-small', 'small', 'medium', 'large', 'x-large') +); diff --git a/internal/endtoend/testdata/enum/mysql/sqlc.json b/internal/endtoend/testdata/enum/mysql/sqlc.json new file mode 100644 index 0000000..f27ded3 --- /dev/null +++ b/internal/endtoend/testdata/enum/mysql/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "schema.sql", + "queries": "query.sql", + "engine": "mysql", + "emit_methods_with_db_argument": true + } + ] +} diff --git a/internal/endtoend/testdata/enum/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/enum/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..abdbd0d --- /dev/null +++ b/internal/endtoend/testdata/enum/postgresql/pgx/v4/go/db.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row +} + +func New() *Queries { + return &Queries{} +} + +type Queries struct { +} diff --git a/internal/endtoend/testdata/enum/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/enum/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..f3a6c1b --- /dev/null +++ b/internal/endtoend/testdata/enum/postgresql/pgx/v4/go/models.go @@ -0,0 +1,65 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + "database/sql/driver" + "fmt" +) + +type Size string + +const ( + SizeXSmall Size = "x-small" + SizeSmall Size = "small" + SizeMedium Size = "medium" + SizeLarge Size = "large" + SizeXLarge Size = "x-large" +) + +func (e *Size) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = Size(s) + case string: + *e = Size(s) + default: + return fmt.Errorf("unsupported scan type for Size: %T", src) + } + return nil +} + +type NullSize struct { + Size Size + Valid bool // Valid is true if Size is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullSize) Scan(value any) error { + if value == nil { + ns.Size, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.Size.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullSize) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.Size), nil +} + +type User struct { + ID int32 + FirstName string + LastName sql.NullString + Age int32 + ShoeSize Size + ShirtSize NullSize +} diff --git a/internal/endtoend/testdata/enum/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/enum/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..c5d0268 --- /dev/null +++ b/internal/endtoend/testdata/enum/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,104 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const deleteBySize = `-- name: DeleteBySize :exec +DELETE FROM users +WHERE shoe_size = $1 AND shirt_size = $2 +` + +type DeleteBySizeParams struct { + ShoeSize Size + ShirtSize NullSize +} + +func (q *Queries) DeleteBySize(ctx context.Context, db DBTX, arg DeleteBySizeParams) error { + _, err := db.Exec(ctx, deleteBySize, arg.ShoeSize, arg.ShirtSize) + return err +} + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, age, shoe_size, shirt_size FROM users +` + +func (q *Queries) GetAll(ctx context.Context, db DBTX) ([]User, error) { + rows, err := db.Query(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + &i.ShoeSize, + &i.ShirtSize, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const newUser = `-- name: NewUser :exec +INSERT INTO users ( + first_name, + last_name, + age, + shoe_size, + shirt_size +) VALUES +($1, $2, $3, $4, $5) +` + +type NewUserParams struct { + FirstName string + LastName sql.NullString + Age int32 + ShoeSize Size + ShirtSize NullSize +} + +func (q *Queries) NewUser(ctx context.Context, db DBTX, arg NewUserParams) error { + _, err := db.Exec(ctx, newUser, + arg.FirstName, + arg.LastName, + arg.Age, + arg.ShoeSize, + arg.ShirtSize, + ) + return err +} + +const updateSizes = `-- name: UpdateSizes :exec +UPDATE users +SET shoe_size = $2, shirt_size = $3 +WHERE id = $1 +` + +type UpdateSizesParams struct { + ID int32 + ShoeSize Size + ShirtSize NullSize +} + +func (q *Queries) UpdateSizes(ctx context.Context, db DBTX, arg UpdateSizesParams) error { + _, err := db.Exec(ctx, updateSizes, arg.ID, arg.ShoeSize, arg.ShirtSize) + return err +} diff --git a/internal/endtoend/testdata/enum/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/enum/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..818eafd --- /dev/null +++ b/internal/endtoend/testdata/enum/postgresql/pgx/v4/query.sql @@ -0,0 +1,21 @@ +-- name: GetAll :many +SELECT * FROM users; + +-- name: NewUser :exec +INSERT INTO users ( + first_name, + last_name, + age, + shoe_size, + shirt_size +) VALUES +($1, $2, $3, $4, $5); + +-- name: UpdateSizes :exec +UPDATE users +SET shoe_size = $2, shirt_size = $3 +WHERE id = $1; + +-- name: DeleteBySize :exec +DELETE FROM users +WHERE shoe_size = $1 AND shirt_size = $2; \ No newline at end of file diff --git a/internal/endtoend/testdata/enum/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/enum/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..ad2802d --- /dev/null +++ b/internal/endtoend/testdata/enum/postgresql/pgx/v4/schema.sql @@ -0,0 +1,11 @@ +CREATE TYPE size AS ENUM('x-small', 'small', 'medium', 'large', 'x-large'); + + +CREATE TABLE users ( + id integer NOT NULL GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL, + shoe_size size NOT NULL, + shirt_size size +); diff --git a/internal/endtoend/testdata/enum/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/enum/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..069e8bc --- /dev/null +++ b/internal/endtoend/testdata/enum/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_methods_with_db_argument": true + } + ] +} diff --git a/internal/endtoend/testdata/enum/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/enum/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..0a95f19 --- /dev/null +++ b/internal/endtoend/testdata/enum/postgresql/pgx/v5/go/db.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row +} + +func New() *Queries { + return &Queries{} +} + +type Queries struct { +} diff --git a/internal/endtoend/testdata/enum/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/enum/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..3f2381d --- /dev/null +++ b/internal/endtoend/testdata/enum/postgresql/pgx/v5/go/models.go @@ -0,0 +1,66 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" + + "github.com/jackc/pgx/v5/pgtype" +) + +type Size string + +const ( + SizeXSmall Size = "x-small" + SizeSmall Size = "small" + SizeMedium Size = "medium" + SizeLarge Size = "large" + SizeXLarge Size = "x-large" +) + +func (e *Size) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = Size(s) + case string: + *e = Size(s) + default: + return fmt.Errorf("unsupported scan type for Size: %T", src) + } + return nil +} + +type NullSize struct { + Size Size + Valid bool // Valid is true if Size is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullSize) Scan(value any) error { + if value == nil { + ns.Size, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.Size.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullSize) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.Size), nil +} + +type User struct { + ID int32 + FirstName string + LastName pgtype.Text + Age int32 + ShoeSize Size + ShirtSize NullSize +} diff --git a/internal/endtoend/testdata/enum/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/enum/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..f26449a --- /dev/null +++ b/internal/endtoend/testdata/enum/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,105 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const deleteBySize = `-- name: DeleteBySize :exec +DELETE FROM users +WHERE shoe_size = $1 AND shirt_size = $2 +` + +type DeleteBySizeParams struct { + ShoeSize Size + ShirtSize NullSize +} + +func (q *Queries) DeleteBySize(ctx context.Context, db DBTX, arg DeleteBySizeParams) error { + _, err := db.Exec(ctx, deleteBySize, arg.ShoeSize, arg.ShirtSize) + return err +} + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, age, shoe_size, shirt_size FROM users +` + +func (q *Queries) GetAll(ctx context.Context, db DBTX) ([]User, error) { + rows, err := db.Query(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + &i.ShoeSize, + &i.ShirtSize, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const newUser = `-- name: NewUser :exec +INSERT INTO users ( + first_name, + last_name, + age, + shoe_size, + shirt_size +) VALUES +($1, $2, $3, $4, $5) +` + +type NewUserParams struct { + FirstName string + LastName pgtype.Text + Age int32 + ShoeSize Size + ShirtSize NullSize +} + +func (q *Queries) NewUser(ctx context.Context, db DBTX, arg NewUserParams) error { + _, err := db.Exec(ctx, newUser, + arg.FirstName, + arg.LastName, + arg.Age, + arg.ShoeSize, + arg.ShirtSize, + ) + return err +} + +const updateSizes = `-- name: UpdateSizes :exec +UPDATE users +SET shoe_size = $2, shirt_size = $3 +WHERE id = $1 +` + +type UpdateSizesParams struct { + ID int32 + ShoeSize Size + ShirtSize NullSize +} + +func (q *Queries) UpdateSizes(ctx context.Context, db DBTX, arg UpdateSizesParams) error { + _, err := db.Exec(ctx, updateSizes, arg.ID, arg.ShoeSize, arg.ShirtSize) + return err +} diff --git a/internal/endtoend/testdata/enum/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/enum/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..1902312 --- /dev/null +++ b/internal/endtoend/testdata/enum/postgresql/pgx/v5/query.sql @@ -0,0 +1,21 @@ +-- name: GetAll :many +SELECT * FROM users; + +-- name: NewUser :exec +INSERT INTO users ( + first_name, + last_name, + age, + shoe_size, + shirt_size +) VALUES +($1, $2, $3, $4, $5); + +-- name: UpdateSizes :exec +UPDATE users +SET shoe_size = $2, shirt_size = $3 +WHERE id = $1; + +-- name: DeleteBySize :exec +DELETE FROM users +WHERE shoe_size = $1 AND shirt_size = $2; diff --git a/internal/endtoend/testdata/enum/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/enum/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..ad2802d --- /dev/null +++ b/internal/endtoend/testdata/enum/postgresql/pgx/v5/schema.sql @@ -0,0 +1,11 @@ +CREATE TYPE size AS ENUM('x-small', 'small', 'medium', 'large', 'x-large'); + + +CREATE TABLE users ( + id integer NOT NULL GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL, + shoe_size size NOT NULL, + shirt_size size +); diff --git a/internal/endtoend/testdata/enum/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/enum/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..558a107 --- /dev/null +++ b/internal/endtoend/testdata/enum/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_methods_with_db_argument": true + } + ] +} diff --git a/internal/endtoend/testdata/enum/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/enum/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..fb46486 --- /dev/null +++ b/internal/endtoend/testdata/enum/postgresql/stdlib/go/db.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *sql.Row +} + +func New() *Queries { + return &Queries{} +} + +type Queries struct { +} diff --git a/internal/endtoend/testdata/enum/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/enum/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..f3a6c1b --- /dev/null +++ b/internal/endtoend/testdata/enum/postgresql/stdlib/go/models.go @@ -0,0 +1,65 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + "database/sql/driver" + "fmt" +) + +type Size string + +const ( + SizeXSmall Size = "x-small" + SizeSmall Size = "small" + SizeMedium Size = "medium" + SizeLarge Size = "large" + SizeXLarge Size = "x-large" +) + +func (e *Size) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = Size(s) + case string: + *e = Size(s) + default: + return fmt.Errorf("unsupported scan type for Size: %T", src) + } + return nil +} + +type NullSize struct { + Size Size + Valid bool // Valid is true if Size is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullSize) Scan(value any) error { + if value == nil { + ns.Size, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.Size.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullSize) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.Size), nil +} + +type User struct { + ID int32 + FirstName string + LastName sql.NullString + Age int32 + ShoeSize Size + ShirtSize NullSize +} diff --git a/internal/endtoend/testdata/enum/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/enum/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..7c6eefe --- /dev/null +++ b/internal/endtoend/testdata/enum/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,107 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const deleteBySize = `-- name: DeleteBySize :exec +DELETE FROM users +WHERE shoe_size = $1 AND shirt_size = $2 +` + +type DeleteBySizeParams struct { + ShoeSize Size + ShirtSize NullSize +} + +func (q *Queries) DeleteBySize(ctx context.Context, db DBTX, arg DeleteBySizeParams) error { + _, err := db.ExecContext(ctx, deleteBySize, arg.ShoeSize, arg.ShirtSize) + return err +} + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, age, shoe_size, shirt_size FROM users +` + +func (q *Queries) GetAll(ctx context.Context, db DBTX) ([]User, error) { + rows, err := db.QueryContext(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + &i.ShoeSize, + &i.ShirtSize, + ); 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 newUser = `-- name: NewUser :exec +INSERT INTO users ( + first_name, + last_name, + age, + shoe_size, + shirt_size +) VALUES +($1, $2, $3, $4, $5) +` + +type NewUserParams struct { + FirstName string + LastName sql.NullString + Age int32 + ShoeSize Size + ShirtSize NullSize +} + +func (q *Queries) NewUser(ctx context.Context, db DBTX, arg NewUserParams) error { + _, err := db.ExecContext(ctx, newUser, + arg.FirstName, + arg.LastName, + arg.Age, + arg.ShoeSize, + arg.ShirtSize, + ) + return err +} + +const updateSizes = `-- name: UpdateSizes :exec +UPDATE users +SET shoe_size = $2, shirt_size = $3 +WHERE id = $1 +` + +type UpdateSizesParams struct { + ID int32 + ShoeSize Size + ShirtSize NullSize +} + +func (q *Queries) UpdateSizes(ctx context.Context, db DBTX, arg UpdateSizesParams) error { + _, err := db.ExecContext(ctx, updateSizes, arg.ID, arg.ShoeSize, arg.ShirtSize) + return err +} diff --git a/internal/endtoend/testdata/enum/postgresql/stdlib/query.sql b/internal/endtoend/testdata/enum/postgresql/stdlib/query.sql new file mode 100644 index 0000000..1902312 --- /dev/null +++ b/internal/endtoend/testdata/enum/postgresql/stdlib/query.sql @@ -0,0 +1,21 @@ +-- name: GetAll :many +SELECT * FROM users; + +-- name: NewUser :exec +INSERT INTO users ( + first_name, + last_name, + age, + shoe_size, + shirt_size +) VALUES +($1, $2, $3, $4, $5); + +-- name: UpdateSizes :exec +UPDATE users +SET shoe_size = $2, shirt_size = $3 +WHERE id = $1; + +-- name: DeleteBySize :exec +DELETE FROM users +WHERE shoe_size = $1 AND shirt_size = $2; diff --git a/internal/endtoend/testdata/enum/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/enum/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..134694a --- /dev/null +++ b/internal/endtoend/testdata/enum/postgresql/stdlib/schema.sql @@ -0,0 +1,10 @@ +CREATE TYPE size AS ENUM('x-small', 'small', 'medium', 'large', 'x-large'); + +CREATE TABLE users ( + id integer NOT NULL GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL, + shoe_size size NOT NULL, + shirt_size size +); diff --git a/internal/endtoend/testdata/enum/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/enum/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..6acde89 --- /dev/null +++ b/internal/endtoend/testdata/enum/postgresql/stdlib/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_methods_with_db_argument": true + } + ] +} diff --git a/internal/endtoend/testdata/enum_column/issue.md b/internal/endtoend/testdata/enum_column/issue.md new file mode 100644 index 0000000..e618d6c --- /dev/null +++ b/internal/endtoend/testdata/enum_column/issue.md @@ -0,0 +1,3 @@ +https://github.com/sqlc-dev/sqlc/issues/1503 +https://github.com/sqlc-dev/sqlc/issues/2475 + diff --git a/internal/endtoend/testdata/enum_column/mysql/go/db.go b/internal/endtoend/testdata/enum_column/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/enum_column/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/enum_column/mysql/go/models.go b/internal/endtoend/testdata/enum_column/mysql/go/models.go new file mode 100644 index 0000000..91aab1a --- /dev/null +++ b/internal/endtoend/testdata/enum_column/mysql/go/models.go @@ -0,0 +1,271 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type AuthorsAddItem string + +const ( + AuthorsAddItemOk AuthorsAddItem = "ok" + AuthorsAddItemAdded AuthorsAddItem = "added" +) + +func (e *AuthorsAddItem) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = AuthorsAddItem(s) + case string: + *e = AuthorsAddItem(s) + default: + return fmt.Errorf("unsupported scan type for AuthorsAddItem: %T", src) + } + return nil +} + +type NullAuthorsAddItem struct { + AuthorsAddItem AuthorsAddItem + Valid bool // Valid is true if AuthorsAddItem is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullAuthorsAddItem) Scan(value any) error { + if value == nil { + ns.AuthorsAddItem, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.AuthorsAddItem.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullAuthorsAddItem) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.AuthorsAddItem), nil +} + +type AuthorsAdded string + +const ( + AuthorsAddedOk AuthorsAdded = "ok" +) + +func (e *AuthorsAdded) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = AuthorsAdded(s) + case string: + *e = AuthorsAdded(s) + default: + return fmt.Errorf("unsupported scan type for AuthorsAdded: %T", src) + } + return nil +} + +type NullAuthorsAdded struct { + AuthorsAdded AuthorsAdded + Valid bool // Valid is true if AuthorsAdded is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullAuthorsAdded) Scan(value any) error { + if value == nil { + ns.AuthorsAdded, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.AuthorsAdded.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullAuthorsAdded) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.AuthorsAdded), nil +} + +type AuthorsBar string + +const ( + AuthorsBarOk AuthorsBar = "ok" +) + +func (e *AuthorsBar) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = AuthorsBar(s) + case string: + *e = AuthorsBar(s) + default: + return fmt.Errorf("unsupported scan type for AuthorsBar: %T", src) + } + return nil +} + +type NullAuthorsBar struct { + AuthorsBar AuthorsBar + Valid bool // Valid is true if AuthorsBar is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullAuthorsBar) Scan(value any) error { + if value == nil { + ns.AuthorsBar, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.AuthorsBar.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullAuthorsBar) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.AuthorsBar), nil +} + +type AuthorsFoo string + +const ( + AuthorsFooOk AuthorsFoo = "ok" +) + +func (e *AuthorsFoo) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = AuthorsFoo(s) + case string: + *e = AuthorsFoo(s) + default: + return fmt.Errorf("unsupported scan type for AuthorsFoo: %T", src) + } + return nil +} + +type NullAuthorsFoo struct { + AuthorsFoo AuthorsFoo + Valid bool // Valid is true if AuthorsFoo is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullAuthorsFoo) Scan(value any) error { + if value == nil { + ns.AuthorsFoo, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.AuthorsFoo.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullAuthorsFoo) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.AuthorsFoo), nil +} + +type AuthorsRemoveItem string + +const ( + AuthorsRemoveItemOk AuthorsRemoveItem = "ok" +) + +func (e *AuthorsRemoveItem) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = AuthorsRemoveItem(s) + case string: + *e = AuthorsRemoveItem(s) + default: + return fmt.Errorf("unsupported scan type for AuthorsRemoveItem: %T", src) + } + return nil +} + +type NullAuthorsRemoveItem struct { + AuthorsRemoveItem AuthorsRemoveItem + Valid bool // Valid is true if AuthorsRemoveItem is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullAuthorsRemoveItem) Scan(value any) error { + if value == nil { + ns.AuthorsRemoveItem, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.AuthorsRemoveItem.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullAuthorsRemoveItem) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.AuthorsRemoveItem), nil +} + +type BooksFoo string + +const ( + BooksFooOk BooksFoo = "ok" +) + +func (e *BooksFoo) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = BooksFoo(s) + case string: + *e = BooksFoo(s) + default: + return fmt.Errorf("unsupported scan type for BooksFoo: %T", src) + } + return nil +} + +type NullBooksFoo struct { + BooksFoo BooksFoo + Valid bool // Valid is true if BooksFoo is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullBooksFoo) Scan(value any) error { + if value == nil { + ns.BooksFoo, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.BooksFoo.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullBooksFoo) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.BooksFoo), nil +} + +type Author struct { + ID int64 + Foo AuthorsFoo + Bar AuthorsBar + Added AuthorsAdded + AddItem AuthorsAddItem + RemoveItem AuthorsRemoveItem +} + +type Book struct { + ID int64 + Foo BooksFoo +} diff --git a/internal/endtoend/testdata/enum_column/mysql/go/query.sql.go b/internal/endtoend/testdata/enum_column/mysql/go/query.sql.go new file mode 100644 index 0000000..9932531 --- /dev/null +++ b/internal/endtoend/testdata/enum_column/mysql/go/query.sql.go @@ -0,0 +1,71 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listAuthors = `-- name: ListAuthors :many +SELECT id, foo, bar, added, add_item, remove_item FROM authors +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan( + &i.ID, + &i.Foo, + &i.Bar, + &i.Added, + &i.AddItem, + &i.RemoveItem, + ); 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 listBooks = `-- name: ListBooks :many +SELECT id, foo FROM books +` + +func (q *Queries) ListBooks(ctx context.Context) ([]Book, error) { + rows, err := q.db.QueryContext(ctx, listBooks) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Book + for rows.Next() { + var i Book + if err := rows.Scan(&i.ID, &i.Foo); 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/enum_column/mysql/query.sql b/internal/endtoend/testdata/enum_column/mysql/query.sql new file mode 100644 index 0000000..893743b --- /dev/null +++ b/internal/endtoend/testdata/enum_column/mysql/query.sql @@ -0,0 +1,5 @@ +/* name: ListAuthors :many */ +SELECT * FROM authors; + +/* name: ListBooks :many */ +SELECT * FROM books; diff --git a/internal/endtoend/testdata/enum_column/mysql/schema.sql b/internal/endtoend/testdata/enum_column/mysql/schema.sql new file mode 100644 index 0000000..82771c1 --- /dev/null +++ b/internal/endtoend/testdata/enum_column/mysql/schema.sql @@ -0,0 +1,39 @@ +CREATE TABLE authors ( + id BIGINT PRIMARY KEY, + foo ENUM("ok") DEFAULT "ok" NOT NULL, + renamed ENUM("ok") DEFAULT "ok" NOT NULL, + removed ENUM("ok") DEFAULT "ok" NOT NULL, + add_item ENUM("ok") DEFAULT "ok" NOT NULL, + remove_item ENUM("ok", "removed") DEFAULT "ok" NOT NULL +); + +CREATE TABLE renamed ( + id BIGINT PRIMARY KEY, + foo ENUM("ok") DEFAULT "ok" NOT NULL +); + +CREATE TABLE removed ( + id BIGINT PRIMARY KEY, + foo ENUM("ok") DEFAULT "ok" NOT NULL +); + +/* Rename column */ +ALTER TABLE authors RENAME COLUMN renamed TO bar; + +/* Drop column */ +ALTER TABLE authors DROP COLUMN removed; + +/* Add column */ +ALTER TABLE authors ADD COLUMN added ENUM("ok") DEFAULT "ok" NOT NULL; + +/* Add enum values */ +ALTER TABLE authors MODIFY add_item ENUM("ok", "added") DEFAULT "ok" NOT NULL; + +/* Remove enum values */ +ALTER TABLE authors MODIFY remove_item ENUM("ok") DEFAULT "ok" NOT NULL; + +/* Drop table */ +DROP TABLE removed; + +/* Rename table */ +ALTER TABLE renamed RENAME TO books; diff --git a/internal/endtoend/testdata/enum_column/mysql/sqlc.yaml b/internal/endtoend/testdata/enum_column/mysql/sqlc.yaml new file mode 100644 index 0000000..b843ef5 --- /dev/null +++ b/internal/endtoend/testdata/enum_column/mysql/sqlc.yaml @@ -0,0 +1,9 @@ +version: "2" +sql: + - engine: "mysql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" diff --git a/internal/endtoend/testdata/enum_ordering/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/enum_ordering/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/enum_ordering/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/enum_ordering/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/enum_ordering/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..9bb7d6a --- /dev/null +++ b/internal/endtoend/testdata/enum_ordering/postgresql/stdlib/go/models.go @@ -0,0 +1,90 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "database/sql/driver" + "fmt" +) + +type EnumType string + +const ( + EnumTypeBeforefirst EnumType = "beforefirst" + EnumTypeFirst EnumType = "first" + EnumTypeSecond EnumType = "second" + EnumTypeThird EnumType = "third" + EnumTypeFourth EnumType = "fourth" + EnumTypeFifth EnumType = "fifth" + EnumTypeLast EnumType = "last" + EnumTypeAfterlast EnumType = "afterlast" +) + +func (e *EnumType) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = EnumType(s) + case string: + *e = EnumType(s) + default: + return fmt.Errorf("unsupported scan type for EnumType: %T", src) + } + return nil +} + +type NullEnumType struct { + EnumType EnumType + Valid bool // Valid is true if EnumType is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullEnumType) Scan(value any) error { + if value == nil { + ns.EnumType, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.EnumType.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullEnumType) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.EnumType), nil +} + +func (e EnumType) Valid() bool { + switch e { + case EnumTypeBeforefirst, + EnumTypeFirst, + EnumTypeSecond, + EnumTypeThird, + EnumTypeFourth, + EnumTypeFifth, + EnumTypeLast, + EnumTypeAfterlast: + return true + } + return false +} + +func AllEnumTypeValues() []EnumType { + return []EnumType{ + EnumTypeBeforefirst, + EnumTypeFirst, + EnumTypeSecond, + EnumTypeThird, + EnumTypeFourth, + EnumTypeFifth, + EnumTypeLast, + EnumTypeAfterlast, + } +} + +type Foo struct { + ID int32 +} diff --git a/internal/endtoend/testdata/enum_ordering/postgresql/stdlib/go/querier.go b/internal/endtoend/testdata/enum_ordering/postgresql/stdlib/go/querier.go new file mode 100644 index 0000000..218ddc8 --- /dev/null +++ b/internal/endtoend/testdata/enum_ordering/postgresql/stdlib/go/querier.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" +) + +type Querier interface { + GetAll(ctx context.Context) ([]int32, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/enum_ordering/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/enum_ordering/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..84b460c --- /dev/null +++ b/internal/endtoend/testdata/enum_ordering/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT id FROM foo +` + +func (q *Queries) GetAll(ctx context.Context) ([]int32, error) { + rows, err := q.db.QueryContext(ctx, getAll) + 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 +} diff --git a/internal/endtoend/testdata/enum_ordering/postgresql/stdlib/query.sql b/internal/endtoend/testdata/enum_ordering/postgresql/stdlib/query.sql new file mode 100644 index 0000000..202b352 --- /dev/null +++ b/internal/endtoend/testdata/enum_ordering/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: GetAll :many +SELECT * FROM foo; \ No newline at end of file diff --git a/internal/endtoend/testdata/enum_ordering/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/enum_ordering/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..6790918 --- /dev/null +++ b/internal/endtoend/testdata/enum_ordering/postgresql/stdlib/schema.sql @@ -0,0 +1,11 @@ +CREATE TYPE enum_type AS ENUM ('first', 'last'); +ALTER TYPE enum_type ADD VALUE 'afterlast' AFTER 'last'; +ALTER TYPE enum_type ADD VALUE 'third' AFTER 'first'; +ALTER TYPE enum_type ADD VALUE 'fourth' BEFORE 'last'; +ALTER TYPE enum_type ADD VALUE 'fifth' AFTER 'fourth'; +ALTER TYPE enum_type ADD VALUE 'second' BEFORE 'third'; +ALTER TYPE enum_type ADD VALUE 'beforefirst' BEFORE 'first'; + +CREATE TABLE foo ( + id SERIAL PRIMARY KEY +); \ No newline at end of file diff --git a/internal/endtoend/testdata/enum_ordering/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/enum_ordering/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..b0d5568 --- /dev/null +++ b/internal/endtoend/testdata/enum_ordering/postgresql/stdlib/sqlc.json @@ -0,0 +1,19 @@ +{ + "version": "2", + "sql": [ + { + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "gen": { + "go": { + "out" : "go", + "package" : "db", + "emit_interface": true, + "emit_all_enum_values": true, + "emit_enum_valid_method": true + } + } + } + ] +} diff --git a/internal/endtoend/testdata/exec_create_table/mysql/db/db.go b/internal/endtoend/testdata/exec_create_table/mysql/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/mysql/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/exec_create_table/mysql/db/models.go b/internal/endtoend/testdata/exec_create_table/mysql/db/models.go new file mode 100644 index 0000000..21f493e --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/mysql/db/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db diff --git a/internal/endtoend/testdata/exec_create_table/mysql/db/mysql.query.sql.go b/internal/endtoend/testdata/exec_create_table/mysql/db/mysql.query.sql.go new file mode 100644 index 0000000..99fbd91 --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/mysql/db/mysql.query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: mysql.query.sql + +package db + +import ( + "context" +) + +const createTable = `-- name: CreateTable :exec +CREATE TABLE test (id INTEGER NOT NULL) +` + +func (q *Queries) CreateTable(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, createTable) + return err +} diff --git a/internal/endtoend/testdata/exec_create_table/mysql/mysql.query.sql b/internal/endtoend/testdata/exec_create_table/mysql/mysql.query.sql new file mode 100644 index 0000000..0a92ebb --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/mysql/mysql.query.sql @@ -0,0 +1,2 @@ +-- name: CreateTable :exec +CREATE TABLE test (id INTEGER NOT NULL); diff --git a/internal/endtoend/testdata/exec_create_table/mysql/mysql.schema.sql b/internal/endtoend/testdata/exec_create_table/mysql/mysql.schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/exec_create_table/mysql/sqlc.yaml b/internal/endtoend/testdata/exec_create_table/mysql/sqlc.yaml new file mode 100644 index 0000000..bd888aa --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/mysql/sqlc.yaml @@ -0,0 +1,8 @@ +version: 2 +sql: +- queries: mysql.query.sql + schema: mysql.schema.sql + engine: mysql + gen: + go: + out: db diff --git a/internal/endtoend/testdata/exec_create_table/postgresql/db/db.go b/internal/endtoend/testdata/exec_create_table/postgresql/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/postgresql/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/exec_create_table/postgresql/db/models.go b/internal/endtoend/testdata/exec_create_table/postgresql/db/models.go new file mode 100644 index 0000000..21f493e --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/postgresql/db/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db diff --git a/internal/endtoend/testdata/exec_create_table/postgresql/db/postgresql.query.sql.go b/internal/endtoend/testdata/exec_create_table/postgresql/db/postgresql.query.sql.go new file mode 100644 index 0000000..0d5b9d8 --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/postgresql/db/postgresql.query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: postgresql.query.sql + +package db + +import ( + "context" +) + +const createTable = `-- name: CreateTable :exec +CREATE TABLE test (id INTEGER NOT NULL) +` + +func (q *Queries) CreateTable(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, createTable) + return err +} diff --git a/internal/endtoend/testdata/exec_create_table/postgresql/postgresql.query.sql b/internal/endtoend/testdata/exec_create_table/postgresql/postgresql.query.sql new file mode 100644 index 0000000..0a92ebb --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/postgresql/postgresql.query.sql @@ -0,0 +1,2 @@ +-- name: CreateTable :exec +CREATE TABLE test (id INTEGER NOT NULL); diff --git a/internal/endtoend/testdata/exec_create_table/postgresql/postgresql.schema.sql b/internal/endtoend/testdata/exec_create_table/postgresql/postgresql.schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/exec_create_table/postgresql/sqlc.yaml b/internal/endtoend/testdata/exec_create_table/postgresql/sqlc.yaml new file mode 100644 index 0000000..6a89eb2 --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/postgresql/sqlc.yaml @@ -0,0 +1,9 @@ +version: 2 +sql: +- queries: postgresql.query.sql + schema: postgresql.schema.sql + engine: postgresql + gen: + go: + out: db + diff --git a/internal/endtoend/testdata/exec_create_table/sqlite/db/db.go b/internal/endtoend/testdata/exec_create_table/sqlite/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/sqlite/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/exec_create_table/sqlite/db/models.go b/internal/endtoend/testdata/exec_create_table/sqlite/db/models.go new file mode 100644 index 0000000..21f493e --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/sqlite/db/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db diff --git a/internal/endtoend/testdata/exec_create_table/sqlite/db/sqlite.query.sql.go b/internal/endtoend/testdata/exec_create_table/sqlite/db/sqlite.query.sql.go new file mode 100644 index 0000000..c80f32b --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/sqlite/db/sqlite.query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: sqlite.query.sql + +package db + +import ( + "context" +) + +const createTable = `-- name: CreateTable :exec +CREATE TABLE test (id INTEGER NOT NULL) +` + +func (q *Queries) CreateTable(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, createTable) + return err +} diff --git a/internal/endtoend/testdata/exec_create_table/sqlite/sqlc.yaml b/internal/endtoend/testdata/exec_create_table/sqlite/sqlc.yaml new file mode 100644 index 0000000..bf2e602 --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/sqlite/sqlc.yaml @@ -0,0 +1,8 @@ +version: 2 +sql: +- queries: sqlite.query.sql + schema: sqlite.schema.sql + engine: sqlite + gen: + go: + out: db diff --git a/internal/endtoend/testdata/exec_create_table/sqlite/sqlite.query.sql b/internal/endtoend/testdata/exec_create_table/sqlite/sqlite.query.sql new file mode 100644 index 0000000..0a92ebb --- /dev/null +++ b/internal/endtoend/testdata/exec_create_table/sqlite/sqlite.query.sql @@ -0,0 +1,2 @@ +-- name: CreateTable :exec +CREATE TABLE test (id INTEGER NOT NULL); diff --git a/internal/endtoend/testdata/exec_create_table/sqlite/sqlite.schema.sql b/internal/endtoend/testdata/exec_create_table/sqlite/sqlite.schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/exec_imports/pgx/v4/go/db.go b/internal/endtoend/testdata/exec_imports/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/exec_imports/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/exec_imports/pgx/v4/go/models.go b/internal/endtoend/testdata/exec_imports/pgx/v4/go/models.go new file mode 100644 index 0000000..7c96889 --- /dev/null +++ b/internal/endtoend/testdata/exec_imports/pgx/v4/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullInt32 + Bars []int32 +} diff --git a/internal/endtoend/testdata/exec_imports/pgx/v4/go/querier.go b/internal/endtoend/testdata/exec_imports/pgx/v4/go/querier.go new file mode 100644 index 0000000..39afcf2 --- /dev/null +++ b/internal/endtoend/testdata/exec_imports/pgx/v4/go/querier.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" +) + +type Querier interface { + Bar(ctx context.Context) error + Bars(ctx context.Context) error +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/exec_imports/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/exec_imports/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..c505de5 --- /dev/null +++ b/internal/endtoend/testdata/exec_imports/pgx/v4/go/query.sql.go @@ -0,0 +1,30 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const bar = `-- name: Bar :exec +SELECT bar +FROM foo +` + +func (q *Queries) Bar(ctx context.Context) error { + _, err := q.db.Exec(ctx, bar) + return err +} + +const bars = `-- name: Bars :exec +SELECT bars +FROM foo +` + +func (q *Queries) Bars(ctx context.Context) error { + _, err := q.db.Exec(ctx, bars) + return err +} diff --git a/internal/endtoend/testdata/exec_imports/pgx/v4/query.sql b/internal/endtoend/testdata/exec_imports/pgx/v4/query.sql new file mode 100644 index 0000000..b1be28c --- /dev/null +++ b/internal/endtoend/testdata/exec_imports/pgx/v4/query.sql @@ -0,0 +1,7 @@ +-- name: Bar :exec +SELECT bar +FROM foo; + +-- name: Bars :exec +SELECT bars +FROM foo; diff --git a/internal/endtoend/testdata/exec_imports/pgx/v4/schema.sql b/internal/endtoend/testdata/exec_imports/pgx/v4/schema.sql new file mode 100644 index 0000000..63886c1 --- /dev/null +++ b/internal/endtoend/testdata/exec_imports/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar int, bars int[] not null); + diff --git a/internal/endtoend/testdata/exec_imports/pgx/v4/sqlc.json b/internal/endtoend/testdata/exec_imports/pgx/v4/sqlc.json new file mode 100644 index 0000000..e0530db --- /dev/null +++ b/internal/endtoend/testdata/exec_imports/pgx/v4/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_interface": true + } + ] +} diff --git a/internal/endtoend/testdata/exec_imports/pgx/v5/go/db.go b/internal/endtoend/testdata/exec_imports/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/exec_imports/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/exec_imports/pgx/v5/go/models.go b/internal/endtoend/testdata/exec_imports/pgx/v5/go/models.go new file mode 100644 index 0000000..32c2dd8 --- /dev/null +++ b/internal/endtoend/testdata/exec_imports/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + Bar pgtype.Int4 + Bars []int32 +} diff --git a/internal/endtoend/testdata/exec_imports/pgx/v5/go/querier.go b/internal/endtoend/testdata/exec_imports/pgx/v5/go/querier.go new file mode 100644 index 0000000..39afcf2 --- /dev/null +++ b/internal/endtoend/testdata/exec_imports/pgx/v5/go/querier.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" +) + +type Querier interface { + Bar(ctx context.Context) error + Bars(ctx context.Context) error +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/exec_imports/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/exec_imports/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..c505de5 --- /dev/null +++ b/internal/endtoend/testdata/exec_imports/pgx/v5/go/query.sql.go @@ -0,0 +1,30 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const bar = `-- name: Bar :exec +SELECT bar +FROM foo +` + +func (q *Queries) Bar(ctx context.Context) error { + _, err := q.db.Exec(ctx, bar) + return err +} + +const bars = `-- name: Bars :exec +SELECT bars +FROM foo +` + +func (q *Queries) Bars(ctx context.Context) error { + _, err := q.db.Exec(ctx, bars) + return err +} diff --git a/internal/endtoend/testdata/exec_imports/pgx/v5/query.sql b/internal/endtoend/testdata/exec_imports/pgx/v5/query.sql new file mode 100644 index 0000000..b1be28c --- /dev/null +++ b/internal/endtoend/testdata/exec_imports/pgx/v5/query.sql @@ -0,0 +1,7 @@ +-- name: Bar :exec +SELECT bar +FROM foo; + +-- name: Bars :exec +SELECT bars +FROM foo; diff --git a/internal/endtoend/testdata/exec_imports/pgx/v5/schema.sql b/internal/endtoend/testdata/exec_imports/pgx/v5/schema.sql new file mode 100644 index 0000000..63886c1 --- /dev/null +++ b/internal/endtoend/testdata/exec_imports/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar int, bars int[] not null); + diff --git a/internal/endtoend/testdata/exec_imports/pgx/v5/sqlc.json b/internal/endtoend/testdata/exec_imports/pgx/v5/sqlc.json new file mode 100644 index 0000000..007fb85 --- /dev/null +++ b/internal/endtoend/testdata/exec_imports/pgx/v5/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_interface": true + } + ] +} diff --git a/internal/endtoend/testdata/exec_imports/stdlib/go/db.go b/internal/endtoend/testdata/exec_imports/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/exec_imports/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/exec_imports/stdlib/go/models.go b/internal/endtoend/testdata/exec_imports/stdlib/go/models.go new file mode 100644 index 0000000..7c96889 --- /dev/null +++ b/internal/endtoend/testdata/exec_imports/stdlib/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullInt32 + Bars []int32 +} diff --git a/internal/endtoend/testdata/exec_imports/stdlib/go/querier.go b/internal/endtoend/testdata/exec_imports/stdlib/go/querier.go new file mode 100644 index 0000000..39afcf2 --- /dev/null +++ b/internal/endtoend/testdata/exec_imports/stdlib/go/querier.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" +) + +type Querier interface { + Bar(ctx context.Context) error + Bars(ctx context.Context) error +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/exec_imports/stdlib/go/query.sql.go b/internal/endtoend/testdata/exec_imports/stdlib/go/query.sql.go new file mode 100644 index 0000000..4b511a4 --- /dev/null +++ b/internal/endtoend/testdata/exec_imports/stdlib/go/query.sql.go @@ -0,0 +1,30 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const bar = `-- name: Bar :exec +SELECT bar +FROM foo +` + +func (q *Queries) Bar(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, bar) + return err +} + +const bars = `-- name: Bars :exec +SELECT bars +FROM foo +` + +func (q *Queries) Bars(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, bars) + return err +} diff --git a/internal/endtoend/testdata/exec_imports/stdlib/query.sql b/internal/endtoend/testdata/exec_imports/stdlib/query.sql new file mode 100644 index 0000000..b1be28c --- /dev/null +++ b/internal/endtoend/testdata/exec_imports/stdlib/query.sql @@ -0,0 +1,7 @@ +-- name: Bar :exec +SELECT bar +FROM foo; + +-- name: Bars :exec +SELECT bars +FROM foo; diff --git a/internal/endtoend/testdata/exec_imports/stdlib/schema.sql b/internal/endtoend/testdata/exec_imports/stdlib/schema.sql new file mode 100644 index 0000000..63886c1 --- /dev/null +++ b/internal/endtoend/testdata/exec_imports/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar int, bars int[] not null); + diff --git a/internal/endtoend/testdata/exec_imports/stdlib/sqlc.json b/internal/endtoend/testdata/exec_imports/stdlib/sqlc.json new file mode 100644 index 0000000..49e9851 --- /dev/null +++ b/internal/endtoend/testdata/exec_imports/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_interface": true + } + ] +} diff --git a/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/db.go b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/exec_lastid/go_postgresql_stdlib/go/models.go b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/querier.go b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/querier.go new file mode 100644 index 0000000..9498197 --- /dev/null +++ b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/querier.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" +) + +type Querier interface { + InsertBar(ctx context.Context) (int64, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/query.sql.go b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/query.sql.go new file mode 100644 index 0000000..6aa6ca6 --- /dev/null +++ b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/query.sql.go @@ -0,0 +1,22 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const insertBar = `-- name: InsertBar :execlastid +INSERT INTO bar () VALUES () +` + +func (q *Queries) InsertBar(ctx context.Context) (int64, error) { + result, err := q.db.ExecContext(ctx, insertBar) + if err != nil { + return 0, err + } + return result.LastInsertId() +} diff --git a/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/query.sql b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/query.sql new file mode 100644 index 0000000..9a96492 --- /dev/null +++ b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: InsertBar :execlastid +INSERT INTO bar () VALUES (); \ No newline at end of file diff --git a/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/schema.sql b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/schema.sql new file mode 100644 index 0000000..f314957 --- /dev/null +++ b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id integer(10) NOT NULL AUTO_INCREMENT PRIMARY KEY); + diff --git a/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/sqlc.json b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/sqlc.json new file mode 100644 index 0000000..536433b --- /dev/null +++ b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "engine": "mysql", + "schema": "schema.sql", + "queries": "query.sql", + "emit_interface": true + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/exec_no_return_struct/issue.md b/internal/endtoend/testdata/exec_no_return_struct/issue.md new file mode 100644 index 0000000..1184d6e --- /dev/null +++ b/internal/endtoend/testdata/exec_no_return_struct/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/2970 diff --git a/internal/endtoend/testdata/exec_no_return_struct/postgresql/pgx/go/db.go b/internal/endtoend/testdata/exec_no_return_struct/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/exec_no_return_struct/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/exec_no_return_struct/postgresql/pgx/go/models.go b/internal/endtoend/testdata/exec_no_return_struct/postgresql/pgx/go/models.go new file mode 100644 index 0000000..201e6f3 --- /dev/null +++ b/internal/endtoend/testdata/exec_no_return_struct/postgresql/pgx/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Job struct { + TaskName string + LastRun pgtype.Timestamptz +} diff --git a/internal/endtoend/testdata/exec_no_return_struct/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/exec_no_return_struct/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..e3e9074 --- /dev/null +++ b/internal/endtoend/testdata/exec_no_return_struct/postgresql/pgx/go/query.sql.go @@ -0,0 +1,30 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const resetTaskRun = `-- name: ResetTaskRun :exec +UPDATE job +SET last_run = NOW() +FROM ( + SELECT last_run, + task_name + FROM job AS o + WHERE o.task_name = $1 + FOR UPDATE + ) AS old_values +WHERE job.task_name = $1 +RETURNING job.last_run AS this_run, + old_values.last_run AS last_run +` + +func (q *Queries) ResetTaskRun(ctx context.Context, taskName string) error { + _, err := q.db.Exec(ctx, resetTaskRun, taskName) + return err +} diff --git a/internal/endtoend/testdata/exec_no_return_struct/postgresql/pgx/query.sql b/internal/endtoend/testdata/exec_no_return_struct/postgresql/pgx/query.sql new file mode 100644 index 0000000..968ce9f --- /dev/null +++ b/internal/endtoend/testdata/exec_no_return_struct/postgresql/pgx/query.sql @@ -0,0 +1,13 @@ +-- name: ResetTaskRun :exec +UPDATE job +SET last_run = NOW() +FROM ( + SELECT last_run, + task_name + FROM job AS o + WHERE o.task_name = $1 + FOR UPDATE + ) AS old_values +WHERE job.task_name = $1 +RETURNING job.last_run AS this_run, + old_values.last_run AS last_run; diff --git a/internal/endtoend/testdata/exec_no_return_struct/postgresql/pgx/schema.sql b/internal/endtoend/testdata/exec_no_return_struct/postgresql/pgx/schema.sql new file mode 100644 index 0000000..6dd162b --- /dev/null +++ b/internal/endtoend/testdata/exec_no_return_struct/postgresql/pgx/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE IF NOT EXISTS job +( + task_name text NOT NULL, + last_run timestamp with time zone DEFAULT now() NOT NULL +); diff --git a/internal/endtoend/testdata/exec_no_return_struct/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/exec_no_return_struct/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/exec_no_return_struct/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/go/db.go b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/exec_result/go_postgresql_pgx/v4/go/models.go b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/go/querier.go b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/go/querier.go new file mode 100644 index 0000000..74bb929 --- /dev/null +++ b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/go/querier.go @@ -0,0 +1,17 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" +) + +type Querier interface { + DeleteBarByID(ctx context.Context, id int32) (pgconn.CommandTag, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/go/query.sql.go b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/go/query.sql.go new file mode 100644 index 0000000..2c403cb --- /dev/null +++ b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/go/query.sql.go @@ -0,0 +1,20 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" +) + +const deleteBarByID = `-- name: DeleteBarByID :execresult +DELETE FROM bar WHERE id = $1 +` + +func (q *Queries) DeleteBarByID(ctx context.Context, id int32) (pgconn.CommandTag, error) { + return q.db.Exec(ctx, deleteBarByID, id) +} diff --git a/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/query.sql b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/query.sql new file mode 100644 index 0000000..7391778 --- /dev/null +++ b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: DeleteBarByID :execresult +DELETE FROM bar WHERE id = $1; diff --git a/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/schema.sql b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/sqlc.json b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/sqlc.json new file mode 100644 index 0000000..e0530db --- /dev/null +++ b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v4/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_interface": true + } + ] +} diff --git a/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/go/db.go b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/exec_result/go_postgresql_pgx/v5/go/models.go b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/go/querier.go b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/go/querier.go new file mode 100644 index 0000000..33eaf83 --- /dev/null +++ b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/go/querier.go @@ -0,0 +1,17 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgconn" +) + +type Querier interface { + DeleteBarByID(ctx context.Context, id int32) (pgconn.CommandTag, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/go/query.sql.go b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/go/query.sql.go new file mode 100644 index 0000000..aab5830 --- /dev/null +++ b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/go/query.sql.go @@ -0,0 +1,20 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgconn" +) + +const deleteBarByID = `-- name: DeleteBarByID :execresult +DELETE FROM bar WHERE id = $1 +` + +func (q *Queries) DeleteBarByID(ctx context.Context, id int32) (pgconn.CommandTag, error) { + return q.db.Exec(ctx, deleteBarByID, id) +} diff --git a/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/query.sql b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/query.sql new file mode 100644 index 0000000..7391778 --- /dev/null +++ b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: DeleteBarByID :execresult +DELETE FROM bar WHERE id = $1; diff --git a/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/schema.sql b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/sqlc.json b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/sqlc.json new file mode 100644 index 0000000..007fb85 --- /dev/null +++ b/internal/endtoend/testdata/exec_result/go_postgresql_pgx/v5/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_interface": true + } + ] +} diff --git a/internal/endtoend/testdata/exec_result/go_postgresql_stdlib/go/db.go b/internal/endtoend/testdata/exec_result/go_postgresql_stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/exec_result/go_postgresql_stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/exec_result/go_postgresql_stdlib/go/models.go b/internal/endtoend/testdata/exec_result/go_postgresql_stdlib/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/exec_result/go_postgresql_stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/exec_result/go_postgresql_stdlib/go/querier.go b/internal/endtoend/testdata/exec_result/go_postgresql_stdlib/go/querier.go new file mode 100644 index 0000000..9dfbdeb --- /dev/null +++ b/internal/endtoend/testdata/exec_result/go_postgresql_stdlib/go/querier.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type Querier interface { + DeleteBarByID(ctx context.Context, id int32) (sql.Result, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/exec_result/go_postgresql_stdlib/go/query.sql.go b/internal/endtoend/testdata/exec_result/go_postgresql_stdlib/go/query.sql.go new file mode 100644 index 0000000..173b4e8 --- /dev/null +++ b/internal/endtoend/testdata/exec_result/go_postgresql_stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const deleteBarByID = `-- name: DeleteBarByID :execresult +DELETE FROM bar WHERE id = $1 +` + +func (q *Queries) DeleteBarByID(ctx context.Context, id int32) (sql.Result, error) { + return q.db.ExecContext(ctx, deleteBarByID, id) +} diff --git a/internal/endtoend/testdata/exec_result/go_postgresql_stdlib/query.sql b/internal/endtoend/testdata/exec_result/go_postgresql_stdlib/query.sql new file mode 100644 index 0000000..7391778 --- /dev/null +++ b/internal/endtoend/testdata/exec_result/go_postgresql_stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: DeleteBarByID :execresult +DELETE FROM bar WHERE id = $1; diff --git a/internal/endtoend/testdata/exec_result/go_postgresql_stdlib/schema.sql b/internal/endtoend/testdata/exec_result/go_postgresql_stdlib/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/exec_result/go_postgresql_stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/exec_result/go_postgresql_stdlib/sqlc.json b/internal/endtoend/testdata/exec_result/go_postgresql_stdlib/sqlc.json new file mode 100644 index 0000000..49e9851 --- /dev/null +++ b/internal/endtoend/testdata/exec_result/go_postgresql_stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_interface": true + } + ] +} diff --git a/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/go/db.go b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/exec_rows/go_postgresql_pgx/v4/go/models.go b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/go/querier.go b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/go/querier.go new file mode 100644 index 0000000..9adaf83 --- /dev/null +++ b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/go/querier.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" +) + +type Querier interface { + DeleteBarByID(ctx context.Context, id int32) (int64, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/go/query.sql.go b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/go/query.sql.go new file mode 100644 index 0000000..edcaa4b --- /dev/null +++ b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/go/query.sql.go @@ -0,0 +1,22 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const deleteBarByID = `-- name: DeleteBarByID :execrows +DELETE FROM bar WHERE id = $1 +` + +func (q *Queries) DeleteBarByID(ctx context.Context, id int32) (int64, error) { + result, err := q.db.Exec(ctx, deleteBarByID, id) + if err != nil { + return 0, err + } + return result.RowsAffected(), nil +} diff --git a/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/query.sql b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/query.sql new file mode 100644 index 0000000..94d2d09 --- /dev/null +++ b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: DeleteBarByID :execrows +DELETE FROM bar WHERE id = $1; diff --git a/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/schema.sql b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/sqlc.json b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/sqlc.json new file mode 100644 index 0000000..e0530db --- /dev/null +++ b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v4/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_interface": true + } + ] +} diff --git a/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/go/db.go b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/exec_rows/go_postgresql_pgx/v5/go/models.go b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/go/querier.go b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/go/querier.go new file mode 100644 index 0000000..9adaf83 --- /dev/null +++ b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/go/querier.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" +) + +type Querier interface { + DeleteBarByID(ctx context.Context, id int32) (int64, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/go/query.sql.go b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/go/query.sql.go new file mode 100644 index 0000000..edcaa4b --- /dev/null +++ b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/go/query.sql.go @@ -0,0 +1,22 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const deleteBarByID = `-- name: DeleteBarByID :execrows +DELETE FROM bar WHERE id = $1 +` + +func (q *Queries) DeleteBarByID(ctx context.Context, id int32) (int64, error) { + result, err := q.db.Exec(ctx, deleteBarByID, id) + if err != nil { + return 0, err + } + return result.RowsAffected(), nil +} diff --git a/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/query.sql b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/query.sql new file mode 100644 index 0000000..94d2d09 --- /dev/null +++ b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: DeleteBarByID :execrows +DELETE FROM bar WHERE id = $1; diff --git a/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/schema.sql b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/sqlc.json b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/sqlc.json new file mode 100644 index 0000000..007fb85 --- /dev/null +++ b/internal/endtoend/testdata/exec_rows/go_postgresql_pgx/v5/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_interface": true + } + ] +} diff --git a/internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/go/db.go b/internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/exec_rows/go_postgresql_stdlib/go/models.go b/internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/go/querier.go b/internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/go/querier.go new file mode 100644 index 0000000..9adaf83 --- /dev/null +++ b/internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/go/querier.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" +) + +type Querier interface { + DeleteBarByID(ctx context.Context, id int32) (int64, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/go/query.sql.go b/internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/go/query.sql.go new file mode 100644 index 0000000..8d51824 --- /dev/null +++ b/internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/go/query.sql.go @@ -0,0 +1,22 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const deleteBarByID = `-- name: DeleteBarByID :execrows +DELETE FROM bar WHERE id = $1 +` + +func (q *Queries) DeleteBarByID(ctx context.Context, id int32) (int64, error) { + result, err := q.db.ExecContext(ctx, deleteBarByID, id) + if err != nil { + return 0, err + } + return result.RowsAffected() +} diff --git a/internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/query.sql b/internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/query.sql new file mode 100644 index 0000000..94d2d09 --- /dev/null +++ b/internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: DeleteBarByID :execrows +DELETE FROM bar WHERE id = $1; diff --git a/internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/schema.sql b/internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/sqlc.json b/internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/sqlc.json new file mode 100644 index 0000000..49e9851 --- /dev/null +++ b/internal/endtoend/testdata/exec_rows/go_postgresql_stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_interface": true + } + ] +} diff --git a/internal/endtoend/testdata/experiment_coreanalyzer/mysql/exec.json b/internal/endtoend/testdata/experiment_coreanalyzer/mysql/exec.json new file mode 100644 index 0000000..8da46d6 --- /dev/null +++ b/internal/endtoend/testdata/experiment_coreanalyzer/mysql/exec.json @@ -0,0 +1,6 @@ +{ + "command": "generate", + "env": { + "SQLCEXPERIMENT": "coreanalyzer" + } +} diff --git a/internal/endtoend/testdata/experiment_coreanalyzer/mysql/go/db.go b/internal/endtoend/testdata/experiment_coreanalyzer/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/experiment_coreanalyzer/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/experiment_coreanalyzer/mysql/go/models.go b/internal/endtoend/testdata/experiment_coreanalyzer/mysql/go/models.go new file mode 100644 index 0000000..2208139 --- /dev/null +++ b/internal/endtoend/testdata/experiment_coreanalyzer/mysql/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/experiment_coreanalyzer/mysql/go/query.sql.go b/internal/endtoend/testdata/experiment_coreanalyzer/mysql/go/query.sql.go new file mode 100644 index 0000000..69c8702 --- /dev/null +++ b/internal/endtoend/testdata/experiment_coreanalyzer/mysql/go/query.sql.go @@ -0,0 +1,81 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const createAuthor = `-- name: CreateAuthor :execresult +INSERT INTO authors (id, name, bio) +VALUES (?, ?, ?) +` + +type CreateAuthorParams struct { + ID int64 + Name string + Bio sql.NullString +} + +func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (sql.Result, error) { + return q.db.ExecContext(ctx, createAuthor, arg.ID, arg.Name, arg.Bio) +} + +const deleteAuthor = `-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = ? +` + +func (q *Queries) DeleteAuthor(ctx context.Context, id int64) error { + _, err := q.db.ExecContext(ctx, deleteAuthor, id) + return err +} + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, bio FROM authors +WHERE id = ? +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name FROM authors +ORDER BY name +` + +type ListAuthorsRow struct { + ID int64 + Name string +} + +func (q *Queries) ListAuthors(ctx context.Context) ([]ListAuthorsRow, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListAuthorsRow + for rows.Next() { + var i ListAuthorsRow + if err := rows.Scan(&i.ID, &i.Name); 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/experiment_coreanalyzer/mysql/query.sql b/internal/endtoend/testdata/experiment_coreanalyzer/mysql/query.sql new file mode 100644 index 0000000..c76ee0c --- /dev/null +++ b/internal/endtoend/testdata/experiment_coreanalyzer/mysql/query.sql @@ -0,0 +1,15 @@ +-- name: GetAuthor :one +SELECT * FROM authors +WHERE id = ?; + +-- name: ListAuthors :many +SELECT id, name FROM authors +ORDER BY name; + +-- name: CreateAuthor :execresult +INSERT INTO authors (id, name, bio) +VALUES (?, ?, ?); + +-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = ?; diff --git a/internal/endtoend/testdata/experiment_coreanalyzer/mysql/schema.sql b/internal/endtoend/testdata/experiment_coreanalyzer/mysql/schema.sql new file mode 100644 index 0000000..bd03609 --- /dev/null +++ b/internal/endtoend/testdata/experiment_coreanalyzer/mysql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE authors ( + id bigint PRIMARY KEY, + name varchar(255) NOT NULL, + bio text +); diff --git a/internal/endtoend/testdata/experiment_coreanalyzer/mysql/sqlc.json b/internal/endtoend/testdata/experiment_coreanalyzer/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/experiment_coreanalyzer/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/experiment_coreanalyzer/postgresql/stdlib/exec.json b/internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/exec.json new file mode 100644 index 0000000..8da46d6 --- /dev/null +++ b/internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/exec.json @@ -0,0 +1,6 @@ +{ + "command": "generate", + "env": { + "SQLCEXPERIMENT": "coreanalyzer" + } +} diff --git a/internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/experiment_coreanalyzer/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..49c67eb --- /dev/null +++ b/internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString + Tags []string +} diff --git a/internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..2e2ced0 --- /dev/null +++ b/internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,97 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" + + "github.com/lib/pq" +) + +const createAuthor = `-- name: CreateAuthor :one +INSERT INTO authors (id, name, bio) +VALUES ($1, $2, $3) +RETURNING id, name, bio, tags +` + +type CreateAuthorParams struct { + ID int64 + Name string + Bio sql.NullString +} + +func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (Author, error) { + row := q.db.QueryRowContext(ctx, createAuthor, arg.ID, arg.Name, arg.Bio) + var i Author + err := row.Scan( + &i.ID, + &i.Name, + &i.Bio, + pq.Array(&i.Tags), + ) + return i, err +} + +const deleteAuthor = `-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = $1 +` + +func (q *Queries) DeleteAuthor(ctx context.Context, id int64) error { + _, err := q.db.ExecContext(ctx, deleteAuthor, id) + return err +} + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, bio, tags FROM authors +WHERE id = $1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Author + err := row.Scan( + &i.ID, + &i.Name, + &i.Bio, + pq.Array(&i.Tags), + ) + return i, err +} + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name FROM authors +ORDER BY name +` + +type ListAuthorsRow struct { + ID int64 + Name string +} + +func (q *Queries) ListAuthors(ctx context.Context) ([]ListAuthorsRow, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListAuthorsRow + for rows.Next() { + var i ListAuthorsRow + if err := rows.Scan(&i.ID, &i.Name); 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/experiment_coreanalyzer/postgresql/stdlib/query.sql b/internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/query.sql new file mode 100644 index 0000000..48bc0dd --- /dev/null +++ b/internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/query.sql @@ -0,0 +1,16 @@ +-- name: GetAuthor :one +SELECT * FROM authors +WHERE id = $1; + +-- name: ListAuthors :many +SELECT id, name FROM authors +ORDER BY name; + +-- name: CreateAuthor :one +INSERT INTO authors (id, name, bio) +VALUES ($1, $2, $3) +RETURNING *; + +-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = $1; diff --git a/internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..a12bc54 --- /dev/null +++ b/internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE authors ( + id bigint PRIMARY KEY, + name text NOT NULL, + bio text, + tags text[] +); diff --git a/internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/experiment_coreanalyzer/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/experiment_coreanalyzer/sqlite/exec.json b/internal/endtoend/testdata/experiment_coreanalyzer/sqlite/exec.json new file mode 100644 index 0000000..8da46d6 --- /dev/null +++ b/internal/endtoend/testdata/experiment_coreanalyzer/sqlite/exec.json @@ -0,0 +1,6 @@ +{ + "command": "generate", + "env": { + "SQLCEXPERIMENT": "coreanalyzer" + } +} diff --git a/internal/endtoend/testdata/experiment_coreanalyzer/sqlite/go/db.go b/internal/endtoend/testdata/experiment_coreanalyzer/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/experiment_coreanalyzer/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/experiment_coreanalyzer/sqlite/go/models.go b/internal/endtoend/testdata/experiment_coreanalyzer/sqlite/go/models.go new file mode 100644 index 0000000..2208139 --- /dev/null +++ b/internal/endtoend/testdata/experiment_coreanalyzer/sqlite/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/experiment_coreanalyzer/sqlite/go/query.sql.go b/internal/endtoend/testdata/experiment_coreanalyzer/sqlite/go/query.sql.go new file mode 100644 index 0000000..d26dc4d --- /dev/null +++ b/internal/endtoend/testdata/experiment_coreanalyzer/sqlite/go/query.sql.go @@ -0,0 +1,87 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const createAuthor = `-- name: CreateAuthor :one +INSERT INTO authors (id, name, bio) +VALUES (?, ?, ?) +RETURNING id, name, bio +` + +type CreateAuthorParams struct { + ID int64 + Name string + Bio sql.NullString +} + +func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (Author, error) { + row := q.db.QueryRowContext(ctx, createAuthor, arg.ID, arg.Name, arg.Bio) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const deleteAuthor = `-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = ? +` + +func (q *Queries) DeleteAuthor(ctx context.Context, id int64) error { + _, err := q.db.ExecContext(ctx, deleteAuthor, id) + return err +} + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, bio +FROM authors +WHERE id = ? +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name +FROM authors +ORDER BY name +` + +type ListAuthorsRow struct { + ID int64 + Name string +} + +func (q *Queries) ListAuthors(ctx context.Context) ([]ListAuthorsRow, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListAuthorsRow + for rows.Next() { + var i ListAuthorsRow + if err := rows.Scan(&i.ID, &i.Name); 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/experiment_coreanalyzer/sqlite/query.sql b/internal/endtoend/testdata/experiment_coreanalyzer/sqlite/query.sql new file mode 100644 index 0000000..00f0bd0 --- /dev/null +++ b/internal/endtoend/testdata/experiment_coreanalyzer/sqlite/query.sql @@ -0,0 +1,18 @@ +-- name: GetAuthor :one +SELECT * +FROM authors +WHERE id = ?; + +-- name: ListAuthors :many +SELECT id, name +FROM authors +ORDER BY name; + +-- name: CreateAuthor :one +INSERT INTO authors (id, name, bio) +VALUES (?, ?, ?) +RETURNING *; + +-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = ?; diff --git a/internal/endtoend/testdata/experiment_coreanalyzer/sqlite/schema.sql b/internal/endtoend/testdata/experiment_coreanalyzer/sqlite/schema.sql new file mode 100644 index 0000000..11599c4 --- /dev/null +++ b/internal/endtoend/testdata/experiment_coreanalyzer/sqlite/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE authors ( + id integer PRIMARY KEY, + name text NOT NULL, + bio text +); diff --git a/internal/endtoend/testdata/experiment_coreanalyzer/sqlite/sqlc.json b/internal/endtoend/testdata/experiment_coreanalyzer/sqlite/sqlc.json new file mode 100644 index 0000000..cd66df0 --- /dev/null +++ b/internal/endtoend/testdata/experiment_coreanalyzer/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/fmt/mysql/exec.json b/internal/endtoend/testdata/fmt/mysql/exec.json new file mode 100644 index 0000000..191cf0c --- /dev/null +++ b/internal/endtoend/testdata/fmt/mysql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "fmt", + "args": ["--diff"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/fmt/mysql/query.sql b/internal/endtoend/testdata/fmt/mysql/query.sql new file mode 100644 index 0000000..c8afff5 --- /dev/null +++ b/internal/endtoend/testdata/fmt/mysql/query.sql @@ -0,0 +1,72 @@ +-- name: GetAuthor :one +select id,name , bio from authors +where id = ? limit 1; + +# hash comment +-- name: ListAuthors :many +SELECT id, name, bio FROM authors +ORDER BY name DESC; + +-- name: PickyQuery :many +SELECT id, -- the primary key + name, + -- computed downstream + bio +FROM authors +-- soft-deleted rows are filtered +WHERE bio IS NOT NULL + AND id > ?; + +-- name: InlineBlock :many +SELECT /* inline note */ id, name FROM authors ORDER BY name; + +-- name: CountSigils :one +SELECT count(*) FROM authors +WHERE id <> ? AND name <> @user_name; # session variable stays + +-- name: CastUnsigned :one +SELECT CAST(id AS UNSIGNED) FROM authors LIMIT 1; + +-- name: FirstTwin :one +SELECT id FROM authors LIMIT 1; + +-- name: SecondTwin :one +SELECT id FROM authors LIMIT 1; + +-- name: CreateAuthor :execresult +insert into authors ( + name, bio +) values ( + ?, ? +); + +-- name: CasePreserved :many +SELECT ID, Name FROM Authors WHERE Name <> '' ORDER BY Name; + +-- name: LiteralsSurvive :one +SELECT true AS t, false AS f, 1.50 AS score, CASE WHEN name = '' THEN NULL ELSE name END AS n FROM authors LIMIT 1; + +-- name: DistinctNames :many +SELECT DISTINCT name FROM authors; + +-- name: UnionOrdered :many +SELECT name AS foo FROM authors +UNION +SELECT bio AS foo FROM authors +ORDER BY foo; + +-- name: ConcatNames :many +SELECT group_concat(DISTINCT name ORDER BY name DESC SEPARATOR ' ') FROM authors GROUP BY bio; + +-- name: Hinted :one +SELECT /*+ MAX_EXECUTION_TIME(1000) */ id FROM authors LIMIT 1; + +-- name: UpdateWithJoin :exec +UPDATE authors AS a JOIN authors AS p ON p.id = a.id +SET a.name = ? +WHERE p.bio IS NOT NULL; + +-- name: ShowWarnings :many +SHOW WARNINGS; + +CREATE TABLE scores (points decimal(10, 5), views bigint unsigned NOT NULL); diff --git a/internal/endtoend/testdata/fmt/mysql/schema.sql b/internal/endtoend/testdata/fmt/mysql/schema.sql new file mode 100644 index 0000000..0fb289c --- /dev/null +++ b/internal/endtoend/testdata/fmt/mysql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE authors ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + name varchar(255) NOT NULL, + bio text +); diff --git a/internal/endtoend/testdata/fmt/mysql/sqlc.yaml b/internal/endtoend/testdata/fmt/mysql/sqlc.yaml new file mode 100644 index 0000000..b843ef5 --- /dev/null +++ b/internal/endtoend/testdata/fmt/mysql/sqlc.yaml @@ -0,0 +1,9 @@ +version: "2" +sql: + - engine: "mysql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" diff --git a/internal/endtoend/testdata/fmt/mysql/stdout.txt b/internal/endtoend/testdata/fmt/mysql/stdout.txt new file mode 100644 index 0000000..a015b7a --- /dev/null +++ b/internal/endtoend/testdata/fmt/mysql/stdout.txt @@ -0,0 +1,73 @@ +--- a/query.sql ++++ b/query.sql +@@ -1,6 +1,8 @@ + -- name: GetAuthor :one ++SELECT id, name, bio ++FROM authors ++WHERE id = ? ++LIMIT 1; +-select id,name , bio from authors +-where id = ? limit 1; + + # hash comment + -- name: ListAuthors :many +@@ -7,4 +9,5 @@ ++SELECT id, name, bio ++FROM authors +-SELECT id, name, bio FROM authors + ORDER BY name DESC; + + -- name: PickyQuery :many +@@ -11,7 +14,8 @@ ++SELECT ++ id, -- the primary key ++ name, ++ -- computed downstream ++ bio +-SELECT id, -- the primary key +- name, +- -- computed downstream +- bio + FROM authors + -- soft-deleted rows are filtered + WHERE bio IS NOT NULL +@@ -21,8 +25,9 @@ + SELECT /* inline note */ id, name FROM authors ORDER BY name; + + -- name: CountSigils :one ++SELECT count(*) ++FROM authors ++WHERE id != ? AND name != @user_name; # session variable stays +-SELECT count(*) FROM authors +-WHERE id <> ? AND name <> @user_name; # session variable stays + + -- name: CastUnsigned :one + SELECT CAST(id AS UNSIGNED) FROM authors LIMIT 1; +@@ -34,14 +39,11 @@ + SELECT id FROM authors LIMIT 1; + + -- name: CreateAuthor :execresult ++INSERT INTO authors (name, bio) ++VALUES (?, ?); +-insert into authors ( +- name, bio +-) values ( +- ?, ? +-); + + -- name: CasePreserved :many ++SELECT ID, Name FROM Authors WHERE Name != '' ORDER BY Name; +-SELECT ID, Name FROM Authors WHERE Name <> '' ORDER BY Name; + + -- name: LiteralsSurvive :one + SELECT true AS t, false AS f, 1.50 AS score, CASE WHEN name = '' THEN NULL ELSE name END AS n FROM authors LIMIT 1; +@@ -62,7 +64,8 @@ + SELECT /*+ MAX_EXECUTION_TIME(1000) */ id FROM authors LIMIT 1; + + -- name: UpdateWithJoin :exec ++UPDATE authors AS a ++JOIN authors AS p ON p.id = a.id +-UPDATE authors AS a JOIN authors AS p ON p.id = a.id + SET a.name = ? + WHERE p.bio IS NOT NULL; + diff --git a/internal/endtoend/testdata/fmt/postgresql/exec.json b/internal/endtoend/testdata/fmt/postgresql/exec.json new file mode 100644 index 0000000..191cf0c --- /dev/null +++ b/internal/endtoend/testdata/fmt/postgresql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "fmt", + "args": ["--diff"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/fmt/postgresql/query.sql b/internal/endtoend/testdata/fmt/postgresql/query.sql new file mode 100644 index 0000000..96e8ed6 --- /dev/null +++ b/internal/endtoend/testdata/fmt/postgresql/query.sql @@ -0,0 +1,33 @@ +-- name: GetAuthor :one +select id,name , bio +from authors +where id = $1 limit 1; -- the primary lookup + +/* This listing powers the admin page. + Keep it ordered by name so the UI stays stable. */ +-- name: ListAuthors :many +SELECT id, name, bio FROM authors +ORDER BY name; + +-- name: CreateAuthor :one +INSERT INTO authors ( + name, bio +) VALUES ( + $1, $2 +) +RETURNING *; + +-- name: PickyQuery :many +SELECT id, -- the primary key + name +FROM authors +WHERE id > $1; + +-- name: SearchAuthors :many +SELECT id, name, bio, created_at FROM authors WHERE name LIKE $1 AND bio IS NOT NULL AND id > $2 AND name <> $3 ORDER BY name, id LIMIT $4; + +-- name: AtParamsGlued :many +SELECT name FROM authors WHERE name = @slug AND @filter::bool; + +-- name: DeleteAuthor :exec +DELETE FROM authors WHERE id = @id \ No newline at end of file diff --git a/internal/endtoend/testdata/fmt/postgresql/schema.sql b/internal/endtoend/testdata/fmt/postgresql/schema.sql new file mode 100644 index 0000000..468ae88 --- /dev/null +++ b/internal/endtoend/testdata/fmt/postgresql/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text, + created_at timestamptz NOT NULL DEFAULT now() +); diff --git a/internal/endtoend/testdata/fmt/postgresql/sqlc.yaml b/internal/endtoend/testdata/fmt/postgresql/sqlc.yaml new file mode 100644 index 0000000..cbd1c13 --- /dev/null +++ b/internal/endtoend/testdata/fmt/postgresql/sqlc.yaml @@ -0,0 +1,9 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" diff --git a/internal/endtoend/testdata/fmt/postgresql/stdout.txt b/internal/endtoend/testdata/fmt/postgresql/stdout.txt new file mode 100644 index 0000000..e580726 --- /dev/null +++ b/internal/endtoend/testdata/fmt/postgresql/stdout.txt @@ -0,0 +1,48 @@ +--- a/query.sql ++++ b/query.sql +@@ -1,7 +1,8 @@ + -- name: GetAuthor :one +-select id,name , bio +-from authors +-where id = $1 limit 1; -- the primary lookup ++SELECT id, name, bio ++FROM authors ++WHERE id = $1 ++LIMIT 1; -- the primary lookup + + /* This listing powers the admin page. + Keep it ordered by name so the UI stays stable. */ +@@ -8,5 +9,6 @@ + -- name: ListAuthors :many +-SELECT id, name, bio FROM authors ++SELECT id, name, bio ++FROM authors + ORDER BY name; + + -- name: CreateAuthor :one +@@ -13,8 +15,5 @@ +-INSERT INTO authors ( +- name, bio +-) VALUES ( +- $1, $2 +-) ++INSERT INTO authors (name, bio) ++VALUES ($1, $2) + RETURNING *; + + -- name: PickyQuery :many +@@ -21,5 +20,6 @@ +-SELECT id, -- the primary key +- name ++SELECT ++ id, -- the primary key ++ name + FROM authors + WHERE id > $1; + +@@ -30,4 +30,4 @@ + SELECT name FROM authors WHERE name = @slug AND @filter::bool; + + -- name: DeleteAuthor :exec +-DELETE FROM authors WHERE id = @id ++DELETE FROM authors WHERE id = @id; diff --git a/internal/endtoend/testdata/fmt/sqlite/exec.json b/internal/endtoend/testdata/fmt/sqlite/exec.json new file mode 100644 index 0000000..191cf0c --- /dev/null +++ b/internal/endtoend/testdata/fmt/sqlite/exec.json @@ -0,0 +1,5 @@ +{ + "command": "fmt", + "args": ["--diff"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/fmt/sqlite/query.sql b/internal/endtoend/testdata/fmt/sqlite/query.sql new file mode 100644 index 0000000..2856ca9 --- /dev/null +++ b/internal/endtoend/testdata/fmt/sqlite/query.sql @@ -0,0 +1,107 @@ +-- name: GetAuthor :one +select id,name , bio from authors +where id = ? limit 1; + +-- name: PickyQuery :many +SELECT id, -- the primary key + name, + -- computed downstream + bio +FROM authors +-- soft-deleted rows are filtered +WHERE bio IS NOT NULL + AND id > ?; + +-- name: InlineBlock :many +SELECT /* inline note */ id, name FROM authors ORDER BY name; + +-- name: ListAuthors :many +SELECT id, name, bio FROM authors +ORDER BY name; + +-- name: GetEvent :one +SELECT "EventName", "order" +FROM "Events" WHERE id = ? LIMIT 1; + +-- name: CountSigils :one +SELECT count(*) FROM authors +WHERE id <> @at_param AND id <> :colon_param AND id <> $dollar_param; + +-- name: TopAuthors :many +WITH ranked AS ( + SELECT id, name FROM authors +) +SELECT * FROM ranked; + +-- name: AddAuthor :exec +INSERT INTO authors (name, bio) +VALUES (?, ?); + +-- name: MakeScratch :exec +CREATE TABLE scratch ( + id INTEGER NOT NULL, + label TEXT +); + +-- name: MakeMeasurements :exec +CREATE TABLE IF NOT EXISTS measurements ( + id INTEGER PRIMARY KEY, + label VARYING CHARACTER(120), + ratio DECIMAL(10,5), + note +); + +-- name: KeepAutoinc :exec +CREATE TABLE counters (id INTEGER PRIMARY KEY AUTOINCREMENT, hits INTEGER DEFAULT 0); + +-- name: CastLabel :one +SELECT CAST(bio AS VARYING CHARACTER(120)) FROM authors LIMIT 1; + +-- name: MakeSearchIndex :exec +CREATE VIRTUAL TABLE IF NOT EXISTS notes_fts USING fts5(body, tag UNINDEXED, tokenize = 'porter'); + +-- name: MakeRecipeIndex :exec +CREATE VIRTUAL TABLE recipes_fts USING fts5( + name, + ingredients +); + +-- name: LoginName :one +SELECT COALESCE(bio, '') AS login FROM authors WHERE id = ? LIMIT 1; + +-- name: SpelledJoins :many +SELECT a.id +FROM authors AS a +INNER JOIN authors AS b ON a.id = b.id +LEFT OUTER JOIN authors AS c ON a.id = c.id +WHERE a.id != ? AND b.id == ? AND c.id <> ?; + +-- name: CommaJoin :one +SELECT count(*) FROM authors AS a, authors AS b WHERE a.id = b.id; + +-- name: PlannerHint :many +SELECT a.id FROM authors AS a CROSS JOIN authors AS b; + +-- name: NumberedParams :many +SELECT id FROM authors WHERE name = ?2 AND bio = ?1; + +-- name: NewestAndOldest :many +SELECT id FROM authors +UNION +SELECT id FROM authors; + +-- name: QuickUnion :many +SELECT id FROM authors UNION ALL SELECT id FROM authors; + +-- name: EnableForeignKeys :exec +PRAGMA foreign_keys = 1; + +-- name: UpsertAuthor :exec +INSERT INTO authors (id, name) +VALUES (?, ?) +ON CONFLICT (id) DO UPDATE SET + name = excluded.name +WHERE excluded.name <> ''; + +-- name: QuickUpsert :exec +INSERT INTO authors (id, name) VALUES (?, ?) ON CONFLICT (id) DO UPDATE SET name = excluded.name; diff --git a/internal/endtoend/testdata/fmt/sqlite/schema.sql b/internal/endtoend/testdata/fmt/sqlite/schema.sql new file mode 100644 index 0000000..1d42f1c --- /dev/null +++ b/internal/endtoend/testdata/fmt/sqlite/schema.sql @@ -0,0 +1,11 @@ +CREATE TABLE authors ( + id integer PRIMARY KEY, + name text NOT NULL, + bio text +); + +CREATE TABLE "Events" ( + id integer PRIMARY KEY, + "EventName" text NOT NULL, + "order" integer NOT NULL +); diff --git a/internal/endtoend/testdata/fmt/sqlite/sqlc.yaml b/internal/endtoend/testdata/fmt/sqlite/sqlc.yaml new file mode 100644 index 0000000..0b5a97a --- /dev/null +++ b/internal/endtoend/testdata/fmt/sqlite/sqlc.yaml @@ -0,0 +1,9 @@ +version: "2" +sql: + - engine: "sqlite" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" diff --git a/internal/endtoend/testdata/fmt/sqlite/stdout.txt b/internal/endtoend/testdata/fmt/sqlite/stdout.txt new file mode 100644 index 0000000..b9201e3 --- /dev/null +++ b/internal/endtoend/testdata/fmt/sqlite/stdout.txt @@ -0,0 +1,84 @@ +--- a/query.sql ++++ b/query.sql +@@ -1,12 +1,15 @@ + -- name: GetAuthor :one ++SELECT id, name, bio ++FROM authors ++WHERE id = ? ++LIMIT 1; +-select id,name , bio from authors +-where id = ? limit 1; + + -- name: PickyQuery :many ++SELECT ++ id, -- the primary key ++ name, ++ -- computed downstream ++ bio +-SELECT id, -- the primary key +- name, +- -- computed downstream +- bio + FROM authors + -- soft-deleted rows are filtered + WHERE bio IS NOT NULL +@@ -16,7 +19,8 @@ + SELECT /* inline note */ id, name FROM authors ORDER BY name; + + -- name: ListAuthors :many ++SELECT id, name, bio ++FROM authors +-SELECT id, name, bio FROM authors + ORDER BY name; + + -- name: GetEvent :one +@@ -23,8 +27,11 @@ + SELECT "EventName", "order" ++FROM "Events" ++WHERE id = ? ++LIMIT 1; +-FROM "Events" WHERE id = ? LIMIT 1; + + -- name: CountSigils :one ++SELECT count(*) ++FROM authors +-SELECT count(*) FROM authors + WHERE id <> @at_param AND id <> :colon_param AND id <> $dollar_param; + + -- name: TopAuthors :many +@@ -46,7 +53,7 @@ + -- name: MakeMeasurements :exec + CREATE TABLE IF NOT EXISTS measurements ( + id INTEGER PRIMARY KEY, ++ label VARYING CHARACTER(120), +- label VARYING CHARACTER(120), + ratio DECIMAL(10,5), + note + ); +@@ -58,7 +65,7 @@ + SELECT CAST(bio AS VARYING CHARACTER(120)) FROM authors LIMIT 1; + + -- name: MakeSearchIndex :exec ++CREATE VIRTUAL TABLE IF NOT EXISTS notes_fts USING fts5(body, tag UNINDEXED, tokenize = 'porter'); +-CREATE VIRTUAL TABLE IF NOT EXISTS notes_fts USING fts5(body, tag UNINDEXED, tokenize = 'porter'); + + -- name: MakeRecipeIndex :exec + CREATE VIRTUAL TABLE recipes_fts USING fts5( +@@ -67,7 +74,7 @@ + ); + + -- name: LoginName :one ++SELECT coalesce(bio, '') AS login FROM authors WHERE id = ? LIMIT 1; +-SELECT COALESCE(bio, '') AS login FROM authors WHERE id = ? LIMIT 1; + + -- name: SpelledJoins :many + SELECT a.id +@@ -74,6 +81,6 @@ + FROM authors AS a ++JOIN authors AS b ON a.id = b.id ++LEFT JOIN authors AS c ON a.id = c.id +-INNER JOIN authors AS b ON a.id = b.id +-LEFT OUTER JOIN authors AS c ON a.id = c.id + WHERE a.id != ? AND b.id == ? AND c.id <> ?; + + -- name: CommaJoin :one diff --git a/internal/endtoend/testdata/full_outer_join/sqlite/go/db.go b/internal/endtoend/testdata/full_outer_join/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/full_outer_join/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/full_outer_join/sqlite/go/models.go b/internal/endtoend/testdata/full_outer_join/sqlite/go/models.go new file mode 100644 index 0000000..91cfc66 --- /dev/null +++ b/internal/endtoend/testdata/full_outer_join/sqlite/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Author struct { + ID int64 + Name string +} + +type Book struct { + ID int64 + Title string +} 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 new file mode 100644 index 0000000..5f51471 --- /dev/null +++ b/internal/endtoend/testdata/full_outer_join/sqlite/go/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const getAuthor = `-- name: GetAuthor :one +SELECT a.id, name, b.id, title +FROM authors AS a +FULL JOIN books AS b ON a.id = b.id +WHERE a.id = ? +LIMIT 1 +` + +type GetAuthorRow struct { + ID sql.NullInt64 + Name sql.NullString + ID_2 sql.NullInt64 + Title sql.NullString +} + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (GetAuthorRow, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i GetAuthorRow + err := row.Scan( + &i.ID, + &i.Name, + &i.ID_2, + &i.Title, + ) + return i, err +} diff --git a/internal/endtoend/testdata/full_outer_join/sqlite/query.sql b/internal/endtoend/testdata/full_outer_join/sqlite/query.sql new file mode 100644 index 0000000..979d255 --- /dev/null +++ b/internal/endtoend/testdata/full_outer_join/sqlite/query.sql @@ -0,0 +1,6 @@ +-- name: GetAuthor :one +SELECT * +FROM authors AS a +FULL JOIN books AS b ON a.id = b.id +WHERE a.id = ? +LIMIT 1; diff --git a/internal/endtoend/testdata/full_outer_join/sqlite/schema.sql b/internal/endtoend/testdata/full_outer_join/sqlite/schema.sql new file mode 100644 index 0000000..2018ca2 --- /dev/null +++ b/internal/endtoend/testdata/full_outer_join/sqlite/schema.sql @@ -0,0 +1,11 @@ +-- Example queries for sqlc +CREATE TABLE authors ( + id INTEGER PRIMARY KEY, + name text NOT NULL +); + +CREATE TABLE books ( + id INTEGER PRIMARY KEY, + title text NOT NULL +); + diff --git a/internal/endtoend/testdata/full_outer_join/sqlite/sqlc.json b/internal/endtoend/testdata/full_outer_join/sqlite/sqlc.json new file mode 100644 index 0000000..99b3b5f --- /dev/null +++ b/internal/endtoend/testdata/full_outer_join/sqlite/sqlc.json @@ -0,0 +1 @@ +{"version": "1", "packages": [{"path": "go", "engine": "sqlite", "schema": "schema.sql", "queries": "query.sql", "name": "querytest"}]} \ No newline at end of file diff --git a/internal/endtoend/testdata/func_aggregate/pganalyze/exec.json b/internal/endtoend/testdata/func_aggregate/pganalyze/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/func_aggregate/pganalyze/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/func_aggregate/pganalyze/go/db.go b/internal/endtoend/testdata/func_aggregate/pganalyze/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/func_aggregate/pganalyze/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/func_aggregate/pganalyze/go/models.go b/internal/endtoend/testdata/func_aggregate/pganalyze/go/models.go new file mode 100644 index 0000000..2208139 --- /dev/null +++ b/internal/endtoend/testdata/func_aggregate/pganalyze/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/func_aggregate/pganalyze/go/query.sql.go b/internal/endtoend/testdata/func_aggregate/pganalyze/go/query.sql.go new file mode 100644 index 0000000..4727e1d --- /dev/null +++ b/internal/endtoend/testdata/func_aggregate/pganalyze/go/query.sql.go @@ -0,0 +1,22 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const percentile = `-- name: Percentile :one +select percentile_disc(0.5) within group (order by authors.name) +from authors +` + +func (q *Queries) Percentile(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, percentile) + var percentile_disc string + err := row.Scan(&percentile_disc) + return percentile_disc, err +} diff --git a/internal/endtoend/testdata/func_aggregate/pganalyze/query.sql b/internal/endtoend/testdata/func_aggregate/pganalyze/query.sql new file mode 100644 index 0000000..cdda823 --- /dev/null +++ b/internal/endtoend/testdata/func_aggregate/pganalyze/query.sql @@ -0,0 +1,3 @@ +-- name: Percentile :one +select percentile_disc(0.5) within group (order by authors.name) +from authors; diff --git a/internal/endtoend/testdata/func_aggregate/pganalyze/schema.sql b/internal/endtoend/testdata/func_aggregate/pganalyze/schema.sql new file mode 100644 index 0000000..290bbe1 --- /dev/null +++ b/internal/endtoend/testdata/func_aggregate/pganalyze/schema.sql @@ -0,0 +1,7 @@ +-- Example queries for sqlc +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); + diff --git a/internal/endtoend/testdata/func_aggregate/pganalyze/sqlc.json b/internal/endtoend/testdata/func_aggregate/pganalyze/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/func_aggregate/pganalyze/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/func_aggregate/postgresql/exec.json b/internal/endtoend/testdata/func_aggregate/postgresql/exec.json new file mode 100644 index 0000000..c16f123 --- /dev/null +++ b/internal/endtoend/testdata/func_aggregate/postgresql/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/func_aggregate/postgresql/go/db.go b/internal/endtoend/testdata/func_aggregate/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/func_aggregate/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/func_aggregate/postgresql/go/models.go b/internal/endtoend/testdata/func_aggregate/postgresql/go/models.go new file mode 100644 index 0000000..2208139 --- /dev/null +++ b/internal/endtoend/testdata/func_aggregate/postgresql/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/func_aggregate/postgresql/go/query.sql.go b/internal/endtoend/testdata/func_aggregate/postgresql/go/query.sql.go new file mode 100644 index 0000000..04707cb --- /dev/null +++ b/internal/endtoend/testdata/func_aggregate/postgresql/go/query.sql.go @@ -0,0 +1,22 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const percentile = `-- name: Percentile :one +select percentile_disc(0.5) within group (order by authors.name) +from authors +` + +func (q *Queries) Percentile(ctx context.Context) (any, error) { + row := q.db.QueryRowContext(ctx, percentile) + var percentile_disc any + err := row.Scan(&percentile_disc) + return percentile_disc, err +} diff --git a/internal/endtoend/testdata/func_aggregate/postgresql/query.sql b/internal/endtoend/testdata/func_aggregate/postgresql/query.sql new file mode 100644 index 0000000..cdda823 --- /dev/null +++ b/internal/endtoend/testdata/func_aggregate/postgresql/query.sql @@ -0,0 +1,3 @@ +-- name: Percentile :one +select percentile_disc(0.5) within group (order by authors.name) +from authors; diff --git a/internal/endtoend/testdata/func_aggregate/postgresql/schema.sql b/internal/endtoend/testdata/func_aggregate/postgresql/schema.sql new file mode 100644 index 0000000..290bbe1 --- /dev/null +++ b/internal/endtoend/testdata/func_aggregate/postgresql/schema.sql @@ -0,0 +1,7 @@ +-- Example queries for sqlc +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); + diff --git a/internal/endtoend/testdata/func_aggregate/postgresql/sqlc.json b/internal/endtoend/testdata/func_aggregate/postgresql/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/func_aggregate/postgresql/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/func_args/pgx/v4/go/db.go b/internal/endtoend/testdata/func_args/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/func_args/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/func_args/pgx/v4/go/models.go b/internal/endtoend/testdata/func_args/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/func_args/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/func_args/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/func_args/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..f520132 --- /dev/null +++ b/internal/endtoend/testdata/func_args/pgx/v4/go/query.sql.go @@ -0,0 +1,70 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const makeIntervalDays = `-- name: MakeIntervalDays :one +SELECT make_interval(days => $1::int) +` + +func (q *Queries) MakeIntervalDays(ctx context.Context, dollar_1 int32) (int64, error) { + row := q.db.QueryRow(ctx, makeIntervalDays, dollar_1) + var make_interval int64 + err := row.Scan(&make_interval) + return make_interval, err +} + +const makeIntervalMonths = `-- name: MakeIntervalMonths :one +SELECT make_interval(months => $1::int) +` + +func (q *Queries) MakeIntervalMonths(ctx context.Context, months int32) (int64, error) { + row := q.db.QueryRow(ctx, makeIntervalMonths, months) + var make_interval int64 + err := row.Scan(&make_interval) + return make_interval, err +} + +const makeIntervalSecs = `-- name: MakeIntervalSecs :one +SELECT make_interval(secs => $1) +` + +func (q *Queries) MakeIntervalSecs(ctx context.Context, secs float64) (int64, error) { + row := q.db.QueryRow(ctx, makeIntervalSecs, secs) + var make_interval int64 + err := row.Scan(&make_interval) + return make_interval, err +} + +const plus = `-- name: Plus :one +SELECT plus(b => $2, a => $1) +` + +type PlusParams struct { + A int32 + B int32 +} + +func (q *Queries) Plus(ctx context.Context, arg PlusParams) (int32, error) { + row := q.db.QueryRow(ctx, plus, arg.A, arg.B) + var plus int32 + err := row.Scan(&plus) + return plus, err +} + +const tableArgs = `-- name: TableArgs :one +SELECT table_args(x => $1) +` + +func (q *Queries) TableArgs(ctx context.Context, x int32) (int32, error) { + row := q.db.QueryRow(ctx, tableArgs, x) + var table_args int32 + err := row.Scan(&table_args) + return table_args, err +} diff --git a/internal/endtoend/testdata/func_args/pgx/v4/query.sql b/internal/endtoend/testdata/func_args/pgx/v4/query.sql new file mode 100644 index 0000000..7ca3eac --- /dev/null +++ b/internal/endtoend/testdata/func_args/pgx/v4/query.sql @@ -0,0 +1,14 @@ +-- name: Plus :one +SELECT plus(b => $2, a => $1); + +-- name: MakeIntervalSecs :one +SELECT make_interval(secs => $1); + +-- name: MakeIntervalDays :one +SELECT make_interval(days => $1::int); + +-- name: MakeIntervalMonths :one +SELECT make_interval(months => sqlc.arg('months')::int); + +-- name: TableArgs :one +SELECT table_args(x => $1); diff --git a/internal/endtoend/testdata/func_args/pgx/v4/schema.sql b/internal/endtoend/testdata/func_args/pgx/v4/schema.sql new file mode 100644 index 0000000..0ba81c1 --- /dev/null +++ b/internal/endtoend/testdata/func_args/pgx/v4/schema.sql @@ -0,0 +1,8 @@ +CREATE FUNCTION plus(a integer, b integer) RETURNS integer AS $$ + BEGIN + RETURN a + b; + END; +$$ LANGUAGE plpgsql; + +CREATE FUNCTION table_args(x INT) RETURNS TABLE (y INT) AS 'SELECT x' LANGUAGE sql; + diff --git a/internal/endtoend/testdata/func_args/pgx/v4/sqlc.json b/internal/endtoend/testdata/func_args/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/func_args/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/func_args/pgx/v5/go/db.go b/internal/endtoend/testdata/func_args/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/func_args/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/func_args/pgx/v5/go/models.go b/internal/endtoend/testdata/func_args/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/func_args/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/func_args/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/func_args/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..953e59d --- /dev/null +++ b/internal/endtoend/testdata/func_args/pgx/v5/go/query.sql.go @@ -0,0 +1,72 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const makeIntervalDays = `-- name: MakeIntervalDays :one +SELECT make_interval(days => $1::int) +` + +func (q *Queries) MakeIntervalDays(ctx context.Context, dollar_1 int32) (pgtype.Interval, error) { + row := q.db.QueryRow(ctx, makeIntervalDays, dollar_1) + var make_interval pgtype.Interval + err := row.Scan(&make_interval) + return make_interval, err +} + +const makeIntervalMonths = `-- name: MakeIntervalMonths :one +SELECT make_interval(months => $1::int) +` + +func (q *Queries) MakeIntervalMonths(ctx context.Context, months int32) (pgtype.Interval, error) { + row := q.db.QueryRow(ctx, makeIntervalMonths, months) + var make_interval pgtype.Interval + err := row.Scan(&make_interval) + return make_interval, err +} + +const makeIntervalSecs = `-- name: MakeIntervalSecs :one +SELECT make_interval(secs => $1) +` + +func (q *Queries) MakeIntervalSecs(ctx context.Context, secs float64) (pgtype.Interval, error) { + row := q.db.QueryRow(ctx, makeIntervalSecs, secs) + var make_interval pgtype.Interval + err := row.Scan(&make_interval) + return make_interval, err +} + +const plus = `-- name: Plus :one +SELECT plus(b => $2, a => $1) +` + +type PlusParams struct { + A int32 + B int32 +} + +func (q *Queries) Plus(ctx context.Context, arg PlusParams) (int32, error) { + row := q.db.QueryRow(ctx, plus, arg.A, arg.B) + var plus int32 + err := row.Scan(&plus) + return plus, err +} + +const tableArgs = `-- name: TableArgs :one +SELECT table_args(x => $1) +` + +func (q *Queries) TableArgs(ctx context.Context, x int32) (int32, error) { + row := q.db.QueryRow(ctx, tableArgs, x) + var table_args int32 + err := row.Scan(&table_args) + return table_args, err +} diff --git a/internal/endtoend/testdata/func_args/pgx/v5/query.sql b/internal/endtoend/testdata/func_args/pgx/v5/query.sql new file mode 100644 index 0000000..7ca3eac --- /dev/null +++ b/internal/endtoend/testdata/func_args/pgx/v5/query.sql @@ -0,0 +1,14 @@ +-- name: Plus :one +SELECT plus(b => $2, a => $1); + +-- name: MakeIntervalSecs :one +SELECT make_interval(secs => $1); + +-- name: MakeIntervalDays :one +SELECT make_interval(days => $1::int); + +-- name: MakeIntervalMonths :one +SELECT make_interval(months => sqlc.arg('months')::int); + +-- name: TableArgs :one +SELECT table_args(x => $1); diff --git a/internal/endtoend/testdata/func_args/pgx/v5/schema.sql b/internal/endtoend/testdata/func_args/pgx/v5/schema.sql new file mode 100644 index 0000000..0ba81c1 --- /dev/null +++ b/internal/endtoend/testdata/func_args/pgx/v5/schema.sql @@ -0,0 +1,8 @@ +CREATE FUNCTION plus(a integer, b integer) RETURNS integer AS $$ + BEGIN + RETURN a + b; + END; +$$ LANGUAGE plpgsql; + +CREATE FUNCTION table_args(x INT) RETURNS TABLE (y INT) AS 'SELECT x' LANGUAGE sql; + diff --git a/internal/endtoend/testdata/func_args/pgx/v5/sqlc.json b/internal/endtoend/testdata/func_args/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/func_args/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/func_args/stdlib/go/db.go b/internal/endtoend/testdata/func_args/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/func_args/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/func_args/stdlib/go/models.go b/internal/endtoend/testdata/func_args/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/func_args/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/func_args/stdlib/go/query.sql.go b/internal/endtoend/testdata/func_args/stdlib/go/query.sql.go new file mode 100644 index 0000000..fbdc347 --- /dev/null +++ b/internal/endtoend/testdata/func_args/stdlib/go/query.sql.go @@ -0,0 +1,70 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const makeIntervalDays = `-- name: MakeIntervalDays :one +SELECT make_interval(days => $1::int) +` + +func (q *Queries) MakeIntervalDays(ctx context.Context, dollar_1 int32) (int64, error) { + row := q.db.QueryRowContext(ctx, makeIntervalDays, dollar_1) + var make_interval int64 + err := row.Scan(&make_interval) + return make_interval, err +} + +const makeIntervalMonths = `-- name: MakeIntervalMonths :one +SELECT make_interval(months => $1::int) +` + +func (q *Queries) MakeIntervalMonths(ctx context.Context, months int32) (int64, error) { + row := q.db.QueryRowContext(ctx, makeIntervalMonths, months) + var make_interval int64 + err := row.Scan(&make_interval) + return make_interval, err +} + +const makeIntervalSecs = `-- name: MakeIntervalSecs :one +SELECT make_interval(secs => $1) +` + +func (q *Queries) MakeIntervalSecs(ctx context.Context, secs float64) (int64, error) { + row := q.db.QueryRowContext(ctx, makeIntervalSecs, secs) + var make_interval int64 + err := row.Scan(&make_interval) + return make_interval, err +} + +const plus = `-- name: Plus :one +SELECT plus(b => $2, a => $1) +` + +type PlusParams struct { + A int32 + B int32 +} + +func (q *Queries) Plus(ctx context.Context, arg PlusParams) (int32, error) { + row := q.db.QueryRowContext(ctx, plus, arg.A, arg.B) + var plus int32 + err := row.Scan(&plus) + return plus, err +} + +const tableArgs = `-- name: TableArgs :one +SELECT table_args(x => $1) +` + +func (q *Queries) TableArgs(ctx context.Context, x int32) (int32, error) { + row := q.db.QueryRowContext(ctx, tableArgs, x) + var table_args int32 + err := row.Scan(&table_args) + return table_args, err +} diff --git a/internal/endtoend/testdata/func_args/stdlib/query.sql b/internal/endtoend/testdata/func_args/stdlib/query.sql new file mode 100644 index 0000000..7ca3eac --- /dev/null +++ b/internal/endtoend/testdata/func_args/stdlib/query.sql @@ -0,0 +1,14 @@ +-- name: Plus :one +SELECT plus(b => $2, a => $1); + +-- name: MakeIntervalSecs :one +SELECT make_interval(secs => $1); + +-- name: MakeIntervalDays :one +SELECT make_interval(days => $1::int); + +-- name: MakeIntervalMonths :one +SELECT make_interval(months => sqlc.arg('months')::int); + +-- name: TableArgs :one +SELECT table_args(x => $1); diff --git a/internal/endtoend/testdata/func_args/stdlib/schema.sql b/internal/endtoend/testdata/func_args/stdlib/schema.sql new file mode 100644 index 0000000..0ba81c1 --- /dev/null +++ b/internal/endtoend/testdata/func_args/stdlib/schema.sql @@ -0,0 +1,8 @@ +CREATE FUNCTION plus(a integer, b integer) RETURNS integer AS $$ + BEGIN + RETURN a + b; + END; +$$ LANGUAGE plpgsql; + +CREATE FUNCTION table_args(x INT) RETURNS TABLE (y INT) AS 'SELECT x' LANGUAGE sql; + diff --git a/internal/endtoend/testdata/func_args/stdlib/sqlc.json b/internal/endtoend/testdata/func_args/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/func_args/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/func_args_typecast/pgx/v4/go/db.go b/internal/endtoend/testdata/func_args_typecast/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/func_args_typecast/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/func_args_typecast/pgx/v4/go/models.go b/internal/endtoend/testdata/func_args_typecast/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/func_args_typecast/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/func_args_typecast/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/func_args_typecast/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..bf68c7c --- /dev/null +++ b/internal/endtoend/testdata/func_args_typecast/pgx/v4/go/query.sql.go @@ -0,0 +1,26 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const plusPositionalCast = `-- name: PlusPositionalCast :one +SELECT plus($1, $2::INTEGER) +` + +type PlusPositionalCastParams struct { + A int32 + Column2 int32 +} + +func (q *Queries) PlusPositionalCast(ctx context.Context, arg PlusPositionalCastParams) (int32, error) { + row := q.db.QueryRow(ctx, plusPositionalCast, arg.A, arg.Column2) + var plus int32 + err := row.Scan(&plus) + return plus, err +} diff --git a/internal/endtoend/testdata/func_args_typecast/pgx/v4/query.sql b/internal/endtoend/testdata/func_args_typecast/pgx/v4/query.sql new file mode 100644 index 0000000..5c5fccf --- /dev/null +++ b/internal/endtoend/testdata/func_args_typecast/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: PlusPositionalCast :one +SELECT plus($1, $2::INTEGER); diff --git a/internal/endtoend/testdata/func_args_typecast/pgx/v4/schema.sql b/internal/endtoend/testdata/func_args_typecast/pgx/v4/schema.sql new file mode 100644 index 0000000..1484900 --- /dev/null +++ b/internal/endtoend/testdata/func_args_typecast/pgx/v4/schema.sql @@ -0,0 +1,6 @@ +CREATE FUNCTION plus(a integer, b integer) RETURNS integer AS $$ + BEGIN + RETURN a + b; + END; +$$ LANGUAGE plpgsql; + diff --git a/internal/endtoend/testdata/func_args_typecast/pgx/v4/sqlc.json b/internal/endtoend/testdata/func_args_typecast/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/func_args_typecast/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/func_args_typecast/pgx/v5/go/db.go b/internal/endtoend/testdata/func_args_typecast/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/func_args_typecast/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/func_args_typecast/pgx/v5/go/models.go b/internal/endtoend/testdata/func_args_typecast/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/func_args_typecast/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/func_args_typecast/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/func_args_typecast/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..bf68c7c --- /dev/null +++ b/internal/endtoend/testdata/func_args_typecast/pgx/v5/go/query.sql.go @@ -0,0 +1,26 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const plusPositionalCast = `-- name: PlusPositionalCast :one +SELECT plus($1, $2::INTEGER) +` + +type PlusPositionalCastParams struct { + A int32 + Column2 int32 +} + +func (q *Queries) PlusPositionalCast(ctx context.Context, arg PlusPositionalCastParams) (int32, error) { + row := q.db.QueryRow(ctx, plusPositionalCast, arg.A, arg.Column2) + var plus int32 + err := row.Scan(&plus) + return plus, err +} diff --git a/internal/endtoend/testdata/func_args_typecast/pgx/v5/query.sql b/internal/endtoend/testdata/func_args_typecast/pgx/v5/query.sql new file mode 100644 index 0000000..5c5fccf --- /dev/null +++ b/internal/endtoend/testdata/func_args_typecast/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: PlusPositionalCast :one +SELECT plus($1, $2::INTEGER); diff --git a/internal/endtoend/testdata/func_args_typecast/pgx/v5/schema.sql b/internal/endtoend/testdata/func_args_typecast/pgx/v5/schema.sql new file mode 100644 index 0000000..1484900 --- /dev/null +++ b/internal/endtoend/testdata/func_args_typecast/pgx/v5/schema.sql @@ -0,0 +1,6 @@ +CREATE FUNCTION plus(a integer, b integer) RETURNS integer AS $$ + BEGIN + RETURN a + b; + END; +$$ LANGUAGE plpgsql; + diff --git a/internal/endtoend/testdata/func_args_typecast/pgx/v5/sqlc.json b/internal/endtoend/testdata/func_args_typecast/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/func_args_typecast/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/func_args_typecast/stdlib/go/db.go b/internal/endtoend/testdata/func_args_typecast/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/func_args_typecast/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/func_args_typecast/stdlib/go/models.go b/internal/endtoend/testdata/func_args_typecast/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/func_args_typecast/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/func_args_typecast/stdlib/go/query.sql.go b/internal/endtoend/testdata/func_args_typecast/stdlib/go/query.sql.go new file mode 100644 index 0000000..1fb0200 --- /dev/null +++ b/internal/endtoend/testdata/func_args_typecast/stdlib/go/query.sql.go @@ -0,0 +1,26 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const plusPositionalCast = `-- name: PlusPositionalCast :one +SELECT plus($1, $2::INTEGER) +` + +type PlusPositionalCastParams struct { + A int32 + Column2 int32 +} + +func (q *Queries) PlusPositionalCast(ctx context.Context, arg PlusPositionalCastParams) (int32, error) { + row := q.db.QueryRowContext(ctx, plusPositionalCast, arg.A, arg.Column2) + var plus int32 + err := row.Scan(&plus) + return plus, err +} diff --git a/internal/endtoend/testdata/func_args_typecast/stdlib/query.sql b/internal/endtoend/testdata/func_args_typecast/stdlib/query.sql new file mode 100644 index 0000000..5c5fccf --- /dev/null +++ b/internal/endtoend/testdata/func_args_typecast/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: PlusPositionalCast :one +SELECT plus($1, $2::INTEGER); diff --git a/internal/endtoend/testdata/func_args_typecast/stdlib/schema.sql b/internal/endtoend/testdata/func_args_typecast/stdlib/schema.sql new file mode 100644 index 0000000..1484900 --- /dev/null +++ b/internal/endtoend/testdata/func_args_typecast/stdlib/schema.sql @@ -0,0 +1,6 @@ +CREATE FUNCTION plus(a integer, b integer) RETURNS integer AS $$ + BEGIN + RETURN a + b; + END; +$$ LANGUAGE plpgsql; + diff --git a/internal/endtoend/testdata/func_args_typecast/stdlib/sqlc.json b/internal/endtoend/testdata/func_args_typecast/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/func_args_typecast/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/func_call_cast/mysql/go/db.go b/internal/endtoend/testdata/func_call_cast/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/func_call_cast/mysql/go/models.go b/internal/endtoend/testdata/func_call_cast/mysql/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/mysql/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/func_call_cast/mysql/go/query.sql.go b/internal/endtoend/testdata/func_call_cast/mysql/go/query.sql.go new file mode 100644 index 0000000..8807bc6 --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/mysql/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const demo = `-- name: Demo :one +SELECT CAST(GREATEST(1,2,3,4,5) AS UNSIGNED) as col1 +` + +func (q *Queries) Demo(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, demo) + var col1 int64 + err := row.Scan(&col1) + return col1, err +} diff --git a/internal/endtoend/testdata/func_call_cast/mysql/query.sql b/internal/endtoend/testdata/func_call_cast/mysql/query.sql new file mode 100644 index 0000000..b653151 --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: Demo :one +SELECT CAST(GREATEST(1,2,3,4,5) AS UNSIGNED) as col1 diff --git a/internal/endtoend/testdata/func_call_cast/mysql/schema.sql b/internal/endtoend/testdata/func_call_cast/mysql/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/func_call_cast/mysql/sqlc.json b/internal/endtoend/testdata/func_call_cast/mysql/sqlc.json new file mode 100644 index 0000000..0390f67 --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/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/func_call_cast/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/func_call_cast/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..02480c0 --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,23 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/google/uuid" +) + +const demo = `-- name: Demo :one +SELECT uuid_generate_v5('7c4597a0-8cfa-4c19-8da0-b8474a36440d', $1)::uuid as col1 +` + +func (q *Queries) Demo(ctx context.Context, name string) (uuid.UUID, error) { + row := q.db.QueryRow(ctx, demo, name) + var col1 uuid.UUID + err := row.Scan(&col1) + return col1, err +} diff --git a/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..fa02ef7 --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Demo :one +SELECT uuid_generate_v5('7c4597a0-8cfa-4c19-8da0-b8474a36440d', $1)::uuid as col1; diff --git a/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..682131d --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v4/schema.sql @@ -0,0 +1 @@ +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; \ No newline at end of file diff --git a/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/func_call_cast/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..9de4f9e --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,23 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const demo = `-- name: Demo :one +SELECT uuid_generate_v5('7c4597a0-8cfa-4c19-8da0-b8474a36440d', $1)::uuid as col1 +` + +func (q *Queries) Demo(ctx context.Context, name string) (pgtype.UUID, error) { + row := q.db.QueryRow(ctx, demo, name) + var col1 pgtype.UUID + err := row.Scan(&col1) + return col1, err +} diff --git a/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..fa02ef7 --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Demo :one +SELECT uuid_generate_v5('7c4597a0-8cfa-4c19-8da0-b8474a36440d', $1)::uuid as col1; diff --git a/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..682131d --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v5/schema.sql @@ -0,0 +1 @@ +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; \ No newline at end of file diff --git a/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/func_call_cast/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/func_call_cast/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/func_call_cast/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/func_call_cast/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/func_call_cast/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/func_call_cast/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..2c648a8 --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,23 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/google/uuid" +) + +const demo = `-- name: Demo :one +SELECT uuid_generate_v5('7c4597a0-8cfa-4c19-8da0-b8474a36440d', $1)::uuid as col1 +` + +func (q *Queries) Demo(ctx context.Context, name string) (uuid.UUID, error) { + row := q.db.QueryRowContext(ctx, demo, name) + var col1 uuid.UUID + err := row.Scan(&col1) + return col1, err +} diff --git a/internal/endtoend/testdata/func_call_cast/postgresql/stdlib/query.sql b/internal/endtoend/testdata/func_call_cast/postgresql/stdlib/query.sql new file mode 100644 index 0000000..fa02ef7 --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Demo :one +SELECT uuid_generate_v5('7c4597a0-8cfa-4c19-8da0-b8474a36440d', $1)::uuid as col1; diff --git a/internal/endtoend/testdata/func_call_cast/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/func_call_cast/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..682131d --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/postgresql/stdlib/schema.sql @@ -0,0 +1 @@ +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; \ No newline at end of file diff --git a/internal/endtoend/testdata/func_call_cast/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/func_call_cast/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/postgresql/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/func_call_cast/sqlite/go/db.go b/internal/endtoend/testdata/func_call_cast/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/func_call_cast/sqlite/go/models.go b/internal/endtoend/testdata/func_call_cast/sqlite/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/sqlite/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/func_call_cast/sqlite/go/query.sql.go b/internal/endtoend/testdata/func_call_cast/sqlite/go/query.sql.go new file mode 100644 index 0000000..5d39885 --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/sqlite/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const demo = `-- name: Demo :one +SELECT CAST(char(1, 2, 3, 4, 5) AS BLOB) AS col1 +` + +func (q *Queries) Demo(ctx context.Context) ([]byte, error) { + row := q.db.QueryRowContext(ctx, demo) + var col1 []byte + err := row.Scan(&col1) + return col1, err +} diff --git a/internal/endtoend/testdata/func_call_cast/sqlite/query.sql b/internal/endtoend/testdata/func_call_cast/sqlite/query.sql new file mode 100644 index 0000000..2f27801 --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: Demo :one +SELECT CAST(char(1, 2, 3, 4, 5) AS BLOB) AS col1; diff --git a/internal/endtoend/testdata/func_call_cast/sqlite/schema.sql b/internal/endtoend/testdata/func_call_cast/sqlite/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/func_call_cast/sqlite/sqlc.json b/internal/endtoend/testdata/func_call_cast/sqlite/sqlc.json new file mode 100644 index 0000000..95b9cd0 --- /dev/null +++ b/internal/endtoend/testdata/func_call_cast/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/func_match_types/mysql/go/db.go b/internal/endtoend/testdata/func_match_types/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/func_match_types/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/func_match_types/mysql/go/models.go b/internal/endtoend/testdata/func_match_types/mysql/go/models.go new file mode 100644 index 0000000..c3bea23 --- /dev/null +++ b/internal/endtoend/testdata/func_match_types/mysql/go/models.go @@ -0,0 +1,12 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Book struct { + ID int32 + Title string + Author string + Pages int32 +} diff --git a/internal/endtoend/testdata/func_match_types/mysql/go/query.sql.go b/internal/endtoend/testdata/func_match_types/mysql/go/query.sql.go new file mode 100644 index 0000000..ebbde97 --- /dev/null +++ b/internal/endtoend/testdata/func_match_types/mysql/go/query.sql.go @@ -0,0 +1,45 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const authorPages = `-- name: AuthorPages :many +select author, count(title) as num_books, SUM(pages) as total_pages +from books +group by author +` + +type AuthorPagesRow struct { + Author string + NumBooks int64 + TotalPages any +} + +func (q *Queries) AuthorPages(ctx context.Context) ([]AuthorPagesRow, error) { + rows, err := q.db.QueryContext(ctx, authorPages) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AuthorPagesRow + for rows.Next() { + var i AuthorPagesRow + if err := rows.Scan(&i.Author, &i.NumBooks, &i.TotalPages); 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/func_match_types/mysql/query.sql b/internal/endtoend/testdata/func_match_types/mysql/query.sql new file mode 100644 index 0000000..e3ad547 --- /dev/null +++ b/internal/endtoend/testdata/func_match_types/mysql/query.sql @@ -0,0 +1,4 @@ +-- name: AuthorPages :many +select author, count(title) as num_books, SUM(pages) as total_pages +from books +group by author; diff --git a/internal/endtoend/testdata/func_match_types/mysql/schema.sql b/internal/endtoend/testdata/func_match_types/mysql/schema.sql new file mode 100644 index 0000000..04aa15f --- /dev/null +++ b/internal/endtoend/testdata/func_match_types/mysql/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE books ( + id integer PRIMARY KEY, + title text NOT NULL, + author text NOT NULL, + pages integer NOT NULL +); diff --git a/internal/endtoend/testdata/func_match_types/mysql/sqlc.json b/internal/endtoend/testdata/func_match_types/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/func_match_types/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/func_match_types/postgresql/go/db.go b/internal/endtoend/testdata/func_match_types/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/func_match_types/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/func_match_types/postgresql/go/models.go b/internal/endtoend/testdata/func_match_types/postgresql/go/models.go new file mode 100644 index 0000000..c3bea23 --- /dev/null +++ b/internal/endtoend/testdata/func_match_types/postgresql/go/models.go @@ -0,0 +1,12 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Book struct { + ID int32 + Title string + Author string + Pages int32 +} diff --git a/internal/endtoend/testdata/func_match_types/postgresql/go/query.sql.go b/internal/endtoend/testdata/func_match_types/postgresql/go/query.sql.go new file mode 100644 index 0000000..5a1be47 --- /dev/null +++ b/internal/endtoend/testdata/func_match_types/postgresql/go/query.sql.go @@ -0,0 +1,45 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const authorPages = `-- name: AuthorPages :many +select author, count(title) as num_books, SUM(pages) as total_pages +from books +group by author +` + +type AuthorPagesRow struct { + Author string + NumBooks int64 + TotalPages int64 +} + +func (q *Queries) AuthorPages(ctx context.Context) ([]AuthorPagesRow, error) { + rows, err := q.db.QueryContext(ctx, authorPages) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AuthorPagesRow + for rows.Next() { + var i AuthorPagesRow + if err := rows.Scan(&i.Author, &i.NumBooks, &i.TotalPages); 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/func_match_types/postgresql/query.sql b/internal/endtoend/testdata/func_match_types/postgresql/query.sql new file mode 100644 index 0000000..e3ad547 --- /dev/null +++ b/internal/endtoend/testdata/func_match_types/postgresql/query.sql @@ -0,0 +1,4 @@ +-- name: AuthorPages :many +select author, count(title) as num_books, SUM(pages) as total_pages +from books +group by author; diff --git a/internal/endtoend/testdata/func_match_types/postgresql/schema.sql b/internal/endtoend/testdata/func_match_types/postgresql/schema.sql new file mode 100644 index 0000000..cf91381 --- /dev/null +++ b/internal/endtoend/testdata/func_match_types/postgresql/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE books ( + id integer PRIMARY KEY, + title text NOT NULL, + author text NOT NULL, + pages integer NOT NULL +); diff --git a/internal/endtoend/testdata/func_match_types/postgresql/sqlc.json b/internal/endtoend/testdata/func_match_types/postgresql/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/func_match_types/postgresql/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/func_match_types/sqlite/go/db.go b/internal/endtoend/testdata/func_match_types/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/func_match_types/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/func_match_types/sqlite/go/models.go b/internal/endtoend/testdata/func_match_types/sqlite/go/models.go new file mode 100644 index 0000000..73110b7 --- /dev/null +++ b/internal/endtoend/testdata/func_match_types/sqlite/go/models.go @@ -0,0 +1,12 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Book struct { + ID int64 + Title string + Author string + Pages int64 +} diff --git a/internal/endtoend/testdata/func_match_types/sqlite/go/query.sql.go b/internal/endtoend/testdata/func_match_types/sqlite/go/query.sql.go new file mode 100644 index 0000000..8e56ea3 --- /dev/null +++ b/internal/endtoend/testdata/func_match_types/sqlite/go/query.sql.go @@ -0,0 +1,46 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const authorPages = `-- name: AuthorPages :many +SELECT author, count(title) AS num_books, sum(pages) AS total_pages +FROM books +GROUP BY author +` + +type AuthorPagesRow struct { + Author string + NumBooks int64 + TotalPages sql.NullFloat64 +} + +func (q *Queries) AuthorPages(ctx context.Context) ([]AuthorPagesRow, error) { + rows, err := q.db.QueryContext(ctx, authorPages) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AuthorPagesRow + for rows.Next() { + var i AuthorPagesRow + if err := rows.Scan(&i.Author, &i.NumBooks, &i.TotalPages); 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/func_match_types/sqlite/query.sql b/internal/endtoend/testdata/func_match_types/sqlite/query.sql new file mode 100644 index 0000000..fb20ace --- /dev/null +++ b/internal/endtoend/testdata/func_match_types/sqlite/query.sql @@ -0,0 +1,4 @@ +-- name: AuthorPages :many +SELECT author, count(title) AS num_books, sum(pages) AS total_pages +FROM books +GROUP BY author; diff --git a/internal/endtoend/testdata/func_match_types/sqlite/schema.sql b/internal/endtoend/testdata/func_match_types/sqlite/schema.sql new file mode 100644 index 0000000..04aa15f --- /dev/null +++ b/internal/endtoend/testdata/func_match_types/sqlite/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE books ( + id integer PRIMARY KEY, + title text NOT NULL, + author text NOT NULL, + pages integer NOT NULL +); diff --git a/internal/endtoend/testdata/func_match_types/sqlite/sqlc.json b/internal/endtoend/testdata/func_match_types/sqlite/sqlc.json new file mode 100644 index 0000000..cd66df0 --- /dev/null +++ b/internal/endtoend/testdata/func_match_types/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/func_out_param/issue.md b/internal/endtoend/testdata/func_out_param/issue.md new file mode 100644 index 0000000..1b8779f --- /dev/null +++ b/internal/endtoend/testdata/func_out_param/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1654 diff --git a/internal/endtoend/testdata/func_out_param/pgx/go/db.go b/internal/endtoend/testdata/func_out_param/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/func_out_param/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/func_out_param/pgx/go/models.go b/internal/endtoend/testdata/func_out_param/pgx/go/models.go new file mode 100644 index 0000000..4e97f66 --- /dev/null +++ b/internal/endtoend/testdata/func_out_param/pgx/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Author struct { + ID int64 + Name string + Bio pgtype.Text +} diff --git a/internal/endtoend/testdata/func_out_param/pgx/go/query.sql.go b/internal/endtoend/testdata/func_out_param/pgx/go/query.sql.go new file mode 100644 index 0000000..2208cc1 --- /dev/null +++ b/internal/endtoend/testdata/func_out_param/pgx/go/query.sql.go @@ -0,0 +1,30 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const createAuthor = `-- name: CreateAuthor :one +SELECT id FROM add_author ( + $1, $2 +) +` + +type CreateAuthorParams struct { + Name string + Bio string +} + +func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (pgtype.Int4, error) { + row := q.db.QueryRow(ctx, createAuthor, arg.Name, arg.Bio) + var id pgtype.Int4 + err := row.Scan(&id) + return id, err +} diff --git a/internal/endtoend/testdata/func_out_param/pgx/query.sql b/internal/endtoend/testdata/func_out_param/pgx/query.sql new file mode 100644 index 0000000..b23c7dc --- /dev/null +++ b/internal/endtoend/testdata/func_out_param/pgx/query.sql @@ -0,0 +1,4 @@ +-- name: CreateAuthor :one +SELECT * FROM add_author ( + sqlc.arg(name), sqlc.arg(bio) +); diff --git a/internal/endtoend/testdata/func_out_param/pgx/schema.sql b/internal/endtoend/testdata/func_out_param/pgx/schema.sql new file mode 100644 index 0000000..97c1022 --- /dev/null +++ b/internal/endtoend/testdata/func_out_param/pgx/schema.sql @@ -0,0 +1,14 @@ +-- Example queries for sqlc +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); + +CREATE OR REPLACE FUNCTION add_author (name text, bio text, out id int) +AS $$ +DECLARE +BEGIN + id = 123; +END; +$$ LANGUAGE plpgsql; diff --git a/internal/endtoend/testdata/func_out_param/pgx/sqlc.yaml b/internal/endtoend/testdata/func_out_param/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/func_out_param/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/func_return_date/postgresql/pganalyze/exec.json b/internal/endtoend/testdata/func_return_date/postgresql/pganalyze/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/func_return_date/postgresql/pganalyze/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/func_return_date/postgresql/pganalyze/go/db.go b/internal/endtoend/testdata/func_return_date/postgresql/pganalyze/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/func_return_date/postgresql/pganalyze/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/func_return_date/postgresql/pganalyze/go/models.go b/internal/endtoend/testdata/func_return_date/postgresql/pganalyze/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/func_return_date/postgresql/pganalyze/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/func_return_date/postgresql/pganalyze/go/query.sql.go b/internal/endtoend/testdata/func_return_date/postgresql/pganalyze/go/query.sql.go new file mode 100644 index 0000000..00ee09a --- /dev/null +++ b/internal/endtoend/testdata/func_return_date/postgresql/pganalyze/go/query.sql.go @@ -0,0 +1,23 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const getDate = `-- name: GetDate :one +SELECT now from NOW() +` + +func (q *Queries) GetDate(ctx context.Context) (pgtype.Timestamptz, error) { + row := q.db.QueryRow(ctx, getDate) + var now pgtype.Timestamptz + err := row.Scan(&now) + return now, err +} diff --git a/internal/endtoend/testdata/func_return_date/postgresql/pganalyze/query.sql b/internal/endtoend/testdata/func_return_date/postgresql/pganalyze/query.sql new file mode 100644 index 0000000..8f71309 --- /dev/null +++ b/internal/endtoend/testdata/func_return_date/postgresql/pganalyze/query.sql @@ -0,0 +1,2 @@ +/* name: GetDate :one */ +SELECT * from NOW(); \ No newline at end of file diff --git a/internal/endtoend/testdata/func_return_date/postgresql/pganalyze/schema.sql b/internal/endtoend/testdata/func_return_date/postgresql/pganalyze/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/func_return_date/postgresql/pganalyze/sqlc.json b/internal/endtoend/testdata/func_return_date/postgresql/pganalyze/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/func_return_date/postgresql/pganalyze/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/exec.json b/internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/func_return_date/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..ebdc67b --- /dev/null +++ b/internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getDate = `-- name: GetDate :one +SELECT from CURRENT_DATE +` + +type GetDateRow struct { +} + +func (q *Queries) GetDate(ctx context.Context) (GetDateRow, error) { + row := q.db.QueryRow(ctx, getDate) + var i GetDateRow + err := row.Scan() + return i, err +} diff --git a/internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..b5696a9 --- /dev/null +++ b/internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +/* name: GetDate :one */ +SELECT * from CURRENT_DATE; diff --git a/internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/func_return_date/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/func_return_date/postgresql/stdlib/exec.json b/internal/endtoend/testdata/func_return_date/postgresql/stdlib/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/func_return_date/postgresql/stdlib/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/func_return_date/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/func_return_date/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/func_return_date/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/func_return_date/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/func_return_date/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/func_return_date/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/func_return_date/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/func_return_date/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..456c692 --- /dev/null +++ b/internal/endtoend/testdata/func_return_date/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getDate = `-- name: GetDate :one +SELECT from CURRENT_DATE +` + +type GetDateRow struct { +} + +func (q *Queries) GetDate(ctx context.Context) (GetDateRow, error) { + row := q.db.QueryRowContext(ctx, getDate) + var i GetDateRow + err := row.Scan() + return i, err +} diff --git a/internal/endtoend/testdata/func_return_date/postgresql/stdlib/query.sql b/internal/endtoend/testdata/func_return_date/postgresql/stdlib/query.sql new file mode 100644 index 0000000..b5696a9 --- /dev/null +++ b/internal/endtoend/testdata/func_return_date/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +/* name: GetDate :one */ +SELECT * from CURRENT_DATE; diff --git a/internal/endtoend/testdata/func_return_date/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/func_return_date/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/func_return_date/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/func_return_date/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/func_return_date/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/func_return_record/issue.md b/internal/endtoend/testdata/func_return_record/issue.md new file mode 100644 index 0000000..56e6829 --- /dev/null +++ b/internal/endtoend/testdata/func_return_record/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1979 diff --git a/internal/endtoend/testdata/func_return_record/postgresql/pgx/exec.json b/internal/endtoend/testdata/func_return_record/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/func_return_record/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/func_return_record/postgresql/pgx/go/db.go b/internal/endtoend/testdata/func_return_record/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/func_return_record/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/func_return_record/postgresql/pgx/go/models.go b/internal/endtoend/testdata/func_return_record/postgresql/pgx/go/models.go new file mode 100644 index 0000000..7d67832 --- /dev/null +++ b/internal/endtoend/testdata/func_return_record/postgresql/pgx/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type MyTable struct { + Data []byte +} diff --git a/internal/endtoend/testdata/func_return_record/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/func_return_record/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..48e3ea3 --- /dev/null +++ b/internal/endtoend/testdata/func_return_record/postgresql/pgx/go/query.sql.go @@ -0,0 +1,30 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const getData = `-- name: GetData :one +SELECT key, value +FROM my_table, jsonb_each(data) +LIMIT 1 +` + +type GetDataRow struct { + Key pgtype.Text + Value []byte +} + +func (q *Queries) GetData(ctx context.Context) (GetDataRow, error) { + row := q.db.QueryRow(ctx, getData) + var i GetDataRow + err := row.Scan(&i.Key, &i.Value) + return i, err +} diff --git a/internal/endtoend/testdata/func_return_record/postgresql/pgx/query.sql b/internal/endtoend/testdata/func_return_record/postgresql/pgx/query.sql new file mode 100644 index 0000000..c540b6a --- /dev/null +++ b/internal/endtoend/testdata/func_return_record/postgresql/pgx/query.sql @@ -0,0 +1,4 @@ +-- name: GetData :one +SELECT key, value +FROM my_table, jsonb_each(data) +LIMIT 1; diff --git a/internal/endtoend/testdata/func_return_record/postgresql/pgx/schema.sql b/internal/endtoend/testdata/func_return_record/postgresql/pgx/schema.sql new file mode 100644 index 0000000..4db45f9 --- /dev/null +++ b/internal/endtoend/testdata/func_return_record/postgresql/pgx/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE my_table ( + data JSONB NOT NULL +); diff --git a/internal/endtoend/testdata/func_return_record/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/func_return_record/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/func_return_record/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/func_return_series/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/func_return_series/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/func_return_series/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/func_return_series/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/func_return_series/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/func_return_series/postgresql/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/func_return_series/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/func_return_series/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..6ada9c4 --- /dev/null +++ b/internal/endtoend/testdata/func_return_series/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,41 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const generateSeries = `-- name: GenerateSeries :many +SELECT ($1::int) + i +FROM generate_series(0, $2::int) AS i +LIMIT 1 +` + +type GenerateSeriesParams struct { + Column1 int32 + Column2 int32 +} + +func (q *Queries) GenerateSeries(ctx context.Context, arg GenerateSeriesParams) ([]int32, error) { + rows, err := q.db.Query(ctx, generateSeries, arg.Column1, arg.Column2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int32 + for rows.Next() { + var column_1 int32 + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/func_return_series/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/func_return_series/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..ac5a434 --- /dev/null +++ b/internal/endtoend/testdata/func_return_series/postgresql/pgx/v4/query.sql @@ -0,0 +1,4 @@ +/* name: GenerateSeries :many */ +SELECT ($1::int) + i +FROM generate_series(0, $2::int) AS i +LIMIT 1; diff --git a/internal/endtoend/testdata/func_return_series/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/func_return_series/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/func_return_series/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/func_return_series/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/func_return_series/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/func_return_series/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/func_return_series/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/func_return_series/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/func_return_series/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/func_return_series/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/func_return_series/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/func_return_series/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/func_return_series/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..6ada9c4 --- /dev/null +++ b/internal/endtoend/testdata/func_return_series/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,41 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const generateSeries = `-- name: GenerateSeries :many +SELECT ($1::int) + i +FROM generate_series(0, $2::int) AS i +LIMIT 1 +` + +type GenerateSeriesParams struct { + Column1 int32 + Column2 int32 +} + +func (q *Queries) GenerateSeries(ctx context.Context, arg GenerateSeriesParams) ([]int32, error) { + rows, err := q.db.Query(ctx, generateSeries, arg.Column1, arg.Column2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int32 + for rows.Next() { + var column_1 int32 + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/func_return_series/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/func_return_series/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..ac5a434 --- /dev/null +++ b/internal/endtoend/testdata/func_return_series/postgresql/pgx/v5/query.sql @@ -0,0 +1,4 @@ +/* name: GenerateSeries :many */ +SELECT ($1::int) + i +FROM generate_series(0, $2::int) AS i +LIMIT 1; diff --git a/internal/endtoend/testdata/func_return_series/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/func_return_series/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/func_return_series/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/func_return_series/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/func_return_series/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/func_return_series/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/func_return_series/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/func_return_series/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/func_return_series/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/func_return_series/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/func_return_series/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/func_return_series/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/func_return_series/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..147fc31 --- /dev/null +++ b/internal/endtoend/testdata/func_return_series/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,44 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const generateSeries = `-- name: GenerateSeries :many +SELECT ($1::int) + i +FROM generate_series(0, $2::int) AS i +LIMIT 1 +` + +type GenerateSeriesParams struct { + Column1 int32 + Column2 int32 +} + +func (q *Queries) GenerateSeries(ctx context.Context, arg GenerateSeriesParams) ([]int32, error) { + rows, err := q.db.QueryContext(ctx, generateSeries, arg.Column1, arg.Column2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int32 + for rows.Next() { + var column_1 int32 + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + 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/func_return_series/postgresql/stdlib/query.sql b/internal/endtoend/testdata/func_return_series/postgresql/stdlib/query.sql new file mode 100644 index 0000000..ac5a434 --- /dev/null +++ b/internal/endtoend/testdata/func_return_series/postgresql/stdlib/query.sql @@ -0,0 +1,4 @@ +/* name: GenerateSeries :many */ +SELECT ($1::int) + i +FROM generate_series(0, $2::int) AS i +LIMIT 1; diff --git a/internal/endtoend/testdata/func_return_series/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/func_return_series/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/func_return_series/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/func_return_series/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/func_return_series/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/func_return_table/issue.md b/internal/endtoend/testdata/func_return_table/issue.md new file mode 100644 index 0000000..119a3cd --- /dev/null +++ b/internal/endtoend/testdata/func_return_table/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1322 diff --git a/internal/endtoend/testdata/func_return_table/postgresql/pgx/exec.json b/internal/endtoend/testdata/func_return_table/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/func_return_table/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/func_return_table/postgresql/pgx/go/db.go b/internal/endtoend/testdata/func_return_table/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/func_return_table/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/func_return_table/postgresql/pgx/go/models.go b/internal/endtoend/testdata/func_return_table/postgresql/pgx/go/models.go new file mode 100644 index 0000000..5c6bea7 --- /dev/null +++ b/internal/endtoend/testdata/func_return_table/postgresql/pgx/go/models.go @@ -0,0 +1,11 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Account struct { + ID int32 + Username string + Password string +} diff --git a/internal/endtoend/testdata/func_return_table/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/func_return_table/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..f09cfb2 --- /dev/null +++ b/internal/endtoend/testdata/func_return_table/postgresql/pgx/go/query.sql.go @@ -0,0 +1,23 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const foo = `-- name: Foo :one +SELECT register_account FROM register_account('a', 'b') +` + +func (q *Queries) Foo(ctx context.Context) (pgtype.Int4, error) { + row := q.db.QueryRow(ctx, foo) + var register_account pgtype.Int4 + err := row.Scan(®ister_account) + return register_account, err +} diff --git a/internal/endtoend/testdata/func_return_table/postgresql/pgx/query.sql b/internal/endtoend/testdata/func_return_table/postgresql/pgx/query.sql new file mode 100644 index 0000000..8a3db0f --- /dev/null +++ b/internal/endtoend/testdata/func_return_table/postgresql/pgx/query.sql @@ -0,0 +1,2 @@ +-- name: Foo :one +SELECT * FROM register_account('a', 'b'); diff --git a/internal/endtoend/testdata/func_return_table/postgresql/pgx/schema.sql b/internal/endtoend/testdata/func_return_table/postgresql/pgx/schema.sql new file mode 100644 index 0000000..e9ebf5e --- /dev/null +++ b/internal/endtoend/testdata/func_return_table/postgresql/pgx/schema.sql @@ -0,0 +1,27 @@ +CREATE TABLE accounts ( + id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + username TEXT NOT NULL UNIQUE, + password TEXT NOT NULL +); + +-- this is a useless and horrifying function cause we don't hash +-- the password, this is just to repro the bug in sqlc +CREATE OR REPLACE FUNCTION register_account( + _username TEXT, + _password VARCHAR(70) +) +RETURNS TABLE ( + account_id INTEGER +) +AS $$ +BEGIN + INSERT INTO accounts (username, password) + VALUES ( + _username, + _password + ) + RETURNING id INTO account_id; + + RETURN NEXT; +END; +$$ LANGUAGE plpgsql; diff --git a/internal/endtoend/testdata/func_return_table/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/func_return_table/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/func_return_table/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/func_return_table_columns/issue.md b/internal/endtoend/testdata/func_return_table_columns/issue.md new file mode 100644 index 0000000..ec4e112 --- /dev/null +++ b/internal/endtoend/testdata/func_return_table_columns/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/2386 diff --git a/internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/exec.json b/internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/go/db.go b/internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/func_return_table_columns/postgresql/pgx/go/models.go b/internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/go/models.go new file mode 100644 index 0000000..e7fce1d --- /dev/null +++ b/internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Blog struct { + ID int32 + Name string +} diff --git a/internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..6d65297 --- /dev/null +++ b/internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/go/query.sql.go @@ -0,0 +1,41 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const testFuncSelectBlog = `-- name: TestFuncSelectBlog :many +select id, name from test_select_blog($1) +` + +type TestFuncSelectBlogRow struct { + ID pgtype.Int4 + Name pgtype.Text +} + +func (q *Queries) TestFuncSelectBlog(ctx context.Context, pID int32) ([]TestFuncSelectBlogRow, error) { + rows, err := q.db.Query(ctx, testFuncSelectBlog, pID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []TestFuncSelectBlogRow + for rows.Next() { + var i TestFuncSelectBlogRow + if err := rows.Scan(&i.ID, &i.Name); 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/func_return_table_columns/postgresql/pgx/query.sql b/internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/query.sql new file mode 100644 index 0000000..73e2396 --- /dev/null +++ b/internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/query.sql @@ -0,0 +1,2 @@ +-- name: TestFuncSelectBlog :many +select id, name from test_select_blog($1); diff --git a/internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/schema.sql b/internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/schema.sql new file mode 100644 index 0000000..ccf032e --- /dev/null +++ b/internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/schema.sql @@ -0,0 +1,11 @@ +create table blog ( + id serial primary key, + name text not null +); + +create function test_select_blog(in p_id int) + returns table (id int, name text) AS $$ +BEGIN RETURN QUERY + select id, name from blog where id = p_id; +END; +$$ language plpgsql; diff --git a/internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/func_return_table_columns/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/func_star_expansion/issue.md b/internal/endtoend/testdata/func_star_expansion/issue.md new file mode 100644 index 0000000..c9b8798 --- /dev/null +++ b/internal/endtoend/testdata/func_star_expansion/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/2364 diff --git a/internal/endtoend/testdata/func_star_expansion/postgresql/pgx/exec.json b/internal/endtoend/testdata/func_star_expansion/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/func_star_expansion/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/func_star_expansion/postgresql/pgx/go/db.go b/internal/endtoend/testdata/func_star_expansion/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/func_star_expansion/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/func_star_expansion/postgresql/pgx/go/models.go b/internal/endtoend/testdata/func_star_expansion/postgresql/pgx/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/func_star_expansion/postgresql/pgx/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/func_star_expansion/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/func_star_expansion/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..1072289 --- /dev/null +++ b/internal/endtoend/testdata/func_star_expansion/postgresql/pgx/go/query.sql.go @@ -0,0 +1,45 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const testFuncGetTime = `-- name: TestFuncGetTime :one +select test_func_get_time from test_func_get_time() +` + +func (q *Queries) TestFuncGetTime(ctx context.Context) (pgtype.Timestamp, error) { + row := q.db.QueryRow(ctx, testFuncGetTime) + var test_func_get_time pgtype.Timestamp + err := row.Scan(&test_func_get_time) + return test_func_get_time, err +} + +const testFuncSelectBlog = `-- name: TestFuncSelectBlog :one +select test_func_select_blog from test_func_select_blog($1) +` + +func (q *Queries) TestFuncSelectBlog(ctx context.Context, pID int32) (any, error) { + row := q.db.QueryRow(ctx, testFuncSelectBlog, pID) + var test_func_select_blog any + err := row.Scan(&test_func_select_blog) + return test_func_select_blog, err +} + +const testFuncSelectString = `-- name: TestFuncSelectString :one +select test_func_select_string from test_func_select_string($1) +` + +func (q *Queries) TestFuncSelectString(ctx context.Context, pString string) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, testFuncSelectString, pString) + var test_func_select_string pgtype.Text + err := row.Scan(&test_func_select_string) + return test_func_select_string, err +} diff --git a/internal/endtoend/testdata/func_star_expansion/postgresql/pgx/query.sql b/internal/endtoend/testdata/func_star_expansion/postgresql/pgx/query.sql new file mode 100644 index 0000000..edb27a3 --- /dev/null +++ b/internal/endtoend/testdata/func_star_expansion/postgresql/pgx/query.sql @@ -0,0 +1,8 @@ +-- name: TestFuncGetTime :one +select * from test_func_get_time(); + +-- name: TestFuncSelectString :one +select * from test_func_select_string($1); + +-- name: TestFuncSelectBlog :one +select * from test_func_select_blog($1); diff --git a/internal/endtoend/testdata/func_star_expansion/postgresql/pgx/schema.sql b/internal/endtoend/testdata/func_star_expansion/postgresql/pgx/schema.sql new file mode 100644 index 0000000..eb3de78 --- /dev/null +++ b/internal/endtoend/testdata/func_star_expansion/postgresql/pgx/schema.sql @@ -0,0 +1,20 @@ +create function test_func_get_time () + returns timestamp AS $$ +Begin + return now(); +End; +$$ language plpgsql; + +create function test_func_select_string (in p_string text) + returns text AS $$ +Begin + return p_string; +End; +$$ language plpgsql; + +create function test_func_select_blog(in p_id int) + returns table (id int, name text, created_at timestamp, updated_at timestamp) AS $$ +BEGIN RETURN QUERY + select id, name, created_at, updated_at from blog where id = p_id; +END; +$$ language plpgsql; diff --git a/internal/endtoend/testdata/func_star_expansion/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/func_star_expansion/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/func_star_expansion/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/func_variadic/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/func_variadic/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/func_variadic/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/func_variadic/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/func_variadic/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..866324d --- /dev/null +++ b/internal/endtoend/testdata/func_variadic/postgresql/stdlib/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + "encoding/json" +) + +type Test struct { + ID sql.NullInt32 + J json.RawMessage +} diff --git a/internal/endtoend/testdata/func_variadic/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/func_variadic/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..cca8f98 --- /dev/null +++ b/internal/endtoend/testdata/func_variadic/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,39 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const updateJ = `-- name: UpdateJ :exec +UPDATE + test +SET + j = jsonb_build_object($1::text, $2::text, $3::text, $4::text) +WHERE + id = $5 +` + +type UpdateJParams struct { + Column1 string + Column2 string + Column3 string + Column4 string + ID sql.NullInt32 +} + +func (q *Queries) UpdateJ(ctx context.Context, arg UpdateJParams) error { + _, err := q.db.ExecContext(ctx, updateJ, + arg.Column1, + arg.Column2, + arg.Column3, + arg.Column4, + arg.ID, + ) + return err +} diff --git a/internal/endtoend/testdata/func_variadic/postgresql/stdlib/query.sql b/internal/endtoend/testdata/func_variadic/postgresql/stdlib/query.sql new file mode 100644 index 0000000..235e7cb --- /dev/null +++ b/internal/endtoend/testdata/func_variadic/postgresql/stdlib/query.sql @@ -0,0 +1,7 @@ +-- name: UpdateJ :exec +UPDATE + test +SET + j = jsonb_build_object($1::text, $2::text, $3::text, $4::text) +WHERE + id = $5; \ No newline at end of file diff --git a/internal/endtoend/testdata/func_variadic/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/func_variadic/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..6fdd78b --- /dev/null +++ b/internal/endtoend/testdata/func_variadic/postgresql/stdlib/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE test ( + id integer, + j jsonb NOT NULL + ); + diff --git a/internal/endtoend/testdata/func_variadic/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/func_variadic/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/func_variadic/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} 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 0000000..9ca5876 --- /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.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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 0000000..99547dd --- /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.31.1 + +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 0000000..fdeffb2 --- /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.31.1 +// 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 0000000..3ab56ee --- /dev/null +++ b/internal/endtoend/testdata/geometric/pgx/v4/query.sql @@ -0,0 +1,3 @@ +-- name: SelectTest :many +SELECT * +from test_table; diff --git a/internal/endtoend/testdata/geometric/pgx/v4/schema.sql b/internal/endtoend/testdata/geometric/pgx/v4/schema.sql new file mode 100644 index 0000000..78a5f21 --- /dev/null +++ b/internal/endtoend/testdata/geometric/pgx/v4/schema.sql @@ -0,0 +1,18 @@ +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 +); + 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 0000000..d1244c9 --- /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": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/geometric/pgx/v5/go/db.go b/internal/endtoend/testdata/geometric/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/geometric/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/v5/go/models.go b/internal/endtoend/testdata/geometric/pgx/v5/go/models.go new file mode 100644 index 0000000..cbec285 --- /dev/null +++ b/internal/endtoend/testdata/geometric/pgx/v5/go/models.go @@ -0,0 +1,26 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/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/v5/go/query.sql.go b/internal/endtoend/testdata/geometric/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..fdeffb2 --- /dev/null +++ b/internal/endtoend/testdata/geometric/pgx/v5/go/query.sql.go @@ -0,0 +1,50 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// 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/v5/query.sql b/internal/endtoend/testdata/geometric/pgx/v5/query.sql new file mode 100644 index 0000000..3ab56ee --- /dev/null +++ b/internal/endtoend/testdata/geometric/pgx/v5/query.sql @@ -0,0 +1,3 @@ +-- name: SelectTest :many +SELECT * +from test_table; diff --git a/internal/endtoend/testdata/geometric/pgx/v5/schema.sql b/internal/endtoend/testdata/geometric/pgx/v5/schema.sql new file mode 100644 index 0000000..78a5f21 --- /dev/null +++ b/internal/endtoend/testdata/geometric/pgx/v5/schema.sql @@ -0,0 +1,18 @@ +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 +); + diff --git a/internal/endtoend/testdata/geometric/pgx/v5/sqlc.json b/internal/endtoend/testdata/geometric/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/geometric/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/go.mod b/internal/endtoend/testdata/go.mod new file mode 100644 index 0000000..502eef7 --- /dev/null +++ b/internal/endtoend/testdata/go.mod @@ -0,0 +1,37 @@ +module github.com/sqlc-dev/sqlc/endtoend + +go 1.24.0 + +toolchain go1.24.7 + +require ( + github.com/go-sql-driver/mysql v1.7.0 + github.com/gofrs/uuid v4.0.0+incompatible + github.com/google/uuid v1.3.0 + github.com/hexon/mysqltsv v0.1.0 + github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853 + github.com/jackc/pgtype v1.6.2 + github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904 + github.com/jackc/pgx/v5 v5.8.0 + github.com/lib/pq v1.9.0 + github.com/sqlc-dev/pqtype v0.2.0 + github.com/sqlc-dev/sqlc-testdata v1.0.0 + github.com/volatiletech/null/v8 v8.1.2 + gopkg.in/guregu/null.v4 v4.0.0 +) + +require ( + github.com/friendsofgo/errors v0.9.2 // indirect + github.com/jackc/chunkreader/v2 v2.0.1 // indirect + github.com/jackc/pgio v1.0.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgproto3/v2 v2.0.1 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/pgvector/pgvector-go v0.1.1 // indirect + github.com/volatiletech/inflect v0.0.1 // indirect + github.com/volatiletech/randomize v0.0.1 // indirect + github.com/volatiletech/strmangle v0.0.1 // indirect + golang.org/x/crypto v0.17.0 // indirect + golang.org/x/text v0.29.0 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect +) diff --git a/internal/endtoend/testdata/go.sum b/internal/endtoend/testdata/go.sum new file mode 100644 index 0000000..0711cb8 --- /dev/null +++ b/internal/endtoend/testdata/go.sum @@ -0,0 +1,219 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/friendsofgo/errors v0.9.2 h1:X6NYxef4efCBdwI7BgS820zFaN7Cphrmb+Pljdzjtgk= +github.com/friendsofgo/errors v0.9.2/go.mod h1:yCvFW5AkDIL9qn7suHVLiI/gH228n7PC4Pn44IGoTOI= +github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hexon/mysqltsv v0.1.0 h1:48wYQlsPH8ZEkKAVCdsOYzMYAlEoevw8ZWD8rqYPdlg= +github.com/hexon/mysqltsv v0.1.0/go.mod h1:p3vPBkpxebjHWF1bWKYNcXx5pFu+yAG89QZQEKSvVrY= +github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= +github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= +github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= +github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= +github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= +github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk= +github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= +github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853 h1:LRlrfJW9S99uiOCY8F/qLvX1yEY1TVAaCBHFb79yHBQ= +github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= +github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= +github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= +github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2 h1:JVX6jT/XfzNqIjye4717ITLaNwV9mWbJx0dLCpcRzdA= +github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= +github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.1 h1:Rdjp4NFjwHnEslx2b66FfCI2S0LhO4itac3hXz6WX9M= +github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= +github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= +github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= +github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0= +github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po= +github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ= +github.com/jackc/pgtype v1.6.2 h1:b3pDeuhbbzBYcg5kwNmNDun4pFUD/0AAr1kLXZLeNt8= +github.com/jackc/pgtype v1.6.2/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig= +github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= +github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= +github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= +github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA= +github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o= +github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904 h1:SdGWuGg+Cpxq6Z+ArXt0nafaKeTvtKGEoW+yvycspUU= +github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg= +github.com/jackc/pgx/v5 v5.0.1 h1:JZu9othr7l8so2JMDAGeDUMXqERAuZpovyfl4H50tdg= +github.com/jackc/pgx/v5 v5.0.1/go.mod h1:JBbvW3Hdw77jKl9uJrEDATUZIFM2VFPzRq4RWIhkF4o= +github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU= +github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= +github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY= +github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= +github.com/jackc/pgx/v5 v5.5.0 h1:NxstgwndsTRy7eq9/kqYc/BZh5w2hHJV86wjvO+1xPw= +github.com/jackc/pgx/v5 v5.5.0/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= +github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY= +github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw= +github.com/jackc/pgx/v5 v5.7.0 h1:FG6VLIdzvAPhnYqP14sQ2xhFLkiUQHCs6ySqO91kF4g= +github.com/jackc/pgx/v5 v5.7.0/go.mod h1:awP1KNnjylvpxHuHP63gzjhnGkI1iw+PMoIwvoleN/8= +github.com/jackc/pgx/v5 v5.8.0 h1:TYPDoleBBme0xGSAX3/+NujXXtpZn9HBONkQC7IEZSo= +github.com/jackc/pgx/v5 v5.8.0/go.mod h1:QVeDInX2m9VyzvNeiCJVjCkNFqzsNb43204HshNSZKw= +github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8= +github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/pgvector/pgvector-go v0.1.1 h1:kqJigGctFnlWvskUiYIvJRNwUtQl/aMSUZVs0YWQe+g= +github.com/pgvector/pgvector-go v0.1.1/go.mod h1:wLJgD/ODkdtd2LJK4l6evHXTuG+8PxymYAVomKHOWac= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= +github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc h1:jUIKcSPO9MoMJBbEoyE/RJoE8vz7Mb8AjvifMMwSyvY= +github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sqlc-dev/pqtype v0.2.0 h1:zfzDpAxjCU0/GO7EgZ7ELUh0w28SrMSHzO3rH5Wd3is= +github.com/sqlc-dev/pqtype v0.2.0/go.mod h1:oyUjp5981ctiL9UYvj1bVvCKi8OXkCa0u645hce7CAs= +github.com/sqlc-dev/sqlc-testdata v1.0.0 h1:NrfFkZ3xh2XHqDNqYE6Q87hhXd1n6GQr3XE0V+CveSQ= +github.com/sqlc-dev/sqlc-testdata v1.0.0/go.mod h1:Ima4gy0tylq+cNW1VSV36/NoAHMbZZKjHNs7SfM9Pns= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/volatiletech/inflect v0.0.1 h1:2a6FcMQyhmPZcLa+uet3VJ8gLn/9svWhJxJYwvE8KsU= +github.com/volatiletech/inflect v0.0.1/go.mod h1:IBti31tG6phkHitLlr5j7shC5SOo//x0AjDzaJU1PLA= +github.com/volatiletech/null/v8 v8.1.2 h1:kiTiX1PpwvuugKwfvUNX/SU/5A2KGZMXfGD0DUHdKEI= +github.com/volatiletech/null/v8 v8.1.2/go.mod h1:98DbwNoKEpRrYtGjWFctievIfm4n4MxG0A6EBUcoS5g= +github.com/volatiletech/randomize v0.0.1 h1:eE5yajattWqTB2/eN8df4dw+8jwAzBtbdo5sbWC4nMk= +github.com/volatiletech/randomize v0.0.1/go.mod h1:GN3U0QYqfZ9FOJ67bzax1cqZ5q2xuj2mXrXBjWaRTlY= +github.com/volatiletech/strmangle v0.0.1 h1:UKQoHmY6be/R3tSvD2nQYrH41k43OJkidwEiC74KIzk= +github.com/volatiletech/strmangle v0.0.1/go.mod h1:F6RA6IkB5vq0yTG4GQ0UsbbRcl3ni9P76i+JrTBKFFg= +github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +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= +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= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= +golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +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/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +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/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +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.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= +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= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/guregu/null.v4 v4.0.0 h1:1Wm3S1WEA2I26Kq+6vcW+w0gcDo44YKYD7YIEJNHDjg= +gopkg.in/guregu/null.v4 v4.0.0/go.mod h1:YoQhUrADuG3i9WqesrCmpNRwm1ypAgSHYqoOcTu/JrI= +gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/internal/endtoend/testdata/golang_initialisms_empty/db/db.go b/internal/endtoend/testdata/golang_initialisms_empty/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/golang_initialisms_empty/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/golang_initialisms_empty/db/models.go b/internal/endtoend/testdata/golang_initialisms_empty/db/models.go new file mode 100644 index 0000000..df28836 --- /dev/null +++ b/internal/endtoend/testdata/golang_initialisms_empty/db/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "database/sql" +) + +type Foo struct { + BarId sql.NullString +} diff --git a/internal/endtoend/testdata/golang_initialisms_empty/db/query.sql.go b/internal/endtoend/testdata/golang_initialisms_empty/db/query.sql.go new file mode 100644 index 0000000..a928562 --- /dev/null +++ b/internal/endtoend/testdata/golang_initialisms_empty/db/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" + "database/sql" +) + +const selectFoo = `-- name: SelectFoo :many +SELECT bar_id FROM foo +` + +func (q *Queries) SelectFoo(ctx context.Context) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, selectFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var bar_id sql.NullString + if err := rows.Scan(&bar_id); err != nil { + return nil, err + } + items = append(items, bar_id) + } + 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/golang_initialisms_empty/query.sql b/internal/endtoend/testdata/golang_initialisms_empty/query.sql new file mode 100644 index 0000000..e32e926 --- /dev/null +++ b/internal/endtoend/testdata/golang_initialisms_empty/query.sql @@ -0,0 +1,2 @@ +-- name: SelectFoo :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/golang_initialisms_empty/schema.sql b/internal/endtoend/testdata/golang_initialisms_empty/schema.sql new file mode 100644 index 0000000..fe692b6 --- /dev/null +++ b/internal/endtoend/testdata/golang_initialisms_empty/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo( + bar_id text +); diff --git a/internal/endtoend/testdata/golang_initialisms_empty/sqlc.json b/internal/endtoend/testdata/golang_initialisms_empty/sqlc.json new file mode 100644 index 0000000..02ab2e3 --- /dev/null +++ b/internal/endtoend/testdata/golang_initialisms_empty/sqlc.json @@ -0,0 +1,16 @@ +{ + "version": "2", + "sql": [ + { + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql", + "gen": { + "go": { + "out": "db", + "initialisms": [] + } + } + } + ] +} diff --git a/internal/endtoend/testdata/golang_initialisms_url/db/db.go b/internal/endtoend/testdata/golang_initialisms_url/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/golang_initialisms_url/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/golang_initialisms_url/db/models.go b/internal/endtoend/testdata/golang_initialisms_url/db/models.go new file mode 100644 index 0000000..e30346a --- /dev/null +++ b/internal/endtoend/testdata/golang_initialisms_url/db/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "database/sql" +) + +type Foo struct { + BarID sql.NullString + SiteURL sql.NullString +} diff --git a/internal/endtoend/testdata/golang_initialisms_url/db/query.sql.go b/internal/endtoend/testdata/golang_initialisms_url/db/query.sql.go new file mode 100644 index 0000000..da4d925 --- /dev/null +++ b/internal/endtoend/testdata/golang_initialisms_url/db/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" +) + +const selectFoo = `-- name: SelectFoo :many +SELECT bar_id, site_url FROM foo +` + +func (q *Queries) SelectFoo(ctx context.Context) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, selectFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.BarID, &i.SiteURL); 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/golang_initialisms_url/query.sql b/internal/endtoend/testdata/golang_initialisms_url/query.sql new file mode 100644 index 0000000..e32e926 --- /dev/null +++ b/internal/endtoend/testdata/golang_initialisms_url/query.sql @@ -0,0 +1,2 @@ +-- name: SelectFoo :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/golang_initialisms_url/schema.sql b/internal/endtoend/testdata/golang_initialisms_url/schema.sql new file mode 100644 index 0000000..d0b2506 --- /dev/null +++ b/internal/endtoend/testdata/golang_initialisms_url/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE foo ( + bar_id text, + site_url text +); diff --git a/internal/endtoend/testdata/golang_initialisms_url/sqlc.json b/internal/endtoend/testdata/golang_initialisms_url/sqlc.json new file mode 100644 index 0000000..2b135ee --- /dev/null +++ b/internal/endtoend/testdata/golang_initialisms_url/sqlc.json @@ -0,0 +1,16 @@ +{ + "version": "2", + "sql": [ + { + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql", + "gen": { + "go": { + "out": "db", + "initialisms": ["id", "url"] + } + } + } + ] +} diff --git a/internal/endtoend/testdata/golang_invalid_sql_driver/db/db.go b/internal/endtoend/testdata/golang_invalid_sql_driver/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/golang_invalid_sql_driver/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/golang_invalid_sql_driver/db/models.go b/internal/endtoend/testdata/golang_invalid_sql_driver/db/models.go new file mode 100644 index 0000000..d9ddf0a --- /dev/null +++ b/internal/endtoend/testdata/golang_invalid_sql_driver/db/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString +} diff --git a/internal/endtoend/testdata/golang_invalid_sql_driver/db/query.sql.go b/internal/endtoend/testdata/golang_invalid_sql_driver/db/query.sql.go new file mode 100644 index 0000000..1b8a297 --- /dev/null +++ b/internal/endtoend/testdata/golang_invalid_sql_driver/db/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" + "database/sql" +) + +const selectFoo = `-- name: SelectFoo :many +SELECT bar FROM foo +` + +func (q *Queries) SelectFoo(ctx context.Context) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, selectFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var bar sql.NullString + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + 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/golang_invalid_sql_driver/query.sql b/internal/endtoend/testdata/golang_invalid_sql_driver/query.sql new file mode 100644 index 0000000..e32e926 --- /dev/null +++ b/internal/endtoend/testdata/golang_invalid_sql_driver/query.sql @@ -0,0 +1,2 @@ +-- name: SelectFoo :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/golang_invalid_sql_driver/schema.sql b/internal/endtoend/testdata/golang_invalid_sql_driver/schema.sql new file mode 100644 index 0000000..1bd7252 --- /dev/null +++ b/internal/endtoend/testdata/golang_invalid_sql_driver/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo( + bar text +); diff --git a/internal/endtoend/testdata/golang_invalid_sql_driver/sqlc.json b/internal/endtoend/testdata/golang_invalid_sql_driver/sqlc.json new file mode 100644 index 0000000..6124f17 --- /dev/null +++ b/internal/endtoend/testdata/golang_invalid_sql_driver/sqlc.json @@ -0,0 +1,16 @@ +{ + "version": "2", + "sql": [ + { + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql", + "gen": { + "go": { + "out": "db", + "sql_driver": "github.com/unknown/driver" + } + } + } + ] +} diff --git a/internal/endtoend/testdata/golang_invalid_sql_driver/stderr.txt b/internal/endtoend/testdata/golang_invalid_sql_driver/stderr.txt new file mode 100644 index 0000000..b71f130 --- /dev/null +++ b/internal/endtoend/testdata/golang_invalid_sql_driver/stderr.txt @@ -0,0 +1,2 @@ +# package +error generating code: invalid options: unknown SQL driver: github.com/unknown/driver diff --git a/internal/endtoend/testdata/golang_invalid_sql_package/db/db.go b/internal/endtoend/testdata/golang_invalid_sql_package/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/golang_invalid_sql_package/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/golang_invalid_sql_package/db/models.go b/internal/endtoend/testdata/golang_invalid_sql_package/db/models.go new file mode 100644 index 0000000..d9ddf0a --- /dev/null +++ b/internal/endtoend/testdata/golang_invalid_sql_package/db/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString +} diff --git a/internal/endtoend/testdata/golang_invalid_sql_package/db/query.sql.go b/internal/endtoend/testdata/golang_invalid_sql_package/db/query.sql.go new file mode 100644 index 0000000..1b8a297 --- /dev/null +++ b/internal/endtoend/testdata/golang_invalid_sql_package/db/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" + "database/sql" +) + +const selectFoo = `-- name: SelectFoo :many +SELECT bar FROM foo +` + +func (q *Queries) SelectFoo(ctx context.Context) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, selectFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var bar sql.NullString + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + 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/golang_invalid_sql_package/query.sql b/internal/endtoend/testdata/golang_invalid_sql_package/query.sql new file mode 100644 index 0000000..e32e926 --- /dev/null +++ b/internal/endtoend/testdata/golang_invalid_sql_package/query.sql @@ -0,0 +1,2 @@ +-- name: SelectFoo :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/golang_invalid_sql_package/schema.sql b/internal/endtoend/testdata/golang_invalid_sql_package/schema.sql new file mode 100644 index 0000000..e29621b --- /dev/null +++ b/internal/endtoend/testdata/golang_invalid_sql_package/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo ( + bar text +); diff --git a/internal/endtoend/testdata/golang_invalid_sql_package/sqlc.json b/internal/endtoend/testdata/golang_invalid_sql_package/sqlc.json new file mode 100644 index 0000000..a6c7260 --- /dev/null +++ b/internal/endtoend/testdata/golang_invalid_sql_package/sqlc.json @@ -0,0 +1,16 @@ +{ + "version": "2", + "sql": [ + { + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql", + "gen": { + "go": { + "out": "db", + "sql_package": "pgx/5" + } + } + } + ] +} diff --git a/internal/endtoend/testdata/golang_invalid_sql_package/stderr.txt b/internal/endtoend/testdata/golang_invalid_sql_package/stderr.txt new file mode 100644 index 0000000..249ae16 --- /dev/null +++ b/internal/endtoend/testdata/golang_invalid_sql_package/stderr.txt @@ -0,0 +1,2 @@ +# package +error generating code: invalid options: unknown SQL package: pgx/5 diff --git a/internal/endtoend/testdata/having/mysql/go/db.go b/internal/endtoend/testdata/having/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/having/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/having/mysql/go/models.go b/internal/endtoend/testdata/having/mysql/go/models.go new file mode 100644 index 0000000..e6b939a --- /dev/null +++ b/internal/endtoend/testdata/having/mysql/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Weather struct { + City string + TempLo int32 +} diff --git a/internal/endtoend/testdata/having/mysql/go/query.sql.go b/internal/endtoend/testdata/having/mysql/go/query.sql.go new file mode 100644 index 0000000..7bfd67d --- /dev/null +++ b/internal/endtoend/testdata/having/mysql/go/query.sql.go @@ -0,0 +1,40 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const coldCities = `-- name: ColdCities :many +SELECT city +FROM weather +GROUP BY city +HAVING max(temp_lo) < ? +` + +func (q *Queries) ColdCities(ctx context.Context, tempLo int32) ([]string, error) { + rows, err := q.db.QueryContext(ctx, coldCities, tempLo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var city string + if err := rows.Scan(&city); err != nil { + return nil, err + } + items = append(items, city) + } + 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/having/mysql/query.sql b/internal/endtoend/testdata/having/mysql/query.sql new file mode 100644 index 0000000..b234352 --- /dev/null +++ b/internal/endtoend/testdata/having/mysql/query.sql @@ -0,0 +1,5 @@ +-- name: ColdCities :many +SELECT city +FROM weather +GROUP BY city +HAVING max(temp_lo) < ?; diff --git a/internal/endtoend/testdata/having/mysql/schema.sql b/internal/endtoend/testdata/having/mysql/schema.sql new file mode 100644 index 0000000..b9e4261 --- /dev/null +++ b/internal/endtoend/testdata/having/mysql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE weather ( + city text NOT NULL, + temp_lo integer NOT NULL +); + diff --git a/internal/endtoend/testdata/having/mysql/sqlc.json b/internal/endtoend/testdata/having/mysql/sqlc.json new file mode 100644 index 0000000..0390f67 --- /dev/null +++ b/internal/endtoend/testdata/having/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/having/postgresql/go/db.go b/internal/endtoend/testdata/having/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/having/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/having/postgresql/go/models.go b/internal/endtoend/testdata/having/postgresql/go/models.go new file mode 100644 index 0000000..e6b939a --- /dev/null +++ b/internal/endtoend/testdata/having/postgresql/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Weather struct { + City string + TempLo int32 +} diff --git a/internal/endtoend/testdata/having/postgresql/go/query.sql.go b/internal/endtoend/testdata/having/postgresql/go/query.sql.go new file mode 100644 index 0000000..d986320 --- /dev/null +++ b/internal/endtoend/testdata/having/postgresql/go/query.sql.go @@ -0,0 +1,40 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const coldCities = `-- name: ColdCities :many +SELECT city +FROM weather +GROUP BY city +HAVING max(temp_lo) < $1 +` + +func (q *Queries) ColdCities(ctx context.Context, tempLo int32) ([]string, error) { + rows, err := q.db.QueryContext(ctx, coldCities, tempLo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var city string + if err := rows.Scan(&city); err != nil { + return nil, err + } + items = append(items, city) + } + 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/having/postgresql/query.sql b/internal/endtoend/testdata/having/postgresql/query.sql new file mode 100644 index 0000000..5861dba --- /dev/null +++ b/internal/endtoend/testdata/having/postgresql/query.sql @@ -0,0 +1,5 @@ +-- name: ColdCities :many +SELECT city +FROM weather +GROUP BY city +HAVING max(temp_lo) < $1; diff --git a/internal/endtoend/testdata/having/postgresql/schema.sql b/internal/endtoend/testdata/having/postgresql/schema.sql new file mode 100644 index 0000000..b9e4261 --- /dev/null +++ b/internal/endtoend/testdata/having/postgresql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE weather ( + city text NOT NULL, + temp_lo integer NOT NULL +); + diff --git a/internal/endtoend/testdata/having/postgresql/sqlc.json b/internal/endtoend/testdata/having/postgresql/sqlc.json new file mode 100644 index 0000000..a590361 --- /dev/null +++ b/internal/endtoend/testdata/having/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/hstore/pgx/v4/go/db.go b/internal/endtoend/testdata/hstore/pgx/v4/go/db.go new file mode 100644 index 0000000..2385b69 --- /dev/null +++ b/internal/endtoend/testdata/hstore/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package hstore + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/hstore/pgx/v4/go/hstore.sql.go b/internal/endtoend/testdata/hstore/pgx/v4/go/hstore.sql.go new file mode 100644 index 0000000..8a30468 --- /dev/null +++ b/internal/endtoend/testdata/hstore/pgx/v4/go/hstore.sql.go @@ -0,0 +1,60 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: hstore.sql + +package hstore + +import ( + "context" + + "github.com/jackc/pgtype" +) + +const listBar = `-- name: ListBar :many +SELECT bar FROM foo +` + +func (q *Queries) ListBar(ctx context.Context) ([]pgtype.Hstore, error) { + rows, err := q.db.Query(ctx, listBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []pgtype.Hstore + for rows.Next() { + var bar pgtype.Hstore + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listBaz = `-- name: ListBaz :many +SELECT baz FROM foo +` + +func (q *Queries) ListBaz(ctx context.Context) ([]pgtype.Hstore, error) { + rows, err := q.db.Query(ctx, listBaz) + if err != nil { + return nil, err + } + defer rows.Close() + var items []pgtype.Hstore + for rows.Next() { + var baz pgtype.Hstore + if err := rows.Scan(&baz); err != nil { + return nil, err + } + items = append(items, baz) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/hstore/pgx/v4/go/models.go b/internal/endtoend/testdata/hstore/pgx/v4/go/models.go new file mode 100644 index 0000000..f6c0d02 --- /dev/null +++ b/internal/endtoend/testdata/hstore/pgx/v4/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package hstore + +import ( + "github.com/jackc/pgtype" +) + +type Foo struct { + Bar pgtype.Hstore + Baz pgtype.Hstore +} diff --git a/internal/endtoend/testdata/hstore/pgx/v4/hstore.sql b/internal/endtoend/testdata/hstore/pgx/v4/hstore.sql new file mode 100644 index 0000000..5299011 --- /dev/null +++ b/internal/endtoend/testdata/hstore/pgx/v4/hstore.sql @@ -0,0 +1,14 @@ +CREATE EXTENSION IF NOT EXISTS hstore; + +CREATE TABLE foo ( + bar hstore NOT NULL, + baz hstore +); + +-- name: ListBar :many +SELECT bar FROM foo; + +-- name: ListBaz :many +SELECT baz FROM foo; + + diff --git a/internal/endtoend/testdata/hstore/pgx/v4/sqlc.json b/internal/endtoend/testdata/hstore/pgx/v4/sqlc.json new file mode 100644 index 0000000..66b4ca8 --- /dev/null +++ b/internal/endtoend/testdata/hstore/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "hstore", + "schema": "hstore.sql", + "queries": "hstore.sql" + } + ] +} diff --git a/internal/endtoend/testdata/hstore/pgx/v5/go/db.go b/internal/endtoend/testdata/hstore/pgx/v5/go/db.go new file mode 100644 index 0000000..7d3f0ac --- /dev/null +++ b/internal/endtoend/testdata/hstore/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package hstore + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/hstore/pgx/v5/go/hstore.sql.go b/internal/endtoend/testdata/hstore/pgx/v5/go/hstore.sql.go new file mode 100644 index 0000000..29e4847 --- /dev/null +++ b/internal/endtoend/testdata/hstore/pgx/v5/go/hstore.sql.go @@ -0,0 +1,60 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: hstore.sql + +package hstore + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const listBar = `-- name: ListBar :many +SELECT bar FROM foo +` + +func (q *Queries) ListBar(ctx context.Context) ([]pgtype.Hstore, error) { + rows, err := q.db.Query(ctx, listBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []pgtype.Hstore + for rows.Next() { + var bar pgtype.Hstore + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listBaz = `-- name: ListBaz :many +SELECT baz FROM foo +` + +func (q *Queries) ListBaz(ctx context.Context) ([]pgtype.Hstore, error) { + rows, err := q.db.Query(ctx, listBaz) + if err != nil { + return nil, err + } + defer rows.Close() + var items []pgtype.Hstore + for rows.Next() { + var baz pgtype.Hstore + if err := rows.Scan(&baz); err != nil { + return nil, err + } + items = append(items, baz) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/hstore/pgx/v5/go/models.go b/internal/endtoend/testdata/hstore/pgx/v5/go/models.go new file mode 100644 index 0000000..60677de --- /dev/null +++ b/internal/endtoend/testdata/hstore/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package hstore + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + Bar pgtype.Hstore + Baz pgtype.Hstore +} diff --git a/internal/endtoend/testdata/hstore/pgx/v5/hstore.sql b/internal/endtoend/testdata/hstore/pgx/v5/hstore.sql new file mode 100644 index 0000000..5299011 --- /dev/null +++ b/internal/endtoend/testdata/hstore/pgx/v5/hstore.sql @@ -0,0 +1,14 @@ +CREATE EXTENSION IF NOT EXISTS hstore; + +CREATE TABLE foo ( + bar hstore NOT NULL, + baz hstore +); + +-- name: ListBar :many +SELECT bar FROM foo; + +-- name: ListBaz :many +SELECT baz FROM foo; + + diff --git a/internal/endtoend/testdata/hstore/pgx/v5/sqlc.json b/internal/endtoend/testdata/hstore/pgx/v5/sqlc.json new file mode 100644 index 0000000..5ae6383 --- /dev/null +++ b/internal/endtoend/testdata/hstore/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "hstore", + "schema": "hstore.sql", + "queries": "hstore.sql" + } + ] +} diff --git a/internal/endtoend/testdata/hstore/stdlib/go/db.go b/internal/endtoend/testdata/hstore/stdlib/go/db.go new file mode 100644 index 0000000..a47155e --- /dev/null +++ b/internal/endtoend/testdata/hstore/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package hstore + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/hstore/stdlib/go/hstore.sql.go b/internal/endtoend/testdata/hstore/stdlib/go/hstore.sql.go new file mode 100644 index 0000000..66bd5eb --- /dev/null +++ b/internal/endtoend/testdata/hstore/stdlib/go/hstore.sql.go @@ -0,0 +1,64 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: hstore.sql + +package hstore + +import ( + "context" +) + +const listBar = `-- name: ListBar :many +SELECT bar FROM foo +` + +func (q *Queries) ListBar(ctx context.Context) ([]any, error) { + rows, err := q.db.QueryContext(ctx, listBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []any + for rows.Next() { + var bar any + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listBaz = `-- name: ListBaz :many +SELECT baz FROM foo +` + +func (q *Queries) ListBaz(ctx context.Context) ([]any, error) { + rows, err := q.db.QueryContext(ctx, listBaz) + if err != nil { + return nil, err + } + defer rows.Close() + var items []any + for rows.Next() { + var baz any + if err := rows.Scan(&baz); err != nil { + return nil, err + } + items = append(items, baz) + } + 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/hstore/stdlib/go/models.go b/internal/endtoend/testdata/hstore/stdlib/go/models.go new file mode 100644 index 0000000..53a6053 --- /dev/null +++ b/internal/endtoend/testdata/hstore/stdlib/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package hstore + +type Foo struct { + Bar any + Baz any +} diff --git a/internal/endtoend/testdata/hstore/stdlib/hstore.sql b/internal/endtoend/testdata/hstore/stdlib/hstore.sql new file mode 100644 index 0000000..5299011 --- /dev/null +++ b/internal/endtoend/testdata/hstore/stdlib/hstore.sql @@ -0,0 +1,14 @@ +CREATE EXTENSION IF NOT EXISTS hstore; + +CREATE TABLE foo ( + bar hstore NOT NULL, + baz hstore +); + +-- name: ListBar :many +SELECT bar FROM foo; + +-- name: ListBaz :many +SELECT baz FROM foo; + + diff --git a/internal/endtoend/testdata/hstore/stdlib/sqlc.json b/internal/endtoend/testdata/hstore/stdlib/sqlc.json new file mode 100644 index 0000000..d218312 --- /dev/null +++ b/internal/endtoend/testdata/hstore/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "hstore", + "schema": "hstore.sql", + "queries": "hstore.sql" + } + ] +} diff --git a/internal/endtoend/testdata/identical_tables/mysql/go/db.go b/internal/endtoend/testdata/identical_tables/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/identical_tables/mysql/go/models.go b/internal/endtoend/testdata/identical_tables/mysql/go/models.go new file mode 100644 index 0000000..73ea222 --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/mysql/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID string +} + +type Foo struct { + ID string +} diff --git a/internal/endtoend/testdata/identical_tables/mysql/go/query.sql.go b/internal/endtoend/testdata/identical_tables/mysql/go/query.sql.go new file mode 100644 index 0000000..79b96bb --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/mysql/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const identicalTable = `-- name: IdenticalTable :many +SELECT id FROM foo +` + +func (q *Queries) IdenticalTable(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, identicalTable) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 +} diff --git a/internal/endtoend/testdata/identical_tables/mysql/query.sql b/internal/endtoend/testdata/identical_tables/mysql/query.sql new file mode 100644 index 0000000..2e71d9a --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: IdenticalTable :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/identical_tables/mysql/schema.sql b/internal/endtoend/testdata/identical_tables/mysql/schema.sql new file mode 100644 index 0000000..0dbf9f6 --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/mysql/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (id text not null); +CREATE TABLE bar (id text not null); + diff --git a/internal/endtoend/testdata/identical_tables/mysql/sqlc.json b/internal/endtoend/testdata/identical_tables/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/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/identical_tables/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/identical_tables/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/identical_tables/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/identical_tables/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..73ea222 --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/postgresql/pgx/v4/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID string +} + +type Foo struct { + ID string +} diff --git a/internal/endtoend/testdata/identical_tables/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/identical_tables/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..d09aae8 --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const identicalTable = `-- name: IdenticalTable :many +SELECT id FROM foo +` + +func (q *Queries) IdenticalTable(ctx context.Context) ([]string, error) { + rows, err := q.db.Query(ctx, identicalTable) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 +} diff --git a/internal/endtoend/testdata/identical_tables/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/identical_tables/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..2e71d9a --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: IdenticalTable :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/identical_tables/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/identical_tables/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..0dbf9f6 --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/postgresql/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (id text not null); +CREATE TABLE bar (id text not null); + diff --git a/internal/endtoend/testdata/identical_tables/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/identical_tables/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/identical_tables/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/identical_tables/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/identical_tables/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/identical_tables/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..73ea222 --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/postgresql/pgx/v5/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID string +} + +type Foo struct { + ID string +} diff --git a/internal/endtoend/testdata/identical_tables/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/identical_tables/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..d09aae8 --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const identicalTable = `-- name: IdenticalTable :many +SELECT id FROM foo +` + +func (q *Queries) IdenticalTable(ctx context.Context) ([]string, error) { + rows, err := q.db.Query(ctx, identicalTable) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 +} diff --git a/internal/endtoend/testdata/identical_tables/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/identical_tables/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..2e71d9a --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: IdenticalTable :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/identical_tables/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/identical_tables/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..0dbf9f6 --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/postgresql/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (id text not null); +CREATE TABLE bar (id text not null); + diff --git a/internal/endtoend/testdata/identical_tables/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/identical_tables/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/identical_tables/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/identical_tables/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/identical_tables/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/identical_tables/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..73ea222 --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/postgresql/stdlib/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID string +} + +type Foo struct { + ID string +} diff --git a/internal/endtoend/testdata/identical_tables/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/identical_tables/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..79b96bb --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const identicalTable = `-- name: IdenticalTable :many +SELECT id FROM foo +` + +func (q *Queries) IdenticalTable(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, identicalTable) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 +} diff --git a/internal/endtoend/testdata/identical_tables/postgresql/stdlib/query.sql b/internal/endtoend/testdata/identical_tables/postgresql/stdlib/query.sql new file mode 100644 index 0000000..2e71d9a --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: IdenticalTable :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/identical_tables/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/identical_tables/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..0dbf9f6 --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/postgresql/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (id text not null); +CREATE TABLE bar (id text not null); + diff --git a/internal/endtoend/testdata/identical_tables/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/identical_tables/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/identical_tables/sqlite/go/db.go b/internal/endtoend/testdata/identical_tables/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/identical_tables/sqlite/go/models.go b/internal/endtoend/testdata/identical_tables/sqlite/go/models.go new file mode 100644 index 0000000..73ea222 --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/sqlite/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID string +} + +type Foo struct { + ID string +} diff --git a/internal/endtoend/testdata/identical_tables/sqlite/go/query.sql.go b/internal/endtoend/testdata/identical_tables/sqlite/go/query.sql.go new file mode 100644 index 0000000..79b96bb --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/sqlite/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const identicalTable = `-- name: IdenticalTable :many +SELECT id FROM foo +` + +func (q *Queries) IdenticalTable(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, identicalTable) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 +} diff --git a/internal/endtoend/testdata/identical_tables/sqlite/query.sql b/internal/endtoend/testdata/identical_tables/sqlite/query.sql new file mode 100644 index 0000000..2e71d9a --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: IdenticalTable :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/identical_tables/sqlite/schema.sql b/internal/endtoend/testdata/identical_tables/sqlite/schema.sql new file mode 100644 index 0000000..0dbf9f6 --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/sqlite/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (id text not null); +CREATE TABLE bar (id text not null); + diff --git a/internal/endtoend/testdata/identical_tables/sqlite/sqlc.json b/internal/endtoend/testdata/identical_tables/sqlite/sqlc.json new file mode 100644 index 0000000..d4963e7 --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/identifier_case_sensitivity/db/db.go b/internal/endtoend/testdata/identifier_case_sensitivity/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/identifier_case_sensitivity/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/identifier_case_sensitivity/db/models.go b/internal/endtoend/testdata/identifier_case_sensitivity/db/models.go new file mode 100644 index 0000000..56c9d4a --- /dev/null +++ b/internal/endtoend/testdata/identifier_case_sensitivity/db/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/identifier_case_sensitivity/db/query.sql.go b/internal/endtoend/testdata/identifier_case_sensitivity/db/query.sql.go new file mode 100644 index 0000000..03a9f67 --- /dev/null +++ b/internal/endtoend/testdata/identifier_case_sensitivity/db/query.sql.go @@ -0,0 +1,78 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" + "database/sql" +) + +const createAuthor = `-- name: CreateAuthor :execresult +INSERT INTO Authors ( + Name, Bio +) VALUES ( + ?, ? +) +` + +type CreateAuthorParams struct { + Name string + Bio sql.NullString +} + +func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (sql.Result, error) { + return q.db.ExecContext(ctx, createAuthor, arg.Name, arg.Bio) +} + +const deleteAuthor = `-- name: DeleteAuthor :exec +DELETE FROM Authors +WHERE ID = ? +` + +func (q *Queries) DeleteAuthor(ctx context.Context, id int64) error { + _, err := q.db.ExecContext(ctx, deleteAuthor, id) + return err +} + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, bio FROM Authors +WHERE ID = ? LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name, bio FROM Authors +ORDER BY Name +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); 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/identifier_case_sensitivity/query.sql b/internal/endtoend/testdata/identifier_case_sensitivity/query.sql new file mode 100644 index 0000000..c9a3b0c --- /dev/null +++ b/internal/endtoend/testdata/identifier_case_sensitivity/query.sql @@ -0,0 +1,18 @@ +-- name: GetAuthor :one +SELECT * FROM Authors +WHERE ID = ? LIMIT 1; + +-- name: ListAuthors :many +SELECT * FROM Authors +ORDER BY Name; + +-- name: CreateAuthor :execresult +INSERT INTO Authors ( + Name, Bio +) VALUES ( + ?, ? +); + +-- name: DeleteAuthor :exec +DELETE FROM Authors +WHERE ID = ?; diff --git a/internal/endtoend/testdata/identifier_case_sensitivity/schema.sql b/internal/endtoend/testdata/identifier_case_sensitivity/schema.sql new file mode 100644 index 0000000..474238c --- /dev/null +++ b/internal/endtoend/testdata/identifier_case_sensitivity/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE Authors ( + ID BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Name text NOT NULL, + Bio text +); + diff --git a/internal/endtoend/testdata/identifier_case_sensitivity/sqlc.json b/internal/endtoend/testdata/identifier_case_sensitivity/sqlc.json new file mode 100644 index 0000000..32a13d6 --- /dev/null +++ b/internal/endtoend/testdata/identifier_case_sensitivity/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "db", + "engine": "mysql", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/identifier_dollar_sign/db/db.go b/internal/endtoend/testdata/identifier_dollar_sign/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/identifier_dollar_sign/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/identifier_dollar_sign/db/models.go b/internal/endtoend/testdata/identifier_dollar_sign/db/models.go new file mode 100644 index 0000000..21f493e --- /dev/null +++ b/internal/endtoend/testdata/identifier_dollar_sign/db/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db diff --git a/internal/endtoend/testdata/identifier_dollar_sign/db/query.sql.go b/internal/endtoend/testdata/identifier_dollar_sign/db/query.sql.go new file mode 100644 index 0000000..48317c8 --- /dev/null +++ b/internal/endtoend/testdata/identifier_dollar_sign/db/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" +) + +const fn = `-- name: Fn :one +SELECT f$n() +` + +func (q *Queries) Fn(ctx context.Context) (int32, error) { + row := q.db.QueryRowContext(ctx, fn) + var f_n int32 + err := row.Scan(&f_n) + return f_n, err +} diff --git a/internal/endtoend/testdata/identifier_dollar_sign/query.sql b/internal/endtoend/testdata/identifier_dollar_sign/query.sql new file mode 100644 index 0000000..6b17cdf --- /dev/null +++ b/internal/endtoend/testdata/identifier_dollar_sign/query.sql @@ -0,0 +1,2 @@ +-- name: Fn :one +SELECT f$n(); diff --git a/internal/endtoend/testdata/identifier_dollar_sign/schema.sql b/internal/endtoend/testdata/identifier_dollar_sign/schema.sql new file mode 100644 index 0000000..fd248d2 --- /dev/null +++ b/internal/endtoend/testdata/identifier_dollar_sign/schema.sql @@ -0,0 +1,3 @@ +CREATE FUNCTION f$n() RETURNS integer + AS $$ SELECT 1 $$ LANGUAGE SQL; + diff --git a/internal/endtoend/testdata/identifier_dollar_sign/sqlc.json b/internal/endtoend/testdata/identifier_dollar_sign/sqlc.json new file mode 100644 index 0000000..2a46100 --- /dev/null +++ b/internal/endtoend/testdata/identifier_dollar_sign/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "db", + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/in_union/mysql/go/db.go b/internal/endtoend/testdata/in_union/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/in_union/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/in_union/mysql/go/models.go b/internal/endtoend/testdata/in_union/mysql/go/models.go new file mode 100644 index 0000000..33ad6a3 --- /dev/null +++ b/internal/endtoend/testdata/in_union/mysql/go/models.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int32 + Name string + Bio sql.NullString +} + +type Book1 struct { + AuthorID int32 + Name sql.NullString +} + +type Book2 struct { + AuthorID int32 + Name sql.NullString +} diff --git a/internal/endtoend/testdata/in_union/mysql/go/query.sql.go b/internal/endtoend/testdata/in_union/mysql/go/query.sql.go new file mode 100644 index 0000000..352b50a --- /dev/null +++ b/internal/endtoend/testdata/in_union/mysql/go/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAuthors = `-- name: GetAuthors :many +SELECT id, name, bio FROM authors +WHERE author_id IN (SELECT author_id FROM book1 UNION SELECT author_id FROM book2) +` + +func (q *Queries) GetAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, getAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); 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/in_union/mysql/query.sql b/internal/endtoend/testdata/in_union/mysql/query.sql new file mode 100644 index 0000000..69606f5 --- /dev/null +++ b/internal/endtoend/testdata/in_union/mysql/query.sql @@ -0,0 +1,3 @@ +-- name: GetAuthors :many +SELECT * FROM authors +WHERE author_id IN (SELECT author_id FROM book1 UNION SELECT author_id FROM book2); diff --git a/internal/endtoend/testdata/in_union/mysql/schema.sql b/internal/endtoend/testdata/in_union/mysql/schema.sql new file mode 100644 index 0000000..47264e2 --- /dev/null +++ b/internal/endtoend/testdata/in_union/mysql/schema.sql @@ -0,0 +1,15 @@ +CREATE TABLE authors ( + id int PRIMARY KEY, + name text NOT NULL, + bio text +); +CREATE TABLE book1 ( + author_id int PRIMARY KEY, + name text, + FOREIGN KEY (`author_id`) REFERENCES `authors` (`id`) ON DELETE CASCADE +); +CREATE TABLE book2 ( + author_id int PRIMARY KEY, + name text, + FOREIGN KEY (`author_id`) REFERENCES `authors` (`id`) ON DELETE CASCADE +); diff --git a/internal/endtoend/testdata/in_union/mysql/sqlc.json b/internal/endtoend/testdata/in_union/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/in_union/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/inflection/mysql/go/db.go b/internal/endtoend/testdata/inflection/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/inflection/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/inflection/mysql/go/models.go b/internal/endtoend/testdata/inflection/mysql/go/models.go new file mode 100644 index 0000000..ba5cb02 --- /dev/null +++ b/internal/endtoend/testdata/inflection/mysql/go/models.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Calorie struct { + ID string +} + +type Campus struct { + ID string +} + +type ProductMetadatum struct { + ID string +} + +type ProductMetum struct { + ID string +} + +type Student struct { + ID string +} diff --git a/internal/endtoend/testdata/inflection/mysql/go/query.sql.go b/internal/endtoend/testdata/inflection/mysql/go/query.sql.go new file mode 100644 index 0000000..ae221c6 --- /dev/null +++ b/internal/endtoend/testdata/inflection/mysql/go/query.sql.go @@ -0,0 +1,145 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getProductMetadata = `-- name: GetProductMetadata :many +SELECT id FROM product_metadata +` + +func (q *Queries) GetProductMetadata(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, getProductMetadata) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 listCalories = `-- name: ListCalories :many +SELECT id FROM calories +` + +func (q *Queries) ListCalories(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, listCalories) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 listCampuses = `-- name: ListCampuses :many +SELECT id FROM campus +` + +func (q *Queries) ListCampuses(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, listCampuses) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 listMetadata = `-- name: ListMetadata :many +SELECT id FROM product_meta +` + +func (q *Queries) ListMetadata(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, listMetadata) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 listStudents = `-- name: ListStudents :many +SELECT id FROM students +` + +func (q *Queries) ListStudents(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, listStudents) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 +} diff --git a/internal/endtoend/testdata/inflection/mysql/query.sql b/internal/endtoend/testdata/inflection/mysql/query.sql new file mode 100644 index 0000000..74e1aaf --- /dev/null +++ b/internal/endtoend/testdata/inflection/mysql/query.sql @@ -0,0 +1,14 @@ +/* name: ListCampuses :many */ +SELECT * FROM campus; + +/* name: ListStudents :many */ +SELECT * FROM students; + +/* name: ListMetadata :many */ +SELECT * FROM product_meta; + +/* name: ListCalories :many */ +SELECT * FROM calories; + +/* name: GetProductMetadata :many */ +SELECT * FROM product_metadata; \ No newline at end of file diff --git a/internal/endtoend/testdata/inflection/mysql/schema.sql b/internal/endtoend/testdata/inflection/mysql/schema.sql new file mode 100644 index 0000000..f7d5c7c --- /dev/null +++ b/internal/endtoend/testdata/inflection/mysql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE campus (id text not null); +CREATE TABLE students (id text not null); +CREATE TABLE product_meta (id text not null); +CREATE TABLE calories (id text not null); +CREATE TABLE product_metadata (id text not null); diff --git a/internal/endtoend/testdata/inflection/mysql/sqlc.json b/internal/endtoend/testdata/inflection/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/inflection/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/inflection/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/inflection/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/inflection/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/inflection/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/inflection/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..ba5cb02 --- /dev/null +++ b/internal/endtoend/testdata/inflection/postgresql/pgx/v4/go/models.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Calorie struct { + ID string +} + +type Campus struct { + ID string +} + +type ProductMetadatum struct { + ID string +} + +type ProductMetum struct { + ID string +} + +type Student struct { + ID string +} diff --git a/internal/endtoend/testdata/inflection/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/inflection/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..950dc18 --- /dev/null +++ b/internal/endtoend/testdata/inflection/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,130 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getProductMetadata = `-- name: GetProductMetadata :many +SELECT id FROM product_metadata +` + +func (q *Queries) GetProductMetadata(ctx context.Context) ([]string, error) { + rows, err := q.db.Query(ctx, getProductMetadata) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 listCalories = `-- name: ListCalories :many +SELECT id FROM calories +` + +func (q *Queries) ListCalories(ctx context.Context) ([]string, error) { + rows, err := q.db.Query(ctx, listCalories) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 listCampuses = `-- name: ListCampuses :many +SELECT id FROM campus +` + +func (q *Queries) ListCampuses(ctx context.Context) ([]string, error) { + rows, err := q.db.Query(ctx, listCampuses) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 listMetadata = `-- name: ListMetadata :many +SELECT id FROM product_meta +` + +func (q *Queries) ListMetadata(ctx context.Context) ([]string, error) { + rows, err := q.db.Query(ctx, listMetadata) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 listStudents = `-- name: ListStudents :many +SELECT id FROM students +` + +func (q *Queries) ListStudents(ctx context.Context) ([]string, error) { + rows, err := q.db.Query(ctx, listStudents) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 +} diff --git a/internal/endtoend/testdata/inflection/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/inflection/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..abc0da2 --- /dev/null +++ b/internal/endtoend/testdata/inflection/postgresql/pgx/v4/query.sql @@ -0,0 +1,14 @@ +-- name: ListCampuses :many +SELECT * FROM campus; + +-- name: ListStudents :many +SELECT * FROM students; + +-- name: ListMetadata :many +SELECT * FROM product_meta; + +-- name: ListCalories :many +SELECT * FROM calories; + +-- name: GetProductMetadata :many +SELECT * FROM product_metadata; \ No newline at end of file diff --git a/internal/endtoend/testdata/inflection/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/inflection/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..ad17ad7 --- /dev/null +++ b/internal/endtoend/testdata/inflection/postgresql/pgx/v4/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE campus (id text not null); +CREATE TABLE students (id text not null); +CREATE TABLE product_meta (id text not null); +CREATE TABLE calories (id text not null); +CREATE TABLE product_metadata (id text not null); \ No newline at end of file diff --git a/internal/endtoend/testdata/inflection/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/inflection/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/inflection/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/inflection/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/inflection/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/inflection/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/inflection/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/inflection/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..ba5cb02 --- /dev/null +++ b/internal/endtoend/testdata/inflection/postgresql/pgx/v5/go/models.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Calorie struct { + ID string +} + +type Campus struct { + ID string +} + +type ProductMetadatum struct { + ID string +} + +type ProductMetum struct { + ID string +} + +type Student struct { + ID string +} diff --git a/internal/endtoend/testdata/inflection/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/inflection/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..950dc18 --- /dev/null +++ b/internal/endtoend/testdata/inflection/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,130 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getProductMetadata = `-- name: GetProductMetadata :many +SELECT id FROM product_metadata +` + +func (q *Queries) GetProductMetadata(ctx context.Context) ([]string, error) { + rows, err := q.db.Query(ctx, getProductMetadata) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 listCalories = `-- name: ListCalories :many +SELECT id FROM calories +` + +func (q *Queries) ListCalories(ctx context.Context) ([]string, error) { + rows, err := q.db.Query(ctx, listCalories) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 listCampuses = `-- name: ListCampuses :many +SELECT id FROM campus +` + +func (q *Queries) ListCampuses(ctx context.Context) ([]string, error) { + rows, err := q.db.Query(ctx, listCampuses) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 listMetadata = `-- name: ListMetadata :many +SELECT id FROM product_meta +` + +func (q *Queries) ListMetadata(ctx context.Context) ([]string, error) { + rows, err := q.db.Query(ctx, listMetadata) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 listStudents = `-- name: ListStudents :many +SELECT id FROM students +` + +func (q *Queries) ListStudents(ctx context.Context) ([]string, error) { + rows, err := q.db.Query(ctx, listStudents) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 +} diff --git a/internal/endtoend/testdata/inflection/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/inflection/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..abc0da2 --- /dev/null +++ b/internal/endtoend/testdata/inflection/postgresql/pgx/v5/query.sql @@ -0,0 +1,14 @@ +-- name: ListCampuses :many +SELECT * FROM campus; + +-- name: ListStudents :many +SELECT * FROM students; + +-- name: ListMetadata :many +SELECT * FROM product_meta; + +-- name: ListCalories :many +SELECT * FROM calories; + +-- name: GetProductMetadata :many +SELECT * FROM product_metadata; \ No newline at end of file diff --git a/internal/endtoend/testdata/inflection/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/inflection/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..ad17ad7 --- /dev/null +++ b/internal/endtoend/testdata/inflection/postgresql/pgx/v5/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE campus (id text not null); +CREATE TABLE students (id text not null); +CREATE TABLE product_meta (id text not null); +CREATE TABLE calories (id text not null); +CREATE TABLE product_metadata (id text not null); \ No newline at end of file diff --git a/internal/endtoend/testdata/inflection/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/inflection/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/inflection/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/inflection/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/inflection/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/inflection/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/inflection/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/inflection/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..ba5cb02 --- /dev/null +++ b/internal/endtoend/testdata/inflection/postgresql/stdlib/go/models.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Calorie struct { + ID string +} + +type Campus struct { + ID string +} + +type ProductMetadatum struct { + ID string +} + +type ProductMetum struct { + ID string +} + +type Student struct { + ID string +} diff --git a/internal/endtoend/testdata/inflection/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/inflection/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..ae221c6 --- /dev/null +++ b/internal/endtoend/testdata/inflection/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,145 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getProductMetadata = `-- name: GetProductMetadata :many +SELECT id FROM product_metadata +` + +func (q *Queries) GetProductMetadata(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, getProductMetadata) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 listCalories = `-- name: ListCalories :many +SELECT id FROM calories +` + +func (q *Queries) ListCalories(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, listCalories) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 listCampuses = `-- name: ListCampuses :many +SELECT id FROM campus +` + +func (q *Queries) ListCampuses(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, listCampuses) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 listMetadata = `-- name: ListMetadata :many +SELECT id FROM product_meta +` + +func (q *Queries) ListMetadata(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, listMetadata) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 listStudents = `-- name: ListStudents :many +SELECT id FROM students +` + +func (q *Queries) ListStudents(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, listStudents) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 +} diff --git a/internal/endtoend/testdata/inflection/postgresql/stdlib/query.sql b/internal/endtoend/testdata/inflection/postgresql/stdlib/query.sql new file mode 100644 index 0000000..abc0da2 --- /dev/null +++ b/internal/endtoend/testdata/inflection/postgresql/stdlib/query.sql @@ -0,0 +1,14 @@ +-- name: ListCampuses :many +SELECT * FROM campus; + +-- name: ListStudents :many +SELECT * FROM students; + +-- name: ListMetadata :many +SELECT * FROM product_meta; + +-- name: ListCalories :many +SELECT * FROM calories; + +-- name: GetProductMetadata :many +SELECT * FROM product_metadata; \ No newline at end of file diff --git a/internal/endtoend/testdata/inflection/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/inflection/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..ad17ad7 --- /dev/null +++ b/internal/endtoend/testdata/inflection/postgresql/stdlib/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE campus (id text not null); +CREATE TABLE students (id text not null); +CREATE TABLE product_meta (id text not null); +CREATE TABLE calories (id text not null); +CREATE TABLE product_metadata (id text not null); \ No newline at end of file diff --git a/internal/endtoend/testdata/inflection/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/inflection/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..cd51867 --- /dev/null +++ b/internal/endtoend/testdata/inflection/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/inflection/sqlite/go/db.go b/internal/endtoend/testdata/inflection/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/inflection/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/inflection/sqlite/go/models.go b/internal/endtoend/testdata/inflection/sqlite/go/models.go new file mode 100644 index 0000000..ba5cb02 --- /dev/null +++ b/internal/endtoend/testdata/inflection/sqlite/go/models.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Calorie struct { + ID string +} + +type Campus struct { + ID string +} + +type ProductMetadatum struct { + ID string +} + +type ProductMetum struct { + ID string +} + +type Student struct { + ID string +} diff --git a/internal/endtoend/testdata/inflection/sqlite/go/query.sql.go b/internal/endtoend/testdata/inflection/sqlite/go/query.sql.go new file mode 100644 index 0000000..ae221c6 --- /dev/null +++ b/internal/endtoend/testdata/inflection/sqlite/go/query.sql.go @@ -0,0 +1,145 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getProductMetadata = `-- name: GetProductMetadata :many +SELECT id FROM product_metadata +` + +func (q *Queries) GetProductMetadata(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, getProductMetadata) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 listCalories = `-- name: ListCalories :many +SELECT id FROM calories +` + +func (q *Queries) ListCalories(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, listCalories) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 listCampuses = `-- name: ListCampuses :many +SELECT id FROM campus +` + +func (q *Queries) ListCampuses(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, listCampuses) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 listMetadata = `-- name: ListMetadata :many +SELECT id FROM product_meta +` + +func (q *Queries) ListMetadata(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, listMetadata) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 listStudents = `-- name: ListStudents :many +SELECT id FROM students +` + +func (q *Queries) ListStudents(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, listStudents) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 +} diff --git a/internal/endtoend/testdata/inflection/sqlite/query.sql b/internal/endtoend/testdata/inflection/sqlite/query.sql new file mode 100644 index 0000000..26fe295 --- /dev/null +++ b/internal/endtoend/testdata/inflection/sqlite/query.sql @@ -0,0 +1,14 @@ +/* name: ListCampuses :many */ +SELECT * FROM campus; + +/* name: ListStudents :many */ +SELECT * FROM students; + +/* name: ListMetadata :many */ +SELECT * FROM product_meta; + +/* name: ListCalories :many */ +SELECT * FROM calories; + +/* name: GetProductMetadata :many */ +SELECT * FROM product_metadata; diff --git a/internal/endtoend/testdata/inflection/sqlite/schema.sql b/internal/endtoend/testdata/inflection/sqlite/schema.sql new file mode 100644 index 0000000..ad17ad7 --- /dev/null +++ b/internal/endtoend/testdata/inflection/sqlite/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE campus (id text not null); +CREATE TABLE students (id text not null); +CREATE TABLE product_meta (id text not null); +CREATE TABLE calories (id text not null); +CREATE TABLE product_metadata (id text not null); \ No newline at end of file diff --git a/internal/endtoend/testdata/inflection/sqlite/sqlc.json b/internal/endtoend/testdata/inflection/sqlite/sqlc.json new file mode 100644 index 0000000..f8e8051 --- /dev/null +++ b/internal/endtoend/testdata/inflection/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "sqlite", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/inflection_exclude_table_names/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..3942891 --- /dev/null +++ b/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v4/go/models.go @@ -0,0 +1,20 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 + Name string +} + +type Exclusions struct { + ID int32 + Name string +} + +type MyData struct { + ID int32 + Name string +} diff --git a/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..15a9da2 --- /dev/null +++ b/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,43 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const deleteBarByID = `-- name: DeleteBarByID :one +DELETE FROM bars WHERE id = $1 RETURNING id, name +` + +func (q *Queries) DeleteBarByID(ctx context.Context, id int32) (Bar, error) { + row := q.db.QueryRow(ctx, deleteBarByID, id) + var i Bar + err := row.Scan(&i.ID, &i.Name) + return i, err +} + +const deleteExclusionByID = `-- name: DeleteExclusionByID :one +DELETE FROM exclusions WHERE id = $1 RETURNING id, name +` + +func (q *Queries) DeleteExclusionByID(ctx context.Context, id int32) (Exclusions, error) { + row := q.db.QueryRow(ctx, deleteExclusionByID, id) + var i Exclusions + err := row.Scan(&i.ID, &i.Name) + return i, err +} + +const deleteMyDataByID = `-- name: DeleteMyDataByID :one +DELETE FROM my_data WHERE id = $1 RETURNING id, name +` + +func (q *Queries) DeleteMyDataByID(ctx context.Context, id int32) (MyData, error) { + row := q.db.QueryRow(ctx, deleteMyDataByID, id) + var i MyData + err := row.Scan(&i.ID, &i.Name) + return i, err +} diff --git a/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..f279a10 --- /dev/null +++ b/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v4/query.sql @@ -0,0 +1,8 @@ +-- name: DeleteBarByID :one +DELETE FROM bars WHERE id = $1 RETURNING id, name; + +-- name: DeleteMyDataByID :one +DELETE FROM my_data WHERE id = $1 RETURNING id, name; + +-- name: DeleteExclusionByID :one +DELETE FROM exclusions WHERE id = $1 RETURNING id, name; diff --git a/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..ea5b797 --- /dev/null +++ b/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v4/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE bars (id serial not null, name text not null, primary key (id)); +CREATE TABLE my_data (id serial not null, name text not null, primary key (id)); +CREATE TABLE exclusions (id serial not null, name text not null, primary key (id)); + diff --git a/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..6c17458 --- /dev/null +++ b/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,21 @@ +{ + "version": "2", + "sql": [ + { + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "gen": { + "go": { + "package": "querytest", + "sql_package": "pgx/v4", + "out": "go", + "inflection_exclude_table_names": [ + "my_data", + "exclusions" + ] + } + } + } + ] +} diff --git a/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/inflection_exclude_table_names/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..3942891 --- /dev/null +++ b/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v5/go/models.go @@ -0,0 +1,20 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 + Name string +} + +type Exclusions struct { + ID int32 + Name string +} + +type MyData struct { + ID int32 + Name string +} diff --git a/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..15a9da2 --- /dev/null +++ b/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,43 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const deleteBarByID = `-- name: DeleteBarByID :one +DELETE FROM bars WHERE id = $1 RETURNING id, name +` + +func (q *Queries) DeleteBarByID(ctx context.Context, id int32) (Bar, error) { + row := q.db.QueryRow(ctx, deleteBarByID, id) + var i Bar + err := row.Scan(&i.ID, &i.Name) + return i, err +} + +const deleteExclusionByID = `-- name: DeleteExclusionByID :one +DELETE FROM exclusions WHERE id = $1 RETURNING id, name +` + +func (q *Queries) DeleteExclusionByID(ctx context.Context, id int32) (Exclusions, error) { + row := q.db.QueryRow(ctx, deleteExclusionByID, id) + var i Exclusions + err := row.Scan(&i.ID, &i.Name) + return i, err +} + +const deleteMyDataByID = `-- name: DeleteMyDataByID :one +DELETE FROM my_data WHERE id = $1 RETURNING id, name +` + +func (q *Queries) DeleteMyDataByID(ctx context.Context, id int32) (MyData, error) { + row := q.db.QueryRow(ctx, deleteMyDataByID, id) + var i MyData + err := row.Scan(&i.ID, &i.Name) + return i, err +} diff --git a/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..f279a10 --- /dev/null +++ b/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v5/query.sql @@ -0,0 +1,8 @@ +-- name: DeleteBarByID :one +DELETE FROM bars WHERE id = $1 RETURNING id, name; + +-- name: DeleteMyDataByID :one +DELETE FROM my_data WHERE id = $1 RETURNING id, name; + +-- name: DeleteExclusionByID :one +DELETE FROM exclusions WHERE id = $1 RETURNING id, name; diff --git a/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..ea5b797 --- /dev/null +++ b/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v5/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE bars (id serial not null, name text not null, primary key (id)); +CREATE TABLE my_data (id serial not null, name text not null, primary key (id)); +CREATE TABLE exclusions (id serial not null, name text not null, primary key (id)); + diff --git a/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..3d058c3 --- /dev/null +++ b/internal/endtoend/testdata/inflection_exclude_table_names/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,21 @@ +{ + "version": "2", + "sql": [ + { + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "gen": { + "go": { + "package": "querytest", + "sql_package": "pgx/v5", + "out": "go", + "inflection_exclude_table_names": [ + "my_data", + "exclusions" + ] + } + } + } + ] +} diff --git a/internal/endtoend/testdata/insert_cte/pgx/v4/go/db.go b/internal/endtoend/testdata/insert_cte/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/insert_cte/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/insert_cte/pgx/v4/go/models.go b/internal/endtoend/testdata/insert_cte/pgx/v4/go/models.go new file mode 100644 index 0000000..97ccea3 --- /dev/null +++ b/internal/endtoend/testdata/insert_cte/pgx/v4/go/models.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + "time" +) + +type Td3Code struct { + ID int32 + TsCreated time.Time + TsUpdated time.Time + CreatedBy string + UpdatedBy string + Code sql.NullString + Hash sql.NullString + IsPrivate sql.NullBool +} + +type Td3TestCode struct { + ID int32 + TsCreated time.Time + TsUpdated time.Time + CreatedBy string + UpdatedBy string + TestID int32 + CodeHash string +} diff --git a/internal/endtoend/testdata/insert_cte/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/insert_cte/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..7fe4ff6 --- /dev/null +++ b/internal/endtoend/testdata/insert_cte/pgx/v4/go/query.sql.go @@ -0,0 +1,51 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const insertCode = `-- name: InsertCode :one +WITH cc AS ( + INSERT INTO td3.codes(created_by, updated_by, code, hash, is_private) + VALUES ($1, $1, $2, $3, false) + RETURNING hash +) +INSERT INTO td3.test_codes(created_by, updated_by, test_id, code_hash) +VALUES( + $1, $1, $4, (select hash from cc) +) +RETURNING id, ts_created, ts_updated, created_by, updated_by, test_id, code_hash +` + +type InsertCodeParams struct { + CreatedBy string + Code sql.NullString + Hash sql.NullString + TestID int32 +} + +func (q *Queries) InsertCode(ctx context.Context, arg InsertCodeParams) (Td3TestCode, error) { + row := q.db.QueryRow(ctx, insertCode, + arg.CreatedBy, + arg.Code, + arg.Hash, + arg.TestID, + ) + var i Td3TestCode + err := row.Scan( + &i.ID, + &i.TsCreated, + &i.TsUpdated, + &i.CreatedBy, + &i.UpdatedBy, + &i.TestID, + &i.CodeHash, + ) + return i, err +} diff --git a/internal/endtoend/testdata/insert_cte/pgx/v4/query.sql b/internal/endtoend/testdata/insert_cte/pgx/v4/query.sql new file mode 100644 index 0000000..7e7483f --- /dev/null +++ b/internal/endtoend/testdata/insert_cte/pgx/v4/query.sql @@ -0,0 +1,11 @@ +-- name: InsertCode :one +WITH cc AS ( + INSERT INTO td3.codes(created_by, updated_by, code, hash, is_private) + VALUES ($1, $1, $2, $3, false) + RETURNING hash +) +INSERT INTO td3.test_codes(created_by, updated_by, test_id, code_hash) +VALUES( + $1, $1, $4, (select hash from cc) +) +RETURNING *; diff --git a/internal/endtoend/testdata/insert_cte/pgx/v4/schema.sql b/internal/endtoend/testdata/insert_cte/pgx/v4/schema.sql new file mode 100644 index 0000000..1eb3dcf --- /dev/null +++ b/internal/endtoend/testdata/insert_cte/pgx/v4/schema.sql @@ -0,0 +1,31 @@ +-- FILE: schema.sql + +DROP SCHEMA IF EXISTS td3 CASCADE; +CREATE SCHEMA td3; + +CREATE TABLE td3.codes ( + id SERIAL PRIMARY KEY, + ts_created timestamptz DEFAULT now() NOT NULL, + ts_updated timestamptz DEFAULT now() NOT NULL, + created_by text NOT NULL, + updated_by text NOT NULL, + + code text, + hash text, + is_private boolean +); + + +CREATE TABLE td3.test_codes ( + id SERIAL PRIMARY KEY, + ts_created timestamptz DEFAULT now() NOT NULL, + ts_updated timestamptz DEFAULT now() NOT NULL, + created_by text NOT NULL, + updated_by text NOT NULL, + + test_id integer NOT NULL, + code_hash text NOT NULL +); + +-- FILE: query.sql + diff --git a/internal/endtoend/testdata/insert_cte/pgx/v4/sqlc.json b/internal/endtoend/testdata/insert_cte/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/insert_cte/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/insert_cte/pgx/v5/go/db.go b/internal/endtoend/testdata/insert_cte/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/insert_cte/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/insert_cte/pgx/v5/go/models.go b/internal/endtoend/testdata/insert_cte/pgx/v5/go/models.go new file mode 100644 index 0000000..6aae2a6 --- /dev/null +++ b/internal/endtoend/testdata/insert_cte/pgx/v5/go/models.go @@ -0,0 +1,30 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Td3Code struct { + ID int32 + TsCreated pgtype.Timestamptz + TsUpdated pgtype.Timestamptz + CreatedBy string + UpdatedBy string + Code pgtype.Text + Hash pgtype.Text + IsPrivate pgtype.Bool +} + +type Td3TestCode struct { + ID int32 + TsCreated pgtype.Timestamptz + TsUpdated pgtype.Timestamptz + CreatedBy string + UpdatedBy string + TestID int32 + CodeHash string +} diff --git a/internal/endtoend/testdata/insert_cte/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/insert_cte/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..f22c13e --- /dev/null +++ b/internal/endtoend/testdata/insert_cte/pgx/v5/go/query.sql.go @@ -0,0 +1,52 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const insertCode = `-- name: InsertCode :one +WITH cc AS ( + INSERT INTO td3.codes(created_by, updated_by, code, hash, is_private) + VALUES ($1, $1, $2, $3, false) + RETURNING hash +) +INSERT INTO td3.test_codes(created_by, updated_by, test_id, code_hash) +VALUES( + $1, $1, $4, (select hash from cc) +) +RETURNING id, ts_created, ts_updated, created_by, updated_by, test_id, code_hash +` + +type InsertCodeParams struct { + CreatedBy string + Code pgtype.Text + Hash pgtype.Text + TestID int32 +} + +func (q *Queries) InsertCode(ctx context.Context, arg InsertCodeParams) (Td3TestCode, error) { + row := q.db.QueryRow(ctx, insertCode, + arg.CreatedBy, + arg.Code, + arg.Hash, + arg.TestID, + ) + var i Td3TestCode + err := row.Scan( + &i.ID, + &i.TsCreated, + &i.TsUpdated, + &i.CreatedBy, + &i.UpdatedBy, + &i.TestID, + &i.CodeHash, + ) + return i, err +} diff --git a/internal/endtoend/testdata/insert_cte/pgx/v5/query.sql b/internal/endtoend/testdata/insert_cte/pgx/v5/query.sql new file mode 100644 index 0000000..7e7483f --- /dev/null +++ b/internal/endtoend/testdata/insert_cte/pgx/v5/query.sql @@ -0,0 +1,11 @@ +-- name: InsertCode :one +WITH cc AS ( + INSERT INTO td3.codes(created_by, updated_by, code, hash, is_private) + VALUES ($1, $1, $2, $3, false) + RETURNING hash +) +INSERT INTO td3.test_codes(created_by, updated_by, test_id, code_hash) +VALUES( + $1, $1, $4, (select hash from cc) +) +RETURNING *; diff --git a/internal/endtoend/testdata/insert_cte/pgx/v5/schema.sql b/internal/endtoend/testdata/insert_cte/pgx/v5/schema.sql new file mode 100644 index 0000000..1eb3dcf --- /dev/null +++ b/internal/endtoend/testdata/insert_cte/pgx/v5/schema.sql @@ -0,0 +1,31 @@ +-- FILE: schema.sql + +DROP SCHEMA IF EXISTS td3 CASCADE; +CREATE SCHEMA td3; + +CREATE TABLE td3.codes ( + id SERIAL PRIMARY KEY, + ts_created timestamptz DEFAULT now() NOT NULL, + ts_updated timestamptz DEFAULT now() NOT NULL, + created_by text NOT NULL, + updated_by text NOT NULL, + + code text, + hash text, + is_private boolean +); + + +CREATE TABLE td3.test_codes ( + id SERIAL PRIMARY KEY, + ts_created timestamptz DEFAULT now() NOT NULL, + ts_updated timestamptz DEFAULT now() NOT NULL, + created_by text NOT NULL, + updated_by text NOT NULL, + + test_id integer NOT NULL, + code_hash text NOT NULL +); + +-- FILE: query.sql + diff --git a/internal/endtoend/testdata/insert_cte/pgx/v5/sqlc.json b/internal/endtoend/testdata/insert_cte/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/insert_cte/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/insert_cte/stdlib/go/db.go b/internal/endtoend/testdata/insert_cte/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/insert_cte/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/insert_cte/stdlib/go/models.go b/internal/endtoend/testdata/insert_cte/stdlib/go/models.go new file mode 100644 index 0000000..97ccea3 --- /dev/null +++ b/internal/endtoend/testdata/insert_cte/stdlib/go/models.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + "time" +) + +type Td3Code struct { + ID int32 + TsCreated time.Time + TsUpdated time.Time + CreatedBy string + UpdatedBy string + Code sql.NullString + Hash sql.NullString + IsPrivate sql.NullBool +} + +type Td3TestCode struct { + ID int32 + TsCreated time.Time + TsUpdated time.Time + CreatedBy string + UpdatedBy string + TestID int32 + CodeHash string +} diff --git a/internal/endtoend/testdata/insert_cte/stdlib/go/query.sql.go b/internal/endtoend/testdata/insert_cte/stdlib/go/query.sql.go new file mode 100644 index 0000000..b5379c4 --- /dev/null +++ b/internal/endtoend/testdata/insert_cte/stdlib/go/query.sql.go @@ -0,0 +1,51 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const insertCode = `-- name: InsertCode :one +WITH cc AS ( + INSERT INTO td3.codes(created_by, updated_by, code, hash, is_private) + VALUES ($1, $1, $2, $3, false) + RETURNING hash +) +INSERT INTO td3.test_codes(created_by, updated_by, test_id, code_hash) +VALUES( + $1, $1, $4, (select hash from cc) +) +RETURNING id, ts_created, ts_updated, created_by, updated_by, test_id, code_hash +` + +type InsertCodeParams struct { + CreatedBy string + Code sql.NullString + Hash sql.NullString + TestID int32 +} + +func (q *Queries) InsertCode(ctx context.Context, arg InsertCodeParams) (Td3TestCode, error) { + row := q.db.QueryRowContext(ctx, insertCode, + arg.CreatedBy, + arg.Code, + arg.Hash, + arg.TestID, + ) + var i Td3TestCode + err := row.Scan( + &i.ID, + &i.TsCreated, + &i.TsUpdated, + &i.CreatedBy, + &i.UpdatedBy, + &i.TestID, + &i.CodeHash, + ) + return i, err +} diff --git a/internal/endtoend/testdata/insert_cte/stdlib/query.sql b/internal/endtoend/testdata/insert_cte/stdlib/query.sql new file mode 100644 index 0000000..7e7483f --- /dev/null +++ b/internal/endtoend/testdata/insert_cte/stdlib/query.sql @@ -0,0 +1,11 @@ +-- name: InsertCode :one +WITH cc AS ( + INSERT INTO td3.codes(created_by, updated_by, code, hash, is_private) + VALUES ($1, $1, $2, $3, false) + RETURNING hash +) +INSERT INTO td3.test_codes(created_by, updated_by, test_id, code_hash) +VALUES( + $1, $1, $4, (select hash from cc) +) +RETURNING *; diff --git a/internal/endtoend/testdata/insert_cte/stdlib/schema.sql b/internal/endtoend/testdata/insert_cte/stdlib/schema.sql new file mode 100644 index 0000000..1eb3dcf --- /dev/null +++ b/internal/endtoend/testdata/insert_cte/stdlib/schema.sql @@ -0,0 +1,31 @@ +-- FILE: schema.sql + +DROP SCHEMA IF EXISTS td3 CASCADE; +CREATE SCHEMA td3; + +CREATE TABLE td3.codes ( + id SERIAL PRIMARY KEY, + ts_created timestamptz DEFAULT now() NOT NULL, + ts_updated timestamptz DEFAULT now() NOT NULL, + created_by text NOT NULL, + updated_by text NOT NULL, + + code text, + hash text, + is_private boolean +); + + +CREATE TABLE td3.test_codes ( + id SERIAL PRIMARY KEY, + ts_created timestamptz DEFAULT now() NOT NULL, + ts_updated timestamptz DEFAULT now() NOT NULL, + created_by text NOT NULL, + updated_by text NOT NULL, + + test_id integer NOT NULL, + code_hash text NOT NULL +); + +-- FILE: query.sql + diff --git a/internal/endtoend/testdata/insert_cte/stdlib/sqlc.json b/internal/endtoend/testdata/insert_cte/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/insert_cte/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/insert_default_values/sqlite/go/db.go b/internal/endtoend/testdata/insert_default_values/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/insert_default_values/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/insert_default_values/sqlite/go/models.go b/internal/endtoend/testdata/insert_default_values/sqlite/go/models.go new file mode 100644 index 0000000..870be15 --- /dev/null +++ b/internal/endtoend/testdata/insert_default_values/sqlite/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Workspace struct { + ID int64 +} diff --git a/internal/endtoend/testdata/insert_default_values/sqlite/go/query.sql.go b/internal/endtoend/testdata/insert_default_values/sqlite/go/query.sql.go new file mode 100644 index 0000000..26ca36f --- /dev/null +++ b/internal/endtoend/testdata/insert_default_values/sqlite/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const insertWorkspace = `-- name: InsertWorkspace :exec +INSERT INTO workspace DEFAULT VALUES +` + +func (q *Queries) InsertWorkspace(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, insertWorkspace) + return err +} diff --git a/internal/endtoend/testdata/insert_default_values/sqlite/query.sql b/internal/endtoend/testdata/insert_default_values/sqlite/query.sql new file mode 100644 index 0000000..89d593c --- /dev/null +++ b/internal/endtoend/testdata/insert_default_values/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: InsertWorkspace :exec +INSERT INTO workspace DEFAULT VALUES; diff --git a/internal/endtoend/testdata/insert_default_values/sqlite/schema.sql b/internal/endtoend/testdata/insert_default_values/sqlite/schema.sql new file mode 100644 index 0000000..f142b7c --- /dev/null +++ b/internal/endtoend/testdata/insert_default_values/sqlite/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE workspace ( + id INTEGER PRIMARY KEY AUTOINCREMENT +); \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_default_values/sqlite/sqlc.json b/internal/endtoend/testdata/insert_default_values/sqlite/sqlc.json new file mode 100644 index 0000000..f8e8051 --- /dev/null +++ b/internal/endtoend/testdata/insert_default_values/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "sqlite", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_select/mysql/go/db.go b/internal/endtoend/testdata/insert_select/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/insert_select/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/insert_select/mysql/go/models.go b/internal/endtoend/testdata/insert_select/mysql/go/models.go new file mode 100644 index 0000000..c99c5f1 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/mysql/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + Name string + Ready bool +} + +type Foo struct { + Name string + Meta string +} diff --git a/internal/endtoend/testdata/insert_select/mysql/go/query.sql.go b/internal/endtoend/testdata/insert_select/mysql/go/query.sql.go new file mode 100644 index 0000000..7b7d191 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/mysql/go/query.sql.go @@ -0,0 +1,26 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const insertSelect = `-- name: InsertSelect :exec +INSERT INTO foo (name, meta) +SELECT name, ? +FROM bar WHERE ready = ? +` + +type InsertSelectParams struct { + Meta string + Ready bool +} + +func (q *Queries) InsertSelect(ctx context.Context, arg InsertSelectParams) error { + _, err := q.db.ExecContext(ctx, insertSelect, arg.Meta, arg.Ready) + return err +} diff --git a/internal/endtoend/testdata/insert_select/mysql/query.sql b/internal/endtoend/testdata/insert_select/mysql/query.sql new file mode 100644 index 0000000..880f083 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/mysql/query.sql @@ -0,0 +1,4 @@ +/* name: InsertSelect :exec */ +INSERT INTO foo (name, meta) +SELECT name, ? +FROM bar WHERE ready = ?; diff --git a/internal/endtoend/testdata/insert_select/mysql/schema.sql b/internal/endtoend/testdata/insert_select/mysql/schema.sql new file mode 100644 index 0000000..1a394f8 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/mysql/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE bar (name text not null, ready bool not null); +CREATE TABLE foo (name text not null, meta text not null); + diff --git a/internal/endtoend/testdata/insert_select/mysql/sqlc.json b/internal/endtoend/testdata/insert_select/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/insert_select/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/insert_select/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/insert_select/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/insert_select/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/insert_select/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..c99c5f1 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/postgresql/pgx/v4/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + Name string + Ready bool +} + +type Foo struct { + Name string + Meta string +} diff --git a/internal/endtoend/testdata/insert_select/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/insert_select/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..a3e177f --- /dev/null +++ b/internal/endtoend/testdata/insert_select/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,26 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const insertSelect = `-- name: InsertSelect :exec +INSERT INTO foo (name, meta) +SELECT name, $1 +FROM bar WHERE ready = $2 +` + +type InsertSelectParams struct { + Meta string + Ready bool +} + +func (q *Queries) InsertSelect(ctx context.Context, arg InsertSelectParams) error { + _, err := q.db.Exec(ctx, insertSelect, arg.Meta, arg.Ready) + return err +} diff --git a/internal/endtoend/testdata/insert_select/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/insert_select/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..8478c05 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/postgresql/pgx/v4/query.sql @@ -0,0 +1,4 @@ +-- name: InsertSelect :exec +INSERT INTO foo (name, meta) +SELECT name, $1 +FROM bar WHERE ready = $2; diff --git a/internal/endtoend/testdata/insert_select/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/insert_select/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..1a394f8 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/postgresql/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE bar (name text not null, ready bool not null); +CREATE TABLE foo (name text not null, meta text not null); + diff --git a/internal/endtoend/testdata/insert_select/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/insert_select/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/insert_select/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/insert_select/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/insert_select/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/insert_select/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/insert_select/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..c99c5f1 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/postgresql/pgx/v5/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + Name string + Ready bool +} + +type Foo struct { + Name string + Meta string +} diff --git a/internal/endtoend/testdata/insert_select/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/insert_select/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..a3e177f --- /dev/null +++ b/internal/endtoend/testdata/insert_select/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,26 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const insertSelect = `-- name: InsertSelect :exec +INSERT INTO foo (name, meta) +SELECT name, $1 +FROM bar WHERE ready = $2 +` + +type InsertSelectParams struct { + Meta string + Ready bool +} + +func (q *Queries) InsertSelect(ctx context.Context, arg InsertSelectParams) error { + _, err := q.db.Exec(ctx, insertSelect, arg.Meta, arg.Ready) + return err +} diff --git a/internal/endtoend/testdata/insert_select/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/insert_select/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..8478c05 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/postgresql/pgx/v5/query.sql @@ -0,0 +1,4 @@ +-- name: InsertSelect :exec +INSERT INTO foo (name, meta) +SELECT name, $1 +FROM bar WHERE ready = $2; diff --git a/internal/endtoend/testdata/insert_select/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/insert_select/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..1a394f8 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/postgresql/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE bar (name text not null, ready bool not null); +CREATE TABLE foo (name text not null, meta text not null); + diff --git a/internal/endtoend/testdata/insert_select/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/insert_select/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/insert_select/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/insert_select/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/insert_select/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/insert_select/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/insert_select/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..c99c5f1 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/postgresql/stdlib/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + Name string + Ready bool +} + +type Foo struct { + Name string + Meta string +} diff --git a/internal/endtoend/testdata/insert_select/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/insert_select/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..bbf3dd7 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,26 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const insertSelect = `-- name: InsertSelect :exec +INSERT INTO foo (name, meta) +SELECT name, $1 +FROM bar WHERE ready = $2 +` + +type InsertSelectParams struct { + Meta string + Ready bool +} + +func (q *Queries) InsertSelect(ctx context.Context, arg InsertSelectParams) error { + _, err := q.db.ExecContext(ctx, insertSelect, arg.Meta, arg.Ready) + return err +} diff --git a/internal/endtoend/testdata/insert_select/postgresql/stdlib/query.sql b/internal/endtoend/testdata/insert_select/postgresql/stdlib/query.sql new file mode 100644 index 0000000..8478c05 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/postgresql/stdlib/query.sql @@ -0,0 +1,4 @@ +-- name: InsertSelect :exec +INSERT INTO foo (name, meta) +SELECT name, $1 +FROM bar WHERE ready = $2; diff --git a/internal/endtoend/testdata/insert_select/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/insert_select/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..1a394f8 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/postgresql/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE bar (name text not null, ready bool not null); +CREATE TABLE foo (name text not null, meta text not null); + diff --git a/internal/endtoend/testdata/insert_select/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/insert_select/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..cd51867 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/insert_select/sqlite/go/db.go b/internal/endtoend/testdata/insert_select/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/insert_select/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/insert_select/sqlite/go/models.go b/internal/endtoend/testdata/insert_select/sqlite/go/models.go new file mode 100644 index 0000000..c99c5f1 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/sqlite/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + Name string + Ready bool +} + +type Foo struct { + Name string + Meta string +} diff --git a/internal/endtoend/testdata/insert_select/sqlite/go/query.sql.go b/internal/endtoend/testdata/insert_select/sqlite/go/query.sql.go new file mode 100644 index 0000000..b158e67 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/sqlite/go/query.sql.go @@ -0,0 +1,27 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const insertSelect = `-- name: InsertSelect :exec +INSERT INTO foo (name, meta) +SELECT name, ? +FROM bar +WHERE ready = ? +` + +type InsertSelectParams struct { + Meta string + Ready bool +} + +func (q *Queries) InsertSelect(ctx context.Context, arg InsertSelectParams) error { + _, err := q.db.ExecContext(ctx, insertSelect, arg.Meta, arg.Ready) + return err +} diff --git a/internal/endtoend/testdata/insert_select/sqlite/query.sql b/internal/endtoend/testdata/insert_select/sqlite/query.sql new file mode 100644 index 0000000..7707a6a --- /dev/null +++ b/internal/endtoend/testdata/insert_select/sqlite/query.sql @@ -0,0 +1,5 @@ +/* name: InsertSelect :exec */ +INSERT INTO foo (name, meta) +SELECT name, ? +FROM bar +WHERE ready = ?; diff --git a/internal/endtoend/testdata/insert_select/sqlite/schema.sql b/internal/endtoend/testdata/insert_select/sqlite/schema.sql new file mode 100644 index 0000000..1a394f8 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/sqlite/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE bar (name text not null, ready bool not null); +CREATE TABLE foo (name text not null, meta text not null); + diff --git a/internal/endtoend/testdata/insert_select/sqlite/sqlc.json b/internal/endtoend/testdata/insert_select/sqlite/sqlc.json new file mode 100644 index 0000000..f8e8051 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "sqlite", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_select_case/issue.md b/internal/endtoend/testdata/insert_select_case/issue.md new file mode 100644 index 0000000..f4090f8 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_case/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1646 diff --git a/internal/endtoend/testdata/insert_select_case/postgresql/pgx/exec.json b/internal/endtoend/testdata/insert_select_case/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/insert_select_case/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/insert_select_case/postgresql/pgx/go/db.go b/internal/endtoend/testdata/insert_select_case/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/insert_select_case/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/insert_select_case/postgresql/pgx/go/models.go b/internal/endtoend/testdata/insert_select_case/postgresql/pgx/go/models.go new file mode 100644 index 0000000..c8e716e --- /dev/null +++ b/internal/endtoend/testdata/insert_select_case/postgresql/pgx/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Order struct { + ID pgtype.Int8 + Name pgtype.Text +} diff --git a/internal/endtoend/testdata/insert_select_case/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/insert_select_case/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..88f2aff --- /dev/null +++ b/internal/endtoend/testdata/insert_select_case/postgresql/pgx/go/query.sql.go @@ -0,0 +1,28 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const insertOrders = `-- name: InsertOrders :exec +insert into Orders (id,name) +select id , CASE WHEN $1::BOOLEAN THEN $2 ELSE s.name END +from Orders s +` + +type InsertOrdersParams struct { + NameDoUpdate pgtype.Bool + Name pgtype.Text +} + +func (q *Queries) InsertOrders(ctx context.Context, arg InsertOrdersParams) error { + _, err := q.db.Exec(ctx, insertOrders, arg.NameDoUpdate, arg.Name) + return err +} diff --git a/internal/endtoend/testdata/insert_select_case/postgresql/pgx/query.sql b/internal/endtoend/testdata/insert_select_case/postgresql/pgx/query.sql new file mode 100644 index 0000000..4396b7b --- /dev/null +++ b/internal/endtoend/testdata/insert_select_case/postgresql/pgx/query.sql @@ -0,0 +1,4 @@ +-- name: InsertOrders :exec +insert into Orders (id,name) +select id , CASE WHEN @name_do_update::BOOLEAN THEN @name ELSE s.name END +from Orders s ; diff --git a/internal/endtoend/testdata/insert_select_case/postgresql/pgx/schema.sql b/internal/endtoend/testdata/insert_select_case/postgresql/pgx/schema.sql new file mode 100644 index 0000000..cbc21a5 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_case/postgresql/pgx/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE orders( + id bigserial, + name text +); diff --git a/internal/endtoend/testdata/insert_select_case/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/insert_select_case/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..ee50c7b --- /dev/null +++ b/internal/endtoend/testdata/insert_select_case/postgresql/pgx/sqlc.yaml @@ -0,0 +1,12 @@ +version: "2" +cloud: + project: "01HAQMMECEYQYKFJN8MP16QC41" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/insert_select_invalid/mysql/query.sql b/internal/endtoend/testdata/insert_select_invalid/mysql/query.sql new file mode 100644 index 0000000..3311b32 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/mysql/query.sql @@ -0,0 +1,3 @@ +-- name: InsertFoo :exec +INSERT INTO foo (bar) +SELECT 1, ?, ?; diff --git a/internal/endtoend/testdata/insert_select_invalid/mysql/schema.sql b/internal/endtoend/testdata/insert_select_invalid/mysql/schema.sql new file mode 100644 index 0000000..d849628 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/mysql/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (bar text); diff --git a/internal/endtoend/testdata/insert_select_invalid/mysql/sqlc.json b/internal/endtoend/testdata/insert_select_invalid/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/insert_select_invalid/mysql/stderr.txt b/internal/endtoend/testdata/insert_select_invalid/mysql/stderr.txt new file mode 100644 index 0000000..91d0b8a --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/mysql/stderr.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:1:1: INSERT has more expressions than target columns diff --git a/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..fad60fe --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v4/query.sql @@ -0,0 +1,3 @@ +-- name: InsertFoo :exec +INSERT INTO foo (bar) +SELECT 1, $1, $2; \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..be35e94 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v4/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (bar text); \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v4/stderr/base.txt b/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v4/stderr/base.txt new file mode 100644 index 0000000..77fedb8 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v4/stderr/base.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:1:1: INSERT has more expressions than target columns \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v4/stderr/managed-db.txt b/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v4/stderr/managed-db.txt new file mode 100644 index 0000000..7448a74 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v4/stderr/managed-db.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:3:11: INSERT has more expressions than target columns \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..fad60fe --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v5/query.sql @@ -0,0 +1,3 @@ +-- name: InsertFoo :exec +INSERT INTO foo (bar) +SELECT 1, $1, $2; \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..be35e94 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v5/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (bar text); \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v5/stderr/base.txt b/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v5/stderr/base.txt new file mode 100644 index 0000000..77fedb8 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v5/stderr/base.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:1:1: INSERT has more expressions than target columns \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v5/stderr/managed-db.txt b/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v5/stderr/managed-db.txt new file mode 100644 index 0000000..7448a74 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/postgresql/pgx/v5/stderr/managed-db.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:3:11: INSERT has more expressions than target columns \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_select_invalid/postgresql/stdlib/query.sql b/internal/endtoend/testdata/insert_select_invalid/postgresql/stdlib/query.sql new file mode 100644 index 0000000..fad60fe --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/postgresql/stdlib/query.sql @@ -0,0 +1,3 @@ +-- name: InsertFoo :exec +INSERT INTO foo (bar) +SELECT 1, $1, $2; \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_select_invalid/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/insert_select_invalid/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..be35e94 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/postgresql/stdlib/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (bar text); \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_select_invalid/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/insert_select_invalid/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..cd51867 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/insert_select_invalid/postgresql/stdlib/stderr/base.txt b/internal/endtoend/testdata/insert_select_invalid/postgresql/stdlib/stderr/base.txt new file mode 100644 index 0000000..77fedb8 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/postgresql/stdlib/stderr/base.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:1:1: INSERT has more expressions than target columns \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_select_invalid/postgresql/stdlib/stderr/managed-db.txt b/internal/endtoend/testdata/insert_select_invalid/postgresql/stdlib/stderr/managed-db.txt new file mode 100644 index 0000000..95a26a4 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/postgresql/stdlib/stderr/managed-db.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:3:11: INSERT has more expressions than target columns diff --git a/internal/endtoend/testdata/insert_select_invalid/sqlite/exec.json b/internal/endtoend/testdata/insert_select_invalid/sqlite/exec.json new file mode 100644 index 0000000..e5dfda7 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/sqlite/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/insert_select_invalid/sqlite/query.sql b/internal/endtoend/testdata/insert_select_invalid/sqlite/query.sql new file mode 100644 index 0000000..3311b32 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/sqlite/query.sql @@ -0,0 +1,3 @@ +-- name: InsertFoo :exec +INSERT INTO foo (bar) +SELECT 1, ?, ?; diff --git a/internal/endtoend/testdata/insert_select_invalid/sqlite/schema.sql b/internal/endtoend/testdata/insert_select_invalid/sqlite/schema.sql new file mode 100644 index 0000000..d849628 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/sqlite/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (bar text); diff --git a/internal/endtoend/testdata/insert_select_invalid/sqlite/sqlc.json b/internal/endtoend/testdata/insert_select_invalid/sqlite/sqlc.json new file mode 100644 index 0000000..f8e8051 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "sqlite", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_select_invalid/sqlite/stderr.txt b/internal/endtoend/testdata/insert_select_invalid/sqlite/stderr.txt new file mode 100644 index 0000000..20a7ac0 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/sqlite/stderr.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:1:1: sqlite3: SQL logic error: 3 values for 1 columns diff --git a/internal/endtoend/testdata/insert_select_param/issue.md b/internal/endtoend/testdata/insert_select_param/issue.md new file mode 100644 index 0000000..bbb421e --- /dev/null +++ b/internal/endtoend/testdata/insert_select_param/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1328 \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_select_param/postgresql/pgx/exec.json b/internal/endtoend/testdata/insert_select_param/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/insert_select_param/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/insert_select_param/postgresql/pgx/go/db.go b/internal/endtoend/testdata/insert_select_param/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/insert_select_param/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/insert_select_param/postgresql/pgx/go/models.go b/internal/endtoend/testdata/insert_select_param/postgresql/pgx/go/models.go new file mode 100644 index 0000000..4e97f66 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_param/postgresql/pgx/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Author struct { + ID int64 + Name string + Bio pgtype.Text +} diff --git a/internal/endtoend/testdata/insert_select_param/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/insert_select_param/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..eaa7421 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_param/postgresql/pgx/go/query.sql.go @@ -0,0 +1,29 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const insertSelect = `-- name: InsertSelect :exec +INSERT INTO authors (id, name, bio) +SELECT $1, name, bio +FROM authors +WHERE name = $2 +` + +type InsertSelectParams struct { + ID pgtype.Int8 + Name pgtype.Text +} + +func (q *Queries) InsertSelect(ctx context.Context, arg InsertSelectParams) error { + _, err := q.db.Exec(ctx, insertSelect, arg.ID, arg.Name) + return err +} diff --git a/internal/endtoend/testdata/insert_select_param/postgresql/pgx/query.sql b/internal/endtoend/testdata/insert_select_param/postgresql/pgx/query.sql new file mode 100644 index 0000000..ab990b0 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_param/postgresql/pgx/query.sql @@ -0,0 +1,5 @@ +-- name: InsertSelect :exec +INSERT INTO authors (id, name, bio) +SELECT @id, name, bio +FROM authors +WHERE name = @name; \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_select_param/postgresql/pgx/schema.sql b/internal/endtoend/testdata/insert_select_param/postgresql/pgx/schema.sql new file mode 100644 index 0000000..6684317 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_param/postgresql/pgx/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_select_param/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/insert_select_param/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..01489e0 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_param/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_values/mysql/go/db.go b/internal/endtoend/testdata/insert_values/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/insert_values/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/insert_values/mysql/go/models.go b/internal/endtoend/testdata/insert_values/mysql/go/models.go new file mode 100644 index 0000000..ee59bcd --- /dev/null +++ b/internal/endtoend/testdata/insert_values/mysql/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString + B sql.NullInt32 +} diff --git a/internal/endtoend/testdata/insert_values/mysql/go/query.sql.go b/internal/endtoend/testdata/insert_values/mysql/go/query.sql.go new file mode 100644 index 0000000..90f9be9 --- /dev/null +++ b/internal/endtoend/testdata/insert_values/mysql/go/query.sql.go @@ -0,0 +1,46 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const insertMultipleValues = `-- name: InsertMultipleValues :exec +INSERT INTO foo (a, b) VALUES (?, ?), (?, ?) +` + +type InsertMultipleValuesParams struct { + A sql.NullString + B sql.NullInt32 + A_2 sql.NullString + B_2 sql.NullInt32 +} + +func (q *Queries) InsertMultipleValues(ctx context.Context, arg InsertMultipleValuesParams) error { + _, err := q.db.ExecContext(ctx, insertMultipleValues, + arg.A, + arg.B, + arg.A_2, + arg.B_2, + ) + return err +} + +const insertValues = `-- name: InsertValues :exec +INSERT INTO foo (a, b) VALUES (?, ?) +` + +type InsertValuesParams struct { + A sql.NullString + B sql.NullInt32 +} + +func (q *Queries) InsertValues(ctx context.Context, arg InsertValuesParams) error { + _, err := q.db.ExecContext(ctx, insertValues, arg.A, arg.B) + return err +} diff --git a/internal/endtoend/testdata/insert_values/mysql/query.sql b/internal/endtoend/testdata/insert_values/mysql/query.sql new file mode 100644 index 0000000..774165b --- /dev/null +++ b/internal/endtoend/testdata/insert_values/mysql/query.sql @@ -0,0 +1,5 @@ +/* name: InsertValues :exec */ +INSERT INTO foo (a, b) VALUES (?, ?); + +/* name: InsertMultipleValues :exec */ +INSERT INTO foo (a, b) VALUES (?, ?), (?, ?); \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_values/mysql/schema.sql b/internal/endtoend/testdata/insert_values/mysql/schema.sql new file mode 100644 index 0000000..ca4d437 --- /dev/null +++ b/internal/endtoend/testdata/insert_values/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b integer); + diff --git a/internal/endtoend/testdata/insert_values/mysql/sqlc.json b/internal/endtoend/testdata/insert_values/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/insert_values/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/insert_values/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/insert_values/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/insert_values/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/insert_values/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/insert_values/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..ee59bcd --- /dev/null +++ b/internal/endtoend/testdata/insert_values/postgresql/pgx/v4/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString + B sql.NullInt32 +} diff --git a/internal/endtoend/testdata/insert_values/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/insert_values/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..a1db323 --- /dev/null +++ b/internal/endtoend/testdata/insert_values/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,46 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const insertMultipleValues = `-- name: InsertMultipleValues :exec +INSERT INTO foo (a, b) VALUES ($1, $2), ($3, $4) +` + +type InsertMultipleValuesParams struct { + A sql.NullString + B sql.NullInt32 + A_2 sql.NullString + B_2 sql.NullInt32 +} + +func (q *Queries) InsertMultipleValues(ctx context.Context, arg InsertMultipleValuesParams) error { + _, err := q.db.Exec(ctx, insertMultipleValues, + arg.A, + arg.B, + arg.A_2, + arg.B_2, + ) + return err +} + +const insertValues = `-- name: InsertValues :exec +INSERT INTO foo (a, b) VALUES ($1, $2) +` + +type InsertValuesParams struct { + A sql.NullString + B sql.NullInt32 +} + +func (q *Queries) InsertValues(ctx context.Context, arg InsertValuesParams) error { + _, err := q.db.Exec(ctx, insertValues, arg.A, arg.B) + return err +} diff --git a/internal/endtoend/testdata/insert_values/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/insert_values/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..0c2b0d6 --- /dev/null +++ b/internal/endtoend/testdata/insert_values/postgresql/pgx/v4/query.sql @@ -0,0 +1,5 @@ +-- name: InsertValues :exec +INSERT INTO foo (a, b) VALUES ($1, $2); + +/* name: InsertMultipleValues :exec */ +INSERT INTO foo (a, b) VALUES ($1, $2), ($3, $4); \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_values/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/insert_values/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..ca4d437 --- /dev/null +++ b/internal/endtoend/testdata/insert_values/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b integer); + diff --git a/internal/endtoend/testdata/insert_values/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/insert_values/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/insert_values/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/insert_values/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/insert_values/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/insert_values/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/insert_values/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/insert_values/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..475f43e --- /dev/null +++ b/internal/endtoend/testdata/insert_values/postgresql/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + A pgtype.Text + B pgtype.Int4 +} diff --git a/internal/endtoend/testdata/insert_values/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/insert_values/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..998054c --- /dev/null +++ b/internal/endtoend/testdata/insert_values/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,47 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const insertMultipleValues = `-- name: InsertMultipleValues :exec +INSERT INTO foo (a, b) VALUES ($1, $2), ($3, $4) +` + +type InsertMultipleValuesParams struct { + A pgtype.Text + B pgtype.Int4 + A_2 pgtype.Text + B_2 pgtype.Int4 +} + +func (q *Queries) InsertMultipleValues(ctx context.Context, arg InsertMultipleValuesParams) error { + _, err := q.db.Exec(ctx, insertMultipleValues, + arg.A, + arg.B, + arg.A_2, + arg.B_2, + ) + return err +} + +const insertValues = `-- name: InsertValues :exec +INSERT INTO foo (a, b) VALUES ($1, $2) +` + +type InsertValuesParams struct { + A pgtype.Text + B pgtype.Int4 +} + +func (q *Queries) InsertValues(ctx context.Context, arg InsertValuesParams) error { + _, err := q.db.Exec(ctx, insertValues, arg.A, arg.B) + return err +} diff --git a/internal/endtoend/testdata/insert_values/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/insert_values/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..0c2b0d6 --- /dev/null +++ b/internal/endtoend/testdata/insert_values/postgresql/pgx/v5/query.sql @@ -0,0 +1,5 @@ +-- name: InsertValues :exec +INSERT INTO foo (a, b) VALUES ($1, $2); + +/* name: InsertMultipleValues :exec */ +INSERT INTO foo (a, b) VALUES ($1, $2), ($3, $4); \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_values/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/insert_values/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..ca4d437 --- /dev/null +++ b/internal/endtoend/testdata/insert_values/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b integer); + diff --git a/internal/endtoend/testdata/insert_values/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/insert_values/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/insert_values/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/insert_values/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/insert_values/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/insert_values/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/insert_values/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/insert_values/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..ee59bcd --- /dev/null +++ b/internal/endtoend/testdata/insert_values/postgresql/stdlib/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString + B sql.NullInt32 +} diff --git a/internal/endtoend/testdata/insert_values/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/insert_values/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..aa5109e --- /dev/null +++ b/internal/endtoend/testdata/insert_values/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,46 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const insertMultipleValues = `-- name: InsertMultipleValues :exec +INSERT INTO foo (a, b) VALUES ($1, $2), ($3, $4) +` + +type InsertMultipleValuesParams struct { + A sql.NullString + B sql.NullInt32 + A_2 sql.NullString + B_2 sql.NullInt32 +} + +func (q *Queries) InsertMultipleValues(ctx context.Context, arg InsertMultipleValuesParams) error { + _, err := q.db.ExecContext(ctx, insertMultipleValues, + arg.A, + arg.B, + arg.A_2, + arg.B_2, + ) + return err +} + +const insertValues = `-- name: InsertValues :exec +INSERT INTO foo (a, b) VALUES ($1, $2) +` + +type InsertValuesParams struct { + A sql.NullString + B sql.NullInt32 +} + +func (q *Queries) InsertValues(ctx context.Context, arg InsertValuesParams) error { + _, err := q.db.ExecContext(ctx, insertValues, arg.A, arg.B) + return err +} diff --git a/internal/endtoend/testdata/insert_values/postgresql/stdlib/query.sql b/internal/endtoend/testdata/insert_values/postgresql/stdlib/query.sql new file mode 100644 index 0000000..0c2b0d6 --- /dev/null +++ b/internal/endtoend/testdata/insert_values/postgresql/stdlib/query.sql @@ -0,0 +1,5 @@ +-- name: InsertValues :exec +INSERT INTO foo (a, b) VALUES ($1, $2); + +/* name: InsertMultipleValues :exec */ +INSERT INTO foo (a, b) VALUES ($1, $2), ($3, $4); \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_values/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/insert_values/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..ca4d437 --- /dev/null +++ b/internal/endtoend/testdata/insert_values/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b integer); + diff --git a/internal/endtoend/testdata/insert_values/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/insert_values/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..cd51867 --- /dev/null +++ b/internal/endtoend/testdata/insert_values/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/insert_values/sqlite/go/db.go b/internal/endtoend/testdata/insert_values/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/insert_values/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/insert_values/sqlite/go/models.go b/internal/endtoend/testdata/insert_values/sqlite/go/models.go new file mode 100644 index 0000000..fd51ca3 --- /dev/null +++ b/internal/endtoend/testdata/insert_values/sqlite/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString + B sql.NullInt64 +} diff --git a/internal/endtoend/testdata/insert_values/sqlite/go/query.sql.go b/internal/endtoend/testdata/insert_values/sqlite/go/query.sql.go new file mode 100644 index 0000000..5bdada7 --- /dev/null +++ b/internal/endtoend/testdata/insert_values/sqlite/go/query.sql.go @@ -0,0 +1,46 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const insertMultipleValues = `-- name: InsertMultipleValues :exec +INSERT INTO foo (a, b) VALUES (?, ?), (?, ?) +` + +type InsertMultipleValuesParams struct { + A sql.NullString + B sql.NullInt64 + A_2 sql.NullString + B_2 sql.NullInt64 +} + +func (q *Queries) InsertMultipleValues(ctx context.Context, arg InsertMultipleValuesParams) error { + _, err := q.db.ExecContext(ctx, insertMultipleValues, + arg.A, + arg.B, + arg.A_2, + arg.B_2, + ) + return err +} + +const insertValues = `-- name: InsertValues :exec +INSERT INTO foo (a, b) VALUES (?, ?) +` + +type InsertValuesParams struct { + A sql.NullString + B sql.NullInt64 +} + +func (q *Queries) InsertValues(ctx context.Context, arg InsertValuesParams) error { + _, err := q.db.ExecContext(ctx, insertValues, arg.A, arg.B) + return err +} diff --git a/internal/endtoend/testdata/insert_values/sqlite/query.sql b/internal/endtoend/testdata/insert_values/sqlite/query.sql new file mode 100644 index 0000000..03f37d3 --- /dev/null +++ b/internal/endtoend/testdata/insert_values/sqlite/query.sql @@ -0,0 +1,5 @@ +/* name: InsertValues :exec */ +INSERT INTO foo (a, b) VALUES (?, ?); + +/* name: InsertMultipleValues :exec */ +INSERT INTO foo (a, b) VALUES (?, ?), (?, ?); diff --git a/internal/endtoend/testdata/insert_values/sqlite/schema.sql b/internal/endtoend/testdata/insert_values/sqlite/schema.sql new file mode 100644 index 0000000..ca4d437 --- /dev/null +++ b/internal/endtoend/testdata/insert_values/sqlite/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b integer); + diff --git a/internal/endtoend/testdata/insert_values/sqlite/sqlc.json b/internal/endtoend/testdata/insert_values/sqlite/sqlc.json new file mode 100644 index 0000000..f8e8051 --- /dev/null +++ b/internal/endtoend/testdata/insert_values/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "sqlite", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_values_only/issue.md b/internal/endtoend/testdata/insert_values_only/issue.md new file mode 100644 index 0000000..a7ea8fc --- /dev/null +++ b/internal/endtoend/testdata/insert_values_only/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/938 \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_values_only/postgresql/pgx/exec.json b/internal/endtoend/testdata/insert_values_only/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/insert_values_only/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/insert_values_only/postgresql/pgx/go/db.go b/internal/endtoend/testdata/insert_values_only/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/insert_values_only/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/insert_values_only/postgresql/pgx/go/models.go b/internal/endtoend/testdata/insert_values_only/postgresql/pgx/go/models.go new file mode 100644 index 0000000..69c245c --- /dev/null +++ b/internal/endtoend/testdata/insert_values_only/postgresql/pgx/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Status struct { + ID int32 + Name string +} diff --git a/internal/endtoend/testdata/insert_values_only/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/insert_values_only/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..ffff33d --- /dev/null +++ b/internal/endtoend/testdata/insert_values_only/postgresql/pgx/go/query.sql.go @@ -0,0 +1,26 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const insertStatus = `-- name: InsertStatus :exec +INSERT INTO status VALUES ($1, $2) +` + +type InsertStatusParams struct { + Column1 pgtype.Int4 + Column2 pgtype.Text +} + +func (q *Queries) InsertStatus(ctx context.Context, arg InsertStatusParams) error { + _, err := q.db.Exec(ctx, insertStatus, arg.Column1, arg.Column2) + return err +} diff --git a/internal/endtoend/testdata/insert_values_only/postgresql/pgx/query.sql b/internal/endtoend/testdata/insert_values_only/postgresql/pgx/query.sql new file mode 100644 index 0000000..97313e7 --- /dev/null +++ b/internal/endtoend/testdata/insert_values_only/postgresql/pgx/query.sql @@ -0,0 +1,2 @@ +-- name: InsertStatus :exec +INSERT INTO status VALUES ($1, $2); \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_values_only/postgresql/pgx/schema.sql b/internal/endtoend/testdata/insert_values_only/postgresql/pgx/schema.sql new file mode 100644 index 0000000..fc8f305 --- /dev/null +++ b/internal/endtoend/testdata/insert_values_only/postgresql/pgx/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE status +( + id integer, + name varchar(100) NOT NULL, + PRIMARY KEY(id) +); \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_values_only/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/insert_values_only/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/insert_values_only/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/insert_values_public/mysql/go/db.go b/internal/endtoend/testdata/insert_values_public/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/insert_values_public/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/insert_values_public/mysql/go/models.go b/internal/endtoend/testdata/insert_values_public/mysql/go/models.go new file mode 100644 index 0000000..ee59bcd --- /dev/null +++ b/internal/endtoend/testdata/insert_values_public/mysql/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString + B sql.NullInt32 +} diff --git a/internal/endtoend/testdata/insert_values_public/mysql/go/query.sql.go b/internal/endtoend/testdata/insert_values_public/mysql/go/query.sql.go new file mode 100644 index 0000000..1dc377d --- /dev/null +++ b/internal/endtoend/testdata/insert_values_public/mysql/go/query.sql.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const insertValues = `-- name: InsertValues :exec +INSERT INTO public.foo (a, b) VALUES (?, ?) +` + +type InsertValuesParams struct { + A sql.NullString + B sql.NullInt32 +} + +func (q *Queries) InsertValues(ctx context.Context, arg InsertValuesParams) error { + _, err := q.db.ExecContext(ctx, insertValues, arg.A, arg.B) + return err +} diff --git a/internal/endtoend/testdata/insert_values_public/mysql/query.sql b/internal/endtoend/testdata/insert_values_public/mysql/query.sql new file mode 100644 index 0000000..22caf7b --- /dev/null +++ b/internal/endtoend/testdata/insert_values_public/mysql/query.sql @@ -0,0 +1,2 @@ +/* name: InsertValues :exec */ +INSERT INTO public.foo (a, b) VALUES (?, ?); diff --git a/internal/endtoend/testdata/insert_values_public/mysql/schema.sql b/internal/endtoend/testdata/insert_values_public/mysql/schema.sql new file mode 100644 index 0000000..ca4d437 --- /dev/null +++ b/internal/endtoend/testdata/insert_values_public/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b integer); + diff --git a/internal/endtoend/testdata/insert_values_public/mysql/sqlc.json b/internal/endtoend/testdata/insert_values_public/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/insert_values_public/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/insert_values_public/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..ee59bcd --- /dev/null +++ b/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v4/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString + B sql.NullInt32 +} diff --git a/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..7146cb6 --- /dev/null +++ b/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const insertValues = `-- name: InsertValues :exec +INSERT INTO public.foo (a, b) VALUES ($1, $2) +` + +type InsertValuesParams struct { + A sql.NullString + B sql.NullInt32 +} + +func (q *Queries) InsertValues(ctx context.Context, arg InsertValuesParams) error { + _, err := q.db.Exec(ctx, insertValues, arg.A, arg.B) + return err +} diff --git a/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..9b6c822 --- /dev/null +++ b/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: InsertValues :exec +INSERT INTO public.foo (a, b) VALUES ($1, $2); diff --git a/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..ca4d437 --- /dev/null +++ b/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b integer); + diff --git a/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/insert_values_public/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..475f43e --- /dev/null +++ b/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + A pgtype.Text + B pgtype.Int4 +} diff --git a/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..73457eb --- /dev/null +++ b/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,26 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const insertValues = `-- name: InsertValues :exec +INSERT INTO public.foo (a, b) VALUES ($1, $2) +` + +type InsertValuesParams struct { + A pgtype.Text + B pgtype.Int4 +} + +func (q *Queries) InsertValues(ctx context.Context, arg InsertValuesParams) error { + _, err := q.db.Exec(ctx, insertValues, arg.A, arg.B) + return err +} diff --git a/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..9b6c822 --- /dev/null +++ b/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: InsertValues :exec +INSERT INTO public.foo (a, b) VALUES ($1, $2); diff --git a/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..ca4d437 --- /dev/null +++ b/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b integer); + diff --git a/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/insert_values_public/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/insert_values_public/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/insert_values_public/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/insert_values_public/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/insert_values_public/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/insert_values_public/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..ee59bcd --- /dev/null +++ b/internal/endtoend/testdata/insert_values_public/postgresql/stdlib/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString + B sql.NullInt32 +} diff --git a/internal/endtoend/testdata/insert_values_public/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/insert_values_public/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..b064886 --- /dev/null +++ b/internal/endtoend/testdata/insert_values_public/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const insertValues = `-- name: InsertValues :exec +INSERT INTO public.foo (a, b) VALUES ($1, $2) +` + +type InsertValuesParams struct { + A sql.NullString + B sql.NullInt32 +} + +func (q *Queries) InsertValues(ctx context.Context, arg InsertValuesParams) error { + _, err := q.db.ExecContext(ctx, insertValues, arg.A, arg.B) + return err +} diff --git a/internal/endtoend/testdata/insert_values_public/postgresql/stdlib/query.sql b/internal/endtoend/testdata/insert_values_public/postgresql/stdlib/query.sql new file mode 100644 index 0000000..9b6c822 --- /dev/null +++ b/internal/endtoend/testdata/insert_values_public/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: InsertValues :exec +INSERT INTO public.foo (a, b) VALUES ($1, $2); diff --git a/internal/endtoend/testdata/insert_values_public/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/insert_values_public/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..ca4d437 --- /dev/null +++ b/internal/endtoend/testdata/insert_values_public/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b integer); + diff --git a/internal/endtoend/testdata/insert_values_public/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/insert_values_public/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..cd51867 --- /dev/null +++ b/internal/endtoend/testdata/insert_values_public/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/interval/pgx/v4/exec.json b/internal/endtoend/testdata/interval/pgx/v4/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/interval/pgx/v4/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/interval/pgx/v4/go/db.go b/internal/endtoend/testdata/interval/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/interval/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/interval/pgx/v4/go/models.go b/internal/endtoend/testdata/interval/pgx/v4/go/models.go new file mode 100644 index 0000000..05ac897 --- /dev/null +++ b/internal/endtoend/testdata/interval/pgx/v4/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar bool + Interval int64 +} diff --git a/internal/endtoend/testdata/interval/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/interval/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..18b6e70 --- /dev/null +++ b/internal/endtoend/testdata/interval/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const get = `-- name: Get :many +SELECT bar, "interval" FROM foo LIMIT $1 +` + +func (q *Queries) Get(ctx context.Context, limit int32) ([]Foo, error) { + rows, err := q.db.Query(ctx, get, limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.Bar, &i.Interval); 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/interval/pgx/v4/query.sql b/internal/endtoend/testdata/interval/pgx/v4/query.sql new file mode 100644 index 0000000..27cd9d7 --- /dev/null +++ b/internal/endtoend/testdata/interval/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Get :many +SELECT bar, "interval" FROM foo LIMIT $1; diff --git a/internal/endtoend/testdata/interval/pgx/v4/schema.sql b/internal/endtoend/testdata/interval/pgx/v4/schema.sql new file mode 100644 index 0000000..feec037 --- /dev/null +++ b/internal/endtoend/testdata/interval/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar bool not null, "interval" interval not null); + diff --git a/internal/endtoend/testdata/interval/pgx/v4/sqlc.json b/internal/endtoend/testdata/interval/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/interval/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/interval/pgx/v5/exec.json b/internal/endtoend/testdata/interval/pgx/v5/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/interval/pgx/v5/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/interval/pgx/v5/go/db.go b/internal/endtoend/testdata/interval/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/interval/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/interval/pgx/v5/go/models.go b/internal/endtoend/testdata/interval/pgx/v5/go/models.go new file mode 100644 index 0000000..a2179e2 --- /dev/null +++ b/internal/endtoend/testdata/interval/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + Bar bool + Interval pgtype.Interval +} diff --git a/internal/endtoend/testdata/interval/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/interval/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..18b6e70 --- /dev/null +++ b/internal/endtoend/testdata/interval/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const get = `-- name: Get :many +SELECT bar, "interval" FROM foo LIMIT $1 +` + +func (q *Queries) Get(ctx context.Context, limit int32) ([]Foo, error) { + rows, err := q.db.Query(ctx, get, limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.Bar, &i.Interval); 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/interval/pgx/v5/query.sql b/internal/endtoend/testdata/interval/pgx/v5/query.sql new file mode 100644 index 0000000..27cd9d7 --- /dev/null +++ b/internal/endtoend/testdata/interval/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Get :many +SELECT bar, "interval" FROM foo LIMIT $1; diff --git a/internal/endtoend/testdata/interval/pgx/v5/schema.sql b/internal/endtoend/testdata/interval/pgx/v5/schema.sql new file mode 100644 index 0000000..feec037 --- /dev/null +++ b/internal/endtoend/testdata/interval/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar bool not null, "interval" interval not null); + diff --git a/internal/endtoend/testdata/interval/pgx/v5/sqlc.json b/internal/endtoend/testdata/interval/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/interval/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/interval/stdlib/exec.json b/internal/endtoend/testdata/interval/stdlib/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/interval/stdlib/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/interval/stdlib/go/db.go b/internal/endtoend/testdata/interval/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/interval/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/interval/stdlib/go/models.go b/internal/endtoend/testdata/interval/stdlib/go/models.go new file mode 100644 index 0000000..05ac897 --- /dev/null +++ b/internal/endtoend/testdata/interval/stdlib/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar bool + Interval int64 +} diff --git a/internal/endtoend/testdata/interval/stdlib/go/query.sql.go b/internal/endtoend/testdata/interval/stdlib/go/query.sql.go new file mode 100644 index 0000000..abdc431 --- /dev/null +++ b/internal/endtoend/testdata/interval/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const get = `-- name: Get :many +SELECT bar, "interval" FROM foo LIMIT $1 +` + +func (q *Queries) Get(ctx context.Context, limit int32) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, get, limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.Bar, &i.Interval); 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/interval/stdlib/query.sql b/internal/endtoend/testdata/interval/stdlib/query.sql new file mode 100644 index 0000000..27cd9d7 --- /dev/null +++ b/internal/endtoend/testdata/interval/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Get :many +SELECT bar, "interval" FROM foo LIMIT $1; diff --git a/internal/endtoend/testdata/interval/stdlib/schema.sql b/internal/endtoend/testdata/interval/stdlib/schema.sql new file mode 100644 index 0000000..feec037 --- /dev/null +++ b/internal/endtoend/testdata/interval/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar bool not null, "interval" interval not null); + diff --git a/internal/endtoend/testdata/interval/stdlib/sqlc.json b/internal/endtoend/testdata/interval/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/interval/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/invalid_func_args/pgx/v4/query.sql b/internal/endtoend/testdata/invalid_func_args/pgx/v4/query.sql new file mode 100644 index 0000000..e92c21d --- /dev/null +++ b/internal/endtoend/testdata/invalid_func_args/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT random(1); diff --git a/internal/endtoend/testdata/invalid_func_args/pgx/v4/schema.sql b/internal/endtoend/testdata/invalid_func_args/pgx/v4/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/invalid_func_args/pgx/v4/sqlc.json b/internal/endtoend/testdata/invalid_func_args/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/invalid_func_args/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/invalid_func_args/pgx/v4/stderr/base.txt b/internal/endtoend/testdata/invalid_func_args/pgx/v4/stderr/base.txt new file mode 100644 index 0000000..2693a08 --- /dev/null +++ b/internal/endtoend/testdata/invalid_func_args/pgx/v4/stderr/base.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:2:8: function random(unknown) does not exist diff --git a/internal/endtoend/testdata/invalid_func_args/pgx/v4/stderr/managed-db.txt b/internal/endtoend/testdata/invalid_func_args/pgx/v4/stderr/managed-db.txt new file mode 100644 index 0000000..d211139 --- /dev/null +++ b/internal/endtoend/testdata/invalid_func_args/pgx/v4/stderr/managed-db.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:2:8: function random(integer) does not exist diff --git a/internal/endtoend/testdata/invalid_func_args/pgx/v5/query.sql b/internal/endtoend/testdata/invalid_func_args/pgx/v5/query.sql new file mode 100644 index 0000000..e92c21d --- /dev/null +++ b/internal/endtoend/testdata/invalid_func_args/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT random(1); diff --git a/internal/endtoend/testdata/invalid_func_args/pgx/v5/schema.sql b/internal/endtoend/testdata/invalid_func_args/pgx/v5/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/invalid_func_args/pgx/v5/sqlc.json b/internal/endtoend/testdata/invalid_func_args/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/invalid_func_args/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/invalid_func_args/pgx/v5/stderr/base.txt b/internal/endtoend/testdata/invalid_func_args/pgx/v5/stderr/base.txt new file mode 100644 index 0000000..2693a08 --- /dev/null +++ b/internal/endtoend/testdata/invalid_func_args/pgx/v5/stderr/base.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:2:8: function random(unknown) does not exist diff --git a/internal/endtoend/testdata/invalid_func_args/pgx/v5/stderr/managed-db.txt b/internal/endtoend/testdata/invalid_func_args/pgx/v5/stderr/managed-db.txt new file mode 100644 index 0000000..d211139 --- /dev/null +++ b/internal/endtoend/testdata/invalid_func_args/pgx/v5/stderr/managed-db.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:2:8: function random(integer) does not exist diff --git a/internal/endtoend/testdata/invalid_func_args/stdlib/query.sql b/internal/endtoend/testdata/invalid_func_args/stdlib/query.sql new file mode 100644 index 0000000..e92c21d --- /dev/null +++ b/internal/endtoend/testdata/invalid_func_args/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT random(1); diff --git a/internal/endtoend/testdata/invalid_func_args/stdlib/schema.sql b/internal/endtoend/testdata/invalid_func_args/stdlib/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/invalid_func_args/stdlib/sqlc.json b/internal/endtoend/testdata/invalid_func_args/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/invalid_func_args/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/invalid_func_args/stdlib/stderr/base.txt b/internal/endtoend/testdata/invalid_func_args/stdlib/stderr/base.txt new file mode 100644 index 0000000..2693a08 --- /dev/null +++ b/internal/endtoend/testdata/invalid_func_args/stdlib/stderr/base.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:2:8: function random(unknown) does not exist diff --git a/internal/endtoend/testdata/invalid_func_args/stdlib/stderr/managed-db.txt b/internal/endtoend/testdata/invalid_func_args/stdlib/stderr/managed-db.txt new file mode 100644 index 0000000..d211139 --- /dev/null +++ b/internal/endtoend/testdata/invalid_func_args/stdlib/stderr/managed-db.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:2:8: function random(integer) does not exist diff --git a/internal/endtoend/testdata/invalid_group_by_reference/mysql/exec.json b/internal/endtoend/testdata/invalid_group_by_reference/mysql/exec.json new file mode 100644 index 0000000..0775566 --- /dev/null +++ b/internal/endtoend/testdata/invalid_group_by_reference/mysql/exec.json @@ -0,0 +1,6 @@ +{ + "meta": { + "invalid_schema": true + } +} + diff --git a/internal/endtoend/testdata/invalid_group_by_reference/mysql/query.sql b/internal/endtoend/testdata/invalid_group_by_reference/mysql/query.sql new file mode 100644 index 0000000..b036fba --- /dev/null +++ b/internal/endtoend/testdata/invalid_group_by_reference/mysql/query.sql @@ -0,0 +1,4 @@ +-- name: ListAuthors :many +SELECT * +FROM authors +GROUP BY invalid_reference; diff --git a/internal/endtoend/testdata/invalid_group_by_reference/mysql/schema.sql b/internal/endtoend/testdata/invalid_group_by_reference/mysql/schema.sql new file mode 100644 index 0000000..5333d48 --- /dev/null +++ b/internal/endtoend/testdata/invalid_group_by_reference/mysql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE authors ( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + name text NOT NULL, + bio text +); diff --git a/internal/endtoend/testdata/invalid_group_by_reference/mysql/sqlc.json b/internal/endtoend/testdata/invalid_group_by_reference/mysql/sqlc.json new file mode 100644 index 0000000..0390f67 --- /dev/null +++ b/internal/endtoend/testdata/invalid_group_by_reference/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/invalid_group_by_reference/mysql/stderr.txt b/internal/endtoend/testdata/invalid_group_by_reference/mysql/stderr.txt new file mode 100644 index 0000000..d686d4f --- /dev/null +++ b/internal/endtoend/testdata/invalid_group_by_reference/mysql/stderr.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:4:10: column reference "invalid_reference" not found diff --git a/internal/endtoend/testdata/invalid_group_by_reference/postgresql/query.sql b/internal/endtoend/testdata/invalid_group_by_reference/postgresql/query.sql new file mode 100644 index 0000000..8275f8c --- /dev/null +++ b/internal/endtoend/testdata/invalid_group_by_reference/postgresql/query.sql @@ -0,0 +1,4 @@ +-- name: ListAuthors :many +SELECT * +FROM authors +GROUP BY invalid_reference; \ No newline at end of file diff --git a/internal/endtoend/testdata/invalid_group_by_reference/postgresql/schema.sql b/internal/endtoend/testdata/invalid_group_by_reference/postgresql/schema.sql new file mode 100644 index 0000000..69b607d --- /dev/null +++ b/internal/endtoend/testdata/invalid_group_by_reference/postgresql/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/invalid_group_by_reference/postgresql/sqlc.json b/internal/endtoend/testdata/invalid_group_by_reference/postgresql/sqlc.json new file mode 100644 index 0000000..a590361 --- /dev/null +++ b/internal/endtoend/testdata/invalid_group_by_reference/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/invalid_group_by_reference/postgresql/stderr/base.txt b/internal/endtoend/testdata/invalid_group_by_reference/postgresql/stderr/base.txt new file mode 100644 index 0000000..d686d4f --- /dev/null +++ b/internal/endtoend/testdata/invalid_group_by_reference/postgresql/stderr/base.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:4:10: column reference "invalid_reference" not found diff --git a/internal/endtoend/testdata/invalid_group_by_reference/postgresql/stderr/managed-db.txt b/internal/endtoend/testdata/invalid_group_by_reference/postgresql/stderr/managed-db.txt new file mode 100644 index 0000000..d13cdba --- /dev/null +++ b/internal/endtoend/testdata/invalid_group_by_reference/postgresql/stderr/managed-db.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:4:22: column "invalid_reference" does not exist diff --git a/internal/endtoend/testdata/invalid_group_by_reference/sqlite/exec.json b/internal/endtoend/testdata/invalid_group_by_reference/sqlite/exec.json new file mode 100644 index 0000000..e5dfda7 --- /dev/null +++ b/internal/endtoend/testdata/invalid_group_by_reference/sqlite/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/invalid_group_by_reference/sqlite/query.sql b/internal/endtoend/testdata/invalid_group_by_reference/sqlite/query.sql new file mode 100644 index 0000000..2fc4c35 --- /dev/null +++ b/internal/endtoend/testdata/invalid_group_by_reference/sqlite/query.sql @@ -0,0 +1,4 @@ +-- name: ListAuthors :many +SELECT * +FROM authors +GROUP BY invalid_reference; diff --git a/internal/endtoend/testdata/invalid_group_by_reference/sqlite/schema.sql b/internal/endtoend/testdata/invalid_group_by_reference/sqlite/schema.sql new file mode 100644 index 0000000..e3ed6b0 --- /dev/null +++ b/internal/endtoend/testdata/invalid_group_by_reference/sqlite/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE authors ( + id integer NOT NULL PRIMARY KEY AUTOINCREMENT, + name text NOT NULL, + bio text, + UNIQUE(name) +); diff --git a/internal/endtoend/testdata/invalid_group_by_reference/sqlite/sqlc.json b/internal/endtoend/testdata/invalid_group_by_reference/sqlite/sqlc.json new file mode 100644 index 0000000..d4963e7 --- /dev/null +++ b/internal/endtoend/testdata/invalid_group_by_reference/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/invalid_group_by_reference/sqlite/stderr.txt b/internal/endtoend/testdata/invalid_group_by_reference/sqlite/stderr.txt new file mode 100644 index 0000000..d255c11 --- /dev/null +++ b/internal/endtoend/testdata/invalid_group_by_reference/sqlite/stderr.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:1:1: sqlite3: SQL logic error: no such column: invalid_reference diff --git a/internal/endtoend/testdata/invalid_insert_unknown_column/issue.md b/internal/endtoend/testdata/invalid_insert_unknown_column/issue.md new file mode 100644 index 0000000..70cc5f2 --- /dev/null +++ b/internal/endtoend/testdata/invalid_insert_unknown_column/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/381 diff --git a/internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/db/db.go b/internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/db/db.go new file mode 100644 index 0000000..42578b7 --- /dev/null +++ b/internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/db/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/invalid_insert_unknown_column/postgresql/pgx/db/models.go b/internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/db/models.go new file mode 100644 index 0000000..761ab0c --- /dev/null +++ b/internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/db/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Author struct { + ID int64 + Name string + Bio pgtype.Text +} diff --git a/internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/db/query.sql.go b/internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/db/query.sql.go new file mode 100644 index 0000000..81c6870 --- /dev/null +++ b/internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/db/query.sql.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const createAuthor = `-- name: CreateAuthor :one +INSERT INTO authors ( + name, bio, missing_column +) VALUES ( + $1, $2, true +) +RETURNING id, name, bio +` + +type CreateAuthorParams struct { + Name string + Bio pgtype.Text +} + +func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (Author, error) { + row := q.db.QueryRow(ctx, createAuthor, arg.Name, arg.Bio) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} diff --git a/internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/exec.json b/internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/query.sql b/internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/query.sql new file mode 100644 index 0000000..db75df3 --- /dev/null +++ b/internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/query.sql @@ -0,0 +1,7 @@ +-- name: CreateAuthor :one +INSERT INTO authors ( + name, bio, missing_column +) VALUES ( + $1, $2, true +) +RETURNING *; diff --git a/internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/schema.sql b/internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/schema.sql new file mode 100644 index 0000000..69b607d --- /dev/null +++ b/internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/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/invalid_insert_unknown_column/postgresql/pgx/sqlc.json b/internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/sqlc.json new file mode 100644 index 0000000..7b7c623 --- /dev/null +++ b/internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/sqlc.json @@ -0,0 +1,19 @@ +{ + "version": "1", + "cloud": { + "project": "01HAQMMECEYQYKFJN8MP16QC41" + }, + "packages": [ + { + "path": "db", + "engine": "postgresql", + "database": { + "managed": true + }, + "sql_package": "pgx/v5", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} + diff --git a/internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/stderr.txt b/internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/stderr.txt new file mode 100644 index 0000000..60421d5 --- /dev/null +++ b/internal/endtoend/testdata/invalid_insert_unknown_column/postgresql/pgx/stderr.txt @@ -0,0 +1,2 @@ +# package db +query.sql:3:14: column "missing_column" of relation "authors" does not exist \ No newline at end of file diff --git a/internal/endtoend/testdata/invalid_named_params/mysql/query.sql b/internal/endtoend/testdata/invalid_named_params/mysql/query.sql new file mode 100644 index 0000000..349d2c2 --- /dev/null +++ b/internal/endtoend/testdata/invalid_named_params/mysql/query.sql @@ -0,0 +1,6 @@ +-- name: ListAuthors :one +SELECT * +FROM authors +WHERE id = sqlc.arg(my_named_param) + OR bio = sqlc.arg(my_named_param) +LIMIT 1; diff --git a/internal/endtoend/testdata/invalid_named_params/mysql/schema.sql b/internal/endtoend/testdata/invalid_named_params/mysql/schema.sql new file mode 100644 index 0000000..9804a5c --- /dev/null +++ b/internal/endtoend/testdata/invalid_named_params/mysql/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE authors ( + id BIGINT PRIMARY KEY, + bio TEXT +); diff --git a/internal/endtoend/testdata/invalid_named_params/mysql/sqlc.json b/internal/endtoend/testdata/invalid_named_params/mysql/sqlc.json new file mode 100644 index 0000000..0390f67 --- /dev/null +++ b/internal/endtoend/testdata/invalid_named_params/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/invalid_named_params/mysql/stderr.txt b/internal/endtoend/testdata/invalid_named_params/mysql/stderr.txt new file mode 100644 index 0000000..9e45d80 --- /dev/null +++ b/internal/endtoend/testdata/invalid_named_params/mysql/stderr.txt @@ -0,0 +1,2 @@ +# package querytest +error generating code: named param MyNamedParam has incompatible types: sql.NullString, int64 diff --git a/internal/endtoend/testdata/invalid_params/pgx/v4/query.sql b/internal/endtoend/testdata/invalid_params/pgx/v4/query.sql new file mode 100644 index 0000000..8a798cb --- /dev/null +++ b/internal/endtoend/testdata/invalid_params/pgx/v4/query.sql @@ -0,0 +1,11 @@ +-- name: baz :one +SELECT foo FROM bar WHERE baz = $4; + +-- name: bar :one +SELECT foo FROM bar WHERE baz = $1 AND baz = $3; + +-- name: foo :one +SELECT foo FROM bar; + +-- name: Named :many +SELECT id FROM bar WHERE id = $1 AND sqlc.arg(named) = true AND id = $5; diff --git a/internal/endtoend/testdata/invalid_params/pgx/v4/schema.sql b/internal/endtoend/testdata/invalid_params/pgx/v4/schema.sql new file mode 100644 index 0000000..b7ee888 --- /dev/null +++ b/internal/endtoend/testdata/invalid_params/pgx/v4/schema.sql @@ -0,0 +1 @@ +CREATE TABLE bar (id serial not null); \ No newline at end of file diff --git a/internal/endtoend/testdata/invalid_params/pgx/v4/sqlc.json b/internal/endtoend/testdata/invalid_params/pgx/v4/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/invalid_params/pgx/v4/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/invalid_params/pgx/v4/stderr/base.txt b/internal/endtoend/testdata/invalid_params/pgx/v4/stderr/base.txt new file mode 100644 index 0000000..c74f98d --- /dev/null +++ b/internal/endtoend/testdata/invalid_params/pgx/v4/stderr/base.txt @@ -0,0 +1,5 @@ +# package querytest +query.sql:1:1: could not determine data type of parameter $1 +query.sql:5:1: could not determine data type of parameter $2 +query.sql:8:8: column "foo" does not exist +query.sql:11:1: could not determine data type of parameter $2 diff --git a/internal/endtoend/testdata/invalid_params/pgx/v4/stderr/managed-db.txt b/internal/endtoend/testdata/invalid_params/pgx/v4/stderr/managed-db.txt new file mode 100644 index 0000000..a7eff89 --- /dev/null +++ b/internal/endtoend/testdata/invalid_params/pgx/v4/stderr/managed-db.txt @@ -0,0 +1,5 @@ +# package querytest +query.sql:2:8: column "foo" does not exist +query.sql:5:8: column "foo" does not exist +query.sql:8:8: column "foo" does not exist +query.sql:8:20: could not determine data type of parameter $3 diff --git a/internal/endtoend/testdata/invalid_params/pgx/v5/query.sql b/internal/endtoend/testdata/invalid_params/pgx/v5/query.sql new file mode 100644 index 0000000..8a798cb --- /dev/null +++ b/internal/endtoend/testdata/invalid_params/pgx/v5/query.sql @@ -0,0 +1,11 @@ +-- name: baz :one +SELECT foo FROM bar WHERE baz = $4; + +-- name: bar :one +SELECT foo FROM bar WHERE baz = $1 AND baz = $3; + +-- name: foo :one +SELECT foo FROM bar; + +-- name: Named :many +SELECT id FROM bar WHERE id = $1 AND sqlc.arg(named) = true AND id = $5; diff --git a/internal/endtoend/testdata/invalid_params/pgx/v5/schema.sql b/internal/endtoend/testdata/invalid_params/pgx/v5/schema.sql new file mode 100644 index 0000000..b7ee888 --- /dev/null +++ b/internal/endtoend/testdata/invalid_params/pgx/v5/schema.sql @@ -0,0 +1 @@ +CREATE TABLE bar (id serial not null); \ No newline at end of file diff --git a/internal/endtoend/testdata/invalid_params/pgx/v5/sqlc.json b/internal/endtoend/testdata/invalid_params/pgx/v5/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/invalid_params/pgx/v5/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/invalid_params/pgx/v5/stderr/base.txt b/internal/endtoend/testdata/invalid_params/pgx/v5/stderr/base.txt new file mode 100644 index 0000000..c74f98d --- /dev/null +++ b/internal/endtoend/testdata/invalid_params/pgx/v5/stderr/base.txt @@ -0,0 +1,5 @@ +# package querytest +query.sql:1:1: could not determine data type of parameter $1 +query.sql:5:1: could not determine data type of parameter $2 +query.sql:8:8: column "foo" does not exist +query.sql:11:1: could not determine data type of parameter $2 diff --git a/internal/endtoend/testdata/invalid_params/pgx/v5/stderr/managed-db.txt b/internal/endtoend/testdata/invalid_params/pgx/v5/stderr/managed-db.txt new file mode 100644 index 0000000..a7eff89 --- /dev/null +++ b/internal/endtoend/testdata/invalid_params/pgx/v5/stderr/managed-db.txt @@ -0,0 +1,5 @@ +# package querytest +query.sql:2:8: column "foo" does not exist +query.sql:5:8: column "foo" does not exist +query.sql:8:8: column "foo" does not exist +query.sql:8:20: could not determine data type of parameter $3 diff --git a/internal/endtoend/testdata/invalid_params/stdlib/query.sql b/internal/endtoend/testdata/invalid_params/stdlib/query.sql new file mode 100644 index 0000000..8a798cb --- /dev/null +++ b/internal/endtoend/testdata/invalid_params/stdlib/query.sql @@ -0,0 +1,11 @@ +-- name: baz :one +SELECT foo FROM bar WHERE baz = $4; + +-- name: bar :one +SELECT foo FROM bar WHERE baz = $1 AND baz = $3; + +-- name: foo :one +SELECT foo FROM bar; + +-- name: Named :many +SELECT id FROM bar WHERE id = $1 AND sqlc.arg(named) = true AND id = $5; diff --git a/internal/endtoend/testdata/invalid_params/stdlib/schema.sql b/internal/endtoend/testdata/invalid_params/stdlib/schema.sql new file mode 100644 index 0000000..b7ee888 --- /dev/null +++ b/internal/endtoend/testdata/invalid_params/stdlib/schema.sql @@ -0,0 +1 @@ +CREATE TABLE bar (id serial not null); \ No newline at end of file diff --git a/internal/endtoend/testdata/invalid_params/stdlib/sqlc.json b/internal/endtoend/testdata/invalid_params/stdlib/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/invalid_params/stdlib/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/invalid_params/stdlib/stderr/base.txt b/internal/endtoend/testdata/invalid_params/stdlib/stderr/base.txt new file mode 100644 index 0000000..c74f98d --- /dev/null +++ b/internal/endtoend/testdata/invalid_params/stdlib/stderr/base.txt @@ -0,0 +1,5 @@ +# package querytest +query.sql:1:1: could not determine data type of parameter $1 +query.sql:5:1: could not determine data type of parameter $2 +query.sql:8:8: column "foo" does not exist +query.sql:11:1: could not determine data type of parameter $2 diff --git a/internal/endtoend/testdata/invalid_params/stdlib/stderr/managed-db.txt b/internal/endtoend/testdata/invalid_params/stdlib/stderr/managed-db.txt new file mode 100644 index 0000000..a7eff89 --- /dev/null +++ b/internal/endtoend/testdata/invalid_params/stdlib/stderr/managed-db.txt @@ -0,0 +1,5 @@ +# package querytest +query.sql:2:8: column "foo" does not exist +query.sql:5:8: column "foo" does not exist +query.sql:8:8: column "foo" does not exist +query.sql:8:20: could not determine data type of parameter $3 diff --git a/internal/endtoend/testdata/invalid_params_type_mismatch/issue.md b/internal/endtoend/testdata/invalid_params_type_mismatch/issue.md new file mode 100644 index 0000000..93fc672 --- /dev/null +++ b/internal/endtoend/testdata/invalid_params_type_mismatch/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/297 diff --git a/internal/endtoend/testdata/invalid_params_type_mismatch/postgresql/pgx/exec.json b/internal/endtoend/testdata/invalid_params_type_mismatch/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/invalid_params_type_mismatch/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/invalid_params_type_mismatch/postgresql/pgx/query.sql b/internal/endtoend/testdata/invalid_params_type_mismatch/postgresql/pgx/query.sql new file mode 100644 index 0000000..c00d547 --- /dev/null +++ b/internal/endtoend/testdata/invalid_params_type_mismatch/postgresql/pgx/query.sql @@ -0,0 +1,4 @@ +-- name: UpdateAuthor :exec +UPDATE authors +SET name = $1 +WHERE id = $1; diff --git a/internal/endtoend/testdata/invalid_params_type_mismatch/postgresql/pgx/schema.sql b/internal/endtoend/testdata/invalid_params_type_mismatch/postgresql/pgx/schema.sql new file mode 100644 index 0000000..e37a99f --- /dev/null +++ b/internal/endtoend/testdata/invalid_params_type_mismatch/postgresql/pgx/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name boolean NOT NULL, + bio text +); diff --git a/internal/endtoend/testdata/invalid_params_type_mismatch/postgresql/pgx/sqlc.json b/internal/endtoend/testdata/invalid_params_type_mismatch/postgresql/pgx/sqlc.json new file mode 100644 index 0000000..14bbe81 --- /dev/null +++ b/internal/endtoend/testdata/invalid_params_type_mismatch/postgresql/pgx/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "db", + "engine": "postgresql", + "sql_package": "pgx/v5", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} + diff --git a/internal/endtoend/testdata/invalid_params_type_mismatch/postgresql/pgx/stderr.txt b/internal/endtoend/testdata/invalid_params_type_mismatch/postgresql/pgx/stderr.txt new file mode 100644 index 0000000..459c2d4 --- /dev/null +++ b/internal/endtoend/testdata/invalid_params_type_mismatch/postgresql/pgx/stderr.txt @@ -0,0 +1,2 @@ +# package db +query.sql:3:12: column "name" is of type boolean but expression is of type bigint diff --git a/internal/endtoend/testdata/invalid_queries_bar/pgx/v4/query.sql b/internal/endtoend/testdata/invalid_queries_bar/pgx/v4/query.sql new file mode 100644 index 0000000..19aaf34 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_bar/pgx/v4/query.sql @@ -0,0 +1,5 @@ +-- name: InsertBarBaz :exec +INSERT INTO foo (bar, baz) VALUES ($1); + +-- name: InsertBar :exec +INSERT INTO foo (bar) VALUES ($1, $2); diff --git a/internal/endtoend/testdata/invalid_queries_bar/pgx/v4/schema.sql b/internal/endtoend/testdata/invalid_queries_bar/pgx/v4/schema.sql new file mode 100644 index 0000000..4904704 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_bar/pgx/v4/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (bar text not null, baz text not null); \ No newline at end of file diff --git a/internal/endtoend/testdata/invalid_queries_bar/pgx/v4/sqlc.json b/internal/endtoend/testdata/invalid_queries_bar/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_bar/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/invalid_queries_bar/pgx/v4/stderr/base.txt b/internal/endtoend/testdata/invalid_queries_bar/pgx/v4/stderr/base.txt new file mode 100644 index 0000000..1e06800 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_bar/pgx/v4/stderr/base.txt @@ -0,0 +1,3 @@ +# package querytest +query.sql:1:1: INSERT has more target columns than expressions +query.sql:5:1: INSERT has more expressions than target columns diff --git a/internal/endtoend/testdata/invalid_queries_bar/pgx/v4/stderr/managed-db.txt b/internal/endtoend/testdata/invalid_queries_bar/pgx/v4/stderr/managed-db.txt new file mode 100644 index 0000000..143dcf6 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_bar/pgx/v4/stderr/managed-db.txt @@ -0,0 +1,3 @@ +# package querytest +query.sql:2:23: INSERT has more target columns than expressions +query.sql:5:35: INSERT has more expressions than target columns diff --git a/internal/endtoend/testdata/invalid_queries_bar/pgx/v5/query.sql b/internal/endtoend/testdata/invalid_queries_bar/pgx/v5/query.sql new file mode 100644 index 0000000..ef02b5e --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_bar/pgx/v5/query.sql @@ -0,0 +1,5 @@ +-- name: InsertBarBaz :exec +INSERT INTO foo (bar, baz) VALUES ($1); + +-- name: InsertBar :exec +INSERT INTO foo (bar) VALUES ($1, $2); \ No newline at end of file diff --git a/internal/endtoend/testdata/invalid_queries_bar/pgx/v5/schema.sql b/internal/endtoend/testdata/invalid_queries_bar/pgx/v5/schema.sql new file mode 100644 index 0000000..4904704 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_bar/pgx/v5/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (bar text not null, baz text not null); \ No newline at end of file diff --git a/internal/endtoend/testdata/invalid_queries_bar/pgx/v5/sqlc.json b/internal/endtoend/testdata/invalid_queries_bar/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_bar/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/invalid_queries_bar/pgx/v5/stderr/base.txt b/internal/endtoend/testdata/invalid_queries_bar/pgx/v5/stderr/base.txt new file mode 100644 index 0000000..1e06800 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_bar/pgx/v5/stderr/base.txt @@ -0,0 +1,3 @@ +# package querytest +query.sql:1:1: INSERT has more target columns than expressions +query.sql:5:1: INSERT has more expressions than target columns diff --git a/internal/endtoend/testdata/invalid_queries_bar/pgx/v5/stderr/managed-db.txt b/internal/endtoend/testdata/invalid_queries_bar/pgx/v5/stderr/managed-db.txt new file mode 100644 index 0000000..143dcf6 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_bar/pgx/v5/stderr/managed-db.txt @@ -0,0 +1,3 @@ +# package querytest +query.sql:2:23: INSERT has more target columns than expressions +query.sql:5:35: INSERT has more expressions than target columns diff --git a/internal/endtoend/testdata/invalid_queries_bar/stdlib/query.sql b/internal/endtoend/testdata/invalid_queries_bar/stdlib/query.sql new file mode 100644 index 0000000..ef02b5e --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_bar/stdlib/query.sql @@ -0,0 +1,5 @@ +-- name: InsertBarBaz :exec +INSERT INTO foo (bar, baz) VALUES ($1); + +-- name: InsertBar :exec +INSERT INTO foo (bar) VALUES ($1, $2); \ No newline at end of file diff --git a/internal/endtoend/testdata/invalid_queries_bar/stdlib/schema.sql b/internal/endtoend/testdata/invalid_queries_bar/stdlib/schema.sql new file mode 100644 index 0000000..4904704 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_bar/stdlib/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (bar text not null, baz text not null); \ No newline at end of file diff --git a/internal/endtoend/testdata/invalid_queries_bar/stdlib/sqlc.json b/internal/endtoend/testdata/invalid_queries_bar/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_bar/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/invalid_queries_bar/stdlib/stderr/base.txt b/internal/endtoend/testdata/invalid_queries_bar/stdlib/stderr/base.txt new file mode 100644 index 0000000..1e06800 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_bar/stdlib/stderr/base.txt @@ -0,0 +1,3 @@ +# package querytest +query.sql:1:1: INSERT has more target columns than expressions +query.sql:5:1: INSERT has more expressions than target columns diff --git a/internal/endtoend/testdata/invalid_queries_bar/stdlib/stderr/managed-db.txt b/internal/endtoend/testdata/invalid_queries_bar/stdlib/stderr/managed-db.txt new file mode 100644 index 0000000..143dcf6 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_bar/stdlib/stderr/managed-db.txt @@ -0,0 +1,3 @@ +# package querytest +query.sql:2:23: INSERT has more target columns than expressions +query.sql:5:35: INSERT has more expressions than target columns diff --git a/internal/endtoend/testdata/invalid_queries_foo/pgx/v4/query.sql b/internal/endtoend/testdata/invalid_queries_foo/pgx/v4/query.sql new file mode 100644 index 0000000..06644a2 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_foo/pgx/v4/query.sql @@ -0,0 +1,20 @@ +-- name: ListFoos +SELECT id FROM foo; + +-- name: ListFoos :one :many +SELECT id FROM foo; + +-- name: ListFoos :two +SELECT id FROM foo; + +-- name: DeleteFoo :one +DELETE FROM foo WHERE id = $1; + +-- name: UpdateFoo :one +UPDATE foo SET id = $2 WHERE id = $1; + +-- name: InsertFoo :one +INSERT INTO foo (id) VALUES ($1); + +-- name: InsertFoo :batchone +INSERT INTO foo (id) VALUES ($1); diff --git a/internal/endtoend/testdata/invalid_queries_foo/pgx/v4/schema.sql b/internal/endtoend/testdata/invalid_queries_foo/pgx/v4/schema.sql new file mode 100644 index 0000000..de83510 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_foo/pgx/v4/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (id text not null); \ No newline at end of file diff --git a/internal/endtoend/testdata/invalid_queries_foo/pgx/v4/sqlc.json b/internal/endtoend/testdata/invalid_queries_foo/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_foo/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/invalid_queries_foo/pgx/v4/stderr.txt b/internal/endtoend/testdata/invalid_queries_foo/pgx/v4/stderr.txt new file mode 100644 index 0000000..8c745b7 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_foo/pgx/v4/stderr.txt @@ -0,0 +1,8 @@ +# package querytest +query.sql:1:1: missing query type [':one', ':many', ':exec', ':execrows', ':execlastid', ':execresult', ':copyfrom', 'batchexec', 'batchmany', 'batchone']: -- name: ListFoos +query.sql:5:1: invalid query comment: -- name: ListFoos :one :many +query.sql:8:1: invalid query type: :two +query.sql:11:1: query "DeleteFoo" specifies parameter ":one" without containing a RETURNING clause +query.sql:14:1: query "UpdateFoo" specifies parameter ":one" without containing a RETURNING clause +query.sql:17:1: query "InsertFoo" specifies parameter ":one" without containing a RETURNING clause +query.sql:20:1: query "InsertFoo" specifies parameter ":batchone" without containing a RETURNING clause diff --git a/internal/endtoend/testdata/invalid_queries_foo/pgx/v5/query.sql b/internal/endtoend/testdata/invalid_queries_foo/pgx/v5/query.sql new file mode 100644 index 0000000..06644a2 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_foo/pgx/v5/query.sql @@ -0,0 +1,20 @@ +-- name: ListFoos +SELECT id FROM foo; + +-- name: ListFoos :one :many +SELECT id FROM foo; + +-- name: ListFoos :two +SELECT id FROM foo; + +-- name: DeleteFoo :one +DELETE FROM foo WHERE id = $1; + +-- name: UpdateFoo :one +UPDATE foo SET id = $2 WHERE id = $1; + +-- name: InsertFoo :one +INSERT INTO foo (id) VALUES ($1); + +-- name: InsertFoo :batchone +INSERT INTO foo (id) VALUES ($1); diff --git a/internal/endtoend/testdata/invalid_queries_foo/pgx/v5/schema.sql b/internal/endtoend/testdata/invalid_queries_foo/pgx/v5/schema.sql new file mode 100644 index 0000000..de83510 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_foo/pgx/v5/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (id text not null); \ No newline at end of file diff --git a/internal/endtoend/testdata/invalid_queries_foo/pgx/v5/sqlc.json b/internal/endtoend/testdata/invalid_queries_foo/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_foo/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/invalid_queries_foo/pgx/v5/stderr.txt b/internal/endtoend/testdata/invalid_queries_foo/pgx/v5/stderr.txt new file mode 100644 index 0000000..8c745b7 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_foo/pgx/v5/stderr.txt @@ -0,0 +1,8 @@ +# package querytest +query.sql:1:1: missing query type [':one', ':many', ':exec', ':execrows', ':execlastid', ':execresult', ':copyfrom', 'batchexec', 'batchmany', 'batchone']: -- name: ListFoos +query.sql:5:1: invalid query comment: -- name: ListFoos :one :many +query.sql:8:1: invalid query type: :two +query.sql:11:1: query "DeleteFoo" specifies parameter ":one" without containing a RETURNING clause +query.sql:14:1: query "UpdateFoo" specifies parameter ":one" without containing a RETURNING clause +query.sql:17:1: query "InsertFoo" specifies parameter ":one" without containing a RETURNING clause +query.sql:20:1: query "InsertFoo" specifies parameter ":batchone" without containing a RETURNING clause diff --git a/internal/endtoend/testdata/invalid_queries_foo/stdlib/query.sql b/internal/endtoend/testdata/invalid_queries_foo/stdlib/query.sql new file mode 100644 index 0000000..0e98fb6 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_foo/stdlib/query.sql @@ -0,0 +1,17 @@ +-- name: ListFoos +SELECT id FROM foo; + +-- name: ListFoos :one :many +SELECT id FROM foo; + +-- name: ListFoos :two +SELECT id FROM foo; + +-- name: DeleteFoo :one +DELETE FROM foo WHERE id = $1; + +-- name: UpdateFoo :one +UPDATE foo SET id = $2 WHERE id = $1; + +-- name: InsertFoo :one +INSERT INTO foo (id) VALUES ($1); diff --git a/internal/endtoend/testdata/invalid_queries_foo/stdlib/schema.sql b/internal/endtoend/testdata/invalid_queries_foo/stdlib/schema.sql new file mode 100644 index 0000000..de83510 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_foo/stdlib/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (id text not null); \ No newline at end of file diff --git a/internal/endtoend/testdata/invalid_queries_foo/stdlib/sqlc.json b/internal/endtoend/testdata/invalid_queries_foo/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_foo/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/invalid_queries_foo/stdlib/stderr.txt b/internal/endtoend/testdata/invalid_queries_foo/stdlib/stderr.txt new file mode 100644 index 0000000..06ec543 --- /dev/null +++ b/internal/endtoend/testdata/invalid_queries_foo/stdlib/stderr.txt @@ -0,0 +1,7 @@ +# package querytest +query.sql:1:1: missing query type [':one', ':many', ':exec', ':execrows', ':execlastid', ':execresult', ':copyfrom', 'batchexec', 'batchmany', 'batchone']: -- name: ListFoos +query.sql:5:1: invalid query comment: -- name: ListFoos :one :many +query.sql:8:1: invalid query type: :two +query.sql:11:1: query "DeleteFoo" specifies parameter ":one" without containing a RETURNING clause +query.sql:14:1: query "UpdateFoo" specifies parameter ":one" without containing a RETURNING clause +query.sql:17:1: query "InsertFoo" specifies parameter ":one" without containing a RETURNING clause \ No newline at end of file diff --git a/internal/endtoend/testdata/invalid_table_alias/mysql/query.sql b/internal/endtoend/testdata/invalid_table_alias/mysql/query.sql new file mode 100644 index 0000000..52f5aae --- /dev/null +++ b/internal/endtoend/testdata/invalid_table_alias/mysql/query.sql @@ -0,0 +1,5 @@ +-- name: GetAuthor :one +SELECT * +FROM authors a +WHERE p.id = ? +LIMIT 1; diff --git a/internal/endtoend/testdata/invalid_table_alias/mysql/schema.sql b/internal/endtoend/testdata/invalid_table_alias/mysql/schema.sql new file mode 100644 index 0000000..ee27f30 --- /dev/null +++ b/internal/endtoend/testdata/invalid_table_alias/mysql/schema.sql @@ -0,0 +1,7 @@ +-- https://github.com/sqlc-dev/sqlc/issues/437 +CREATE TABLE authors ( + id INT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + bio text +); + diff --git a/internal/endtoend/testdata/invalid_table_alias/mysql/sqlc.json b/internal/endtoend/testdata/invalid_table_alias/mysql/sqlc.json new file mode 100644 index 0000000..0390f67 --- /dev/null +++ b/internal/endtoend/testdata/invalid_table_alias/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/invalid_table_alias/mysql/stderr.txt b/internal/endtoend/testdata/invalid_table_alias/mysql/stderr.txt new file mode 100644 index 0000000..1eddeaa --- /dev/null +++ b/internal/endtoend/testdata/invalid_table_alias/mysql/stderr.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:4:9: table alias "p" does not exist diff --git a/internal/endtoend/testdata/invalid_table_alias/postgresql/exec.json b/internal/endtoend/testdata/invalid_table_alias/postgresql/exec.json new file mode 100644 index 0000000..9f208fb --- /dev/null +++ b/internal/endtoend/testdata/invalid_table_alias/postgresql/exec.json @@ -0,0 +1,3 @@ +{ + "os": ["darwin", "linux"] +} diff --git a/internal/endtoend/testdata/invalid_table_alias/postgresql/query.sql b/internal/endtoend/testdata/invalid_table_alias/postgresql/query.sql new file mode 100644 index 0000000..f09a94b --- /dev/null +++ b/internal/endtoend/testdata/invalid_table_alias/postgresql/query.sql @@ -0,0 +1,5 @@ +-- name: GetAuthor :one +SELECT * +FROM authors a +WHERE p.id = $1 +LIMIT 1; diff --git a/internal/endtoend/testdata/invalid_table_alias/postgresql/schema.sql b/internal/endtoend/testdata/invalid_table_alias/postgresql/schema.sql new file mode 100644 index 0000000..9c4b796 --- /dev/null +++ b/internal/endtoend/testdata/invalid_table_alias/postgresql/schema.sql @@ -0,0 +1,6 @@ +-- https://github.com/sqlc-dev/sqlc/issues/437 +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); \ No newline at end of file diff --git a/internal/endtoend/testdata/invalid_table_alias/postgresql/sqlc.json b/internal/endtoend/testdata/invalid_table_alias/postgresql/sqlc.json new file mode 100644 index 0000000..a590361 --- /dev/null +++ b/internal/endtoend/testdata/invalid_table_alias/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/invalid_table_alias/postgresql/stderr/base.txt b/internal/endtoend/testdata/invalid_table_alias/postgresql/stderr/base.txt new file mode 100644 index 0000000..1eddeaa --- /dev/null +++ b/internal/endtoend/testdata/invalid_table_alias/postgresql/stderr/base.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:4:9: table alias "p" does not exist diff --git a/internal/endtoend/testdata/invalid_table_alias/postgresql/stderr/managed-db.txt b/internal/endtoend/testdata/invalid_table_alias/postgresql/stderr/managed-db.txt new file mode 100644 index 0000000..2de34ae --- /dev/null +++ b/internal/endtoend/testdata/invalid_table_alias/postgresql/stderr/managed-db.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:5:3: missing FROM-clause entry for table "p" diff --git a/internal/endtoend/testdata/invalid_table_alias/sqlite/exec.json b/internal/endtoend/testdata/invalid_table_alias/sqlite/exec.json new file mode 100644 index 0000000..e5dfda7 --- /dev/null +++ b/internal/endtoend/testdata/invalid_table_alias/sqlite/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/invalid_table_alias/sqlite/query.sql b/internal/endtoend/testdata/invalid_table_alias/sqlite/query.sql new file mode 100644 index 0000000..658a966 --- /dev/null +++ b/internal/endtoend/testdata/invalid_table_alias/sqlite/query.sql @@ -0,0 +1,5 @@ +-- name: GetAuthor :one +SELECT * +FROM authors AS a +WHERE p.id = ? +LIMIT 1; diff --git a/internal/endtoend/testdata/invalid_table_alias/sqlite/schema.sql b/internal/endtoend/testdata/invalid_table_alias/sqlite/schema.sql new file mode 100644 index 0000000..fe5a44f --- /dev/null +++ b/internal/endtoend/testdata/invalid_table_alias/sqlite/schema.sql @@ -0,0 +1,6 @@ +-- https://github.com/sqlc-dev/sqlc/issues/437 +CREATE TABLE authors ( + id INTEGER PRIMARY KEY, + name VARCHAR(255) NOT NULL, + bio text +); diff --git a/internal/endtoend/testdata/invalid_table_alias/sqlite/sqlc.json b/internal/endtoend/testdata/invalid_table_alias/sqlite/sqlc.json new file mode 100644 index 0000000..d4963e7 --- /dev/null +++ b/internal/endtoend/testdata/invalid_table_alias/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/invalid_table_alias/sqlite/stderr.txt b/internal/endtoend/testdata/invalid_table_alias/sqlite/stderr.txt new file mode 100644 index 0000000..97e4385 --- /dev/null +++ b/internal/endtoend/testdata/invalid_table_alias/sqlite/stderr.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:1:1: sqlite3: SQL logic error: no such column: p.id diff --git a/internal/endtoend/testdata/invalid_update_unknown_column/issue.md b/internal/endtoend/testdata/invalid_update_unknown_column/issue.md new file mode 100644 index 0000000..822c605 --- /dev/null +++ b/internal/endtoend/testdata/invalid_update_unknown_column/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/884 \ No newline at end of file diff --git a/internal/endtoend/testdata/invalid_update_unknown_column/postgresql/pgx/exec.json b/internal/endtoend/testdata/invalid_update_unknown_column/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/invalid_update_unknown_column/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/invalid_update_unknown_column/postgresql/pgx/query.sql b/internal/endtoend/testdata/invalid_update_unknown_column/postgresql/pgx/query.sql new file mode 100644 index 0000000..59d42df --- /dev/null +++ b/internal/endtoend/testdata/invalid_update_unknown_column/postgresql/pgx/query.sql @@ -0,0 +1,7 @@ +-- name: UpdateArticles :exec +UPDATE + public.articles +SET + is_deleted = TRUE +WHERE + id = $1; \ No newline at end of file diff --git a/internal/endtoend/testdata/invalid_update_unknown_column/postgresql/pgx/schema.sql b/internal/endtoend/testdata/invalid_update_unknown_column/postgresql/pgx/schema.sql new file mode 100644 index 0000000..6f94b60 --- /dev/null +++ b/internal/endtoend/testdata/invalid_update_unknown_column/postgresql/pgx/schema.sql @@ -0,0 +1,10 @@ +CREATE TABLE public.articles ( + id integer NOT NULL, + company integer NOT NULL, + name text NOT NULL, + sort_order integer DEFAULT 0 NOT NULL, + object_type smallint NOT NULL, + image text, + "group" integer, + notes text DEFAULT ''::text NOT NULL +); \ No newline at end of file diff --git a/internal/endtoend/testdata/invalid_update_unknown_column/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/invalid_update_unknown_column/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..01489e0 --- /dev/null +++ b/internal/endtoend/testdata/invalid_update_unknown_column/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" \ No newline at end of file diff --git a/internal/endtoend/testdata/invalid_update_unknown_column/postgresql/pgx/stderr.txt b/internal/endtoend/testdata/invalid_update_unknown_column/postgresql/pgx/stderr.txt new file mode 100644 index 0000000..8260c8f --- /dev/null +++ b/internal/endtoend/testdata/invalid_update_unknown_column/postgresql/pgx/stderr.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:5:2: column "is_deleted" of relation "articles" does not exist \ No newline at end of file diff --git a/internal/endtoend/testdata/join_alias/mysql/go/db.go b/internal/endtoend/testdata/join_alias/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_alias/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_alias/mysql/go/models.go b/internal/endtoend/testdata/join_alias/mysql/go/models.go new file mode 100644 index 0000000..33aa0f7 --- /dev/null +++ b/internal/endtoend/testdata/join_alias/mysql/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ID uint64 + Title sql.NullString +} + +type Foo struct { + ID uint64 +} diff --git a/internal/endtoend/testdata/join_alias/mysql/go/query.sql.go b/internal/endtoend/testdata/join_alias/mysql/go/query.sql.go new file mode 100644 index 0000000..ecfe147 --- /dev/null +++ b/internal/endtoend/testdata/join_alias/mysql/go/query.sql.go @@ -0,0 +1,82 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const aliasExpand = `-- name: AliasExpand :many +SELECT f.id, b.id, title +FROM foo f +JOIN bar b ON b.id = f.id +WHERE f.id = ? +` + +type AliasExpandRow struct { + ID uint64 + ID_2 uint64 + Title sql.NullString +} + +func (q *Queries) AliasExpand(ctx context.Context, id uint64) ([]AliasExpandRow, error) { + rows, err := q.db.QueryContext(ctx, aliasExpand, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AliasExpandRow + for rows.Next() { + var i AliasExpandRow + if err := rows.Scan(&i.ID, &i.ID_2, &i.Title); 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 aliasJoin = `-- name: AliasJoin :many +SELECT f.id, b.title +FROM foo f +JOIN bar b ON b.id = f.id +WHERE f.id = ? +` + +type AliasJoinRow struct { + ID uint64 + Title sql.NullString +} + +func (q *Queries) AliasJoin(ctx context.Context, id uint64) ([]AliasJoinRow, error) { + rows, err := q.db.QueryContext(ctx, aliasJoin, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AliasJoinRow + for rows.Next() { + var i AliasJoinRow + if err := rows.Scan(&i.ID, &i.Title); 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/join_alias/mysql/query.sql b/internal/endtoend/testdata/join_alias/mysql/query.sql new file mode 100644 index 0000000..9b087bc --- /dev/null +++ b/internal/endtoend/testdata/join_alias/mysql/query.sql @@ -0,0 +1,11 @@ +-- name: AliasJoin :many +SELECT f.id, b.title +FROM foo f +JOIN bar b ON b.id = f.id +WHERE f.id = ?; + +-- name: AliasExpand :many +SELECT * +FROM foo f +JOIN bar b ON b.id = f.id +WHERE f.id = ?; diff --git a/internal/endtoend/testdata/join_alias/mysql/schema.sql b/internal/endtoend/testdata/join_alias/mysql/schema.sql new file mode 100644 index 0000000..1eab1cf --- /dev/null +++ b/internal/endtoend/testdata/join_alias/mysql/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (id serial not null); +CREATE TABLE bar (id serial not null references foo(id), title text); + diff --git a/internal/endtoend/testdata/join_alias/mysql/sqlc.json b/internal/endtoend/testdata/join_alias/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/join_alias/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/join_alias/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/join_alias/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/join_alias/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/join_alias/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/join_alias/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..28c016a --- /dev/null +++ b/internal/endtoend/testdata/join_alias/postgresql/pgx/v4/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ID int32 + Title sql.NullString +} + +type Foo struct { + ID int32 +} diff --git a/internal/endtoend/testdata/join_alias/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/join_alias/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8dc5d8f --- /dev/null +++ b/internal/endtoend/testdata/join_alias/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,76 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const aliasExpand = `-- name: AliasExpand :many +SELECT f.id, b.id, title +FROM foo f +JOIN bar b ON b.id = f.id +WHERE f.id = $1 +` + +type AliasExpandRow struct { + ID int32 + ID_2 int32 + Title sql.NullString +} + +func (q *Queries) AliasExpand(ctx context.Context, id int32) ([]AliasExpandRow, error) { + rows, err := q.db.Query(ctx, aliasExpand, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AliasExpandRow + for rows.Next() { + var i AliasExpandRow + if err := rows.Scan(&i.ID, &i.ID_2, &i.Title); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const aliasJoin = `-- name: AliasJoin :many +SELECT f.id, b.title +FROM foo f +JOIN bar b ON b.id = f.id +WHERE f.id = $1 +` + +type AliasJoinRow struct { + ID int32 + Title sql.NullString +} + +func (q *Queries) AliasJoin(ctx context.Context, id int32) ([]AliasJoinRow, error) { + rows, err := q.db.Query(ctx, aliasJoin, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AliasJoinRow + for rows.Next() { + var i AliasJoinRow + if err := rows.Scan(&i.ID, &i.Title); 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/join_alias/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/join_alias/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..23f3825 --- /dev/null +++ b/internal/endtoend/testdata/join_alias/postgresql/pgx/v4/query.sql @@ -0,0 +1,11 @@ +-- name: AliasJoin :many +SELECT f.id, b.title +FROM foo f +JOIN bar b ON b.id = f.id +WHERE f.id = $1; + +-- name: AliasExpand :many +SELECT * +FROM foo f +JOIN bar b ON b.id = f.id +WHERE f.id = $1; diff --git a/internal/endtoend/testdata/join_alias/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/join_alias/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..d2fdc30 --- /dev/null +++ b/internal/endtoend/testdata/join_alias/postgresql/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (id serial not null unique); +CREATE TABLE bar (id serial not null references foo(id), title text); + diff --git a/internal/endtoend/testdata/join_alias/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/join_alias/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/join_alias/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/join_alias/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/join_alias/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/join_alias/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/join_alias/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/join_alias/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..c275626 --- /dev/null +++ b/internal/endtoend/testdata/join_alias/postgresql/pgx/v5/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Bar struct { + ID int32 + Title pgtype.Text +} + +type Foo struct { + ID int32 +} diff --git a/internal/endtoend/testdata/join_alias/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/join_alias/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..59c0c8a --- /dev/null +++ b/internal/endtoend/testdata/join_alias/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,77 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const aliasExpand = `-- name: AliasExpand :many +SELECT f.id, b.id, title +FROM foo f +JOIN bar b ON b.id = f.id +WHERE f.id = $1 +` + +type AliasExpandRow struct { + ID int32 + ID_2 int32 + Title pgtype.Text +} + +func (q *Queries) AliasExpand(ctx context.Context, id int32) ([]AliasExpandRow, error) { + rows, err := q.db.Query(ctx, aliasExpand, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AliasExpandRow + for rows.Next() { + var i AliasExpandRow + if err := rows.Scan(&i.ID, &i.ID_2, &i.Title); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const aliasJoin = `-- name: AliasJoin :many +SELECT f.id, b.title +FROM foo f +JOIN bar b ON b.id = f.id +WHERE f.id = $1 +` + +type AliasJoinRow struct { + ID int32 + Title pgtype.Text +} + +func (q *Queries) AliasJoin(ctx context.Context, id int32) ([]AliasJoinRow, error) { + rows, err := q.db.Query(ctx, aliasJoin, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AliasJoinRow + for rows.Next() { + var i AliasJoinRow + if err := rows.Scan(&i.ID, &i.Title); 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/join_alias/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/join_alias/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..23f3825 --- /dev/null +++ b/internal/endtoend/testdata/join_alias/postgresql/pgx/v5/query.sql @@ -0,0 +1,11 @@ +-- name: AliasJoin :many +SELECT f.id, b.title +FROM foo f +JOIN bar b ON b.id = f.id +WHERE f.id = $1; + +-- name: AliasExpand :many +SELECT * +FROM foo f +JOIN bar b ON b.id = f.id +WHERE f.id = $1; diff --git a/internal/endtoend/testdata/join_alias/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/join_alias/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..d2fdc30 --- /dev/null +++ b/internal/endtoend/testdata/join_alias/postgresql/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (id serial not null unique); +CREATE TABLE bar (id serial not null references foo(id), title text); + diff --git a/internal/endtoend/testdata/join_alias/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/join_alias/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/join_alias/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/join_alias/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/join_alias/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_alias/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_alias/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/join_alias/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..28c016a --- /dev/null +++ b/internal/endtoend/testdata/join_alias/postgresql/stdlib/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ID int32 + Title sql.NullString +} + +type Foo struct { + ID int32 +} diff --git a/internal/endtoend/testdata/join_alias/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/join_alias/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..ae1350d --- /dev/null +++ b/internal/endtoend/testdata/join_alias/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,82 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const aliasExpand = `-- name: AliasExpand :many +SELECT f.id, b.id, title +FROM foo f +JOIN bar b ON b.id = f.id +WHERE f.id = $1 +` + +type AliasExpandRow struct { + ID int32 + ID_2 int32 + Title sql.NullString +} + +func (q *Queries) AliasExpand(ctx context.Context, id int32) ([]AliasExpandRow, error) { + rows, err := q.db.QueryContext(ctx, aliasExpand, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AliasExpandRow + for rows.Next() { + var i AliasExpandRow + if err := rows.Scan(&i.ID, &i.ID_2, &i.Title); 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 aliasJoin = `-- name: AliasJoin :many +SELECT f.id, b.title +FROM foo f +JOIN bar b ON b.id = f.id +WHERE f.id = $1 +` + +type AliasJoinRow struct { + ID int32 + Title sql.NullString +} + +func (q *Queries) AliasJoin(ctx context.Context, id int32) ([]AliasJoinRow, error) { + rows, err := q.db.QueryContext(ctx, aliasJoin, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AliasJoinRow + for rows.Next() { + var i AliasJoinRow + if err := rows.Scan(&i.ID, &i.Title); 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/join_alias/postgresql/stdlib/query.sql b/internal/endtoend/testdata/join_alias/postgresql/stdlib/query.sql new file mode 100644 index 0000000..23f3825 --- /dev/null +++ b/internal/endtoend/testdata/join_alias/postgresql/stdlib/query.sql @@ -0,0 +1,11 @@ +-- name: AliasJoin :many +SELECT f.id, b.title +FROM foo f +JOIN bar b ON b.id = f.id +WHERE f.id = $1; + +-- name: AliasExpand :many +SELECT * +FROM foo f +JOIN bar b ON b.id = f.id +WHERE f.id = $1; diff --git a/internal/endtoend/testdata/join_alias/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/join_alias/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..d2fdc30 --- /dev/null +++ b/internal/endtoend/testdata/join_alias/postgresql/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (id serial not null unique); +CREATE TABLE bar (id serial not null references foo(id), title text); + diff --git a/internal/endtoend/testdata/join_alias/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/join_alias/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/join_alias/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/join_alias/sqlite/go/db.go b/internal/endtoend/testdata/join_alias/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_alias/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_alias/sqlite/go/models.go b/internal/endtoend/testdata/join_alias/sqlite/go/models.go new file mode 100644 index 0000000..0eafe6d --- /dev/null +++ b/internal/endtoend/testdata/join_alias/sqlite/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ID int64 + Title sql.NullString +} + +type Foo struct { + ID int64 +} diff --git a/internal/endtoend/testdata/join_alias/sqlite/go/query.sql.go b/internal/endtoend/testdata/join_alias/sqlite/go/query.sql.go new file mode 100644 index 0000000..c7ef880 --- /dev/null +++ b/internal/endtoend/testdata/join_alias/sqlite/go/query.sql.go @@ -0,0 +1,82 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const aliasExpand = `-- name: AliasExpand :many +SELECT f.id, b.id, title +FROM foo AS f +JOIN bar AS b ON b.id = f.id +WHERE f.id = ? +` + +type AliasExpandRow struct { + ID int64 + ID_2 int64 + Title sql.NullString +} + +func (q *Queries) AliasExpand(ctx context.Context, id int64) ([]AliasExpandRow, error) { + rows, err := q.db.QueryContext(ctx, aliasExpand, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AliasExpandRow + for rows.Next() { + var i AliasExpandRow + if err := rows.Scan(&i.ID, &i.ID_2, &i.Title); 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 aliasJoin = `-- name: AliasJoin :many +SELECT f.id, b.title +FROM foo AS f +JOIN bar AS b ON b.id = f.id +WHERE f.id = ? +` + +type AliasJoinRow struct { + ID int64 + Title sql.NullString +} + +func (q *Queries) AliasJoin(ctx context.Context, id int64) ([]AliasJoinRow, error) { + rows, err := q.db.QueryContext(ctx, aliasJoin, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AliasJoinRow + for rows.Next() { + var i AliasJoinRow + if err := rows.Scan(&i.ID, &i.Title); 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/join_alias/sqlite/query.sql b/internal/endtoend/testdata/join_alias/sqlite/query.sql new file mode 100644 index 0000000..cfb69f0 --- /dev/null +++ b/internal/endtoend/testdata/join_alias/sqlite/query.sql @@ -0,0 +1,11 @@ +-- name: AliasJoin :many +SELECT f.id, b.title +FROM foo AS f +JOIN bar AS b ON b.id = f.id +WHERE f.id = ?; + +-- name: AliasExpand :many +SELECT * +FROM foo AS f +JOIN bar AS b ON b.id = f.id +WHERE f.id = ?; diff --git a/internal/endtoend/testdata/join_alias/sqlite/schema.sql b/internal/endtoend/testdata/join_alias/sqlite/schema.sql new file mode 100644 index 0000000..b622f98 --- /dev/null +++ b/internal/endtoend/testdata/join_alias/sqlite/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (id integer not null); +CREATE TABLE bar (id integer not null references foo(id), title text); + diff --git a/internal/endtoend/testdata/join_alias/sqlite/sqlc.json b/internal/endtoend/testdata/join_alias/sqlite/sqlc.json new file mode 100644 index 0000000..d4963e7 --- /dev/null +++ b/internal/endtoend/testdata/join_alias/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/join_clauses_order/postgresql/go/db.go b/internal/endtoend/testdata/join_clauses_order/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_clauses_order/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_clauses_order/postgresql/go/models.go b/internal/endtoend/testdata/join_clauses_order/postgresql/go/models.go new file mode 100644 index 0000000..1797128 --- /dev/null +++ b/internal/endtoend/testdata/join_clauses_order/postgresql/go/models.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type A struct { + ID int64 + A string +} + +type B struct { + ID int64 + B string + AID int64 +} + +type C struct { + ID int64 + C string + AID int64 +} + +type D struct { + ID int64 + D string + AID int64 +} + +type E struct { + ID int64 + E string + AID int64 +} diff --git a/internal/endtoend/testdata/join_clauses_order/postgresql/go/query.sql.go b/internal/endtoend/testdata/join_clauses_order/postgresql/go/query.sql.go new file mode 100644 index 0000000..e617a64 --- /dev/null +++ b/internal/endtoend/testdata/join_clauses_order/postgresql/go/query.sql.go @@ -0,0 +1,175 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const testInnerLeft = `-- name: TestInnerLeft :many +SELECT a.a, b.b, c.c +FROM a +INNER JOIN b ON b.a_id = a.id +LEFT JOIN c ON c.a_id = a.id +` + +type TestInnerLeftRow struct { + A string + B string + C sql.NullString +} + +func (q *Queries) TestInnerLeft(ctx context.Context) ([]TestInnerLeftRow, error) { + rows, err := q.db.QueryContext(ctx, testInnerLeft) + if err != nil { + return nil, err + } + defer rows.Close() + var items []TestInnerLeftRow + for rows.Next() { + var i TestInnerLeftRow + if err := rows.Scan(&i.A, &i.B, &i.C); 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 testInnerLeftInnerLeft = `-- name: TestInnerLeftInnerLeft :many +SELECT a.a, b.b, c.c, d.d, e.e +FROM a +INNER JOIN b ON b.a_id = a.id +LEFT JOIN c ON c.a_id = a.id +INNER JOIN d ON d.a_id = a.id +LEFT JOIN e ON e.a_id = a.id +` + +type TestInnerLeftInnerLeftRow struct { + A string + B string + C sql.NullString + D string + E sql.NullString +} + +func (q *Queries) TestInnerLeftInnerLeft(ctx context.Context) ([]TestInnerLeftInnerLeftRow, error) { + rows, err := q.db.QueryContext(ctx, testInnerLeftInnerLeft) + if err != nil { + return nil, err + } + defer rows.Close() + var items []TestInnerLeftInnerLeftRow + for rows.Next() { + var i TestInnerLeftInnerLeftRow + if err := rows.Scan( + &i.A, + &i.B, + &i.C, + &i.D, + &i.E, + ); 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 testLeftInner = `-- name: TestLeftInner :many +SELECT a.a, b.b, c.c +FROM a +LEFT JOIN b ON b.a_id = a.id +INNER JOIN c ON c.a_id = a.id +` + +type TestLeftInnerRow struct { + A string + B sql.NullString + C string +} + +func (q *Queries) TestLeftInner(ctx context.Context) ([]TestLeftInnerRow, error) { + rows, err := q.db.QueryContext(ctx, testLeftInner) + if err != nil { + return nil, err + } + defer rows.Close() + var items []TestLeftInnerRow + for rows.Next() { + var i TestLeftInnerRow + if err := rows.Scan(&i.A, &i.B, &i.C); 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 testLeftInnerLeftInner = `-- name: TestLeftInnerLeftInner :many +SELECT a.a, b.b, c.c, d.d, e.e +FROM a +LEFT JOIN b ON b.a_id = a.id +INNER JOIN c ON c.a_id = a.id +LEFT JOIN d ON d.a_id = a.id +INNER JOIN e ON e.a_id = a.id +` + +type TestLeftInnerLeftInnerRow struct { + A string + B sql.NullString + C string + D sql.NullString + E string +} + +func (q *Queries) TestLeftInnerLeftInner(ctx context.Context) ([]TestLeftInnerLeftInnerRow, error) { + rows, err := q.db.QueryContext(ctx, testLeftInnerLeftInner) + if err != nil { + return nil, err + } + defer rows.Close() + var items []TestLeftInnerLeftInnerRow + for rows.Next() { + var i TestLeftInnerLeftInnerRow + if err := rows.Scan( + &i.A, + &i.B, + &i.C, + &i.D, + &i.E, + ); 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/join_clauses_order/postgresql/query.sql b/internal/endtoend/testdata/join_clauses_order/postgresql/query.sql new file mode 100644 index 0000000..3980181 --- /dev/null +++ b/internal/endtoend/testdata/join_clauses_order/postgresql/query.sql @@ -0,0 +1,27 @@ +-- name: TestLeftInner :many +SELECT a.a, b.b, c.c +FROM a +LEFT JOIN b ON b.a_id = a.id +INNER JOIN c ON c.a_id = a.id; + +-- name: TestInnerLeft :many +SELECT a.a, b.b, c.c +FROM a +INNER JOIN b ON b.a_id = a.id +LEFT JOIN c ON c.a_id = a.id; + +-- name: TestLeftInnerLeftInner :many +SELECT a.a, b.b, c.c, d.d, e.e +FROM a +LEFT JOIN b ON b.a_id = a.id +INNER JOIN c ON c.a_id = a.id +LEFT JOIN d ON d.a_id = a.id +INNER JOIN e ON e.a_id = a.id; + +-- name: TestInnerLeftInnerLeft :many +SELECT a.a, b.b, c.c, d.d, e.e +FROM a +INNER JOIN b ON b.a_id = a.id +LEFT JOIN c ON c.a_id = a.id +INNER JOIN d ON d.a_id = a.id +LEFT JOIN e ON e.a_id = a.id; diff --git a/internal/endtoend/testdata/join_clauses_order/postgresql/schema.sql b/internal/endtoend/testdata/join_clauses_order/postgresql/schema.sql new file mode 100644 index 0000000..890f94f --- /dev/null +++ b/internal/endtoend/testdata/join_clauses_order/postgresql/schema.sql @@ -0,0 +1,29 @@ +CREATE TABLE a ( + id BIGSERIAL PRIMARY KEY, + a TEXT NOT NULL +); + +CREATE TABLE b ( + id BIGSERIAL PRIMARY KEY, + b TEXT NOT NULL, + a_id BIGINT NOT NULL REFERENCES a (id) +); + +CREATE TABLE c ( + id BIGSERIAL PRIMARY KEY, + c TEXT NOT NULL, + a_id BIGINT NOT NULL REFERENCES a (id) +); + +CREATE TABLE d ( + id BIGSERIAL PRIMARY KEY, + d TEXT NOT NULL, + a_id BIGINT NOT NULL REFERENCES a (id) +); + +CREATE TABLE e ( + id BIGSERIAL PRIMARY KEY, + e TEXT NOT NULL, + a_id BIGINT NOT NULL REFERENCES a (id) +); + diff --git a/internal/endtoend/testdata/join_clauses_order/postgresql/sqlc.json b/internal/endtoend/testdata/join_clauses_order/postgresql/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/join_clauses_order/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/join_from/mysql/go/db.go b/internal/endtoend/testdata/join_from/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_from/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_from/mysql/go/models.go b/internal/endtoend/testdata/join_from/mysql/go/models.go new file mode 100644 index 0000000..26f421e --- /dev/null +++ b/internal/endtoend/testdata/join_from/mysql/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + Login string +} + +type Foo struct { + Email string +} diff --git a/internal/endtoend/testdata/join_from/mysql/go/query.sql.go b/internal/endtoend/testdata/join_from/mysql/go/query.sql.go new file mode 100644 index 0000000..8c391e6 --- /dev/null +++ b/internal/endtoend/testdata/join_from/mysql/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const multiFrom = `-- name: MultiFrom :many +SELECT email FROM bar, foo WHERE login = ? +` + +func (q *Queries) MultiFrom(ctx context.Context, login string) ([]string, error) { + rows, err := q.db.QueryContext(ctx, multiFrom, login) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var email string + if err := rows.Scan(&email); err != nil { + return nil, err + } + items = append(items, email) + } + 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/join_from/mysql/query.sql b/internal/endtoend/testdata/join_from/mysql/query.sql new file mode 100644 index 0000000..377aeae --- /dev/null +++ b/internal/endtoend/testdata/join_from/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: MultiFrom :many +SELECT email FROM bar, foo WHERE login = ?; diff --git a/internal/endtoend/testdata/join_from/mysql/schema.sql b/internal/endtoend/testdata/join_from/mysql/schema.sql new file mode 100644 index 0000000..c1c6f48 --- /dev/null +++ b/internal/endtoend/testdata/join_from/mysql/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (email text not null); +CREATE TABLE bar (login text not null); + diff --git a/internal/endtoend/testdata/join_from/mysql/sqlc.json b/internal/endtoend/testdata/join_from/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/join_from/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/join_from/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/join_from/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/join_from/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/join_from/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/join_from/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..26f421e --- /dev/null +++ b/internal/endtoend/testdata/join_from/postgresql/pgx/v4/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + Login string +} + +type Foo struct { + Email string +} diff --git a/internal/endtoend/testdata/join_from/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/join_from/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..ec85e0a --- /dev/null +++ b/internal/endtoend/testdata/join_from/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const multiFrom = `-- name: MultiFrom :many +SELECT email FROM bar, foo WHERE login = $1 +` + +func (q *Queries) MultiFrom(ctx context.Context, login string) ([]string, error) { + rows, err := q.db.Query(ctx, multiFrom, login) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var email string + if err := rows.Scan(&email); err != nil { + return nil, err + } + items = append(items, email) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/join_from/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/join_from/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..c4eec21 --- /dev/null +++ b/internal/endtoend/testdata/join_from/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: MultiFrom :many +SELECT email FROM bar, foo WHERE login = $1; diff --git a/internal/endtoend/testdata/join_from/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/join_from/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..c1c6f48 --- /dev/null +++ b/internal/endtoend/testdata/join_from/postgresql/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (email text not null); +CREATE TABLE bar (login text not null); + diff --git a/internal/endtoend/testdata/join_from/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/join_from/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/join_from/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/join_from/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/join_from/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/join_from/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/join_from/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/join_from/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..26f421e --- /dev/null +++ b/internal/endtoend/testdata/join_from/postgresql/pgx/v5/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + Login string +} + +type Foo struct { + Email string +} diff --git a/internal/endtoend/testdata/join_from/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/join_from/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..ec85e0a --- /dev/null +++ b/internal/endtoend/testdata/join_from/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const multiFrom = `-- name: MultiFrom :many +SELECT email FROM bar, foo WHERE login = $1 +` + +func (q *Queries) MultiFrom(ctx context.Context, login string) ([]string, error) { + rows, err := q.db.Query(ctx, multiFrom, login) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var email string + if err := rows.Scan(&email); err != nil { + return nil, err + } + items = append(items, email) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/join_from/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/join_from/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..c4eec21 --- /dev/null +++ b/internal/endtoend/testdata/join_from/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: MultiFrom :many +SELECT email FROM bar, foo WHERE login = $1; diff --git a/internal/endtoend/testdata/join_from/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/join_from/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..c1c6f48 --- /dev/null +++ b/internal/endtoend/testdata/join_from/postgresql/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (email text not null); +CREATE TABLE bar (login text not null); + diff --git a/internal/endtoend/testdata/join_from/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/join_from/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/join_from/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/join_from/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/join_from/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_from/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_from/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/join_from/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..26f421e --- /dev/null +++ b/internal/endtoend/testdata/join_from/postgresql/stdlib/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + Login string +} + +type Foo struct { + Email string +} diff --git a/internal/endtoend/testdata/join_from/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/join_from/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..9a69c14 --- /dev/null +++ b/internal/endtoend/testdata/join_from/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const multiFrom = `-- name: MultiFrom :many +SELECT email FROM bar, foo WHERE login = $1 +` + +func (q *Queries) MultiFrom(ctx context.Context, login string) ([]string, error) { + rows, err := q.db.QueryContext(ctx, multiFrom, login) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var email string + if err := rows.Scan(&email); err != nil { + return nil, err + } + items = append(items, email) + } + 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/join_from/postgresql/stdlib/query.sql b/internal/endtoend/testdata/join_from/postgresql/stdlib/query.sql new file mode 100644 index 0000000..c4eec21 --- /dev/null +++ b/internal/endtoend/testdata/join_from/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: MultiFrom :many +SELECT email FROM bar, foo WHERE login = $1; diff --git a/internal/endtoend/testdata/join_from/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/join_from/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..c1c6f48 --- /dev/null +++ b/internal/endtoend/testdata/join_from/postgresql/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (email text not null); +CREATE TABLE bar (login text not null); + diff --git a/internal/endtoend/testdata/join_from/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/join_from/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/join_from/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/join_from/sqlite/go/db.go b/internal/endtoend/testdata/join_from/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_from/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_from/sqlite/go/models.go b/internal/endtoend/testdata/join_from/sqlite/go/models.go new file mode 100644 index 0000000..26f421e --- /dev/null +++ b/internal/endtoend/testdata/join_from/sqlite/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + Login string +} + +type Foo struct { + Email string +} diff --git a/internal/endtoend/testdata/join_from/sqlite/go/query.sql.go b/internal/endtoend/testdata/join_from/sqlite/go/query.sql.go new file mode 100644 index 0000000..8c391e6 --- /dev/null +++ b/internal/endtoend/testdata/join_from/sqlite/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const multiFrom = `-- name: MultiFrom :many +SELECT email FROM bar, foo WHERE login = ? +` + +func (q *Queries) MultiFrom(ctx context.Context, login string) ([]string, error) { + rows, err := q.db.QueryContext(ctx, multiFrom, login) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var email string + if err := rows.Scan(&email); err != nil { + return nil, err + } + items = append(items, email) + } + 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/join_from/sqlite/query.sql b/internal/endtoend/testdata/join_from/sqlite/query.sql new file mode 100644 index 0000000..377aeae --- /dev/null +++ b/internal/endtoend/testdata/join_from/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: MultiFrom :many +SELECT email FROM bar, foo WHERE login = ?; diff --git a/internal/endtoend/testdata/join_from/sqlite/schema.sql b/internal/endtoend/testdata/join_from/sqlite/schema.sql new file mode 100644 index 0000000..c1c6f48 --- /dev/null +++ b/internal/endtoend/testdata/join_from/sqlite/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (email text not null); +CREATE TABLE bar (login text not null); + diff --git a/internal/endtoend/testdata/join_from/sqlite/sqlc.json b/internal/endtoend/testdata/join_from/sqlite/sqlc.json new file mode 100644 index 0000000..d4963e7 --- /dev/null +++ b/internal/endtoend/testdata/join_from/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/join_full/postgresql/go/db.go b/internal/endtoend/testdata/join_full/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_full/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_full/postgresql/go/models.go b/internal/endtoend/testdata/join_full/postgresql/go/models.go new file mode 100644 index 0000000..6878c1d --- /dev/null +++ b/internal/endtoend/testdata/join_full/postgresql/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ID int32 +} + +type Foo struct { + ID int32 + BarID sql.NullInt32 +} diff --git a/internal/endtoend/testdata/join_full/postgresql/go/query.sql.go b/internal/endtoend/testdata/join_full/postgresql/go/query.sql.go new file mode 100644 index 0000000..9e631ea --- /dev/null +++ b/internal/endtoend/testdata/join_full/postgresql/go/query.sql.go @@ -0,0 +1,47 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const fullJoin = `-- name: FullJoin :many +SELECT f.id, f.bar_id, b.id +FROM foo f +FULL OUTER JOIN bar b ON b.id = f.bar_id +WHERE f.id = $1 +` + +type FullJoinRow struct { + ID sql.NullInt32 + BarID sql.NullInt32 + ID_2 sql.NullInt32 +} + +func (q *Queries) FullJoin(ctx context.Context, id int32) ([]FullJoinRow, error) { + rows, err := q.db.QueryContext(ctx, fullJoin, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []FullJoinRow + for rows.Next() { + var i FullJoinRow + if err := rows.Scan(&i.ID, &i.BarID, &i.ID_2); 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/join_full/postgresql/query.sql b/internal/endtoend/testdata/join_full/postgresql/query.sql new file mode 100644 index 0000000..d5ddf2b --- /dev/null +++ b/internal/endtoend/testdata/join_full/postgresql/query.sql @@ -0,0 +1,5 @@ +-- name: FullJoin :many +SELECT f.id, f.bar_id, b.id +FROM foo f +FULL OUTER JOIN bar b ON b.id = f.bar_id +WHERE f.id = $1; diff --git a/internal/endtoend/testdata/join_full/postgresql/schema.sql b/internal/endtoend/testdata/join_full/postgresql/schema.sql new file mode 100644 index 0000000..c7d2a76 --- /dev/null +++ b/internal/endtoend/testdata/join_full/postgresql/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE bar (id serial not null unique); +CREATE TABLE foo (id serial not null, bar_id int references bar(id)); + diff --git a/internal/endtoend/testdata/join_full/postgresql/sqlc.json b/internal/endtoend/testdata/join_full/postgresql/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/join_full/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/join_group_by_alias/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/join_group_by_alias/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_group_by_alias/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_group_by_alias/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/join_group_by_alias/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..fa99fe4 --- /dev/null +++ b/internal/endtoend/testdata/join_group_by_alias/postgresql/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Email string +} diff --git a/internal/endtoend/testdata/join_group_by_alias/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/join_group_by_alias/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..c9d164f --- /dev/null +++ b/internal/endtoend/testdata/join_group_by_alias/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,39 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const columnAsGroupBy = `-- name: ColumnAsGroupBy :many +SELECT a.email AS id +FROM foo a JOIN foo b ON a.email = b.email +GROUP BY id +` + +func (q *Queries) ColumnAsGroupBy(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, columnAsGroupBy) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 +} diff --git a/internal/endtoend/testdata/join_group_by_alias/postgresql/stdlib/query.sql b/internal/endtoend/testdata/join_group_by_alias/postgresql/stdlib/query.sql new file mode 100644 index 0000000..3d04553 --- /dev/null +++ b/internal/endtoend/testdata/join_group_by_alias/postgresql/stdlib/query.sql @@ -0,0 +1,4 @@ +-- name: ColumnAsGroupBy :many +SELECT a.email AS id +FROM foo a JOIN foo b ON a.email = b.email +GROUP BY id; diff --git a/internal/endtoend/testdata/join_group_by_alias/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/join_group_by_alias/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..da8ec19 --- /dev/null +++ b/internal/endtoend/testdata/join_group_by_alias/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (email text not null); + diff --git a/internal/endtoend/testdata/join_group_by_alias/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/join_group_by_alias/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..cd51867 --- /dev/null +++ b/internal/endtoend/testdata/join_group_by_alias/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/join_inner/postgresql/go/db.go b/internal/endtoend/testdata/join_inner/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_inner/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_inner/postgresql/go/models.go b/internal/endtoend/testdata/join_inner/postgresql/go/models.go new file mode 100644 index 0000000..4ad815c --- /dev/null +++ b/internal/endtoend/testdata/join_inner/postgresql/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Event struct { + ID sql.NullInt32 +} + +type HandledEvent struct { + LastHandledID sql.NullInt32 + Handler sql.NullString +} diff --git a/internal/endtoend/testdata/join_inner/postgresql/go/query.sql.go b/internal/endtoend/testdata/join_inner/postgresql/go/query.sql.go new file mode 100644 index 0000000..6730533 --- /dev/null +++ b/internal/endtoend/testdata/join_inner/postgresql/go/query.sql.go @@ -0,0 +1,73 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const selectAllJoined = `-- name: SelectAllJoined :many +select events.id from events + inner join handled_events + on events.ID > handled_events.last_handled_id +where handled_events.handler = $1 + for update of handled_events skip locked +` + +func (q *Queries) SelectAllJoined(ctx context.Context, handler sql.NullString) ([]sql.NullInt32, error) { + rows, err := q.db.QueryContext(ctx, selectAllJoined, handler) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullInt32 + for rows.Next() { + var id sql.NullInt32 + 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 selectAllJoinedAlias = `-- name: SelectAllJoinedAlias :many +select e.id from events e + inner join handled_events he + on e.ID > he.last_handled_id +where he.handler = $1 + for update of he skip locked +` + +func (q *Queries) SelectAllJoinedAlias(ctx context.Context, handler sql.NullString) ([]sql.NullInt32, error) { + rows, err := q.db.QueryContext(ctx, selectAllJoinedAlias, handler) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullInt32 + for rows.Next() { + var id sql.NullInt32 + 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 +} diff --git a/internal/endtoend/testdata/join_inner/postgresql/query.sql b/internal/endtoend/testdata/join_inner/postgresql/query.sql new file mode 100644 index 0000000..dbea737 --- /dev/null +++ b/internal/endtoend/testdata/join_inner/postgresql/query.sql @@ -0,0 +1,13 @@ +-- name: SelectAllJoinedAlias :many +select e.* from events e + inner join handled_events he + on e.ID > he.last_handled_id +where he.handler = $1 + for update of he skip locked; + +-- name: SelectAllJoined :many +select events.* from events + inner join handled_events + on events.ID > handled_events.last_handled_id +where handled_events.handler = $1 + for update of handled_events skip locked; diff --git a/internal/endtoend/testdata/join_inner/postgresql/schema.sql b/internal/endtoend/testdata/join_inner/postgresql/schema.sql new file mode 100644 index 0000000..5283e3a --- /dev/null +++ b/internal/endtoend/testdata/join_inner/postgresql/schema.sql @@ -0,0 +1,12 @@ +create table events +( + ID int +); + +create table handled_events +( + last_handled_id int, + handler text +); + + diff --git a/internal/endtoend/testdata/join_inner/postgresql/sqlc.json b/internal/endtoend/testdata/join_inner/postgresql/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/join_inner/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/join_left/mysql/go/db.go b/internal/endtoend/testdata/join_left/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_left/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_left/mysql/go/models.go b/internal/endtoend/testdata/join_left/mysql/go/models.go new file mode 100644 index 0000000..473543e --- /dev/null +++ b/internal/endtoend/testdata/join_left/mysql/go/models.go @@ -0,0 +1,60 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + "time" +) + +type Author struct { + ID int32 + Name string + ParentID sql.NullInt32 +} + +type City struct { + CityID int32 + MayorID int32 +} + +type Mayor struct { + MayorID int32 + FullName string +} + +type Medium struct { + MediaID int32 + MediaCreatedAt time.Time + MediaHash string + MediaDirectory string + MediaAuthorID int32 + MediaWidth int32 + MediaHeight int32 +} + +type SuperAuthor struct { + SuperID int32 + SuperName string + SuperParentID sql.NullInt32 +} + +type User struct { + UserID int32 + CityID sql.NullInt32 +} + +type Users2 struct { + UserID int32 + UserNickname string + UserEmail string + UserDisplayName string + UserPassword sql.NullString + UserGoogleID sql.NullString + UserAppleID sql.NullString + UserBio string + UserCreatedAt time.Time + UserAvatarID sql.NullInt32 +} diff --git a/internal/endtoend/testdata/join_left/mysql/go/query.sql.go b/internal/endtoend/testdata/join_left/mysql/go/query.sql.go new file mode 100644 index 0000000..8bf5532 --- /dev/null +++ b/internal/endtoend/testdata/join_left/mysql/go/query.sql.go @@ -0,0 +1,433 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" + "time" +) + +const allAuthors = `-- name: AllAuthors :many +SELECT a.id, a.name, a.parent_id, p.id, p.name, p.parent_id +FROM authors a + LEFT JOIN authors p + ON a.parent_id = p.id +` + +type AllAuthorsRow struct { + ID int32 + Name string + ParentID sql.NullInt32 + ID_2 sql.NullInt32 + Name_2 sql.NullString + ParentID_2 sql.NullInt32 +} + +func (q *Queries) AllAuthors(ctx context.Context) ([]AllAuthorsRow, error) { + rows, err := q.db.QueryContext(ctx, allAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllAuthorsRow + for rows.Next() { + var i AllAuthorsRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ParentID, + &i.ID_2, + &i.Name_2, + &i.ParentID_2, + ); 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 allAuthorsAliases = `-- name: AllAuthorsAliases :many +SELECT a.id, a.name, a.parent_id, p.id, p.name, p.parent_id +FROM authors a + LEFT JOIN authors p + ON a.parent_id = p.id +` + +type AllAuthorsAliasesRow struct { + ID int32 + Name string + ParentID sql.NullInt32 + ID_2 sql.NullInt32 + Name_2 sql.NullString + ParentID_2 sql.NullInt32 +} + +func (q *Queries) AllAuthorsAliases(ctx context.Context) ([]AllAuthorsAliasesRow, error) { + rows, err := q.db.QueryContext(ctx, allAuthorsAliases) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllAuthorsAliasesRow + for rows.Next() { + var i AllAuthorsAliasesRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ParentID, + &i.ID_2, + &i.Name_2, + &i.ParentID_2, + ); 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 allAuthorsAliases2 = `-- name: AllAuthorsAliases2 :many +SELECT a.id, a.name, a.parent_id, p.id, p.name, p.parent_id +FROM authors a + LEFT JOIN authors p + ON a.parent_id = p.id +` + +type AllAuthorsAliases2Row struct { + ID int32 + Name string + ParentID sql.NullInt32 + ID_2 sql.NullInt32 + Name_2 sql.NullString + ParentID_2 sql.NullInt32 +} + +func (q *Queries) AllAuthorsAliases2(ctx context.Context) ([]AllAuthorsAliases2Row, error) { + rows, err := q.db.QueryContext(ctx, allAuthorsAliases2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllAuthorsAliases2Row + for rows.Next() { + var i AllAuthorsAliases2Row + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ParentID, + &i.ID_2, + &i.Name_2, + &i.ParentID_2, + ); 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 allSuperAuthors = `-- name: AllSuperAuthors :many +SELECT id, name, parent_id, super_id, super_name, super_parent_id +FROM authors + LEFT JOIN super_authors + ON authors.parent_id = super_authors.super_id +` + +type AllSuperAuthorsRow struct { + ID int32 + Name string + ParentID sql.NullInt32 + SuperID sql.NullInt32 + SuperName sql.NullString + SuperParentID sql.NullInt32 +} + +func (q *Queries) AllSuperAuthors(ctx context.Context) ([]AllSuperAuthorsRow, error) { + rows, err := q.db.QueryContext(ctx, allSuperAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllSuperAuthorsRow + for rows.Next() { + var i AllSuperAuthorsRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ParentID, + &i.SuperID, + &i.SuperName, + &i.SuperParentID, + ); 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 allSuperAuthorsAliases = `-- name: AllSuperAuthorsAliases :many +SELECT id, name, parent_id, super_id, super_name, super_parent_id +FROM authors a + LEFT JOIN super_authors sa + ON a.parent_id = sa.super_id +` + +type AllSuperAuthorsAliasesRow struct { + ID int32 + Name string + ParentID sql.NullInt32 + SuperID sql.NullInt32 + SuperName sql.NullString + SuperParentID sql.NullInt32 +} + +func (q *Queries) AllSuperAuthorsAliases(ctx context.Context) ([]AllSuperAuthorsAliasesRow, error) { + rows, err := q.db.QueryContext(ctx, allSuperAuthorsAliases) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllSuperAuthorsAliasesRow + for rows.Next() { + var i AllSuperAuthorsAliasesRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ParentID, + &i.SuperID, + &i.SuperName, + &i.SuperParentID, + ); 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 allSuperAuthorsAliases2 = `-- name: AllSuperAuthorsAliases2 :many +SELECT a.id, a.name, a.parent_id, sa.super_id, sa.super_name, sa.super_parent_id +FROM authors a + LEFT JOIN super_authors sa + ON a.parent_id = sa.super_id +` + +type AllSuperAuthorsAliases2Row struct { + ID int32 + Name string + ParentID sql.NullInt32 + SuperID sql.NullInt32 + SuperName sql.NullString + SuperParentID sql.NullInt32 +} + +func (q *Queries) AllSuperAuthorsAliases2(ctx context.Context) ([]AllSuperAuthorsAliases2Row, error) { + rows, err := q.db.QueryContext(ctx, allSuperAuthorsAliases2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllSuperAuthorsAliases2Row + for rows.Next() { + var i AllSuperAuthorsAliases2Row + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ParentID, + &i.SuperID, + &i.SuperName, + &i.SuperParentID, + ); 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 getMayors = `-- name: GetMayors :many +SELECT + user_id, + mayors.full_name +FROM users +LEFT JOIN cities USING (city_id) +INNER JOIN mayors USING (mayor_id) +` + +type GetMayorsRow struct { + UserID int32 + FullName string +} + +func (q *Queries) GetMayors(ctx context.Context) ([]GetMayorsRow, error) { + rows, err := q.db.QueryContext(ctx, getMayors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetMayorsRow + for rows.Next() { + var i GetMayorsRow + if err := rows.Scan(&i.UserID, &i.FullName); 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 getMayorsOptional = `-- name: GetMayorsOptional :many +SELECT + user_id, + cities.city_id, + mayors.full_name +FROM users +LEFT JOIN cities USING (city_id) +LEFT JOIN mayors USING (mayor_id) +` + +type GetMayorsOptionalRow struct { + UserID int32 + CityID sql.NullInt32 + FullName sql.NullString +} + +func (q *Queries) GetMayorsOptional(ctx context.Context) ([]GetMayorsOptionalRow, error) { + rows, err := q.db.QueryContext(ctx, getMayorsOptional) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetMayorsOptionalRow + for rows.Next() { + var i GetMayorsOptionalRow + if err := rows.Scan(&i.UserID, &i.CityID, &i.FullName); 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 getSuggestedUsersByID = `-- name: GetSuggestedUsersByID :many +SELECT DISTINCT u.user_id, u.user_nickname, u.user_email, u.user_display_name, u.user_password, u.user_google_id, u.user_apple_id, u.user_bio, u.user_created_at, u.user_avatar_id, m.media_id, m.media_created_at, m.media_hash, m.media_directory, m.media_author_id, m.media_width, m.media_height +FROM users_2 u + LEFT JOIN media m + ON u.user_avatar_id = m.media_id +WHERE u.user_id != @user_id +` + +type GetSuggestedUsersByIDRow struct { + UserID int32 + UserNickname string + UserEmail string + UserDisplayName string + UserPassword sql.NullString + UserGoogleID sql.NullString + UserAppleID sql.NullString + UserBio string + UserCreatedAt time.Time + UserAvatarID sql.NullInt32 + MediaID sql.NullInt32 + MediaCreatedAt sql.NullTime + MediaHash sql.NullString + MediaDirectory sql.NullString + MediaAuthorID sql.NullInt32 + MediaWidth sql.NullInt32 + MediaHeight sql.NullInt32 +} + +func (q *Queries) GetSuggestedUsersByID(ctx context.Context) ([]GetSuggestedUsersByIDRow, error) { + rows, err := q.db.QueryContext(ctx, getSuggestedUsersByID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetSuggestedUsersByIDRow + for rows.Next() { + var i GetSuggestedUsersByIDRow + if err := rows.Scan( + &i.UserID, + &i.UserNickname, + &i.UserEmail, + &i.UserDisplayName, + &i.UserPassword, + &i.UserGoogleID, + &i.UserAppleID, + &i.UserBio, + &i.UserCreatedAt, + &i.UserAvatarID, + &i.MediaID, + &i.MediaCreatedAt, + &i.MediaHash, + &i.MediaDirectory, + &i.MediaAuthorID, + &i.MediaWidth, + &i.MediaHeight, + ); 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/join_left/mysql/query.sql b/internal/endtoend/testdata/join_left/mysql/query.sql new file mode 100644 index 0000000..ff96bb9 --- /dev/null +++ b/internal/endtoend/testdata/join_left/mysql/query.sql @@ -0,0 +1,59 @@ +-- name: GetMayors :many +SELECT + user_id, + mayors.full_name +FROM users +LEFT JOIN cities USING (city_id) +INNER JOIN mayors USING (mayor_id); + +-- name: GetMayorsOptional :many +SELECT + user_id, + cities.city_id, + mayors.full_name +FROM users +LEFT JOIN cities USING (city_id) +LEFT JOIN mayors USING (mayor_id); + +-- name: AllAuthors :many +SELECT * +FROM authors a + LEFT JOIN authors p + ON a.parent_id = p.id; + +-- name: AllAuthorsAliases :many +SELECT * +FROM authors a + LEFT JOIN authors p + ON a.parent_id = p.id; + +-- name: AllAuthorsAliases2 :many +SELECT a.*, p.* +FROM authors a + LEFT JOIN authors p + ON a.parent_id = p.id; + +-- name: AllSuperAuthors :many +SELECT * +FROM authors + LEFT JOIN super_authors + ON authors.parent_id = super_authors.super_id; + +-- name: AllSuperAuthorsAliases :many +SELECT * +FROM authors a + LEFT JOIN super_authors sa + ON a.parent_id = sa.super_id; + +-- name: AllSuperAuthorsAliases2 :many +SELECT a.*, sa.* +FROM authors a + LEFT JOIN super_authors sa + ON a.parent_id = sa.super_id; + +-- name: GetSuggestedUsersByID :many +SELECT DISTINCT u.*, m.* +FROM users_2 u + LEFT JOIN media m + ON u.user_avatar_id = m.media_id +WHERE u.user_id != @user_id; diff --git a/internal/endtoend/testdata/join_left/mysql/schema.sql b/internal/endtoend/testdata/join_left/mysql/schema.sql new file mode 100644 index 0000000..9b15eae --- /dev/null +++ b/internal/endtoend/testdata/join_left/mysql/schema.sql @@ -0,0 +1,55 @@ +-- https://github.com/sqlc-dev/sqlc/issues/604 +CREATE TABLE users ( + user_id INT PRIMARY KEY, + city_id INT -- nullable +); +CREATE TABLE cities ( + city_id INT PRIMARY KEY, + mayor_id INT NOT NULL +); +CREATE TABLE mayors ( + mayor_id INT PRIMARY KEY, + full_name TEXT NOT NULL +); +-- https://github.com/sqlc-dev/sqlc/issues/1334 +CREATE TABLE authors ( + id INT PRIMARY KEY, + name TEXT NOT NULL, + parent_id INT -- nullable +); + +CREATE TABLE super_authors ( + super_id INT PRIMARY KEY, + super_name TEXT NOT NULL, + super_parent_id INT -- nullable +); + +-- https://github.com/sqlc-dev/sqlc/issues/1334 +CREATE TABLE users_2 ( + user_id INT PRIMARY KEY, + user_nickname VARCHAR(30) UNIQUE NOT NULL, + user_email VARCHAR(20) UNIQUE NOT NULL, + user_display_name TEXT NOT NULL, + user_password TEXT NULL, + user_google_id VARCHAR(20) UNIQUE NULL, + user_apple_id VARCHAR(20) UNIQUE NULL, + user_bio VARCHAR(160) NOT NULL DEFAULT '', + user_created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + user_avatar_id INT UNIQUE NULL +); + +CREATE TABLE media ( + media_id INT PRIMARY KEY, + media_created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + media_hash TEXT NOT NULL, + media_directory TEXT NOT NULL, + media_author_id INT NOT NULL, + media_width INT NOT NULL, + media_height INT NOT NULL +); + +ALTER TABLE users_2 +ADD FOREIGN KEY (user_avatar_id) +REFERENCES media(media_id) +ON DELETE SET DEFAULT +ON UPDATE CASCADE; diff --git a/internal/endtoend/testdata/join_left/mysql/sqlc.json b/internal/endtoend/testdata/join_left/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/join_left/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/join_left/postgresql/exec.json b/internal/endtoend/testdata/join_left/postgresql/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/join_left/postgresql/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/join_left/postgresql/go/db.go b/internal/endtoend/testdata/join_left/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_left/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_left/postgresql/go/models.go b/internal/endtoend/testdata/join_left/postgresql/go/models.go new file mode 100644 index 0000000..1199f5d --- /dev/null +++ b/internal/endtoend/testdata/join_left/postgresql/go/models.go @@ -0,0 +1,62 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + "time" + + "github.com/google/uuid" +) + +type Author struct { + ID int32 + Name string + ParentID sql.NullInt32 +} + +type City struct { + CityID int32 + MayorID int32 +} + +type Mayor struct { + MayorID int32 + FullName string +} + +type Medium struct { + MediaID uuid.UUID + MediaCreatedAt time.Time + MediaHash string + MediaDirectory string + MediaAuthorID uuid.UUID + MediaWidth int32 + MediaHeight int32 +} + +type SuperAuthor struct { + SuperID int32 + SuperName string + SuperParentID sql.NullInt32 +} + +type User struct { + UserID int32 + CityID sql.NullInt32 +} + +type Users2 struct { + UserID uuid.UUID + UserNickname string + UserEmail string + UserDisplayName string + UserPassword sql.NullString + UserGoogleID sql.NullString + UserAppleID sql.NullString + UserBio string + UserCreatedAt time.Time + UserAvatarID uuid.NullUUID +} diff --git a/internal/endtoend/testdata/join_left/postgresql/go/query.sql.go b/internal/endtoend/testdata/join_left/postgresql/go/query.sql.go new file mode 100644 index 0000000..f8d2316 --- /dev/null +++ b/internal/endtoend/testdata/join_left/postgresql/go/query.sql.go @@ -0,0 +1,439 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" + "time" + + "github.com/google/uuid" +) + +const allAuthors = `-- name: AllAuthors :many +SELECT a.id, a.name, a.parent_id, p.id, p.name, p.parent_id +FROM authors a + LEFT JOIN authors p + ON a.parent_id = p.id +` + +type AllAuthorsRow struct { + ID int32 + Name string + ParentID sql.NullInt32 + ID_2 sql.NullInt32 + Name_2 sql.NullString + ParentID_2 sql.NullInt32 +} + +func (q *Queries) AllAuthors(ctx context.Context) ([]AllAuthorsRow, error) { + rows, err := q.db.QueryContext(ctx, allAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllAuthorsRow + for rows.Next() { + var i AllAuthorsRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ParentID, + &i.ID_2, + &i.Name_2, + &i.ParentID_2, + ); 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 allAuthorsAliases = `-- name: AllAuthorsAliases :many +SELECT a.id, a.name, a.parent_id, p.id, p.name, p.parent_id +FROM authors a + LEFT JOIN authors p + ON a.parent_id = p.id +` + +type AllAuthorsAliasesRow struct { + ID int32 + Name string + ParentID sql.NullInt32 + ID_2 sql.NullInt32 + Name_2 sql.NullString + ParentID_2 sql.NullInt32 +} + +func (q *Queries) AllAuthorsAliases(ctx context.Context) ([]AllAuthorsAliasesRow, error) { + rows, err := q.db.QueryContext(ctx, allAuthorsAliases) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllAuthorsAliasesRow + for rows.Next() { + var i AllAuthorsAliasesRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ParentID, + &i.ID_2, + &i.Name_2, + &i.ParentID_2, + ); 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 allAuthorsAliases2 = `-- name: AllAuthorsAliases2 :many +SELECT a.id, a.name, a.parent_id, p.id, p.name, p.parent_id +FROM authors a + LEFT JOIN authors p + ON a.parent_id = p.id +` + +type AllAuthorsAliases2Row struct { + ID int32 + Name string + ParentID sql.NullInt32 + ID_2 sql.NullInt32 + Name_2 sql.NullString + ParentID_2 sql.NullInt32 +} + +func (q *Queries) AllAuthorsAliases2(ctx context.Context) ([]AllAuthorsAliases2Row, error) { + rows, err := q.db.QueryContext(ctx, allAuthorsAliases2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllAuthorsAliases2Row + for rows.Next() { + var i AllAuthorsAliases2Row + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ParentID, + &i.ID_2, + &i.Name_2, + &i.ParentID_2, + ); 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 allSuperAuthors = `-- name: AllSuperAuthors :many +SELECT id, name, parent_id, super_id, super_name, super_parent_id +FROM authors + LEFT JOIN super_authors + ON authors.parent_id = super_authors.super_id +` + +type AllSuperAuthorsRow struct { + ID int32 + Name string + ParentID sql.NullInt32 + SuperID sql.NullInt32 + SuperName sql.NullString + SuperParentID sql.NullInt32 +} + +func (q *Queries) AllSuperAuthors(ctx context.Context) ([]AllSuperAuthorsRow, error) { + rows, err := q.db.QueryContext(ctx, allSuperAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllSuperAuthorsRow + for rows.Next() { + var i AllSuperAuthorsRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ParentID, + &i.SuperID, + &i.SuperName, + &i.SuperParentID, + ); 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 allSuperAuthorsAliases = `-- name: AllSuperAuthorsAliases :many +SELECT id, name, parent_id, super_id, super_name, super_parent_id +FROM authors a + LEFT JOIN super_authors sa + ON a.parent_id = sa.super_id +` + +type AllSuperAuthorsAliasesRow struct { + ID int32 + Name string + ParentID sql.NullInt32 + SuperID sql.NullInt32 + SuperName sql.NullString + SuperParentID sql.NullInt32 +} + +func (q *Queries) AllSuperAuthorsAliases(ctx context.Context) ([]AllSuperAuthorsAliasesRow, error) { + rows, err := q.db.QueryContext(ctx, allSuperAuthorsAliases) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllSuperAuthorsAliasesRow + for rows.Next() { + var i AllSuperAuthorsAliasesRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ParentID, + &i.SuperID, + &i.SuperName, + &i.SuperParentID, + ); 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 allSuperAuthorsAliases2 = `-- name: AllSuperAuthorsAliases2 :many +SELECT a.id, a.name, a.parent_id, sa.super_id, sa.super_name, sa.super_parent_id +FROM authors a + LEFT JOIN super_authors sa + ON a.parent_id = sa.super_id +` + +type AllSuperAuthorsAliases2Row struct { + ID int32 + Name string + ParentID sql.NullInt32 + SuperID sql.NullInt32 + SuperName sql.NullString + SuperParentID sql.NullInt32 +} + +func (q *Queries) AllSuperAuthorsAliases2(ctx context.Context) ([]AllSuperAuthorsAliases2Row, error) { + rows, err := q.db.QueryContext(ctx, allSuperAuthorsAliases2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllSuperAuthorsAliases2Row + for rows.Next() { + var i AllSuperAuthorsAliases2Row + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ParentID, + &i.SuperID, + &i.SuperName, + &i.SuperParentID, + ); 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 getMayors = `-- name: GetMayors :many +SELECT + user_id, + mayors.full_name +FROM users +LEFT JOIN cities USING (city_id) +INNER JOIN mayors USING (mayor_id) +` + +type GetMayorsRow struct { + UserID int32 + FullName string +} + +func (q *Queries) GetMayors(ctx context.Context) ([]GetMayorsRow, error) { + rows, err := q.db.QueryContext(ctx, getMayors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetMayorsRow + for rows.Next() { + var i GetMayorsRow + if err := rows.Scan(&i.UserID, &i.FullName); 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 getMayorsOptional = `-- name: GetMayorsOptional :many +SELECT + user_id, + mayors.full_name +FROM users +LEFT JOIN cities USING (city_id) +LEFT JOIN mayors USING (mayor_id) +` + +type GetMayorsOptionalRow struct { + UserID int32 + FullName sql.NullString +} + +func (q *Queries) GetMayorsOptional(ctx context.Context) ([]GetMayorsOptionalRow, error) { + rows, err := q.db.QueryContext(ctx, getMayorsOptional) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetMayorsOptionalRow + for rows.Next() { + var i GetMayorsOptionalRow + if err := rows.Scan(&i.UserID, &i.FullName); 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 getSuggestedUsersByID = `-- name: GetSuggestedUsersByID :many +SELECT DISTINCT u.user_id, u.user_nickname, u.user_email, u.user_display_name, u.user_password, u.user_google_id, u.user_apple_id, u.user_bio, u.user_created_at, u.user_avatar_id, m.media_id, m.media_created_at, m.media_hash, m.media_directory, m.media_author_id, m.media_width, m.media_height +FROM users_2 u + LEFT JOIN media m + ON u.user_avatar_id = m.media_id +WHERE u.user_id != $1 +LIMIT $2 +` + +type GetSuggestedUsersByIDParams struct { + UserID uuid.UUID + UserImit int32 +} + +type GetSuggestedUsersByIDRow struct { + UserID uuid.UUID + UserNickname string + UserEmail string + UserDisplayName string + UserPassword sql.NullString + UserGoogleID sql.NullString + UserAppleID sql.NullString + UserBio string + UserCreatedAt time.Time + UserAvatarID uuid.NullUUID + MediaID uuid.NullUUID + MediaCreatedAt sql.NullTime + MediaHash sql.NullString + MediaDirectory sql.NullString + MediaAuthorID uuid.NullUUID + MediaWidth sql.NullInt32 + MediaHeight sql.NullInt32 +} + +func (q *Queries) GetSuggestedUsersByID(ctx context.Context, arg GetSuggestedUsersByIDParams) ([]GetSuggestedUsersByIDRow, error) { + rows, err := q.db.QueryContext(ctx, getSuggestedUsersByID, arg.UserID, arg.UserImit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetSuggestedUsersByIDRow + for rows.Next() { + var i GetSuggestedUsersByIDRow + if err := rows.Scan( + &i.UserID, + &i.UserNickname, + &i.UserEmail, + &i.UserDisplayName, + &i.UserPassword, + &i.UserGoogleID, + &i.UserAppleID, + &i.UserBio, + &i.UserCreatedAt, + &i.UserAvatarID, + &i.MediaID, + &i.MediaCreatedAt, + &i.MediaHash, + &i.MediaDirectory, + &i.MediaAuthorID, + &i.MediaWidth, + &i.MediaHeight, + ); 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/join_left/postgresql/query.sql b/internal/endtoend/testdata/join_left/postgresql/query.sql new file mode 100644 index 0000000..15e3d6e --- /dev/null +++ b/internal/endtoend/testdata/join_left/postgresql/query.sql @@ -0,0 +1,59 @@ +-- name: GetMayors :many +SELECT + user_id, + mayors.full_name +FROM users +LEFT JOIN cities USING (city_id) +INNER JOIN mayors USING (mayor_id); + +-- name: GetMayorsOptional :many +SELECT + user_id, + mayors.full_name +FROM users +LEFT JOIN cities USING (city_id) +LEFT JOIN mayors USING (mayor_id); + +-- name: AllAuthors :many +SELECT * +FROM authors a + LEFT JOIN authors p + ON a.parent_id = p.id; + +-- name: AllAuthorsAliases :many +SELECT * +FROM authors a + LEFT JOIN authors p + ON a.parent_id = p.id; + +-- name: AllAuthorsAliases2 :many +SELECT a.*, p.* +FROM authors a + LEFT JOIN authors p + ON a.parent_id = p.id; + +-- name: AllSuperAuthors :many +SELECT * +FROM authors + LEFT JOIN super_authors + ON authors.parent_id = super_authors.super_id; + +-- name: AllSuperAuthorsAliases :many +SELECT * +FROM authors a + LEFT JOIN super_authors sa + ON a.parent_id = sa.super_id; + +-- name: AllSuperAuthorsAliases2 :many +SELECT a.*, sa.* +FROM authors a + LEFT JOIN super_authors sa + ON a.parent_id = sa.super_id; + +-- name: GetSuggestedUsersByID :many +SELECT DISTINCT u.*, m.* +FROM users_2 u + LEFT JOIN media m + ON u.user_avatar_id = m.media_id +WHERE u.user_id != @user_id +LIMIT @user_imit; diff --git a/internal/endtoend/testdata/join_left/postgresql/schema.sql b/internal/endtoend/testdata/join_left/postgresql/schema.sql new file mode 100644 index 0000000..3cb9197 --- /dev/null +++ b/internal/endtoend/testdata/join_left/postgresql/schema.sql @@ -0,0 +1,53 @@ +--- https://github.com/sqlc-dev/sqlc/issues/604 +CREATE TABLE users ( + user_id INT PRIMARY KEY, + city_id INT -- nullable +); +CREATE TABLE cities ( + city_id INT PRIMARY KEY, + mayor_id INT NOT NULL +); +CREATE TABLE mayors ( + mayor_id INT PRIMARY KEY, + full_name TEXT NOT NULL +); + +-- https://github.com/sqlc-dev/sqlc/issues/1334 +CREATE TABLE authors ( + id INT PRIMARY KEY, + name TEXT NOT NULL, + parent_id INT -- nullable +); + +CREATE TABLE super_authors ( + super_id INT PRIMARY KEY, + super_name TEXT NOT NULL, + super_parent_id INT -- nullable +); + +-- https://github.com/sqlc-dev/sqlc/issues/1334 +CREATE TABLE "users_2" ( + "user_id" uuid PRIMARY KEY, + "user_nickname" VARCHAR(30) UNIQUE NOT NULL, + "user_email" TEXT UNIQUE NOT NULL, + "user_display_name" TEXT NOT NULL, + "user_password" TEXT NULL, + "user_google_id" TEXT UNIQUE NULL, + "user_apple_id" TEXT UNIQUE NULL, + "user_bio" VARCHAR(160) NOT NULL DEFAULT '', + "user_created_at" TIMESTAMP NOT NULL DEFAULT (NOW()), + "user_avatar_id" uuid UNIQUE NULL +); + +CREATE TABLE "media" ( + "media_id" uuid PRIMARY KEY, + "media_created_at" TIMESTAMP NOT NULL DEFAULT (NOW()), + "media_hash" TEXT NOT NULL, + "media_directory" TEXT NOT NULL, + "media_author_id" uuid NOT NULL, + "media_width" INT NOT NULL, + "media_height" INT NOT NULL +); + +ALTER TABLE "users_2" + ADD FOREIGN KEY ("user_avatar_id") REFERENCES "media" ("media_id") ON DELETE SET DEFAULT ON UPDATE CASCADE; diff --git a/internal/endtoend/testdata/join_left/postgresql/sqlc.json b/internal/endtoend/testdata/join_left/postgresql/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/join_left/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/join_left/sqlite/go/db.go b/internal/endtoend/testdata/join_left/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_left/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_left/sqlite/go/models.go b/internal/endtoend/testdata/join_left/sqlite/go/models.go new file mode 100644 index 0000000..520b0cb --- /dev/null +++ b/internal/endtoend/testdata/join_left/sqlite/go/models.go @@ -0,0 +1,60 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + "time" +) + +type Author struct { + ID int64 + Name string + ParentID sql.NullInt64 +} + +type City struct { + CityID int64 + MayorID int64 +} + +type Mayor struct { + MayorID int64 + FullName string +} + +type Medium struct { + MediaID int64 + MediaCreatedAt time.Time + MediaHash string + MediaDirectory string + MediaAuthorID int64 + MediaWidth int64 + MediaHeight int64 +} + +type SuperAuthor struct { + SuperID int64 + SuperName string + SuperParentID sql.NullInt64 +} + +type User struct { + UserID int64 + CityID sql.NullInt64 +} + +type Users2 struct { + UserID int64 + UserNickname string + UserEmail string + UserDisplayName string + UserPassword sql.NullString + UserGoogleID sql.NullString + UserAppleID sql.NullString + UserBio string + UserCreatedAt time.Time + UserAvatarID sql.NullInt64 +} diff --git a/internal/endtoend/testdata/join_left/sqlite/go/query.sql.go b/internal/endtoend/testdata/join_left/sqlite/go/query.sql.go new file mode 100644 index 0000000..4037bc4 --- /dev/null +++ b/internal/endtoend/testdata/join_left/sqlite/go/query.sql.go @@ -0,0 +1,456 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" + "time" +) + +const allAuthors = `-- name: AllAuthors :many +SELECT a.id, a.name, a.parent_id, p.id, p.name, p.parent_id +FROM authors AS a +LEFT JOIN authors AS p ON a.parent_id = p.id +` + +type AllAuthorsRow struct { + ID int64 + Name string + ParentID sql.NullInt64 + ID_2 sql.NullInt64 + Name_2 sql.NullString + ParentID_2 sql.NullInt64 +} + +func (q *Queries) AllAuthors(ctx context.Context) ([]AllAuthorsRow, error) { + rows, err := q.db.QueryContext(ctx, allAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllAuthorsRow + for rows.Next() { + var i AllAuthorsRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ParentID, + &i.ID_2, + &i.Name_2, + &i.ParentID_2, + ); 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 allAuthorsAliases = `-- name: AllAuthorsAliases :many +SELECT a.id, a.name, a.parent_id, p.id, p.name, p.parent_id +FROM authors AS a +LEFT JOIN authors AS p ON a.parent_id = p.id +` + +type AllAuthorsAliasesRow struct { + ID int64 + Name string + ParentID sql.NullInt64 + ID_2 sql.NullInt64 + Name_2 sql.NullString + ParentID_2 sql.NullInt64 +} + +func (q *Queries) AllAuthorsAliases(ctx context.Context) ([]AllAuthorsAliasesRow, error) { + rows, err := q.db.QueryContext(ctx, allAuthorsAliases) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllAuthorsAliasesRow + for rows.Next() { + var i AllAuthorsAliasesRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ParentID, + &i.ID_2, + &i.Name_2, + &i.ParentID_2, + ); 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 allAuthorsAliases2 = `-- name: AllAuthorsAliases2 :many +SELECT a.id, a.name, a.parent_id, p.id, p.name, p.parent_id +FROM authors AS a +LEFT JOIN authors AS p ON a.parent_id = p.id +` + +type AllAuthorsAliases2Row struct { + ID int64 + Name string + ParentID sql.NullInt64 + ID_2 sql.NullInt64 + Name_2 sql.NullString + ParentID_2 sql.NullInt64 +} + +func (q *Queries) AllAuthorsAliases2(ctx context.Context) ([]AllAuthorsAliases2Row, error) { + rows, err := q.db.QueryContext(ctx, allAuthorsAliases2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllAuthorsAliases2Row + for rows.Next() { + var i AllAuthorsAliases2Row + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ParentID, + &i.ID_2, + &i.Name_2, + &i.ParentID_2, + ); 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 allSuperAuthors = `-- name: AllSuperAuthors :many +SELECT id, name, parent_id, super_id, super_name, super_parent_id +FROM authors +LEFT JOIN super_authors ON authors.parent_id = super_authors.super_id +` + +type AllSuperAuthorsRow struct { + ID int64 + Name string + ParentID sql.NullInt64 + SuperID sql.NullInt64 + SuperName sql.NullString + SuperParentID sql.NullInt64 +} + +func (q *Queries) AllSuperAuthors(ctx context.Context) ([]AllSuperAuthorsRow, error) { + rows, err := q.db.QueryContext(ctx, allSuperAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllSuperAuthorsRow + for rows.Next() { + var i AllSuperAuthorsRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ParentID, + &i.SuperID, + &i.SuperName, + &i.SuperParentID, + ); 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 allSuperAuthorsAliases = `-- name: AllSuperAuthorsAliases :many +SELECT id, name, parent_id, super_id, super_name, super_parent_id +FROM authors AS a +LEFT JOIN super_authors AS sa ON a.parent_id = sa.super_id +` + +type AllSuperAuthorsAliasesRow struct { + ID int64 + Name string + ParentID sql.NullInt64 + SuperID sql.NullInt64 + SuperName sql.NullString + SuperParentID sql.NullInt64 +} + +func (q *Queries) AllSuperAuthorsAliases(ctx context.Context) ([]AllSuperAuthorsAliasesRow, error) { + rows, err := q.db.QueryContext(ctx, allSuperAuthorsAliases) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllSuperAuthorsAliasesRow + for rows.Next() { + var i AllSuperAuthorsAliasesRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ParentID, + &i.SuperID, + &i.SuperName, + &i.SuperParentID, + ); 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 allSuperAuthorsAliases2 = `-- name: AllSuperAuthorsAliases2 :many +SELECT a.id, a.name, a.parent_id, sa.super_id, sa.super_name, sa.super_parent_id +FROM authors AS a +LEFT JOIN super_authors AS sa ON a.parent_id = sa.super_id +` + +type AllSuperAuthorsAliases2Row struct { + ID int64 + Name string + ParentID sql.NullInt64 + SuperID sql.NullInt64 + SuperName sql.NullString + SuperParentID sql.NullInt64 +} + +func (q *Queries) AllSuperAuthorsAliases2(ctx context.Context) ([]AllSuperAuthorsAliases2Row, error) { + rows, err := q.db.QueryContext(ctx, allSuperAuthorsAliases2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllSuperAuthorsAliases2Row + for rows.Next() { + var i AllSuperAuthorsAliases2Row + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ParentID, + &i.SuperID, + &i.SuperName, + &i.SuperParentID, + ); 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 getMayors = `-- name: GetMayors :many +SELECT + user_id, + mayors.full_name +FROM users +LEFT JOIN cities USING (city_id) +JOIN mayors USING (mayor_id) +` + +type GetMayorsRow struct { + UserID int64 + FullName string +} + +func (q *Queries) GetMayors(ctx context.Context) ([]GetMayorsRow, error) { + rows, err := q.db.QueryContext(ctx, getMayors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetMayorsRow + for rows.Next() { + var i GetMayorsRow + if err := rows.Scan(&i.UserID, &i.FullName); 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 getMayorsOptional = `-- name: GetMayorsOptional :many +SELECT + user_id, + cities.city_id, + mayors.full_name +FROM users +LEFT JOIN cities USING (city_id) +LEFT JOIN mayors USING (mayor_id) +` + +type GetMayorsOptionalRow struct { + UserID int64 + CityID sql.NullInt64 + FullName sql.NullString +} + +func (q *Queries) GetMayorsOptional(ctx context.Context) ([]GetMayorsOptionalRow, error) { + rows, err := q.db.QueryContext(ctx, getMayorsOptional) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetMayorsOptionalRow + for rows.Next() { + var i GetMayorsOptionalRow + if err := rows.Scan(&i.UserID, &i.CityID, &i.FullName); 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 getSuggestedUsersByID = `-- name: GetSuggestedUsersByID :many +SELECT DISTINCT u.user_id, u.user_nickname, u.user_email, u.user_display_name, u.user_password, u.user_google_id, u.user_apple_id, u.user_bio, u.user_created_at, u.user_avatar_id, m.media_id, m.media_created_at, m.media_hash, m.media_directory, m.media_author_id, m.media_width, m.media_height +FROM users_2 AS u +LEFT JOIN media AS m ON u.user_avatar_id = m.media_id +WHERE u.user_id != ?1 +` + +type GetSuggestedUsersByIDRow struct { + UserID int64 + UserNickname string + UserEmail string + UserDisplayName string + UserPassword sql.NullString + UserGoogleID sql.NullString + UserAppleID sql.NullString + UserBio string + UserCreatedAt time.Time + UserAvatarID sql.NullInt64 + 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) { + rows, err := q.db.QueryContext(ctx, getSuggestedUsersByID, userID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetSuggestedUsersByIDRow + for rows.Next() { + var i GetSuggestedUsersByIDRow + if err := rows.Scan( + &i.UserID, + &i.UserNickname, + &i.UserEmail, + &i.UserDisplayName, + &i.UserPassword, + &i.UserGoogleID, + &i.UserAppleID, + &i.UserBio, + &i.UserCreatedAt, + &i.UserAvatarID, + &i.MediaID, + &i.MediaCreatedAt, + &i.MediaHash, + &i.MediaDirectory, + &i.MediaAuthorID, + &i.MediaWidth, + &i.MediaHeight, + ); 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 getSuggestedUsersByID2 = `-- name: GetSuggestedUsersByID2 :many +SELECT users_2.user_id +FROM users_2 +LEFT JOIN media AS m ON user_avatar_id = m.media_id +WHERE user_id != ?1 +` + +func (q *Queries) GetSuggestedUsersByID2(ctx context.Context, userID int64) ([]int64, error) { + rows, err := q.db.QueryContext(ctx, getSuggestedUsersByID2, userID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var user_id int64 + if err := rows.Scan(&user_id); err != nil { + return nil, err + } + items = append(items, user_id) + } + 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/join_left/sqlite/query.sql b/internal/endtoend/testdata/join_left/sqlite/query.sql new file mode 100644 index 0000000..863f0d2 --- /dev/null +++ b/internal/endtoend/testdata/join_left/sqlite/query.sql @@ -0,0 +1,58 @@ +-- name: GetMayors :many +SELECT + user_id, + mayors.full_name +FROM users +LEFT JOIN cities USING (city_id) +JOIN mayors USING (mayor_id); + +-- name: GetMayorsOptional :many +SELECT + user_id, + cities.city_id, + mayors.full_name +FROM users +LEFT JOIN cities USING (city_id) +LEFT JOIN mayors USING (mayor_id); + +-- name: AllAuthors :many +SELECT * +FROM authors AS a +LEFT JOIN authors AS p ON a.parent_id = p.id; + +-- name: AllAuthorsAliases :many +SELECT * +FROM authors AS a +LEFT JOIN authors AS p ON a.parent_id = p.id; + +-- name: AllSuperAuthors :many +SELECT * +FROM authors +LEFT JOIN super_authors ON authors.parent_id = super_authors.super_id; + +-- name: AllAuthorsAliases2 :many +SELECT a.*, p.* +FROM authors AS a +LEFT JOIN authors AS p ON a.parent_id = p.id; + +-- name: AllSuperAuthorsAliases :many +SELECT * +FROM authors AS a +LEFT JOIN super_authors AS sa ON a.parent_id = sa.super_id; + +-- name: AllSuperAuthorsAliases2 :many +SELECT a.*, sa.* +FROM authors AS a +LEFT JOIN super_authors AS sa ON a.parent_id = sa.super_id; + +-- name: GetSuggestedUsersByID :many +SELECT DISTINCT u.*, m.* +FROM users_2 AS u +LEFT JOIN media AS m ON u.user_avatar_id = m.media_id +WHERE u.user_id != @user_id; + +-- name: GetSuggestedUsersByID2 :many +SELECT users_2.user_id +FROM users_2 +LEFT JOIN media AS m ON user_avatar_id = m.media_id +WHERE user_id != @user_id; diff --git a/internal/endtoend/testdata/join_left/sqlite/schema.sql b/internal/endtoend/testdata/join_left/sqlite/schema.sql new file mode 100644 index 0000000..e5b2db5 --- /dev/null +++ b/internal/endtoend/testdata/join_left/sqlite/schema.sql @@ -0,0 +1,50 @@ +-- https://github.com/sqlc-dev/sqlc/issues/604 +CREATE TABLE users ( + user_id INT PRIMARY KEY, + city_id INT -- nullable +); +CREATE TABLE cities ( + city_id INT PRIMARY KEY, + mayor_id INT NOT NULL +); +CREATE TABLE mayors ( + mayor_id INT PRIMARY KEY, + full_name TEXT NOT NULL +); + +-- https://github.com/sqlc-dev/sqlc/issues/1334 +CREATE TABLE authors ( + id INT PRIMARY KEY, + name TEXT NOT NULL, + parent_id INT -- nullable +); + +CREATE TABLE super_authors ( + super_id INT PRIMARY KEY, + super_name TEXT NOT NULL, + super_parent_id INT -- nullable +); + +-- https://github.com/sqlc-dev/sqlc/issues/1334 +CREATE TABLE users_2 ( + user_id INT PRIMARY KEY, + user_nickname VARCHAR(30) UNIQUE NOT NULL, + user_email TEXT UNIQUE NOT NULL, + user_display_name TEXT NOT NULL, + user_password TEXT , + user_google_id TEXT UNIQUE , + user_apple_id TEXT UNIQUE , + user_bio VARCHAR(160) NOT NULL DEFAULT '', + user_created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + user_avatar_id INT UNIQUE +); + +CREATE TABLE media ( + media_id INT PRIMARY KEY, + media_created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + media_hash TEXT NOT NULL, + media_directory TEXT NOT NULL, + media_author_id INT NOT NULL, + media_width INT NOT NULL, + media_height INT NOT NULL +); diff --git a/internal/endtoend/testdata/join_left/sqlite/sqlc.json b/internal/endtoend/testdata/join_left/sqlite/sqlc.json new file mode 100644 index 0000000..d4963e7 --- /dev/null +++ b/internal/endtoend/testdata/join_left/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/join_left_same_table/mysql/go/db.go b/internal/endtoend/testdata/join_left_same_table/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_left_same_table/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_left_same_table/mysql/go/models.go b/internal/endtoend/testdata/join_left_same_table/mysql/go/models.go new file mode 100644 index 0000000..287c217 --- /dev/null +++ b/internal/endtoend/testdata/join_left_same_table/mysql/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int32 + Name string + ParentID sql.NullInt32 +} diff --git a/internal/endtoend/testdata/join_left_same_table/mysql/go/query.sql.go b/internal/endtoend/testdata/join_left_same_table/mysql/go/query.sql.go new file mode 100644 index 0000000..65ee188 --- /dev/null +++ b/internal/endtoend/testdata/join_left_same_table/mysql/go/query.sql.go @@ -0,0 +1,56 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const allAuthors = `-- name: AllAuthors :many +SELECT a.id, + a.name, + p.id as alias_id, + p.name as alias_name +FROM authors a + LEFT JOIN authors p + ON (authors.parent_id = p.id) +` + +type AllAuthorsRow struct { + ID int32 + Name string + AliasID sql.NullInt32 + AliasName sql.NullString +} + +func (q *Queries) AllAuthors(ctx context.Context) ([]AllAuthorsRow, error) { + rows, err := q.db.QueryContext(ctx, allAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllAuthorsRow + for rows.Next() { + var i AllAuthorsRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.AliasID, + &i.AliasName, + ); 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/join_left_same_table/mysql/query.sql b/internal/endtoend/testdata/join_left_same_table/mysql/query.sql new file mode 100644 index 0000000..26bd026 --- /dev/null +++ b/internal/endtoend/testdata/join_left_same_table/mysql/query.sql @@ -0,0 +1,8 @@ +-- name: AllAuthors :many +SELECT a.id, + a.name, + p.id as alias_id, + p.name as alias_name +FROM authors a + LEFT JOIN authors p + ON (authors.parent_id = p.id); diff --git a/internal/endtoend/testdata/join_left_same_table/mysql/schema.sql b/internal/endtoend/testdata/join_left_same_table/mysql/schema.sql new file mode 100644 index 0000000..e543131 --- /dev/null +++ b/internal/endtoend/testdata/join_left_same_table/mysql/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE authors ( + id INT(10) NOT NULL, + name VARCHAR(255) NOT NULL, + parent_id INT(10), + PRIMARY KEY (id) +); + diff --git a/internal/endtoend/testdata/join_left_same_table/mysql/sqlc.json b/internal/endtoend/testdata/join_left_same_table/mysql/sqlc.json new file mode 100644 index 0000000..0390f67 --- /dev/null +++ b/internal/endtoend/testdata/join_left_same_table/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/join_left_same_table/postgres/go/db.go b/internal/endtoend/testdata/join_left_same_table/postgres/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_left_same_table/postgres/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_left_same_table/postgres/go/models.go b/internal/endtoend/testdata/join_left_same_table/postgres/go/models.go new file mode 100644 index 0000000..287c217 --- /dev/null +++ b/internal/endtoend/testdata/join_left_same_table/postgres/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int32 + Name string + ParentID sql.NullInt32 +} diff --git a/internal/endtoend/testdata/join_left_same_table/postgres/go/query.sql.go b/internal/endtoend/testdata/join_left_same_table/postgres/go/query.sql.go new file mode 100644 index 0000000..0afcffc --- /dev/null +++ b/internal/endtoend/testdata/join_left_same_table/postgres/go/query.sql.go @@ -0,0 +1,55 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const allAuthors = `-- name: AllAuthors :many +SELECT a.id, + a.name, + p.id as alias_id, + p.name as alias_name +FROM authors a + LEFT JOIN authors p USING (parent_id) +` + +type AllAuthorsRow struct { + ID int32 + Name string + AliasID sql.NullInt32 + AliasName sql.NullString +} + +func (q *Queries) AllAuthors(ctx context.Context) ([]AllAuthorsRow, error) { + rows, err := q.db.QueryContext(ctx, allAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllAuthorsRow + for rows.Next() { + var i AllAuthorsRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.AliasID, + &i.AliasName, + ); 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/join_left_same_table/postgres/query.sql b/internal/endtoend/testdata/join_left_same_table/postgres/query.sql new file mode 100644 index 0000000..6fb2fce --- /dev/null +++ b/internal/endtoend/testdata/join_left_same_table/postgres/query.sql @@ -0,0 +1,7 @@ +-- name: AllAuthors :many +SELECT a.id, + a.name, + p.id as alias_id, + p.name as alias_name +FROM authors a + LEFT JOIN authors p USING (parent_id); diff --git a/internal/endtoend/testdata/join_left_same_table/postgres/schema.sql b/internal/endtoend/testdata/join_left_same_table/postgres/schema.sql new file mode 100644 index 0000000..b15882b --- /dev/null +++ b/internal/endtoend/testdata/join_left_same_table/postgres/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE authors ( + id INT PRIMARY KEY, + name TEXT NOT NULL, + parent_id INT -- nullable +); + diff --git a/internal/endtoend/testdata/join_left_same_table/postgres/sqlc.json b/internal/endtoend/testdata/join_left_same_table/postgres/sqlc.json new file mode 100644 index 0000000..a590361 --- /dev/null +++ b/internal/endtoend/testdata/join_left_same_table/postgres/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/join_left_same_table/sqlite/go/db.go b/internal/endtoend/testdata/join_left_same_table/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_left_same_table/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_left_same_table/sqlite/go/models.go b/internal/endtoend/testdata/join_left_same_table/sqlite/go/models.go new file mode 100644 index 0000000..dc60127 --- /dev/null +++ b/internal/endtoend/testdata/join_left_same_table/sqlite/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + ParentID sql.NullInt64 +} 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 new file mode 100644 index 0000000..1e566df --- /dev/null +++ b/internal/endtoend/testdata/join_left_same_table/sqlite/go/query.sql.go @@ -0,0 +1,56 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const allAuthors = `-- name: AllAuthors :many +SELECT + a.id, + a.name, + p.id AS alias_id, + p.name AS alias_name +FROM authors AS a +LEFT JOIN authors AS p ON a.parent_id = p.id +` + +type AllAuthorsRow struct { + ID int64 + Name string + AliasID sql.NullInt64 + AliasName sql.NullString +} + +func (q *Queries) AllAuthors(ctx context.Context) ([]AllAuthorsRow, error) { + rows, err := q.db.QueryContext(ctx, allAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllAuthorsRow + for rows.Next() { + var i AllAuthorsRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.AliasID, + &i.AliasName, + ); 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/join_left_same_table/sqlite/query.sql b/internal/endtoend/testdata/join_left_same_table/sqlite/query.sql new file mode 100644 index 0000000..6430a52 --- /dev/null +++ b/internal/endtoend/testdata/join_left_same_table/sqlite/query.sql @@ -0,0 +1,8 @@ +-- name: AllAuthors :many +SELECT + a.id, + a.name, + p.id AS alias_id, + p.name AS alias_name +FROM authors AS a +LEFT JOIN authors AS p ON a.parent_id = p.id; diff --git a/internal/endtoend/testdata/join_left_same_table/sqlite/schema.sql b/internal/endtoend/testdata/join_left_same_table/sqlite/schema.sql new file mode 100644 index 0000000..4958ea6 --- /dev/null +++ b/internal/endtoend/testdata/join_left_same_table/sqlite/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE authors ( + id INT NOT NULL PRIMARY KEY, + name TEXT NOT NULL, + parent_id INT +); + diff --git a/internal/endtoend/testdata/join_left_same_table/sqlite/sqlc.json b/internal/endtoend/testdata/join_left_same_table/sqlite/sqlc.json new file mode 100644 index 0000000..d4963e7 --- /dev/null +++ b/internal/endtoend/testdata/join_left_same_table/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/join_left_table_alias/issue.md b/internal/endtoend/testdata/join_left_table_alias/issue.md new file mode 100644 index 0000000..77e67d1 --- /dev/null +++ b/internal/endtoend/testdata/join_left_table_alias/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1897 diff --git a/internal/endtoend/testdata/join_left_table_alias/postgresql/pgx/go/db.go b/internal/endtoend/testdata/join_left_table_alias/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/join_left_table_alias/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/join_left_table_alias/postgresql/pgx/go/models.go b/internal/endtoend/testdata/join_left_table_alias/postgresql/pgx/go/models.go new file mode 100644 index 0000000..1f8c846 --- /dev/null +++ b/internal/endtoend/testdata/join_left_table_alias/postgresql/pgx/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + FooID int64 + Info string +} + +type Foo struct { + ID int64 +} diff --git a/internal/endtoend/testdata/join_left_table_alias/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/join_left_table_alias/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..4f8dfac --- /dev/null +++ b/internal/endtoend/testdata/join_left_table_alias/postgresql/pgx/go/query.sql.go @@ -0,0 +1,48 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const joinBar = `-- name: JoinBar :one +SELECT f.id, info +FROM foo f +LEFT JOIN bar b ON b.foo_id = f.id +` + +type JoinBarRow struct { + ID int64 + Info pgtype.Text +} + +func (q *Queries) JoinBar(ctx context.Context) (JoinBarRow, error) { + row := q.db.QueryRow(ctx, joinBar) + var i JoinBarRow + err := row.Scan(&i.ID, &i.Info) + return i, err +} + +const joinBarAlias = `-- name: JoinBarAlias :one +SELECT f.id, b.info +FROM foo f +LEFT JOIN bar b ON b.foo_id = f.id +` + +type JoinBarAliasRow struct { + ID int64 + Info pgtype.Text +} + +func (q *Queries) JoinBarAlias(ctx context.Context) (JoinBarAliasRow, error) { + row := q.db.QueryRow(ctx, joinBarAlias) + var i JoinBarAliasRow + err := row.Scan(&i.ID, &i.Info) + return i, err +} diff --git a/internal/endtoend/testdata/join_left_table_alias/postgresql/pgx/query.sql b/internal/endtoend/testdata/join_left_table_alias/postgresql/pgx/query.sql new file mode 100644 index 0000000..ad61f17 --- /dev/null +++ b/internal/endtoend/testdata/join_left_table_alias/postgresql/pgx/query.sql @@ -0,0 +1,9 @@ +-- name: JoinBar :one +SELECT f.id, info +FROM foo f +LEFT JOIN bar b ON b.foo_id = f.id; + +-- name: JoinBarAlias :one +SELECT f.id, b.info +FROM foo f +LEFT JOIN bar b ON b.foo_id = f.id; diff --git a/internal/endtoend/testdata/join_left_table_alias/postgresql/pgx/schema.sql b/internal/endtoend/testdata/join_left_table_alias/postgresql/pgx/schema.sql new file mode 100644 index 0000000..2961590 --- /dev/null +++ b/internal/endtoend/testdata/join_left_table_alias/postgresql/pgx/schema.sql @@ -0,0 +1,9 @@ +CREATE TABLE foo ( + id BIGINT PRIMARY KEY +); + +CREATE TABLE bar +( + foo_id BIGINT NOT NULL, + info TEXT NOT NULL +); diff --git a/internal/endtoend/testdata/join_left_table_alias/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/join_left_table_alias/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/join_left_table_alias/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/join_order_by/issue.md b/internal/endtoend/testdata/join_order_by/issue.md new file mode 100644 index 0000000..1c3c36f --- /dev/null +++ b/internal/endtoend/testdata/join_order_by/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/2538 diff --git a/internal/endtoend/testdata/join_order_by/postgresql/pgx/exec.json b/internal/endtoend/testdata/join_order_by/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/join_order_by/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/join_order_by/postgresql/pgx/go/db.go b/internal/endtoend/testdata/join_order_by/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/join_order_by/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/join_order_by/postgresql/pgx/go/models.go b/internal/endtoend/testdata/join_order_by/postgresql/pgx/go/models.go new file mode 100644 index 0000000..4e97f66 --- /dev/null +++ b/internal/endtoend/testdata/join_order_by/postgresql/pgx/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Author struct { + ID int64 + Name string + Bio pgtype.Text +} diff --git a/internal/endtoend/testdata/join_order_by/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/join_order_by/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..9fe80c0 --- /dev/null +++ b/internal/endtoend/testdata/join_order_by/postgresql/pgx/go/query.sql.go @@ -0,0 +1,23 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAuthor = `-- name: GetAuthor :one +SELECT a.name +FROM authors a JOIN authors b ON a.id = b.id +ORDER BY name +` + +func (q *Queries) GetAuthor(ctx context.Context) (string, error) { + row := q.db.QueryRow(ctx, getAuthor) + var name string + err := row.Scan(&name) + return name, err +} diff --git a/internal/endtoend/testdata/join_order_by/postgresql/pgx/query.sql b/internal/endtoend/testdata/join_order_by/postgresql/pgx/query.sql new file mode 100644 index 0000000..39cf01c --- /dev/null +++ b/internal/endtoend/testdata/join_order_by/postgresql/pgx/query.sql @@ -0,0 +1,4 @@ +-- name: GetAuthor :one +SELECT a.name +FROM authors a JOIN authors b ON a.id = b.id +ORDER BY name; diff --git a/internal/endtoend/testdata/join_order_by/postgresql/pgx/schema.sql b/internal/endtoend/testdata/join_order_by/postgresql/pgx/schema.sql new file mode 100644 index 0000000..69b607d --- /dev/null +++ b/internal/endtoend/testdata/join_order_by/postgresql/pgx/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/join_order_by/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/join_order_by/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/join_order_by/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/join_order_by_alias/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/join_order_by_alias/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_order_by_alias/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_order_by_alias/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/join_order_by_alias/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..fa99fe4 --- /dev/null +++ b/internal/endtoend/testdata/join_order_by_alias/postgresql/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Email string +} diff --git a/internal/endtoend/testdata/join_order_by_alias/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/join_order_by_alias/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..2e58db3 --- /dev/null +++ b/internal/endtoend/testdata/join_order_by_alias/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,39 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const columnAsOrderBy = `-- name: ColumnAsOrderBy :many +SELECT a.email AS id +FROM foo a JOIN foo b ON a.email = b.email +ORDER BY id +` + +func (q *Queries) ColumnAsOrderBy(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, columnAsOrderBy) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 +} diff --git a/internal/endtoend/testdata/join_order_by_alias/postgresql/stdlib/query.sql b/internal/endtoend/testdata/join_order_by_alias/postgresql/stdlib/query.sql new file mode 100644 index 0000000..7a47032 --- /dev/null +++ b/internal/endtoend/testdata/join_order_by_alias/postgresql/stdlib/query.sql @@ -0,0 +1,4 @@ +-- name: ColumnAsOrderBy :many +SELECT a.email AS id +FROM foo a JOIN foo b ON a.email = b.email +ORDER BY id; diff --git a/internal/endtoend/testdata/join_order_by_alias/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/join_order_by_alias/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..da8ec19 --- /dev/null +++ b/internal/endtoend/testdata/join_order_by_alias/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (email text not null); + diff --git a/internal/endtoend/testdata/join_order_by_alias/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/join_order_by_alias/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..cd51867 --- /dev/null +++ b/internal/endtoend/testdata/join_order_by_alias/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/join_right/mysql/go/db.go b/internal/endtoend/testdata/join_right/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_right/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_right/mysql/go/models.go b/internal/endtoend/testdata/join_right/mysql/go/models.go new file mode 100644 index 0000000..6878c1d --- /dev/null +++ b/internal/endtoend/testdata/join_right/mysql/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ID int32 +} + +type Foo struct { + ID int32 + BarID sql.NullInt32 +} diff --git a/internal/endtoend/testdata/join_right/mysql/go/query.sql.go b/internal/endtoend/testdata/join_right/mysql/go/query.sql.go new file mode 100644 index 0000000..182045a --- /dev/null +++ b/internal/endtoend/testdata/join_right/mysql/go/query.sql.go @@ -0,0 +1,47 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const rightJoin = `-- name: RightJoin :many +SELECT f.id, f.bar_id, b.id +FROM foo f +RIGHT JOIN bar b ON b.id = f.bar_id +WHERE f.id = ? +` + +type RightJoinRow struct { + ID sql.NullInt32 + BarID sql.NullInt32 + ID_2 int32 +} + +func (q *Queries) RightJoin(ctx context.Context, id int32) ([]RightJoinRow, error) { + rows, err := q.db.QueryContext(ctx, rightJoin, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []RightJoinRow + for rows.Next() { + var i RightJoinRow + if err := rows.Scan(&i.ID, &i.BarID, &i.ID_2); 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/join_right/mysql/query.sql b/internal/endtoend/testdata/join_right/mysql/query.sql new file mode 100644 index 0000000..cfdf82f --- /dev/null +++ b/internal/endtoend/testdata/join_right/mysql/query.sql @@ -0,0 +1,5 @@ +-- name: RightJoin :many +SELECT f.id, f.bar_id, b.id +FROM foo f +RIGHT JOIN bar b ON b.id = f.bar_id +WHERE f.id = ?; diff --git a/internal/endtoend/testdata/join_right/mysql/schema.sql b/internal/endtoend/testdata/join_right/mysql/schema.sql new file mode 100644 index 0000000..f0f2cb1 --- /dev/null +++ b/internal/endtoend/testdata/join_right/mysql/schema.sql @@ -0,0 +1,8 @@ +CREATE TABLE bar ( + id integer not null, + UNIQUE(id) +); + +CREATE TABLE foo (id integer not null, bar_id integer references bar(id)); + + diff --git a/internal/endtoend/testdata/join_right/mysql/sqlc.json b/internal/endtoend/testdata/join_right/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/join_right/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/join_right/postgresql/go/db.go b/internal/endtoend/testdata/join_right/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_right/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_right/postgresql/go/models.go b/internal/endtoend/testdata/join_right/postgresql/go/models.go new file mode 100644 index 0000000..6878c1d --- /dev/null +++ b/internal/endtoend/testdata/join_right/postgresql/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ID int32 +} + +type Foo struct { + ID int32 + BarID sql.NullInt32 +} diff --git a/internal/endtoend/testdata/join_right/postgresql/go/query.sql.go b/internal/endtoend/testdata/join_right/postgresql/go/query.sql.go new file mode 100644 index 0000000..d70da97 --- /dev/null +++ b/internal/endtoend/testdata/join_right/postgresql/go/query.sql.go @@ -0,0 +1,47 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const rightJoin = `-- name: RightJoin :many +SELECT f.id, f.bar_id, b.id +FROM foo f +RIGHT JOIN bar b ON b.id = f.bar_id +WHERE f.id = $1 +` + +type RightJoinRow struct { + ID sql.NullInt32 + BarID sql.NullInt32 + ID_2 int32 +} + +func (q *Queries) RightJoin(ctx context.Context, id int32) ([]RightJoinRow, error) { + rows, err := q.db.QueryContext(ctx, rightJoin, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []RightJoinRow + for rows.Next() { + var i RightJoinRow + if err := rows.Scan(&i.ID, &i.BarID, &i.ID_2); 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/join_right/postgresql/query.sql b/internal/endtoend/testdata/join_right/postgresql/query.sql new file mode 100644 index 0000000..f7d9c48 --- /dev/null +++ b/internal/endtoend/testdata/join_right/postgresql/query.sql @@ -0,0 +1,5 @@ +-- name: RightJoin :many +SELECT f.id, f.bar_id, b.id +FROM foo f +RIGHT JOIN bar b ON b.id = f.bar_id +WHERE f.id = $1; diff --git a/internal/endtoend/testdata/join_right/postgresql/schema.sql b/internal/endtoend/testdata/join_right/postgresql/schema.sql new file mode 100644 index 0000000..c7d2a76 --- /dev/null +++ b/internal/endtoend/testdata/join_right/postgresql/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE bar (id serial not null unique); +CREATE TABLE foo (id serial not null, bar_id int references bar(id)); + diff --git a/internal/endtoend/testdata/join_right/postgresql/sqlc.json b/internal/endtoend/testdata/join_right/postgresql/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/join_right/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/join_table_name/mysql/go/db.go b/internal/endtoend/testdata/join_table_name/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_table_name/mysql/go/models.go b/internal/endtoend/testdata/join_table_name/mysql/go/models.go new file mode 100644 index 0000000..b72efbb --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/mysql/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ID int32 +} + +type Foo struct { + ID int32 + Bar sql.NullInt32 +} diff --git a/internal/endtoend/testdata/join_table_name/mysql/go/query.sql.go b/internal/endtoend/testdata/join_table_name/mysql/go/query.sql.go new file mode 100644 index 0000000..ed04160 --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/mysql/go/query.sql.go @@ -0,0 +1,29 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const tableName = `-- name: TableName :one +SELECT foo.id +FROM foo +JOIN bar ON foo.bar = bar.id +WHERE bar.id = ? AND foo.id = ? +` + +type TableNameParams struct { + ID int32 + ID_2 int32 +} + +func (q *Queries) TableName(ctx context.Context, arg TableNameParams) (int32, error) { + row := q.db.QueryRowContext(ctx, tableName, arg.ID, arg.ID_2) + var id int32 + err := row.Scan(&id) + return id, err +} diff --git a/internal/endtoend/testdata/join_table_name/mysql/query.sql b/internal/endtoend/testdata/join_table_name/mysql/query.sql new file mode 100644 index 0000000..8af0c45 --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/mysql/query.sql @@ -0,0 +1,5 @@ +-- name: TableName :one +SELECT foo.id +FROM foo +JOIN bar ON foo.bar = bar.id +WHERE bar.id = ? AND foo.id = ?; diff --git a/internal/endtoend/testdata/join_table_name/mysql/schema.sql b/internal/endtoend/testdata/join_table_name/mysql/schema.sql new file mode 100644 index 0000000..f54c3b4 --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/mysql/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE bar ( + id integer not null, + UNIQUE (id) +); + +CREATE TABLE foo (id integer not null, bar integer references bar(id)); + diff --git a/internal/endtoend/testdata/join_table_name/mysql/sqlc.json b/internal/endtoend/testdata/join_table_name/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/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/join_table_name/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/join_table_name/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/join_table_name/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/join_table_name/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..b72efbb --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/postgresql/pgx/v4/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ID int32 +} + +type Foo struct { + ID int32 + Bar sql.NullInt32 +} diff --git a/internal/endtoend/testdata/join_table_name/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/join_table_name/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..975f2be --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,29 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const tableName = `-- name: TableName :one +SELECT foo.id +FROM foo +JOIN bar ON foo.bar = bar.id +WHERE bar.id = $1 AND foo.id = $2 +` + +type TableNameParams struct { + ID int32 + ID_2 int32 +} + +func (q *Queries) TableName(ctx context.Context, arg TableNameParams) (int32, error) { + row := q.db.QueryRow(ctx, tableName, arg.ID, arg.ID_2) + var id int32 + err := row.Scan(&id) + return id, err +} diff --git a/internal/endtoend/testdata/join_table_name/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/join_table_name/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..3d11146 --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/postgresql/pgx/v4/query.sql @@ -0,0 +1,5 @@ +-- name: TableName :one +SELECT foo.id +FROM foo +JOIN bar ON foo.bar = bar.id +WHERE bar.id = $1 AND foo.id = $2; diff --git a/internal/endtoend/testdata/join_table_name/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/join_table_name/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..44c9874 --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/postgresql/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE bar (id serial not null); +CREATE TABLE foo (id serial not null, bar serial); + diff --git a/internal/endtoend/testdata/join_table_name/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/join_table_name/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/join_table_name/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/join_table_name/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/join_table_name/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/join_table_name/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..977ceaa --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/postgresql/pgx/v5/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Bar struct { + ID int32 +} + +type Foo struct { + ID int32 + Bar pgtype.Int4 +} diff --git a/internal/endtoend/testdata/join_table_name/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/join_table_name/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..975f2be --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,29 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const tableName = `-- name: TableName :one +SELECT foo.id +FROM foo +JOIN bar ON foo.bar = bar.id +WHERE bar.id = $1 AND foo.id = $2 +` + +type TableNameParams struct { + ID int32 + ID_2 int32 +} + +func (q *Queries) TableName(ctx context.Context, arg TableNameParams) (int32, error) { + row := q.db.QueryRow(ctx, tableName, arg.ID, arg.ID_2) + var id int32 + err := row.Scan(&id) + return id, err +} diff --git a/internal/endtoend/testdata/join_table_name/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/join_table_name/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..3d11146 --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/postgresql/pgx/v5/query.sql @@ -0,0 +1,5 @@ +-- name: TableName :one +SELECT foo.id +FROM foo +JOIN bar ON foo.bar = bar.id +WHERE bar.id = $1 AND foo.id = $2; diff --git a/internal/endtoend/testdata/join_table_name/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/join_table_name/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..44c9874 --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/postgresql/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE bar (id serial not null); +CREATE TABLE foo (id serial not null, bar serial); + diff --git a/internal/endtoend/testdata/join_table_name/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/join_table_name/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/join_table_name/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/join_table_name/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_table_name/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/join_table_name/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..b72efbb --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/postgresql/stdlib/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ID int32 +} + +type Foo struct { + ID int32 + Bar sql.NullInt32 +} diff --git a/internal/endtoend/testdata/join_table_name/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/join_table_name/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..6dfba96 --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,29 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const tableName = `-- name: TableName :one +SELECT foo.id +FROM foo +JOIN bar ON foo.bar = bar.id +WHERE bar.id = $1 AND foo.id = $2 +` + +type TableNameParams struct { + ID int32 + ID_2 int32 +} + +func (q *Queries) TableName(ctx context.Context, arg TableNameParams) (int32, error) { + row := q.db.QueryRowContext(ctx, tableName, arg.ID, arg.ID_2) + var id int32 + err := row.Scan(&id) + return id, err +} diff --git a/internal/endtoend/testdata/join_table_name/postgresql/stdlib/query.sql b/internal/endtoend/testdata/join_table_name/postgresql/stdlib/query.sql new file mode 100644 index 0000000..3d11146 --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/postgresql/stdlib/query.sql @@ -0,0 +1,5 @@ +-- name: TableName :one +SELECT foo.id +FROM foo +JOIN bar ON foo.bar = bar.id +WHERE bar.id = $1 AND foo.id = $2; diff --git a/internal/endtoend/testdata/join_table_name/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/join_table_name/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..44c9874 --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/postgresql/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE bar (id serial not null); +CREATE TABLE foo (id serial not null, bar serial); + diff --git a/internal/endtoend/testdata/join_table_name/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/join_table_name/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/join_table_name/sqlite/go/db.go b/internal/endtoend/testdata/join_table_name/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_table_name/sqlite/go/models.go b/internal/endtoend/testdata/join_table_name/sqlite/go/models.go new file mode 100644 index 0000000..f9b758f --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/sqlite/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ID int64 +} + +type Foo struct { + ID int64 + Bar sql.NullInt64 +} diff --git a/internal/endtoend/testdata/join_table_name/sqlite/go/query.sql.go b/internal/endtoend/testdata/join_table_name/sqlite/go/query.sql.go new file mode 100644 index 0000000..2e36481 --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/sqlite/go/query.sql.go @@ -0,0 +1,29 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const tableName = `-- name: TableName :one +SELECT foo.id +FROM foo +JOIN bar ON foo.bar = bar.id +WHERE bar.id = ? AND foo.id = ? +` + +type TableNameParams struct { + ID int64 + ID_2 int64 +} + +func (q *Queries) TableName(ctx context.Context, arg TableNameParams) (int64, error) { + row := q.db.QueryRowContext(ctx, tableName, arg.ID, arg.ID_2) + var id int64 + err := row.Scan(&id) + return id, err +} diff --git a/internal/endtoend/testdata/join_table_name/sqlite/query.sql b/internal/endtoend/testdata/join_table_name/sqlite/query.sql new file mode 100644 index 0000000..8af0c45 --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/sqlite/query.sql @@ -0,0 +1,5 @@ +-- name: TableName :one +SELECT foo.id +FROM foo +JOIN bar ON foo.bar = bar.id +WHERE bar.id = ? AND foo.id = ?; diff --git a/internal/endtoend/testdata/join_table_name/sqlite/schema.sql b/internal/endtoend/testdata/join_table_name/sqlite/schema.sql new file mode 100644 index 0000000..fe600c9 --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/sqlite/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE bar (id integer not null); +CREATE TABLE foo (id integer not null, bar integer references bar(id)); + diff --git a/internal/endtoend/testdata/join_table_name/sqlite/sqlc.json b/internal/endtoend/testdata/join_table_name/sqlite/sqlc.json new file mode 100644 index 0000000..d4963e7 --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/join_two_tables/mysql/go/db.go b/internal/endtoend/testdata/join_two_tables/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_two_tables/mysql/go/models.go b/internal/endtoend/testdata/join_two_tables/mysql/go/models.go new file mode 100644 index 0000000..500b6e8 --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/mysql/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID uint64 +} + +type Baz struct { + ID uint64 +} + +type Foo struct { + BarID uint64 + BazID int32 +} diff --git a/internal/endtoend/testdata/join_two_tables/mysql/go/query.sql.go b/internal/endtoend/testdata/join_two_tables/mysql/go/query.sql.go new file mode 100644 index 0000000..2176a91 --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/mysql/go/query.sql.go @@ -0,0 +1,40 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const twoJoins = `-- name: TwoJoins :many +SELECT foo.bar_id, foo.baz_id +FROM foo +JOIN bar ON bar.id = bar_id +JOIN baz ON baz.id = baz_id +` + +func (q *Queries) TwoJoins(ctx context.Context) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, twoJoins) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.BarID, &i.BazID); 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/join_two_tables/mysql/query.sql b/internal/endtoend/testdata/join_two_tables/mysql/query.sql new file mode 100644 index 0000000..f38154c --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/mysql/query.sql @@ -0,0 +1,5 @@ +-- name: TwoJoins :many +SELECT foo.* +FROM foo +JOIN bar ON bar.id = bar_id +JOIN baz ON baz.id = baz_id; diff --git a/internal/endtoend/testdata/join_two_tables/mysql/schema.sql b/internal/endtoend/testdata/join_two_tables/mysql/schema.sql new file mode 100644 index 0000000..d8b5e50 --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/mysql/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE foo (bar_id serial not null, baz_id integer not null); +CREATE TABLE bar (id serial not null); +CREATE TABLE baz (id serial not null); + diff --git a/internal/endtoend/testdata/join_two_tables/mysql/sqlc.json b/internal/endtoend/testdata/join_two_tables/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/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/join_two_tables/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/join_two_tables/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..bb768ad --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v4/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} + +type Baz struct { + ID int32 +} + +type Foo struct { + BarID int32 + BazID int32 +} diff --git a/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..e8875e1 --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const twoJoins = `-- name: TwoJoins :many +SELECT foo.bar_id, foo.baz_id +FROM foo +JOIN bar ON bar.id = bar_id +JOIN baz ON baz.id = baz_id +` + +func (q *Queries) TwoJoins(ctx context.Context) ([]Foo, error) { + rows, err := q.db.Query(ctx, twoJoins) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.BarID, &i.BazID); 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/join_two_tables/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..f38154c --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v4/query.sql @@ -0,0 +1,5 @@ +-- name: TwoJoins :many +SELECT foo.* +FROM foo +JOIN bar ON bar.id = bar_id +JOIN baz ON baz.id = baz_id; diff --git a/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..86eb87a --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v4/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE foo (bar_id serial not null, baz_id serial not null); +CREATE TABLE bar (id serial not null); +CREATE TABLE baz (id serial not null); + diff --git a/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/join_two_tables/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..bb768ad --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v5/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} + +type Baz struct { + ID int32 +} + +type Foo struct { + BarID int32 + BazID int32 +} diff --git a/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..e8875e1 --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const twoJoins = `-- name: TwoJoins :many +SELECT foo.bar_id, foo.baz_id +FROM foo +JOIN bar ON bar.id = bar_id +JOIN baz ON baz.id = baz_id +` + +func (q *Queries) TwoJoins(ctx context.Context) ([]Foo, error) { + rows, err := q.db.Query(ctx, twoJoins) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.BarID, &i.BazID); 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/join_two_tables/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..f38154c --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v5/query.sql @@ -0,0 +1,5 @@ +-- name: TwoJoins :many +SELECT foo.* +FROM foo +JOIN bar ON bar.id = bar_id +JOIN baz ON baz.id = baz_id; diff --git a/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..86eb87a --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v5/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE foo (bar_id serial not null, baz_id serial not null); +CREATE TABLE bar (id serial not null); +CREATE TABLE baz (id serial not null); + diff --git a/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/join_two_tables/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/join_two_tables/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_two_tables/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/join_two_tables/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..bb768ad --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/postgresql/stdlib/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} + +type Baz struct { + ID int32 +} + +type Foo struct { + BarID int32 + BazID int32 +} diff --git a/internal/endtoend/testdata/join_two_tables/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/join_two_tables/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..2176a91 --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,40 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const twoJoins = `-- name: TwoJoins :many +SELECT foo.bar_id, foo.baz_id +FROM foo +JOIN bar ON bar.id = bar_id +JOIN baz ON baz.id = baz_id +` + +func (q *Queries) TwoJoins(ctx context.Context) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, twoJoins) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.BarID, &i.BazID); 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/join_two_tables/postgresql/stdlib/query.sql b/internal/endtoend/testdata/join_two_tables/postgresql/stdlib/query.sql new file mode 100644 index 0000000..f38154c --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/postgresql/stdlib/query.sql @@ -0,0 +1,5 @@ +-- name: TwoJoins :many +SELECT foo.* +FROM foo +JOIN bar ON bar.id = bar_id +JOIN baz ON baz.id = baz_id; diff --git a/internal/endtoend/testdata/join_two_tables/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/join_two_tables/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..86eb87a --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/postgresql/stdlib/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE foo (bar_id serial not null, baz_id serial not null); +CREATE TABLE bar (id serial not null); +CREATE TABLE baz (id serial not null); + diff --git a/internal/endtoend/testdata/join_two_tables/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/join_two_tables/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/join_two_tables/sqlite/go/db.go b/internal/endtoend/testdata/join_two_tables/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_two_tables/sqlite/go/models.go b/internal/endtoend/testdata/join_two_tables/sqlite/go/models.go new file mode 100644 index 0000000..fa387e2 --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/sqlite/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int64 +} + +type Baz struct { + ID int64 +} + +type Foo struct { + BarID int64 + BazID int64 +} diff --git a/internal/endtoend/testdata/join_two_tables/sqlite/go/query.sql.go b/internal/endtoend/testdata/join_two_tables/sqlite/go/query.sql.go new file mode 100644 index 0000000..2176a91 --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/sqlite/go/query.sql.go @@ -0,0 +1,40 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const twoJoins = `-- name: TwoJoins :many +SELECT foo.bar_id, foo.baz_id +FROM foo +JOIN bar ON bar.id = bar_id +JOIN baz ON baz.id = baz_id +` + +func (q *Queries) TwoJoins(ctx context.Context) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, twoJoins) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.BarID, &i.BazID); 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/join_two_tables/sqlite/query.sql b/internal/endtoend/testdata/join_two_tables/sqlite/query.sql new file mode 100644 index 0000000..f38154c --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/sqlite/query.sql @@ -0,0 +1,5 @@ +-- name: TwoJoins :many +SELECT foo.* +FROM foo +JOIN bar ON bar.id = bar_id +JOIN baz ON baz.id = baz_id; diff --git a/internal/endtoend/testdata/join_two_tables/sqlite/schema.sql b/internal/endtoend/testdata/join_two_tables/sqlite/schema.sql new file mode 100644 index 0000000..381a084 --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/sqlite/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE foo (bar_id integer not null, baz_id integer not null); +CREATE TABLE bar (id integer not null); +CREATE TABLE baz (id integer not null); + diff --git a/internal/endtoend/testdata/join_two_tables/sqlite/sqlc.json b/internal/endtoend/testdata/join_two_tables/sqlite/sqlc.json new file mode 100644 index 0000000..d4963e7 --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/join_update/issue.md b/internal/endtoend/testdata/join_update/issue.md new file mode 100644 index 0000000..2b95748 --- /dev/null +++ b/internal/endtoend/testdata/join_update/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1100 diff --git a/internal/endtoend/testdata/join_update/postgresql/pgx/go/db.go b/internal/endtoend/testdata/join_update/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/join_update/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/join_update/postgresql/pgx/go/models.go b/internal/endtoend/testdata/join_update/postgresql/pgx/go/models.go new file mode 100644 index 0000000..40ddb24 --- /dev/null +++ b/internal/endtoend/testdata/join_update/postgresql/pgx/go/models.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type GroupCalcTotal struct { + Npn pgtype.Text + GroupID pgtype.Text +} + +type NpnExternalMap struct { + ID pgtype.Text + Npn pgtype.Text +} + +type ProducerGroupAttribute struct { + NpnExternalMapID pgtype.Text + GroupID pgtype.Text +} diff --git a/internal/endtoend/testdata/join_update/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/join_update/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..1c68a22 --- /dev/null +++ b/internal/endtoend/testdata/join_update/postgresql/pgx/go/query.sql.go @@ -0,0 +1,23 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const percentile = `-- name: Percentile :exec +UPDATE group_calc_totals gct +SET npn = nem.npn +FROM producer_group_attribute ga +JOIN npn_external_map nem ON ga.npn_external_map_id = nem.id +WHERE gct.group_id = ga.group_id +` + +func (q *Queries) Percentile(ctx context.Context) error { + _, err := q.db.Exec(ctx, percentile) + return err +} diff --git a/internal/endtoend/testdata/join_update/postgresql/pgx/query.sql b/internal/endtoend/testdata/join_update/postgresql/pgx/query.sql new file mode 100644 index 0000000..7765170 --- /dev/null +++ b/internal/endtoend/testdata/join_update/postgresql/pgx/query.sql @@ -0,0 +1,6 @@ +-- name: Percentile :exec +UPDATE group_calc_totals gct +SET npn = nem.npn +FROM producer_group_attribute ga +JOIN npn_external_map nem ON ga.npn_external_map_id = nem.id +WHERE gct.group_id = ga.group_id; diff --git a/internal/endtoend/testdata/join_update/postgresql/pgx/schema.sql b/internal/endtoend/testdata/join_update/postgresql/pgx/schema.sql new file mode 100644 index 0000000..c91a086 --- /dev/null +++ b/internal/endtoend/testdata/join_update/postgresql/pgx/schema.sql @@ -0,0 +1,14 @@ +CREATE TABLE group_calc_totals ( + npn text, + group_id text +); + +CREATE TABLE producer_group_attribute ( + npn_external_map_id text, + group_id text +); + +CREATE TABLE npn_external_map ( + id text, + npn text +); diff --git a/internal/endtoend/testdata/join_update/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/join_update/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/join_update/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/join_using/issue.md b/internal/endtoend/testdata/join_using/issue.md new file mode 100644 index 0000000..29861d9 --- /dev/null +++ b/internal/endtoend/testdata/join_using/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1425 diff --git a/internal/endtoend/testdata/join_using/postgresql/pgx/exec.json b/internal/endtoend/testdata/join_using/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/join_using/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/join_using/postgresql/pgx/go/db.go b/internal/endtoend/testdata/join_using/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/join_using/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/join_using/postgresql/pgx/go/models.go b/internal/endtoend/testdata/join_using/postgresql/pgx/go/models.go new file mode 100644 index 0000000..1ab7501 --- /dev/null +++ b/internal/endtoend/testdata/join_using/postgresql/pgx/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type T1 struct { + Fk int32 +} + +type T2 struct { + Fk int32 +} diff --git a/internal/endtoend/testdata/join_using/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/join_using/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..132e955 --- /dev/null +++ b/internal/endtoend/testdata/join_using/postgresql/pgx/go/query.sql.go @@ -0,0 +1,41 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const selectJoinUsing = `-- name: SelectJoinUsing :many +select t1.fk, sum(t2.fk) from t1 join t2 using (fk) group by fk +` + +type SelectJoinUsingRow struct { + Fk int32 + Sum pgtype.Int8 +} + +func (q *Queries) SelectJoinUsing(ctx context.Context) ([]SelectJoinUsingRow, error) { + rows, err := q.db.Query(ctx, selectJoinUsing) + if err != nil { + return nil, err + } + defer rows.Close() + var items []SelectJoinUsingRow + for rows.Next() { + var i SelectJoinUsingRow + if err := rows.Scan(&i.Fk, &i.Sum); 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/join_using/postgresql/pgx/query.sql b/internal/endtoend/testdata/join_using/postgresql/pgx/query.sql new file mode 100644 index 0000000..67a732e --- /dev/null +++ b/internal/endtoend/testdata/join_using/postgresql/pgx/query.sql @@ -0,0 +1,2 @@ +-- name: SelectJoinUsing :many +select t1.fk, sum(t2.fk) from t1 join t2 using (fk) group by fk; diff --git a/internal/endtoend/testdata/join_using/postgresql/pgx/schema.sql b/internal/endtoend/testdata/join_using/postgresql/pgx/schema.sql new file mode 100644 index 0000000..1e7b5a8 --- /dev/null +++ b/internal/endtoend/testdata/join_using/postgresql/pgx/schema.sql @@ -0,0 +1,6 @@ +create table t1 ( + fk integer not null unique +); +create table t2 ( + fk integer not null references t1(fk) +); diff --git a/internal/endtoend/testdata/join_using/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/join_using/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/join_using/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/join_validate_columns/issue.md b/internal/endtoend/testdata/join_validate_columns/issue.md new file mode 100644 index 0000000..0050218 --- /dev/null +++ b/internal/endtoend/testdata/join_validate_columns/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1239 \ No newline at end of file diff --git a/internal/endtoend/testdata/join_validate_columns/postgresql/pgx/exec.json b/internal/endtoend/testdata/join_validate_columns/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/join_validate_columns/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/join_validate_columns/postgresql/pgx/query.sql b/internal/endtoend/testdata/join_validate_columns/postgresql/pgx/query.sql new file mode 100644 index 0000000..8fe51af --- /dev/null +++ b/internal/endtoend/testdata/join_validate_columns/postgresql/pgx/query.sql @@ -0,0 +1,2 @@ +-- name: ListAuthors :many +SELECT * FROM authors JOIN books ON authors.id = book.author_id1; \ No newline at end of file diff --git a/internal/endtoend/testdata/join_validate_columns/postgresql/pgx/schema.sql b/internal/endtoend/testdata/join_validate_columns/postgresql/pgx/schema.sql new file mode 100644 index 0000000..d322893 --- /dev/null +++ b/internal/endtoend/testdata/join_validate_columns/postgresql/pgx/schema.sql @@ -0,0 +1,10 @@ +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL +); + +CREATE TABLE books ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + author_id BIGSERIAL REFERENCES authors(id) +); \ No newline at end of file diff --git a/internal/endtoend/testdata/join_validate_columns/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/join_validate_columns/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/join_validate_columns/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/join_validate_columns/postgresql/pgx/stderr.txt b/internal/endtoend/testdata/join_validate_columns/postgresql/pgx/stderr.txt new file mode 100644 index 0000000..0dfd315 --- /dev/null +++ b/internal/endtoend/testdata/join_validate_columns/postgresql/pgx/stderr.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:2:65: missing FROM-clause entry for table "book" \ No newline at end of file diff --git a/internal/endtoend/testdata/join_where_clause/mysql/go/db.go b/internal/endtoend/testdata/join_where_clause/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_where_clause/mysql/go/models.go b/internal/endtoend/testdata/join_where_clause/mysql/go/models.go new file mode 100644 index 0000000..68e5019 --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/mysql/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID uint64 + Owner string +} + +type Foo struct { + Barid uint64 +} 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 new file mode 100644 index 0000000..cce2078 --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/mysql/go/query.sql.go @@ -0,0 +1,110 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const joinNoConstraints = `-- name: JoinNoConstraints :many +SELECT foo.barid +FROM foo +CROSS JOIN bar +WHERE bar.id = ? AND owner = ? +` + +type JoinNoConstraintsParams struct { + ID uint64 + Owner string +} + +func (q *Queries) JoinNoConstraints(ctx context.Context, arg JoinNoConstraintsParams) ([]uint64, error) { + rows, err := q.db.QueryContext(ctx, joinNoConstraints, 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 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 +JOIN bar ON bar.id = barid +WHERE owner = ? +` + +func (q *Queries) JoinWhereClause(ctx context.Context, owner string) ([]uint64, error) { + rows, err := q.db.QueryContext(ctx, joinWhereClause, 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 +} diff --git a/internal/endtoend/testdata/join_where_clause/mysql/query.sql b/internal/endtoend/testdata/join_where_clause/mysql/query.sql new file mode 100644 index 0000000..bdff39a --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/mysql/query.sql @@ -0,0 +1,17 @@ +-- name: JoinWhereClause :many +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 = ?; + +-- name: JoinNoConstraints :many +SELECT foo.* +FROM foo +CROSS JOIN bar +WHERE bar.id = ? AND owner = ?; diff --git a/internal/endtoend/testdata/join_where_clause/mysql/schema.sql b/internal/endtoend/testdata/join_where_clause/mysql/schema.sql new file mode 100644 index 0000000..10bbaec --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/mysql/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (barid serial not null); +CREATE TABLE bar (id serial not null, owner text not null); + diff --git a/internal/endtoend/testdata/join_where_clause/mysql/sqlc.json b/internal/endtoend/testdata/join_where_clause/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/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/join_where_clause/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/join_where_clause/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..5dda8f0 --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 + Owner string +} + +type Foo struct { + Barid int32 +} 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 new file mode 100644 index 0000000..9415c40 --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,101 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const joinNoConstraints = `-- name: JoinNoConstraints :many +SELECT foo.barid +FROM foo +CROSS JOIN bar +WHERE bar.id = $2 AND owner = $1 +` + +type JoinNoConstraintsParams struct { + Owner string + ID int32 +} + +func (q *Queries) JoinNoConstraints(ctx context.Context, arg JoinNoConstraintsParams) ([]int32, error) { + rows, err := q.db.Query(ctx, joinNoConstraints, 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 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 +JOIN bar ON bar.id = barid +WHERE owner = $1 +` + +func (q *Queries) JoinWhereClause(ctx context.Context, owner string) ([]int32, error) { + rows, err := q.db.Query(ctx, joinWhereClause, owner) + 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 +} 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 new file mode 100644 index 0000000..776cd41 --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/query.sql @@ -0,0 +1,17 @@ +-- name: JoinWhereClause :many +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; + +-- name: JoinNoConstraints :many +SELECT foo.* +FROM foo +CROSS JOIN bar +WHERE bar.id = $2 AND owner = $1; \ No newline at end of file diff --git a/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..10bbaec --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (barid serial not null); +CREATE TABLE bar (id serial not null, owner text not null); + diff --git a/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/join_where_clause/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..5dda8f0 --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 + Owner string +} + +type Foo struct { + Barid int32 +} 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 new file mode 100644 index 0000000..9415c40 --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,101 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const joinNoConstraints = `-- name: JoinNoConstraints :many +SELECT foo.barid +FROM foo +CROSS JOIN bar +WHERE bar.id = $2 AND owner = $1 +` + +type JoinNoConstraintsParams struct { + Owner string + ID int32 +} + +func (q *Queries) JoinNoConstraints(ctx context.Context, arg JoinNoConstraintsParams) ([]int32, error) { + rows, err := q.db.Query(ctx, joinNoConstraints, 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 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 +JOIN bar ON bar.id = barid +WHERE owner = $1 +` + +func (q *Queries) JoinWhereClause(ctx context.Context, owner string) ([]int32, error) { + rows, err := q.db.Query(ctx, joinWhereClause, owner) + 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 +} 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 new file mode 100644 index 0000000..776cd41 --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/query.sql @@ -0,0 +1,17 @@ +-- name: JoinWhereClause :many +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; + +-- name: JoinNoConstraints :many +SELECT foo.* +FROM foo +CROSS JOIN bar +WHERE bar.id = $2 AND owner = $1; \ No newline at end of file diff --git a/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..10bbaec --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (barid serial not null); +CREATE TABLE bar (id serial not null, owner text not null); + diff --git a/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/join_where_clause/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/join_where_clause/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_where_clause/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/join_where_clause/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..5dda8f0 --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/postgresql/stdlib/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 + Owner string +} + +type Foo struct { + Barid int32 +} 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 new file mode 100644 index 0000000..a3d3265 --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,110 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const joinNoConstraints = `-- name: JoinNoConstraints :many +SELECT foo.barid +FROM foo +CROSS JOIN bar +WHERE bar.id = $2 AND owner = $1 +` + +type JoinNoConstraintsParams struct { + Owner string + ID int32 +} + +func (q *Queries) JoinNoConstraints(ctx context.Context, arg JoinNoConstraintsParams) ([]int32, error) { + rows, err := q.db.QueryContext(ctx, joinNoConstraints, 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 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 +JOIN bar ON bar.id = barid +WHERE owner = $1 +` + +func (q *Queries) JoinWhereClause(ctx context.Context, owner string) ([]int32, error) { + rows, err := q.db.QueryContext(ctx, joinWhereClause, owner) + 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 +} diff --git a/internal/endtoend/testdata/join_where_clause/postgresql/stdlib/query.sql b/internal/endtoend/testdata/join_where_clause/postgresql/stdlib/query.sql new file mode 100644 index 0000000..776cd41 --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/postgresql/stdlib/query.sql @@ -0,0 +1,17 @@ +-- name: JoinWhereClause :many +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; + +-- name: JoinNoConstraints :many +SELECT foo.* +FROM foo +CROSS JOIN bar +WHERE bar.id = $2 AND owner = $1; \ No newline at end of file diff --git a/internal/endtoend/testdata/join_where_clause/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/join_where_clause/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..10bbaec --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/postgresql/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (barid serial not null); +CREATE TABLE bar (id serial not null, owner text not null); + diff --git a/internal/endtoend/testdata/join_where_clause/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/join_where_clause/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/join_where_clause/sqlite/go/db.go b/internal/endtoend/testdata/join_where_clause/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/join_where_clause/sqlite/go/models.go b/internal/endtoend/testdata/join_where_clause/sqlite/go/models.go new file mode 100644 index 0000000..2abca21 --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/sqlite/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int64 + Owner string +} + +type Foo struct { + Barid int64 +} 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 new file mode 100644 index 0000000..8451dbb --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/sqlite/go/query.sql.go @@ -0,0 +1,110 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const joinNoConstraints = `-- name: JoinNoConstraints :many +SELECT foo.barid +FROM foo +CROSS JOIN bar +WHERE bar.id = ? AND owner = ? +` + +type JoinNoConstraintsParams struct { + ID int64 + Owner string +} + +func (q *Queries) JoinNoConstraints(ctx context.Context, arg JoinNoConstraintsParams) ([]int64, error) { + rows, err := q.db.QueryContext(ctx, joinNoConstraints, 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 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 +JOIN bar ON bar.id = barid +WHERE owner = ? +` + +func (q *Queries) JoinWhereClause(ctx context.Context, owner string) ([]int64, error) { + rows, err := q.db.QueryContext(ctx, joinWhereClause, 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 +} diff --git a/internal/endtoend/testdata/join_where_clause/sqlite/query.sql b/internal/endtoend/testdata/join_where_clause/sqlite/query.sql new file mode 100644 index 0000000..bdff39a --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/sqlite/query.sql @@ -0,0 +1,17 @@ +-- name: JoinWhereClause :many +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 = ?; + +-- name: JoinNoConstraints :many +SELECT foo.* +FROM foo +CROSS JOIN bar +WHERE bar.id = ? AND owner = ?; diff --git a/internal/endtoend/testdata/join_where_clause/sqlite/schema.sql b/internal/endtoend/testdata/join_where_clause/sqlite/schema.sql new file mode 100644 index 0000000..e2e8f9d --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/sqlite/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (barid integer not null); +CREATE TABLE bar (id integer not null, owner text not null); + diff --git a/internal/endtoend/testdata/join_where_clause/sqlite/sqlc.json b/internal/endtoend/testdata/join_where_clause/sqlite/sqlc.json new file mode 100644 index 0000000..d4963e7 --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/json/mysql/go/copyfrom.go b/internal/endtoend/testdata/json/mysql/go/copyfrom.go new file mode 100644 index 0000000..c2989e4 --- /dev/null +++ b/internal/endtoend/testdata/json/mysql/go/copyfrom.go @@ -0,0 +1,51 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: copyfrom.go + +package querytest + +import ( + "context" + "fmt" + "io" + "sync/atomic" + + "github.com/go-sql-driver/mysql" + "github.com/hexon/mysqltsv" +) + +var readerHandlerSequenceForBulkInsert uint32 = 1 + +func convertRowsForBulkInsert(w *io.PipeWriter, arg []BulkInsertParams) { + e := mysqltsv.NewEncoder(w, 2, nil) + for _, row := range arg { + e.AppendBytes(row.A) + e.AppendBytes(row.B) + } + w.CloseWithError(e.Close()) +} + +// BulkInsert uses MySQL's LOAD DATA LOCAL INFILE and is not atomic. +// +// Errors and duplicate keys are treated as warnings and insertion will +// continue, even without an error for some cases. Use this in a transaction +// and use SHOW WARNINGS to check for any problems and roll back if you want to. +// +// Check the documentation for more information: +// https://dev.mysql.com/doc/refman/8.0/en/load-data.html#load-data-error-handling +func (q *Queries) BulkInsert(ctx context.Context, arg []BulkInsertParams) (int64, error) { + pr, pw := io.Pipe() + defer pr.Close() + rh := fmt.Sprintf("BulkInsert_%d", atomic.AddUint32(&readerHandlerSequenceForBulkInsert, 1)) + mysql.RegisterReaderHandler(rh, func() io.Reader { return pr }) + defer mysql.DeregisterReaderHandler(rh) + go convertRowsForBulkInsert(pw, arg) + // The string interpolation is necessary because LOAD DATA INFILE requires + // the file name to be given as a literal string. + result, err := q.db.ExecContext(ctx, fmt.Sprintf("LOAD DATA LOCAL INFILE '%s' INTO TABLE `foo` %s (a, b)", "Reader::"+rh, mysqltsv.Escaping)) + if err != nil { + return 0, err + } + return result.RowsAffected() +} diff --git a/internal/endtoend/testdata/json/mysql/go/db.go b/internal/endtoend/testdata/json/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/json/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/json/mysql/go/models.go b/internal/endtoend/testdata/json/mysql/go/models.go new file mode 100644 index 0000000..a82d576 --- /dev/null +++ b/internal/endtoend/testdata/json/mysql/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "encoding/json" +) + +type Foo struct { + A json.RawMessage + B json.RawMessage +} diff --git a/internal/endtoend/testdata/json/mysql/go/query.sql.go b/internal/endtoend/testdata/json/mysql/go/query.sql.go new file mode 100644 index 0000000..f65e680 --- /dev/null +++ b/internal/endtoend/testdata/json/mysql/go/query.sql.go @@ -0,0 +1,29 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "encoding/json" +) + +const bulkInsert = `-- name: BulkInsert :copyfrom +INSERT INTO foo (a, b) VALUES (?, ?) +` + +type BulkInsertParams struct { + A json.RawMessage + B json.RawMessage +} + +const selectFoo = `-- name: SelectFoo :exec +SELECT a, b FROM foo +` + +func (q *Queries) SelectFoo(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, selectFoo) + return err +} diff --git a/internal/endtoend/testdata/json/mysql/query.sql b/internal/endtoend/testdata/json/mysql/query.sql new file mode 100644 index 0000000..927e597 --- /dev/null +++ b/internal/endtoend/testdata/json/mysql/query.sql @@ -0,0 +1,5 @@ +-- name: SelectFoo :exec +SELECT * FROM foo; + +-- name: BulkInsert :copyfrom +INSERT INTO foo (a, b) VALUES (?, ?); diff --git a/internal/endtoend/testdata/json/mysql/schema.sql b/internal/endtoend/testdata/json/mysql/schema.sql new file mode 100644 index 0000000..8f3d639 --- /dev/null +++ b/internal/endtoend/testdata/json/mysql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE foo ( + a json not null, + b json +); + diff --git a/internal/endtoend/testdata/json/mysql/sqlc.json b/internal/endtoend/testdata/json/mysql/sqlc.json new file mode 100644 index 0000000..b1127e2 --- /dev/null +++ b/internal/endtoend/testdata/json/mysql/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "mysql", + "sql_driver": "github.com/go-sql-driver/mysql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/json/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/json/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/json/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/json/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/json/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..1387f53 --- /dev/null +++ b/internal/endtoend/testdata/json/postgresql/pgx/v4/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgtype" +) + +type Foo struct { + A pgtype.JSON + B pgtype.JSONB + C pgtype.JSON + D pgtype.JSONB +} diff --git a/internal/endtoend/testdata/json/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/json/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..76286c2 --- /dev/null +++ b/internal/endtoend/testdata/json/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const selectFoo = `-- name: SelectFoo :exec +SELECT a, b, c, d FROM foo +` + +func (q *Queries) SelectFoo(ctx context.Context) error { + _, err := q.db.Exec(ctx, selectFoo) + return err +} diff --git a/internal/endtoend/testdata/json/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/json/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..a8629cc --- /dev/null +++ b/internal/endtoend/testdata/json/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: SelectFoo :exec +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/json/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/json/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..6b4a1bb --- /dev/null +++ b/internal/endtoend/testdata/json/postgresql/pgx/v4/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE foo ( + a json not null, + b jsonb not null, + c json, + d jsonb +); + diff --git a/internal/endtoend/testdata/json/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/json/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/json/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/json/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/json/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/json/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/json/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/json/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..9d668a2 --- /dev/null +++ b/internal/endtoend/testdata/json/postgresql/pgx/v5/go/models.go @@ -0,0 +1,12 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + A []byte + B []byte + C []byte + D []byte +} diff --git a/internal/endtoend/testdata/json/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/json/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..76286c2 --- /dev/null +++ b/internal/endtoend/testdata/json/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const selectFoo = `-- name: SelectFoo :exec +SELECT a, b, c, d FROM foo +` + +func (q *Queries) SelectFoo(ctx context.Context) error { + _, err := q.db.Exec(ctx, selectFoo) + return err +} diff --git a/internal/endtoend/testdata/json/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/json/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..a8629cc --- /dev/null +++ b/internal/endtoend/testdata/json/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: SelectFoo :exec +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/json/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/json/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..6b4a1bb --- /dev/null +++ b/internal/endtoend/testdata/json/postgresql/pgx/v5/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE foo ( + a json not null, + b jsonb not null, + c json, + d jsonb +); + diff --git a/internal/endtoend/testdata/json/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/json/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/json/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/json/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/json/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/json/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/json/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/json/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..c638776 --- /dev/null +++ b/internal/endtoend/testdata/json/postgresql/stdlib/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "encoding/json" + + "github.com/sqlc-dev/pqtype" +) + +type Foo struct { + A json.RawMessage + B json.RawMessage + C pqtype.NullRawMessage + D pqtype.NullRawMessage +} diff --git a/internal/endtoend/testdata/json/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/json/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..b57ef45 --- /dev/null +++ b/internal/endtoend/testdata/json/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const selectFoo = `-- name: SelectFoo :exec +SELECT a, b, c, d FROM foo +` + +func (q *Queries) SelectFoo(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, selectFoo) + return err +} diff --git a/internal/endtoend/testdata/json/postgresql/stdlib/query.sql b/internal/endtoend/testdata/json/postgresql/stdlib/query.sql new file mode 100644 index 0000000..a8629cc --- /dev/null +++ b/internal/endtoend/testdata/json/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: SelectFoo :exec +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/json/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/json/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..6b4a1bb --- /dev/null +++ b/internal/endtoend/testdata/json/postgresql/stdlib/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE foo ( + a json not null, + b jsonb not null, + c json, + d jsonb +); + diff --git a/internal/endtoend/testdata/json/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/json/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/json/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/json_array_elements/issue.md b/internal/endtoend/testdata/json_array_elements/issue.md new file mode 100644 index 0000000..d33962b --- /dev/null +++ b/internal/endtoend/testdata/json_array_elements/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/2731 diff --git a/internal/endtoend/testdata/json_array_elements/postgresql/pgx/exec.json b/internal/endtoend/testdata/json_array_elements/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/json_array_elements/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/json_array_elements/postgresql/pgx/go/db.go b/internal/endtoend/testdata/json_array_elements/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/json_array_elements/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/json_array_elements/postgresql/pgx/go/models.go b/internal/endtoend/testdata/json_array_elements/postgresql/pgx/go/models.go new file mode 100644 index 0000000..2c2f3e5 --- /dev/null +++ b/internal/endtoend/testdata/json_array_elements/postgresql/pgx/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type SysAction struct { + ID int64 + Code string + Menu string + Title string + Resources []byte +} diff --git a/internal/endtoend/testdata/json_array_elements/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/json_array_elements/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..7ccbdce --- /dev/null +++ b/internal/endtoend/testdata/json_array_elements/postgresql/pgx/go/query.sql.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const getActionCodeByResource = `-- name: GetActionCodeByResource :one +SELECT code, arr.item_object ->> 'code' as resource_code +FROM sys_actions, + jsonb_array_elements(resources) with ordinality arr(item_object, resource) + WHERE item_object->>'resource' = $1 + LIMIT 1 +` + +type GetActionCodeByResourceRow struct { + Code string + ResourceCode pgtype.Text +} + +func (q *Queries) GetActionCodeByResource(ctx context.Context, resource pgtype.Text) (GetActionCodeByResourceRow, error) { + row := q.db.QueryRow(ctx, getActionCodeByResource, resource) + var i GetActionCodeByResourceRow + err := row.Scan(&i.Code, &i.ResourceCode) + return i, err +} diff --git a/internal/endtoend/testdata/json_array_elements/postgresql/pgx/query.sql b/internal/endtoend/testdata/json_array_elements/postgresql/pgx/query.sql new file mode 100644 index 0000000..44fe758 --- /dev/null +++ b/internal/endtoend/testdata/json_array_elements/postgresql/pgx/query.sql @@ -0,0 +1,6 @@ +-- name: GetActionCodeByResource :one +SELECT code, arr.item_object ->> 'code' as resource_code +FROM sys_actions, + jsonb_array_elements(resources) with ordinality arr(item_object, resource) + WHERE item_object->>'resource' = sqlc.arg('resource') + LIMIT 1; diff --git a/internal/endtoend/testdata/json_array_elements/postgresql/pgx/schema.sql b/internal/endtoend/testdata/json_array_elements/postgresql/pgx/schema.sql new file mode 100644 index 0000000..b10a6c1 --- /dev/null +++ b/internal/endtoend/testdata/json_array_elements/postgresql/pgx/schema.sql @@ -0,0 +1,8 @@ +CREATE TABLE "sys_actions" ( + "id" int8 NOT NULL, + "code" varchar(20) NOT NULL, + "menu" varchar(255) NOT NULL, + "title" varchar(20) NOT NULL, + "resources" jsonb, + PRIMARY KEY ("id") +); diff --git a/internal/endtoend/testdata/json_array_elements/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/json_array_elements/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/json_array_elements/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/json_build/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/json_build/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/json_build/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/json_build/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/json_build/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/json_build/postgresql/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/json_build/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/json_build/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..667f9de --- /dev/null +++ b/internal/endtoend/testdata/json_build/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,132 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgtype" +) + +const selectJSONBBuildArray = `-- name: SelectJSONBBuildArray :one +SELECT + jsonb_build_array(), + jsonb_build_array(1), + jsonb_build_array(1, 2), + jsonb_build_array(1, 2, 'foo'), + jsonb_build_array(1, 2, 'foo', 4) +` + +type SelectJSONBBuildArrayRow struct { + JsonbBuildArray pgtype.JSONB + JsonbBuildArray_2 pgtype.JSONB + JsonbBuildArray_3 pgtype.JSONB + JsonbBuildArray_4 pgtype.JSONB + JsonbBuildArray_5 pgtype.JSONB +} + +func (q *Queries) SelectJSONBBuildArray(ctx context.Context) (SelectJSONBBuildArrayRow, error) { + row := q.db.QueryRow(ctx, selectJSONBBuildArray) + var i SelectJSONBBuildArrayRow + err := row.Scan( + &i.JsonbBuildArray, + &i.JsonbBuildArray_2, + &i.JsonbBuildArray_3, + &i.JsonbBuildArray_4, + &i.JsonbBuildArray_5, + ) + return i, err +} + +const selectJSONBBuildObject = `-- name: SelectJSONBBuildObject :one +SELECT + jsonb_build_object(), + jsonb_build_object('foo'), + jsonb_build_object('foo', 1), + jsonb_build_object('foo', 1, 2), + jsonb_build_object('foo', 1, 2, 'bar') +` + +type SelectJSONBBuildObjectRow struct { + JsonbBuildObject pgtype.JSONB + JsonbBuildObject_2 pgtype.JSONB + JsonbBuildObject_3 pgtype.JSONB + JsonbBuildObject_4 pgtype.JSONB + JsonbBuildObject_5 pgtype.JSONB +} + +func (q *Queries) SelectJSONBBuildObject(ctx context.Context) (SelectJSONBBuildObjectRow, error) { + row := q.db.QueryRow(ctx, selectJSONBBuildObject) + var i SelectJSONBBuildObjectRow + err := row.Scan( + &i.JsonbBuildObject, + &i.JsonbBuildObject_2, + &i.JsonbBuildObject_3, + &i.JsonbBuildObject_4, + &i.JsonbBuildObject_5, + ) + return i, err +} + +const selectJSONBuildArray = `-- name: SelectJSONBuildArray :one +SELECT + json_build_array(), + json_build_array(1), + json_build_array(1, 2), + json_build_array(1, 2, 'foo'), + json_build_array(1, 2, 'foo', 4) +` + +type SelectJSONBuildArrayRow struct { + JsonBuildArray pgtype.JSON + JsonBuildArray_2 pgtype.JSON + JsonBuildArray_3 pgtype.JSON + JsonBuildArray_4 pgtype.JSON + JsonBuildArray_5 pgtype.JSON +} + +func (q *Queries) SelectJSONBuildArray(ctx context.Context) (SelectJSONBuildArrayRow, error) { + row := q.db.QueryRow(ctx, selectJSONBuildArray) + var i SelectJSONBuildArrayRow + err := row.Scan( + &i.JsonBuildArray, + &i.JsonBuildArray_2, + &i.JsonBuildArray_3, + &i.JsonBuildArray_4, + &i.JsonBuildArray_5, + ) + return i, err +} + +const selectJSONBuildObject = `-- name: SelectJSONBuildObject :one +SELECT + json_build_object(), + json_build_object('foo'), + json_build_object('foo', 1), + json_build_object('foo', 1, 2), + json_build_object('foo', 1, 2, 'bar') +` + +type SelectJSONBuildObjectRow struct { + JsonBuildObject pgtype.JSON + JsonBuildObject_2 pgtype.JSON + JsonBuildObject_3 pgtype.JSON + JsonBuildObject_4 pgtype.JSON + JsonBuildObject_5 pgtype.JSON +} + +func (q *Queries) SelectJSONBuildObject(ctx context.Context) (SelectJSONBuildObjectRow, error) { + row := q.db.QueryRow(ctx, selectJSONBuildObject) + var i SelectJSONBuildObjectRow + err := row.Scan( + &i.JsonBuildObject, + &i.JsonBuildObject_2, + &i.JsonBuildObject_3, + &i.JsonBuildObject_4, + &i.JsonBuildObject_5, + ) + return i, err +} diff --git a/internal/endtoend/testdata/json_build/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/json_build/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..160eab5 --- /dev/null +++ b/internal/endtoend/testdata/json_build/postgresql/pgx/v4/query.sql @@ -0,0 +1,31 @@ +-- name: SelectJSONBuildObject :one +SELECT + json_build_object(), + json_build_object('foo'), + json_build_object('foo', 1), + json_build_object('foo', 1, 2), + json_build_object('foo', 1, 2, 'bar'); + +-- name: SelectJSONBuildArray :one +SELECT + json_build_array(), + json_build_array(1), + json_build_array(1, 2), + json_build_array(1, 2, 'foo'), + json_build_array(1, 2, 'foo', 4); + +-- name: SelectJSONBBuildObject :one +SELECT + jsonb_build_object(), + jsonb_build_object('foo'), + jsonb_build_object('foo', 1), + jsonb_build_object('foo', 1, 2), + jsonb_build_object('foo', 1, 2, 'bar'); + +-- name: SelectJSONBBuildArray :one +SELECT + jsonb_build_array(), + jsonb_build_array(1), + jsonb_build_array(1, 2), + jsonb_build_array(1, 2, 'foo'), + jsonb_build_array(1, 2, 'foo', 4); diff --git a/internal/endtoend/testdata/json_build/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/json_build/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/json_build/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/json_build/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/json_build/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/json_build/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/json_build/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/json_build/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/json_build/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/json_build/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/json_build/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/json_build/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/json_build/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..02daa76 --- /dev/null +++ b/internal/endtoend/testdata/json_build/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,130 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const selectJSONBBuildArray = `-- name: SelectJSONBBuildArray :one +SELECT + jsonb_build_array(), + jsonb_build_array(1), + jsonb_build_array(1, 2), + jsonb_build_array(1, 2, 'foo'), + jsonb_build_array(1, 2, 'foo', 4) +` + +type SelectJSONBBuildArrayRow struct { + JsonbBuildArray []byte + JsonbBuildArray_2 []byte + JsonbBuildArray_3 []byte + JsonbBuildArray_4 []byte + JsonbBuildArray_5 []byte +} + +func (q *Queries) SelectJSONBBuildArray(ctx context.Context) (SelectJSONBBuildArrayRow, error) { + row := q.db.QueryRow(ctx, selectJSONBBuildArray) + var i SelectJSONBBuildArrayRow + err := row.Scan( + &i.JsonbBuildArray, + &i.JsonbBuildArray_2, + &i.JsonbBuildArray_3, + &i.JsonbBuildArray_4, + &i.JsonbBuildArray_5, + ) + return i, err +} + +const selectJSONBBuildObject = `-- name: SelectJSONBBuildObject :one +SELECT + jsonb_build_object(), + jsonb_build_object('foo'), + jsonb_build_object('foo', 1), + jsonb_build_object('foo', 1, 2), + jsonb_build_object('foo', 1, 2, 'bar') +` + +type SelectJSONBBuildObjectRow struct { + JsonbBuildObject []byte + JsonbBuildObject_2 []byte + JsonbBuildObject_3 []byte + JsonbBuildObject_4 []byte + JsonbBuildObject_5 []byte +} + +func (q *Queries) SelectJSONBBuildObject(ctx context.Context) (SelectJSONBBuildObjectRow, error) { + row := q.db.QueryRow(ctx, selectJSONBBuildObject) + var i SelectJSONBBuildObjectRow + err := row.Scan( + &i.JsonbBuildObject, + &i.JsonbBuildObject_2, + &i.JsonbBuildObject_3, + &i.JsonbBuildObject_4, + &i.JsonbBuildObject_5, + ) + return i, err +} + +const selectJSONBuildArray = `-- name: SelectJSONBuildArray :one +SELECT + json_build_array(), + json_build_array(1), + json_build_array(1, 2), + json_build_array(1, 2, 'foo'), + json_build_array(1, 2, 'foo', 4) +` + +type SelectJSONBuildArrayRow struct { + JsonBuildArray []byte + JsonBuildArray_2 []byte + JsonBuildArray_3 []byte + JsonBuildArray_4 []byte + JsonBuildArray_5 []byte +} + +func (q *Queries) SelectJSONBuildArray(ctx context.Context) (SelectJSONBuildArrayRow, error) { + row := q.db.QueryRow(ctx, selectJSONBuildArray) + var i SelectJSONBuildArrayRow + err := row.Scan( + &i.JsonBuildArray, + &i.JsonBuildArray_2, + &i.JsonBuildArray_3, + &i.JsonBuildArray_4, + &i.JsonBuildArray_5, + ) + return i, err +} + +const selectJSONBuildObject = `-- name: SelectJSONBuildObject :one +SELECT + json_build_object(), + json_build_object('foo'), + json_build_object('foo', 1), + json_build_object('foo', 1, 2), + json_build_object('foo', 1, 2, 'bar') +` + +type SelectJSONBuildObjectRow struct { + JsonBuildObject []byte + JsonBuildObject_2 []byte + JsonBuildObject_3 []byte + JsonBuildObject_4 []byte + JsonBuildObject_5 []byte +} + +func (q *Queries) SelectJSONBuildObject(ctx context.Context) (SelectJSONBuildObjectRow, error) { + row := q.db.QueryRow(ctx, selectJSONBuildObject) + var i SelectJSONBuildObjectRow + err := row.Scan( + &i.JsonBuildObject, + &i.JsonBuildObject_2, + &i.JsonBuildObject_3, + &i.JsonBuildObject_4, + &i.JsonBuildObject_5, + ) + return i, err +} diff --git a/internal/endtoend/testdata/json_build/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/json_build/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..160eab5 --- /dev/null +++ b/internal/endtoend/testdata/json_build/postgresql/pgx/v5/query.sql @@ -0,0 +1,31 @@ +-- name: SelectJSONBuildObject :one +SELECT + json_build_object(), + json_build_object('foo'), + json_build_object('foo', 1), + json_build_object('foo', 1, 2), + json_build_object('foo', 1, 2, 'bar'); + +-- name: SelectJSONBuildArray :one +SELECT + json_build_array(), + json_build_array(1), + json_build_array(1, 2), + json_build_array(1, 2, 'foo'), + json_build_array(1, 2, 'foo', 4); + +-- name: SelectJSONBBuildObject :one +SELECT + jsonb_build_object(), + jsonb_build_object('foo'), + jsonb_build_object('foo', 1), + jsonb_build_object('foo', 1, 2), + jsonb_build_object('foo', 1, 2, 'bar'); + +-- name: SelectJSONBBuildArray :one +SELECT + jsonb_build_array(), + jsonb_build_array(1), + jsonb_build_array(1, 2), + jsonb_build_array(1, 2, 'foo'), + jsonb_build_array(1, 2, 'foo', 4); diff --git a/internal/endtoend/testdata/json_build/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/json_build/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/json_build/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/json_build/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/json_build/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/json_build/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/json_build/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/json_build/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/json_build/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/json_build/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/json_build/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/json_build/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/json_build/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..4aba355 --- /dev/null +++ b/internal/endtoend/testdata/json_build/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,131 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "encoding/json" +) + +const selectJSONBBuildArray = `-- name: SelectJSONBBuildArray :one +SELECT + jsonb_build_array(), + jsonb_build_array(1), + jsonb_build_array(1, 2), + jsonb_build_array(1, 2, 'foo'), + jsonb_build_array(1, 2, 'foo', 4) +` + +type SelectJSONBBuildArrayRow struct { + JsonbBuildArray json.RawMessage + JsonbBuildArray_2 json.RawMessage + JsonbBuildArray_3 json.RawMessage + JsonbBuildArray_4 json.RawMessage + JsonbBuildArray_5 json.RawMessage +} + +func (q *Queries) SelectJSONBBuildArray(ctx context.Context) (SelectJSONBBuildArrayRow, error) { + row := q.db.QueryRowContext(ctx, selectJSONBBuildArray) + var i SelectJSONBBuildArrayRow + err := row.Scan( + &i.JsonbBuildArray, + &i.JsonbBuildArray_2, + &i.JsonbBuildArray_3, + &i.JsonbBuildArray_4, + &i.JsonbBuildArray_5, + ) + return i, err +} + +const selectJSONBBuildObject = `-- name: SelectJSONBBuildObject :one +SELECT + jsonb_build_object(), + jsonb_build_object('foo'), + jsonb_build_object('foo', 1), + jsonb_build_object('foo', 1, 2), + jsonb_build_object('foo', 1, 2, 'bar') +` + +type SelectJSONBBuildObjectRow struct { + JsonbBuildObject json.RawMessage + JsonbBuildObject_2 json.RawMessage + JsonbBuildObject_3 json.RawMessage + JsonbBuildObject_4 json.RawMessage + JsonbBuildObject_5 json.RawMessage +} + +func (q *Queries) SelectJSONBBuildObject(ctx context.Context) (SelectJSONBBuildObjectRow, error) { + row := q.db.QueryRowContext(ctx, selectJSONBBuildObject) + var i SelectJSONBBuildObjectRow + err := row.Scan( + &i.JsonbBuildObject, + &i.JsonbBuildObject_2, + &i.JsonbBuildObject_3, + &i.JsonbBuildObject_4, + &i.JsonbBuildObject_5, + ) + return i, err +} + +const selectJSONBuildArray = `-- name: SelectJSONBuildArray :one +SELECT + json_build_array(), + json_build_array(1), + json_build_array(1, 2), + json_build_array(1, 2, 'foo'), + json_build_array(1, 2, 'foo', 4) +` + +type SelectJSONBuildArrayRow struct { + JsonBuildArray json.RawMessage + JsonBuildArray_2 json.RawMessage + JsonBuildArray_3 json.RawMessage + JsonBuildArray_4 json.RawMessage + JsonBuildArray_5 json.RawMessage +} + +func (q *Queries) SelectJSONBuildArray(ctx context.Context) (SelectJSONBuildArrayRow, error) { + row := q.db.QueryRowContext(ctx, selectJSONBuildArray) + var i SelectJSONBuildArrayRow + err := row.Scan( + &i.JsonBuildArray, + &i.JsonBuildArray_2, + &i.JsonBuildArray_3, + &i.JsonBuildArray_4, + &i.JsonBuildArray_5, + ) + return i, err +} + +const selectJSONBuildObject = `-- name: SelectJSONBuildObject :one +SELECT + json_build_object(), + json_build_object('foo'), + json_build_object('foo', 1), + json_build_object('foo', 1, 2), + json_build_object('foo', 1, 2, 'bar') +` + +type SelectJSONBuildObjectRow struct { + JsonBuildObject json.RawMessage + JsonBuildObject_2 json.RawMessage + JsonBuildObject_3 json.RawMessage + JsonBuildObject_4 json.RawMessage + JsonBuildObject_5 json.RawMessage +} + +func (q *Queries) SelectJSONBuildObject(ctx context.Context) (SelectJSONBuildObjectRow, error) { + row := q.db.QueryRowContext(ctx, selectJSONBuildObject) + var i SelectJSONBuildObjectRow + err := row.Scan( + &i.JsonBuildObject, + &i.JsonBuildObject_2, + &i.JsonBuildObject_3, + &i.JsonBuildObject_4, + &i.JsonBuildObject_5, + ) + return i, err +} diff --git a/internal/endtoend/testdata/json_build/postgresql/stdlib/query.sql b/internal/endtoend/testdata/json_build/postgresql/stdlib/query.sql new file mode 100644 index 0000000..160eab5 --- /dev/null +++ b/internal/endtoend/testdata/json_build/postgresql/stdlib/query.sql @@ -0,0 +1,31 @@ +-- name: SelectJSONBuildObject :one +SELECT + json_build_object(), + json_build_object('foo'), + json_build_object('foo', 1), + json_build_object('foo', 1, 2), + json_build_object('foo', 1, 2, 'bar'); + +-- name: SelectJSONBuildArray :one +SELECT + json_build_array(), + json_build_array(1), + json_build_array(1, 2), + json_build_array(1, 2, 'foo'), + json_build_array(1, 2, 'foo', 4); + +-- name: SelectJSONBBuildObject :one +SELECT + jsonb_build_object(), + jsonb_build_object('foo'), + jsonb_build_object('foo', 1), + jsonb_build_object('foo', 1, 2), + jsonb_build_object('foo', 1, 2, 'bar'); + +-- name: SelectJSONBBuildArray :one +SELECT + jsonb_build_array(), + jsonb_build_array(1), + jsonb_build_array(1, 2), + jsonb_build_array(1, 2, 'foo'), + jsonb_build_array(1, 2, 'foo', 4); diff --git a/internal/endtoend/testdata/json_build/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/json_build/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/json_build/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/json_build/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/json_build/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/json_param_type/issue.md b/internal/endtoend/testdata/json_param_type/issue.md new file mode 100644 index 0000000..a04d7da --- /dev/null +++ b/internal/endtoend/testdata/json_param_type/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/743 \ No newline at end of file diff --git a/internal/endtoend/testdata/json_param_type/postgresql/pgx/exec.json b/internal/endtoend/testdata/json_param_type/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/json_param_type/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/json_param_type/postgresql/pgx/go/db.go b/internal/endtoend/testdata/json_param_type/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/json_param_type/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/json_param_type/postgresql/pgx/go/models.go b/internal/endtoend/testdata/json_param_type/postgresql/pgx/go/models.go new file mode 100644 index 0000000..cebb98f --- /dev/null +++ b/internal/endtoend/testdata/json_param_type/postgresql/pgx/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type User struct { + ID int32 + Metadata []byte +} diff --git a/internal/endtoend/testdata/json_param_type/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/json_param_type/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..99aef6b --- /dev/null +++ b/internal/endtoend/testdata/json_param_type/postgresql/pgx/go/query.sql.go @@ -0,0 +1,23 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const findByAddress = `-- name: FindByAddress :one +SELECT id, metadata FROM "user" WHERE "metadata"->>'address1' = $1 LIMIT 1 +` + +func (q *Queries) FindByAddress(ctx context.Context, metadata pgtype.Text) (User, error) { + row := q.db.QueryRow(ctx, findByAddress, metadata) + var i User + err := row.Scan(&i.ID, &i.Metadata) + return i, err +} diff --git a/internal/endtoend/testdata/json_param_type/postgresql/pgx/query.sql b/internal/endtoend/testdata/json_param_type/postgresql/pgx/query.sql new file mode 100644 index 0000000..61da05b --- /dev/null +++ b/internal/endtoend/testdata/json_param_type/postgresql/pgx/query.sql @@ -0,0 +1,2 @@ +-- name: FindByAddress :one +SELECT * FROM "user" WHERE "metadata"->>'address1' = $1 LIMIT 1; diff --git a/internal/endtoend/testdata/json_param_type/postgresql/pgx/schema.sql b/internal/endtoend/testdata/json_param_type/postgresql/pgx/schema.sql new file mode 100644 index 0000000..9d2499c --- /dev/null +++ b/internal/endtoend/testdata/json_param_type/postgresql/pgx/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE "user" ( + "id" INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, + "metadata" JSONB +); diff --git a/internal/endtoend/testdata/json_param_type/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/json_param_type/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..01489e0 --- /dev/null +++ b/internal/endtoend/testdata/json_param_type/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" \ No newline at end of file diff --git a/internal/endtoend/testdata/json_param_type/sqlite/go/db.go b/internal/endtoend/testdata/json_param_type/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/json_param_type/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/json_param_type/sqlite/go/models.go b/internal/endtoend/testdata/json_param_type/sqlite/go/models.go new file mode 100644 index 0000000..c5a402e --- /dev/null +++ b/internal/endtoend/testdata/json_param_type/sqlite/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID sql.NullInt64 + Metadata sql.NullString +} diff --git a/internal/endtoend/testdata/json_param_type/sqlite/go/query.sql.go b/internal/endtoend/testdata/json_param_type/sqlite/go/query.sql.go new file mode 100644 index 0000000..9433531 --- /dev/null +++ b/internal/endtoend/testdata/json_param_type/sqlite/go/query.sql.go @@ -0,0 +1,22 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const findByAddress = `-- name: FindByAddress :one +SELECT id, metadata FROM "user" WHERE "metadata"->>'address1' = ?1 LIMIT 1 +` + +func (q *Queries) FindByAddress(ctx context.Context, metadata sql.NullString) (User, error) { + row := q.db.QueryRowContext(ctx, findByAddress, metadata) + var i User + err := row.Scan(&i.ID, &i.Metadata) + return i, err +} diff --git a/internal/endtoend/testdata/json_param_type/sqlite/query.sql b/internal/endtoend/testdata/json_param_type/sqlite/query.sql new file mode 100644 index 0000000..7060d6e --- /dev/null +++ b/internal/endtoend/testdata/json_param_type/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: FindByAddress :one +SELECT * FROM "user" WHERE "metadata"->>'address1' = ?1 LIMIT 1; \ No newline at end of file diff --git a/internal/endtoend/testdata/json_param_type/sqlite/schema.sql b/internal/endtoend/testdata/json_param_type/sqlite/schema.sql new file mode 100644 index 0000000..26c8295 --- /dev/null +++ b/internal/endtoend/testdata/json_param_type/sqlite/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE "user" ( + "id" INT, + "metadata" TEXT +); diff --git a/internal/endtoend/testdata/json_param_type/sqlite/sqlc.yaml b/internal/endtoend/testdata/json_param_type/sqlite/sqlc.yaml new file mode 100644 index 0000000..0608985 --- /dev/null +++ b/internal/endtoend/testdata/json_param_type/sqlite/sqlc.yaml @@ -0,0 +1,9 @@ +version: "2" +sql: + - engine: "sqlite" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" \ No newline at end of file diff --git a/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/json_tags/camel_case/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..5e60ced --- /dev/null +++ b/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v4/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + FirstName sql.NullString `json:"firstName"` + LastName sql.NullString `json:"lastName"` + Age sql.NullInt16 `json:"age"` +} diff --git a/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..9f094da --- /dev/null +++ b/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]User, error) { + rows, err := q.db.Query(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan(&i.FirstName, &i.LastName, &i.Age); 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/json_tags/camel_case/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..237b201 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: GetAll :many +SELECT * FROM users; diff --git a/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..8ca8f26 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v4/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + first_name varchar(255), + last_name varchar(255), + age smallint +); + diff --git a/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..45ed536 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,15 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_json_tags": true, + "json_tags_case_style": "camel" + } + ] +} diff --git a/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/json_tags/camel_case/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..3b9027d --- /dev/null +++ b/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v5/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type User struct { + FirstName pgtype.Text `json:"firstName"` + LastName pgtype.Text `json:"lastName"` + Age pgtype.Int2 `json:"age"` +} diff --git a/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..9f094da --- /dev/null +++ b/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]User, error) { + rows, err := q.db.Query(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan(&i.FirstName, &i.LastName, &i.Age); 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/json_tags/camel_case/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..237b201 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: GetAll :many +SELECT * FROM users; diff --git a/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..8ca8f26 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v5/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + first_name varchar(255), + last_name varchar(255), + age smallint +); + diff --git a/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..9f8193e --- /dev/null +++ b/internal/endtoend/testdata/json_tags/camel_case/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,15 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_json_tags": true, + "json_tags_case_style": "camel" + } + ] +} diff --git a/internal/endtoend/testdata/json_tags/camel_case/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/json_tags/camel_case/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/json_tags/camel_case/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/json_tags/camel_case/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/json_tags/camel_case/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..5e60ced --- /dev/null +++ b/internal/endtoend/testdata/json_tags/camel_case/postgresql/stdlib/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + FirstName sql.NullString `json:"firstName"` + LastName sql.NullString `json:"lastName"` + Age sql.NullInt16 `json:"age"` +} diff --git a/internal/endtoend/testdata/json_tags/camel_case/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/json_tags/camel_case/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..a332798 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/camel_case/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]User, error) { + rows, err := q.db.QueryContext(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan(&i.FirstName, &i.LastName, &i.Age); 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/json_tags/camel_case/postgresql/stdlib/query.sql b/internal/endtoend/testdata/json_tags/camel_case/postgresql/stdlib/query.sql new file mode 100644 index 0000000..237b201 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/camel_case/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: GetAll :many +SELECT * FROM users; diff --git a/internal/endtoend/testdata/json_tags/camel_case/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/json_tags/camel_case/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..8ca8f26 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/camel_case/postgresql/stdlib/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + first_name varchar(255), + last_name varchar(255), + age smallint +); + diff --git a/internal/endtoend/testdata/json_tags/camel_case/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/json_tags/camel_case/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..c83c1ec --- /dev/null +++ b/internal/endtoend/testdata/json_tags/camel_case/postgresql/stdlib/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_json_tags": true, + "json_tags_case_style": "camel" + } + ] +} diff --git a/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/json_tags/pascal_case/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..fc5a94d --- /dev/null +++ b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v4/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + FirstName sql.NullString `json:"FirstName"` + LastName sql.NullString `json:"LastName"` + Age sql.NullInt16 `json:"Age"` +} diff --git a/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..9f094da --- /dev/null +++ b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]User, error) { + rows, err := q.db.Query(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan(&i.FirstName, &i.LastName, &i.Age); 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/json_tags/pascal_case/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..237b201 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: GetAll :many +SELECT * FROM users; diff --git a/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..8ca8f26 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v4/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + first_name varchar(255), + last_name varchar(255), + age smallint +); + diff --git a/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..a0701ce --- /dev/null +++ b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,15 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_json_tags": true, + "json_tags_case_style": "pascal" + } + ] +} diff --git a/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/json_tags/pascal_case/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..f3ea3af --- /dev/null +++ b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v5/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type User struct { + FirstName pgtype.Text `json:"FirstName"` + LastName pgtype.Text `json:"LastName"` + Age pgtype.Int2 `json:"Age"` +} diff --git a/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..9f094da --- /dev/null +++ b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]User, error) { + rows, err := q.db.Query(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan(&i.FirstName, &i.LastName, &i.Age); 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/json_tags/pascal_case/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..237b201 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: GetAll :many +SELECT * FROM users; diff --git a/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..8ca8f26 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v5/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + first_name varchar(255), + last_name varchar(255), + age smallint +); + diff --git a/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..43a61e2 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,15 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_json_tags": true, + "json_tags_case_style": "pascal" + } + ] +} diff --git a/internal/endtoend/testdata/json_tags/pascal_case/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/json_tags/pascal_case/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..fc5a94d --- /dev/null +++ b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/stdlib/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + FirstName sql.NullString `json:"FirstName"` + LastName sql.NullString `json:"LastName"` + Age sql.NullInt16 `json:"Age"` +} diff --git a/internal/endtoend/testdata/json_tags/pascal_case/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..a332798 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]User, error) { + rows, err := q.db.QueryContext(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan(&i.FirstName, &i.LastName, &i.Age); 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/json_tags/pascal_case/postgresql/stdlib/query.sql b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/stdlib/query.sql new file mode 100644 index 0000000..237b201 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: GetAll :many +SELECT * FROM users; diff --git a/internal/endtoend/testdata/json_tags/pascal_case/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..8ca8f26 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/stdlib/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + first_name varchar(255), + last_name varchar(255), + age smallint +); + diff --git a/internal/endtoend/testdata/json_tags/pascal_case/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..55f529a --- /dev/null +++ b/internal/endtoend/testdata/json_tags/pascal_case/postgresql/stdlib/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_json_tags": true, + "json_tags_case_style": "pascal" + } + ] +} diff --git a/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/json_tags/snake_case/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..3769919 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v4/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + FirstName sql.NullString `json:"first_name"` + LastName sql.NullString `json:"last_name"` + Age sql.NullInt16 `json:"age"` +} diff --git a/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..9f094da --- /dev/null +++ b/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]User, error) { + rows, err := q.db.Query(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan(&i.FirstName, &i.LastName, &i.Age); 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/json_tags/snake_case/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..237b201 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: GetAll :many +SELECT * FROM users; diff --git a/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..8ca8f26 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v4/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + first_name varchar(255), + last_name varchar(255), + age smallint +); + diff --git a/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..813fde0 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,15 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_json_tags": true, + "json_tags_case_style": "snake" + } + ] +} diff --git a/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/json_tags/snake_case/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..0cea14a --- /dev/null +++ b/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v5/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type User struct { + FirstName pgtype.Text `json:"first_name"` + LastName pgtype.Text `json:"last_name"` + Age pgtype.Int2 `json:"age"` +} diff --git a/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..9f094da --- /dev/null +++ b/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]User, error) { + rows, err := q.db.Query(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan(&i.FirstName, &i.LastName, &i.Age); 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/json_tags/snake_case/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..237b201 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: GetAll :many +SELECT * FROM users; diff --git a/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..8ca8f26 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v5/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + first_name varchar(255), + last_name varchar(255), + age smallint +); + diff --git a/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..d592761 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/snake_case/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,15 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_json_tags": true, + "json_tags_case_style": "snake" + } + ] +} diff --git a/internal/endtoend/testdata/json_tags/snake_case/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/json_tags/snake_case/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/json_tags/snake_case/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/json_tags/snake_case/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/json_tags/snake_case/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..3769919 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/snake_case/postgresql/stdlib/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + FirstName sql.NullString `json:"first_name"` + LastName sql.NullString `json:"last_name"` + Age sql.NullInt16 `json:"age"` +} diff --git a/internal/endtoend/testdata/json_tags/snake_case/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/json_tags/snake_case/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..a332798 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/snake_case/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]User, error) { + rows, err := q.db.QueryContext(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan(&i.FirstName, &i.LastName, &i.Age); 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/json_tags/snake_case/postgresql/stdlib/query.sql b/internal/endtoend/testdata/json_tags/snake_case/postgresql/stdlib/query.sql new file mode 100644 index 0000000..237b201 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/snake_case/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: GetAll :many +SELECT * FROM users; diff --git a/internal/endtoend/testdata/json_tags/snake_case/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/json_tags/snake_case/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..8ca8f26 --- /dev/null +++ b/internal/endtoend/testdata/json_tags/snake_case/postgresql/stdlib/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + first_name varchar(255), + last_name varchar(255), + age smallint +); + diff --git a/internal/endtoend/testdata/json_tags/snake_case/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/json_tags/snake_case/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..4b2a25b --- /dev/null +++ b/internal/endtoend/testdata/json_tags/snake_case/postgresql/stdlib/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_json_tags": true, + "json_tags_case_style": "snake" + } + ] +} diff --git a/internal/endtoend/testdata/json_tags_null_enum/camel_case/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/json_tags_null_enum/camel_case/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/camel_case/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/json_tags_null_enum/camel_case/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/json_tags_null_enum/camel_case/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..0393e3a --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/camel_case/postgresql/stdlib/go/models.go @@ -0,0 +1,61 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "database/sql" + "database/sql/driver" + "fmt" +) + +type JobPostLocationType string + +const ( + JobPostLocationTypeRemote JobPostLocationType = "remote" + JobPostLocationTypeInOffice JobPostLocationType = "in_office" + JobPostLocationTypeHybrid JobPostLocationType = "hybrid" +) + +func (e *JobPostLocationType) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = JobPostLocationType(s) + case string: + *e = JobPostLocationType(s) + default: + return fmt.Errorf("unsupported scan type for JobPostLocationType: %T", src) + } + return nil +} + +type NullJobPostLocationType struct { + JobPostLocationType JobPostLocationType `json:"jobPostLocationType"` + Valid bool `json:"valid"` // Valid is true if JobPostLocationType is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullJobPostLocationType) Scan(value any) error { + if value == nil { + ns.JobPostLocationType, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.JobPostLocationType.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullJobPostLocationType) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.JobPostLocationType), nil +} + +type Author struct { + ID int64 `json:"id"` + Type NullJobPostLocationType `json:"type"` + Name string `json:"name"` + Bio sql.NullString `json:"bio"` +} diff --git a/internal/endtoend/testdata/json_tags_null_enum/camel_case/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/json_tags_null_enum/camel_case/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..9e99374 --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/camel_case/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,27 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" +) + +const getAuthor = `-- name: GetAuthor :one +SELECT id, type, name, bio FROM authors +WHERE id = $1 LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Author + err := row.Scan( + &i.ID, + &i.Type, + &i.Name, + &i.Bio, + ) + return i, err +} diff --git a/internal/endtoend/testdata/json_tags_null_enum/camel_case/postgresql/stdlib/query.sql b/internal/endtoend/testdata/json_tags_null_enum/camel_case/postgresql/stdlib/query.sql new file mode 100644 index 0000000..592b192 --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/camel_case/postgresql/stdlib/query.sql @@ -0,0 +1,3 @@ +-- name: GetAuthor :one +SELECT * FROM authors +WHERE id = $1 LIMIT 1; \ No newline at end of file diff --git a/internal/endtoend/testdata/json_tags_null_enum/camel_case/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/json_tags_null_enum/camel_case/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..eedb393 --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/camel_case/postgresql/stdlib/schema.sql @@ -0,0 +1,9 @@ +CREATE TYPE job_post_location_type AS ENUM('remote', 'in_office', 'hybrid'); + +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + type job_post_location_type, + name text NOT NULL, + bio text +); + diff --git a/internal/endtoend/testdata/json_tags_null_enum/camel_case/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/json_tags_null_enum/camel_case/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..b8f4852 --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/camel_case/postgresql/stdlib/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "db", + "schema": "schema.sql", + "queries": "query.sql", + "emit_json_tags": true, + "json_tags_case_style": "camel" + } + ] +} diff --git a/internal/endtoend/testdata/json_tags_null_enum/none/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/json_tags_null_enum/none/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/none/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/json_tags_null_enum/none/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/json_tags_null_enum/none/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a3a8f7d --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/none/postgresql/stdlib/go/models.go @@ -0,0 +1,61 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "database/sql" + "database/sql/driver" + "fmt" +) + +type JobPostLocationType string + +const ( + JobPostLocationTypeRemote JobPostLocationType = "remote" + JobPostLocationTypeInOffice JobPostLocationType = "in_office" + JobPostLocationTypeHybrid JobPostLocationType = "hybrid" +) + +func (e *JobPostLocationType) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = JobPostLocationType(s) + case string: + *e = JobPostLocationType(s) + default: + return fmt.Errorf("unsupported scan type for JobPostLocationType: %T", src) + } + return nil +} + +type NullJobPostLocationType struct { + JobPostLocationType JobPostLocationType `json:"job_post_location_type"` + Valid bool `json:"valid"` // Valid is true if JobPostLocationType is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullJobPostLocationType) Scan(value any) error { + if value == nil { + ns.JobPostLocationType, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.JobPostLocationType.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullJobPostLocationType) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.JobPostLocationType), nil +} + +type Author struct { + ID int64 `json:"id"` + Type NullJobPostLocationType `json:"type"` + Name string `json:"name"` + Bio sql.NullString `json:"bio"` +} diff --git a/internal/endtoend/testdata/json_tags_null_enum/none/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/json_tags_null_enum/none/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..9e99374 --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/none/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,27 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" +) + +const getAuthor = `-- name: GetAuthor :one +SELECT id, type, name, bio FROM authors +WHERE id = $1 LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Author + err := row.Scan( + &i.ID, + &i.Type, + &i.Name, + &i.Bio, + ) + return i, err +} diff --git a/internal/endtoend/testdata/json_tags_null_enum/none/postgresql/stdlib/query.sql b/internal/endtoend/testdata/json_tags_null_enum/none/postgresql/stdlib/query.sql new file mode 100644 index 0000000..592b192 --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/none/postgresql/stdlib/query.sql @@ -0,0 +1,3 @@ +-- name: GetAuthor :one +SELECT * FROM authors +WHERE id = $1 LIMIT 1; \ No newline at end of file diff --git a/internal/endtoend/testdata/json_tags_null_enum/none/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/json_tags_null_enum/none/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..eedb393 --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/none/postgresql/stdlib/schema.sql @@ -0,0 +1,9 @@ +CREATE TYPE job_post_location_type AS ENUM('remote', 'in_office', 'hybrid'); + +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + type job_post_location_type, + name text NOT NULL, + bio text +); + diff --git a/internal/endtoend/testdata/json_tags_null_enum/none/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/json_tags_null_enum/none/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..0736391 --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/none/postgresql/stdlib/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "db", + "schema": "schema.sql", + "queries": "query.sql", + "emit_json_tags": true, + "json_tags_case_style": "none" + } + ] +} diff --git a/internal/endtoend/testdata/json_tags_null_enum/pascal_case/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/json_tags_null_enum/pascal_case/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/pascal_case/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/json_tags_null_enum/pascal_case/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/json_tags_null_enum/pascal_case/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..389e8d7 --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/pascal_case/postgresql/stdlib/go/models.go @@ -0,0 +1,61 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "database/sql" + "database/sql/driver" + "fmt" +) + +type JobPostLocationType string + +const ( + JobPostLocationTypeRemote JobPostLocationType = "remote" + JobPostLocationTypeInOffice JobPostLocationType = "in_office" + JobPostLocationTypeHybrid JobPostLocationType = "hybrid" +) + +func (e *JobPostLocationType) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = JobPostLocationType(s) + case string: + *e = JobPostLocationType(s) + default: + return fmt.Errorf("unsupported scan type for JobPostLocationType: %T", src) + } + return nil +} + +type NullJobPostLocationType struct { + JobPostLocationType JobPostLocationType `json:"JobPostLocationType"` + Valid bool `json:"Valid"` // Valid is true if JobPostLocationType is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullJobPostLocationType) Scan(value any) error { + if value == nil { + ns.JobPostLocationType, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.JobPostLocationType.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullJobPostLocationType) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.JobPostLocationType), nil +} + +type Author struct { + ID int64 `json:"ID"` + Type NullJobPostLocationType `json:"Type"` + Name string `json:"Name"` + Bio sql.NullString `json:"Bio"` +} diff --git a/internal/endtoend/testdata/json_tags_null_enum/pascal_case/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/json_tags_null_enum/pascal_case/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..9e99374 --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/pascal_case/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,27 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" +) + +const getAuthor = `-- name: GetAuthor :one +SELECT id, type, name, bio FROM authors +WHERE id = $1 LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Author + err := row.Scan( + &i.ID, + &i.Type, + &i.Name, + &i.Bio, + ) + return i, err +} diff --git a/internal/endtoend/testdata/json_tags_null_enum/pascal_case/postgresql/stdlib/query.sql b/internal/endtoend/testdata/json_tags_null_enum/pascal_case/postgresql/stdlib/query.sql new file mode 100644 index 0000000..592b192 --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/pascal_case/postgresql/stdlib/query.sql @@ -0,0 +1,3 @@ +-- name: GetAuthor :one +SELECT * FROM authors +WHERE id = $1 LIMIT 1; \ No newline at end of file diff --git a/internal/endtoend/testdata/json_tags_null_enum/pascal_case/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/json_tags_null_enum/pascal_case/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..eedb393 --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/pascal_case/postgresql/stdlib/schema.sql @@ -0,0 +1,9 @@ +CREATE TYPE job_post_location_type AS ENUM('remote', 'in_office', 'hybrid'); + +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + type job_post_location_type, + name text NOT NULL, + bio text +); + diff --git a/internal/endtoend/testdata/json_tags_null_enum/pascal_case/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/json_tags_null_enum/pascal_case/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..59e3fcd --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/pascal_case/postgresql/stdlib/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "db", + "schema": "schema.sql", + "queries": "query.sql", + "emit_json_tags": true, + "json_tags_case_style": "pascal" + } + ] +} diff --git a/internal/endtoend/testdata/json_tags_null_enum/snake_case/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/json_tags_null_enum/snake_case/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/snake_case/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/json_tags_null_enum/snake_case/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/json_tags_null_enum/snake_case/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a3a8f7d --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/snake_case/postgresql/stdlib/go/models.go @@ -0,0 +1,61 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "database/sql" + "database/sql/driver" + "fmt" +) + +type JobPostLocationType string + +const ( + JobPostLocationTypeRemote JobPostLocationType = "remote" + JobPostLocationTypeInOffice JobPostLocationType = "in_office" + JobPostLocationTypeHybrid JobPostLocationType = "hybrid" +) + +func (e *JobPostLocationType) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = JobPostLocationType(s) + case string: + *e = JobPostLocationType(s) + default: + return fmt.Errorf("unsupported scan type for JobPostLocationType: %T", src) + } + return nil +} + +type NullJobPostLocationType struct { + JobPostLocationType JobPostLocationType `json:"job_post_location_type"` + Valid bool `json:"valid"` // Valid is true if JobPostLocationType is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullJobPostLocationType) Scan(value any) error { + if value == nil { + ns.JobPostLocationType, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.JobPostLocationType.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullJobPostLocationType) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.JobPostLocationType), nil +} + +type Author struct { + ID int64 `json:"id"` + Type NullJobPostLocationType `json:"type"` + Name string `json:"name"` + Bio sql.NullString `json:"bio"` +} diff --git a/internal/endtoend/testdata/json_tags_null_enum/snake_case/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/json_tags_null_enum/snake_case/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..9e99374 --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/snake_case/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,27 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" +) + +const getAuthor = `-- name: GetAuthor :one +SELECT id, type, name, bio FROM authors +WHERE id = $1 LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Author + err := row.Scan( + &i.ID, + &i.Type, + &i.Name, + &i.Bio, + ) + return i, err +} diff --git a/internal/endtoend/testdata/json_tags_null_enum/snake_case/postgresql/stdlib/query.sql b/internal/endtoend/testdata/json_tags_null_enum/snake_case/postgresql/stdlib/query.sql new file mode 100644 index 0000000..592b192 --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/snake_case/postgresql/stdlib/query.sql @@ -0,0 +1,3 @@ +-- name: GetAuthor :one +SELECT * FROM authors +WHERE id = $1 LIMIT 1; \ No newline at end of file diff --git a/internal/endtoend/testdata/json_tags_null_enum/snake_case/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/json_tags_null_enum/snake_case/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..eedb393 --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/snake_case/postgresql/stdlib/schema.sql @@ -0,0 +1,9 @@ +CREATE TYPE job_post_location_type AS ENUM('remote', 'in_office', 'hybrid'); + +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + type job_post_location_type, + name text NOT NULL, + bio text +); + diff --git a/internal/endtoend/testdata/json_tags_null_enum/snake_case/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/json_tags_null_enum/snake_case/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..4d30bb4 --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/snake_case/postgresql/stdlib/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "db", + "schema": "schema.sql", + "queries": "query.sql", + "emit_json_tags": true, + "json_tags_case_style": "snake" + } + ] +} diff --git a/internal/endtoend/testdata/json_tags_null_enum/v2_config/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/json_tags_null_enum/v2_config/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/v2_config/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/json_tags_null_enum/v2_config/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/json_tags_null_enum/v2_config/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a3a8f7d --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/v2_config/postgresql/stdlib/go/models.go @@ -0,0 +1,61 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "database/sql" + "database/sql/driver" + "fmt" +) + +type JobPostLocationType string + +const ( + JobPostLocationTypeRemote JobPostLocationType = "remote" + JobPostLocationTypeInOffice JobPostLocationType = "in_office" + JobPostLocationTypeHybrid JobPostLocationType = "hybrid" +) + +func (e *JobPostLocationType) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = JobPostLocationType(s) + case string: + *e = JobPostLocationType(s) + default: + return fmt.Errorf("unsupported scan type for JobPostLocationType: %T", src) + } + return nil +} + +type NullJobPostLocationType struct { + JobPostLocationType JobPostLocationType `json:"job_post_location_type"` + Valid bool `json:"valid"` // Valid is true if JobPostLocationType is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullJobPostLocationType) Scan(value any) error { + if value == nil { + ns.JobPostLocationType, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.JobPostLocationType.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullJobPostLocationType) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.JobPostLocationType), nil +} + +type Author struct { + ID int64 `json:"id"` + Type NullJobPostLocationType `json:"type"` + Name string `json:"name"` + Bio sql.NullString `json:"bio"` +} diff --git a/internal/endtoend/testdata/json_tags_null_enum/v2_config/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/json_tags_null_enum/v2_config/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..9e99374 --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/v2_config/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,27 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" +) + +const getAuthor = `-- name: GetAuthor :one +SELECT id, type, name, bio FROM authors +WHERE id = $1 LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Author + err := row.Scan( + &i.ID, + &i.Type, + &i.Name, + &i.Bio, + ) + return i, err +} diff --git a/internal/endtoend/testdata/json_tags_null_enum/v2_config/postgresql/stdlib/query.sql b/internal/endtoend/testdata/json_tags_null_enum/v2_config/postgresql/stdlib/query.sql new file mode 100644 index 0000000..592b192 --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/v2_config/postgresql/stdlib/query.sql @@ -0,0 +1,3 @@ +-- name: GetAuthor :one +SELECT * FROM authors +WHERE id = $1 LIMIT 1; \ No newline at end of file diff --git a/internal/endtoend/testdata/json_tags_null_enum/v2_config/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/json_tags_null_enum/v2_config/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..eedb393 --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/v2_config/postgresql/stdlib/schema.sql @@ -0,0 +1,9 @@ +CREATE TYPE job_post_location_type AS ENUM('remote', 'in_office', 'hybrid'); + +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + type job_post_location_type, + name text NOT NULL, + bio text +); + diff --git a/internal/endtoend/testdata/json_tags_null_enum/v2_config/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/json_tags_null_enum/v2_config/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..e65ee32 --- /dev/null +++ b/internal/endtoend/testdata/json_tags_null_enum/v2_config/postgresql/stdlib/sqlc.json @@ -0,0 +1,17 @@ +{ + "version": "2", + "sql": [ + { + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql", + "gen": { + "go": { + "out": "go", + "package": "db", + "emit_json_tags": true + } + } + } + ] +} diff --git a/internal/endtoend/testdata/jsonb/pgx/go/db.go b/internal/endtoend/testdata/jsonb/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/jsonb/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/jsonb/pgx/go/models.go b/internal/endtoend/testdata/jsonb/pgx/go/models.go new file mode 100644 index 0000000..9d668a2 --- /dev/null +++ b/internal/endtoend/testdata/jsonb/pgx/go/models.go @@ -0,0 +1,12 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + A []byte + B []byte + C []byte + D []byte +} diff --git a/internal/endtoend/testdata/jsonb/pgx/go/query.sql.go b/internal/endtoend/testdata/jsonb/pgx/go/query.sql.go new file mode 100644 index 0000000..9358ffe --- /dev/null +++ b/internal/endtoend/testdata/jsonb/pgx/go/query.sql.go @@ -0,0 +1,50 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const insertFoo = `-- name: InsertFoo :exec +INSERT INTO foo ( + a, + b, + c, + d +) VALUES ( + $1, + $2, + $3, + $4 +) RETURNING a, b, c, d +` + +type InsertFooParams struct { + A []byte + B []byte + C []byte + D []byte +} + +func (q *Queries) InsertFoo(ctx context.Context, arg InsertFooParams) error { + _, err := q.db.Exec(ctx, insertFoo, + arg.A, + arg.B, + arg.C, + arg.D, + ) + return err +} + +const selectFoo = `-- name: SelectFoo :exec +SELECT a, b, c, d FROM foo +` + +func (q *Queries) SelectFoo(ctx context.Context) error { + _, err := q.db.Exec(ctx, selectFoo) + return err +} diff --git a/internal/endtoend/testdata/jsonb/pgx/query.sql b/internal/endtoend/testdata/jsonb/pgx/query.sql new file mode 100644 index 0000000..6959bd1 --- /dev/null +++ b/internal/endtoend/testdata/jsonb/pgx/query.sql @@ -0,0 +1,15 @@ +-- name: InsertFoo :exec +INSERT INTO foo ( + a, + b, + c, + d +) VALUES ( + @a, + @b, + @c, + @d +) RETURNING *; + +-- name: SelectFoo :exec +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/jsonb/pgx/schema.sql b/internal/endtoend/testdata/jsonb/pgx/schema.sql new file mode 100644 index 0000000..6b4a1bb --- /dev/null +++ b/internal/endtoend/testdata/jsonb/pgx/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE foo ( + a json not null, + b jsonb not null, + c json, + d jsonb +); + diff --git a/internal/endtoend/testdata/jsonb/pgx/sqlc.json b/internal/endtoend/testdata/jsonb/pgx/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/jsonb/pgx/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/jsonb/sqlite/go/db.go b/internal/endtoend/testdata/jsonb/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/jsonb/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/jsonb/sqlite/go/models.go b/internal/endtoend/testdata/jsonb/sqlite/go/models.go new file mode 100644 index 0000000..a19424c --- /dev/null +++ b/internal/endtoend/testdata/jsonb/sqlite/go/models.go @@ -0,0 +1,20 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "encoding/json" +) + +type Foo struct { + A json.RawMessage + B json.RawMessage + C json.RawMessage + D json.RawMessage + E json.RawMessage + F json.RawMessage + G json.RawMessage + H json.RawMessage +} diff --git a/internal/endtoend/testdata/jsonb/sqlite/go/query.sql.go b/internal/endtoend/testdata/jsonb/sqlite/go/query.sql.go new file mode 100644 index 0000000..655f57a --- /dev/null +++ b/internal/endtoend/testdata/jsonb/sqlite/go/query.sql.go @@ -0,0 +1,69 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "encoding/json" +) + +const insertFoo = `-- name: InsertFoo :exec +INSERT INTO foo ( + a, + b, + c, + d, + e, + f, + g, + h +) +VALUES ( + ?1, + ?2, + ?3, + ?4, + ?5, + ?6, + ?7, + ?8 +) +RETURNING a, json(b), c, json(d), e, json(f), g, json(h) +` + +type InsertFooParams struct { + A json.RawMessage + B json.RawMessage + C json.RawMessage + D json.RawMessage + E json.RawMessage + F json.RawMessage + G json.RawMessage + H json.RawMessage +} + +func (q *Queries) InsertFoo(ctx context.Context, arg InsertFooParams) error { + _, err := q.db.ExecContext(ctx, insertFoo, + arg.A, + arg.B, + arg.C, + arg.D, + arg.E, + arg.F, + arg.G, + arg.H, + ) + return err +} + +const selectFoo = `-- name: SelectFoo :exec +SELECT a, json(b), c, json(d), e, json(f), g, json(h) FROM foo +` + +func (q *Queries) SelectFoo(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, selectFoo) + return err +} diff --git a/internal/endtoend/testdata/jsonb/sqlite/query.sql b/internal/endtoend/testdata/jsonb/sqlite/query.sql new file mode 100644 index 0000000..0fe40ee --- /dev/null +++ b/internal/endtoend/testdata/jsonb/sqlite/query.sql @@ -0,0 +1,25 @@ +-- name: InsertFoo :exec +INSERT INTO foo ( + a, + b, + c, + d, + e, + f, + g, + h +) +VALUES ( + @a, + @b, + @c, + @d, + @e, + @f, + @g, + @h +) +RETURNING *; + +-- name: SelectFoo :exec +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/jsonb/sqlite/schema.sql b/internal/endtoend/testdata/jsonb/sqlite/schema.sql new file mode 100644 index 0000000..cc237ce --- /dev/null +++ b/internal/endtoend/testdata/jsonb/sqlite/schema.sql @@ -0,0 +1,11 @@ +CREATE TABLE foo ( + a json not null, + b jsonb not null, + c json, + d jsonb, + e JSON not null, + f JSONB not null, + g JSON, + h JSONB +); + diff --git a/internal/endtoend/testdata/jsonb/sqlite/sqlc.json b/internal/endtoend/testdata/jsonb/sqlite/sqlc.json new file mode 100644 index 0000000..cd66df0 --- /dev/null +++ b/internal/endtoend/testdata/jsonb/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/limit/mysql/go/db.go b/internal/endtoend/testdata/limit/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/limit/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/limit/mysql/go/models.go b/internal/endtoend/testdata/limit/mysql/go/models.go new file mode 100644 index 0000000..e2a9591 --- /dev/null +++ b/internal/endtoend/testdata/limit/mysql/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar bool +} diff --git a/internal/endtoend/testdata/limit/mysql/go/query.sql.go b/internal/endtoend/testdata/limit/mysql/go/query.sql.go new file mode 100644 index 0000000..37df69d --- /dev/null +++ b/internal/endtoend/testdata/limit/mysql/go/query.sql.go @@ -0,0 +1,28 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const limitMe = `-- name: LimitMe :exec +UPDATE foo SET bar='baz' LIMIT ? +` + +func (q *Queries) LimitMe(ctx context.Context, limit int32) error { + _, err := q.db.ExecContext(ctx, limitMe, limit) + return err +} + +const limitMeToo = `-- name: LimitMeToo :exec +DELETE FROM foo LIMIT ? +` + +func (q *Queries) LimitMeToo(ctx context.Context, limit int32) error { + _, err := q.db.ExecContext(ctx, limitMeToo, limit) + return err +} diff --git a/internal/endtoend/testdata/limit/mysql/query.sql b/internal/endtoend/testdata/limit/mysql/query.sql new file mode 100644 index 0000000..44f8b7d --- /dev/null +++ b/internal/endtoend/testdata/limit/mysql/query.sql @@ -0,0 +1,5 @@ +-- name: LimitMe :exec +UPDATE foo SET bar='baz' LIMIT ?; + +-- name: LimitMeToo :exec +DELETE FROM foo LIMIT ?; diff --git a/internal/endtoend/testdata/limit/mysql/schema.sql b/internal/endtoend/testdata/limit/mysql/schema.sql new file mode 100644 index 0000000..1d3eb6d --- /dev/null +++ b/internal/endtoend/testdata/limit/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar bool not null); + diff --git a/internal/endtoend/testdata/limit/mysql/sqlc.json b/internal/endtoend/testdata/limit/mysql/sqlc.json new file mode 100644 index 0000000..6c2a984 --- /dev/null +++ b/internal/endtoend/testdata/limit/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/limit/pgx/v4/exec.json b/internal/endtoend/testdata/limit/pgx/v4/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/limit/pgx/v4/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/limit/pgx/v4/go/db.go b/internal/endtoend/testdata/limit/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/limit/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/limit/pgx/v4/go/models.go b/internal/endtoend/testdata/limit/pgx/v4/go/models.go new file mode 100644 index 0000000..e2a9591 --- /dev/null +++ b/internal/endtoend/testdata/limit/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar bool +} diff --git a/internal/endtoend/testdata/limit/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/limit/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..d0b0b08 --- /dev/null +++ b/internal/endtoend/testdata/limit/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const limitMe = `-- name: LimitMe :many +SELECT bar FROM foo LIMIT $1 +` + +func (q *Queries) LimitMe(ctx context.Context, limit int32) ([]bool, error) { + rows, err := q.db.Query(ctx, limitMe, limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var bar bool + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/limit/pgx/v4/query.sql b/internal/endtoend/testdata/limit/pgx/v4/query.sql new file mode 100644 index 0000000..a190c5b --- /dev/null +++ b/internal/endtoend/testdata/limit/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: LimitMe :many +SELECT bar FROM foo LIMIT $1; diff --git a/internal/endtoend/testdata/limit/pgx/v4/schema.sql b/internal/endtoend/testdata/limit/pgx/v4/schema.sql new file mode 100644 index 0000000..1d3eb6d --- /dev/null +++ b/internal/endtoend/testdata/limit/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar bool not null); + diff --git a/internal/endtoend/testdata/limit/pgx/v4/sqlc.json b/internal/endtoend/testdata/limit/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/limit/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/limit/pgx/v5/exec.json b/internal/endtoend/testdata/limit/pgx/v5/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/limit/pgx/v5/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/limit/pgx/v5/go/db.go b/internal/endtoend/testdata/limit/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/limit/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/limit/pgx/v5/go/models.go b/internal/endtoend/testdata/limit/pgx/v5/go/models.go new file mode 100644 index 0000000..e2a9591 --- /dev/null +++ b/internal/endtoend/testdata/limit/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar bool +} diff --git a/internal/endtoend/testdata/limit/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/limit/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..d0b0b08 --- /dev/null +++ b/internal/endtoend/testdata/limit/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const limitMe = `-- name: LimitMe :many +SELECT bar FROM foo LIMIT $1 +` + +func (q *Queries) LimitMe(ctx context.Context, limit int32) ([]bool, error) { + rows, err := q.db.Query(ctx, limitMe, limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var bar bool + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/limit/pgx/v5/query.sql b/internal/endtoend/testdata/limit/pgx/v5/query.sql new file mode 100644 index 0000000..a190c5b --- /dev/null +++ b/internal/endtoend/testdata/limit/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: LimitMe :many +SELECT bar FROM foo LIMIT $1; diff --git a/internal/endtoend/testdata/limit/pgx/v5/schema.sql b/internal/endtoend/testdata/limit/pgx/v5/schema.sql new file mode 100644 index 0000000..1d3eb6d --- /dev/null +++ b/internal/endtoend/testdata/limit/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar bool not null); + diff --git a/internal/endtoend/testdata/limit/pgx/v5/sqlc.json b/internal/endtoend/testdata/limit/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/limit/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/limit/sqlite/go/db.go b/internal/endtoend/testdata/limit/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/limit/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/limit/sqlite/go/models.go b/internal/endtoend/testdata/limit/sqlite/go/models.go new file mode 100644 index 0000000..e2a9591 --- /dev/null +++ b/internal/endtoend/testdata/limit/sqlite/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar bool +} diff --git a/internal/endtoend/testdata/limit/sqlite/go/query.sql.go b/internal/endtoend/testdata/limit/sqlite/go/query.sql.go new file mode 100644 index 0000000..4800120 --- /dev/null +++ b/internal/endtoend/testdata/limit/sqlite/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const limitMe = `-- name: LimitMe :many +SELECT bar FROM foo LIMIT ? +` + +func (q *Queries) LimitMe(ctx context.Context, limit int64) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, limitMe, limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var bar bool + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + 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/limit/sqlite/query.sql b/internal/endtoend/testdata/limit/sqlite/query.sql new file mode 100644 index 0000000..8514c9b --- /dev/null +++ b/internal/endtoend/testdata/limit/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: LimitMe :many +SELECT bar FROM foo LIMIT ?; diff --git a/internal/endtoend/testdata/limit/sqlite/schema.sql b/internal/endtoend/testdata/limit/sqlite/schema.sql new file mode 100644 index 0000000..1d3eb6d --- /dev/null +++ b/internal/endtoend/testdata/limit/sqlite/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar bool not null); + diff --git a/internal/endtoend/testdata/limit/sqlite/sqlc.json b/internal/endtoend/testdata/limit/sqlite/sqlc.json new file mode 100644 index 0000000..d4963e7 --- /dev/null +++ b/internal/endtoend/testdata/limit/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/limit/stdlib/exec.json b/internal/endtoend/testdata/limit/stdlib/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/limit/stdlib/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/limit/stdlib/go/db.go b/internal/endtoend/testdata/limit/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/limit/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/limit/stdlib/go/models.go b/internal/endtoend/testdata/limit/stdlib/go/models.go new file mode 100644 index 0000000..e2a9591 --- /dev/null +++ b/internal/endtoend/testdata/limit/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar bool +} diff --git a/internal/endtoend/testdata/limit/stdlib/go/query.sql.go b/internal/endtoend/testdata/limit/stdlib/go/query.sql.go new file mode 100644 index 0000000..c2aa026 --- /dev/null +++ b/internal/endtoend/testdata/limit/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const limitMe = `-- name: LimitMe :many +SELECT bar FROM foo LIMIT $1 +` + +func (q *Queries) LimitMe(ctx context.Context, limit int32) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, limitMe, limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var bar bool + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + 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/limit/stdlib/query.sql b/internal/endtoend/testdata/limit/stdlib/query.sql new file mode 100644 index 0000000..a190c5b --- /dev/null +++ b/internal/endtoend/testdata/limit/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: LimitMe :many +SELECT bar FROM foo LIMIT $1; diff --git a/internal/endtoend/testdata/limit/stdlib/schema.sql b/internal/endtoend/testdata/limit/stdlib/schema.sql new file mode 100644 index 0000000..1d3eb6d --- /dev/null +++ b/internal/endtoend/testdata/limit/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar bool not null); + diff --git a/internal/endtoend/testdata/limit/stdlib/sqlc.json b/internal/endtoend/testdata/limit/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/limit/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/lower/pgx/v4/go/db.go b/internal/endtoend/testdata/lower/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/lower/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/lower/pgx/v4/go/models.go b/internal/endtoend/testdata/lower/pgx/v4/go/models.go new file mode 100644 index 0000000..d0f806e --- /dev/null +++ b/internal/endtoend/testdata/lower/pgx/v4/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar string + Bat string +} diff --git a/internal/endtoend/testdata/lower/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/lower/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..4777bbf --- /dev/null +++ b/internal/endtoend/testdata/lower/pgx/v4/go/query.sql.go @@ -0,0 +1,39 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const lower = `-- name: Lower :many +SELECT bar FROM foo WHERE bar = $1 AND LOWER(bat) = $2 +` + +type LowerParams struct { + Bar string + Bat string +} + +func (q *Queries) Lower(ctx context.Context, arg LowerParams) ([]string, error) { + rows, err := q.db.Query(ctx, lower, arg.Bar, arg.Bat) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var bar string + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/lower/pgx/v4/query.sql b/internal/endtoend/testdata/lower/pgx/v4/query.sql new file mode 100644 index 0000000..5d7c35b --- /dev/null +++ b/internal/endtoend/testdata/lower/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Lower :many +SELECT bar FROM foo WHERE bar = $1 AND LOWER(bat) = $2; diff --git a/internal/endtoend/testdata/lower/pgx/v4/schema.sql b/internal/endtoend/testdata/lower/pgx/v4/schema.sql new file mode 100644 index 0000000..f9f4adf --- /dev/null +++ b/internal/endtoend/testdata/lower/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text not null, bat text not null); + diff --git a/internal/endtoend/testdata/lower/pgx/v4/sqlc.json b/internal/endtoend/testdata/lower/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/lower/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/lower/pgx/v5/go/db.go b/internal/endtoend/testdata/lower/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/lower/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/lower/pgx/v5/go/models.go b/internal/endtoend/testdata/lower/pgx/v5/go/models.go new file mode 100644 index 0000000..d0f806e --- /dev/null +++ b/internal/endtoend/testdata/lower/pgx/v5/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar string + Bat string +} diff --git a/internal/endtoend/testdata/lower/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/lower/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..4777bbf --- /dev/null +++ b/internal/endtoend/testdata/lower/pgx/v5/go/query.sql.go @@ -0,0 +1,39 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const lower = `-- name: Lower :many +SELECT bar FROM foo WHERE bar = $1 AND LOWER(bat) = $2 +` + +type LowerParams struct { + Bar string + Bat string +} + +func (q *Queries) Lower(ctx context.Context, arg LowerParams) ([]string, error) { + rows, err := q.db.Query(ctx, lower, arg.Bar, arg.Bat) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var bar string + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/lower/pgx/v5/query.sql b/internal/endtoend/testdata/lower/pgx/v5/query.sql new file mode 100644 index 0000000..5d7c35b --- /dev/null +++ b/internal/endtoend/testdata/lower/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Lower :many +SELECT bar FROM foo WHERE bar = $1 AND LOWER(bat) = $2; diff --git a/internal/endtoend/testdata/lower/pgx/v5/schema.sql b/internal/endtoend/testdata/lower/pgx/v5/schema.sql new file mode 100644 index 0000000..f9f4adf --- /dev/null +++ b/internal/endtoend/testdata/lower/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text not null, bat text not null); + diff --git a/internal/endtoend/testdata/lower/pgx/v5/sqlc.json b/internal/endtoend/testdata/lower/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/lower/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/lower/stdlib/go/db.go b/internal/endtoend/testdata/lower/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/lower/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/lower/stdlib/go/models.go b/internal/endtoend/testdata/lower/stdlib/go/models.go new file mode 100644 index 0000000..d0f806e --- /dev/null +++ b/internal/endtoend/testdata/lower/stdlib/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar string + Bat string +} diff --git a/internal/endtoend/testdata/lower/stdlib/go/query.sql.go b/internal/endtoend/testdata/lower/stdlib/go/query.sql.go new file mode 100644 index 0000000..9ee4b58 --- /dev/null +++ b/internal/endtoend/testdata/lower/stdlib/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const lower = `-- name: Lower :many +SELECT bar FROM foo WHERE bar = $1 AND LOWER(bat) = $2 +` + +type LowerParams struct { + Bar string + Bat string +} + +func (q *Queries) Lower(ctx context.Context, arg LowerParams) ([]string, error) { + rows, err := q.db.QueryContext(ctx, lower, arg.Bar, arg.Bat) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var bar string + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + 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/lower/stdlib/query.sql b/internal/endtoend/testdata/lower/stdlib/query.sql new file mode 100644 index 0000000..5d7c35b --- /dev/null +++ b/internal/endtoend/testdata/lower/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Lower :many +SELECT bar FROM foo WHERE bar = $1 AND LOWER(bat) = $2; diff --git a/internal/endtoend/testdata/lower/stdlib/schema.sql b/internal/endtoend/testdata/lower/stdlib/schema.sql new file mode 100644 index 0000000..f9f4adf --- /dev/null +++ b/internal/endtoend/testdata/lower/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text not null, bat text not null); + diff --git a/internal/endtoend/testdata/lower/stdlib/sqlc.json b/internal/endtoend/testdata/lower/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/lower/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/lower_switched_order/pgx/v4/go/db.go b/internal/endtoend/testdata/lower_switched_order/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/lower_switched_order/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/lower_switched_order/pgx/v4/go/models.go b/internal/endtoend/testdata/lower_switched_order/pgx/v4/go/models.go new file mode 100644 index 0000000..d0f806e --- /dev/null +++ b/internal/endtoend/testdata/lower_switched_order/pgx/v4/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar string + Bat string +} diff --git a/internal/endtoend/testdata/lower_switched_order/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/lower_switched_order/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..9203b1c --- /dev/null +++ b/internal/endtoend/testdata/lower_switched_order/pgx/v4/go/query.sql.go @@ -0,0 +1,39 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const lowerSwitchedOrder = `-- name: LowerSwitchedOrder :many +SELECT bar FROM foo WHERE bar = $1 AND bat = LOWER($2) +` + +type LowerSwitchedOrderParams struct { + Bar string + Lower string +} + +func (q *Queries) LowerSwitchedOrder(ctx context.Context, arg LowerSwitchedOrderParams) ([]string, error) { + rows, err := q.db.Query(ctx, lowerSwitchedOrder, arg.Bar, arg.Lower) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var bar string + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/lower_switched_order/pgx/v4/query.sql b/internal/endtoend/testdata/lower_switched_order/pgx/v4/query.sql new file mode 100644 index 0000000..f4a9b83 --- /dev/null +++ b/internal/endtoend/testdata/lower_switched_order/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: LowerSwitchedOrder :many +SELECT bar FROM foo WHERE bar = $1 AND bat = LOWER($2); diff --git a/internal/endtoend/testdata/lower_switched_order/pgx/v4/schema.sql b/internal/endtoend/testdata/lower_switched_order/pgx/v4/schema.sql new file mode 100644 index 0000000..f9f4adf --- /dev/null +++ b/internal/endtoend/testdata/lower_switched_order/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text not null, bat text not null); + diff --git a/internal/endtoend/testdata/lower_switched_order/pgx/v4/sqlc.json b/internal/endtoend/testdata/lower_switched_order/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/lower_switched_order/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/lower_switched_order/pgx/v5/go/db.go b/internal/endtoend/testdata/lower_switched_order/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/lower_switched_order/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/lower_switched_order/pgx/v5/go/models.go b/internal/endtoend/testdata/lower_switched_order/pgx/v5/go/models.go new file mode 100644 index 0000000..d0f806e --- /dev/null +++ b/internal/endtoend/testdata/lower_switched_order/pgx/v5/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar string + Bat string +} diff --git a/internal/endtoend/testdata/lower_switched_order/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/lower_switched_order/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..9203b1c --- /dev/null +++ b/internal/endtoend/testdata/lower_switched_order/pgx/v5/go/query.sql.go @@ -0,0 +1,39 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const lowerSwitchedOrder = `-- name: LowerSwitchedOrder :many +SELECT bar FROM foo WHERE bar = $1 AND bat = LOWER($2) +` + +type LowerSwitchedOrderParams struct { + Bar string + Lower string +} + +func (q *Queries) LowerSwitchedOrder(ctx context.Context, arg LowerSwitchedOrderParams) ([]string, error) { + rows, err := q.db.Query(ctx, lowerSwitchedOrder, arg.Bar, arg.Lower) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var bar string + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/lower_switched_order/pgx/v5/query.sql b/internal/endtoend/testdata/lower_switched_order/pgx/v5/query.sql new file mode 100644 index 0000000..f4a9b83 --- /dev/null +++ b/internal/endtoend/testdata/lower_switched_order/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: LowerSwitchedOrder :many +SELECT bar FROM foo WHERE bar = $1 AND bat = LOWER($2); diff --git a/internal/endtoend/testdata/lower_switched_order/pgx/v5/schema.sql b/internal/endtoend/testdata/lower_switched_order/pgx/v5/schema.sql new file mode 100644 index 0000000..f9f4adf --- /dev/null +++ b/internal/endtoend/testdata/lower_switched_order/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text not null, bat text not null); + diff --git a/internal/endtoend/testdata/lower_switched_order/pgx/v5/sqlc.json b/internal/endtoend/testdata/lower_switched_order/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/lower_switched_order/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/lower_switched_order/stdlib/go/db.go b/internal/endtoend/testdata/lower_switched_order/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/lower_switched_order/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/lower_switched_order/stdlib/go/models.go b/internal/endtoend/testdata/lower_switched_order/stdlib/go/models.go new file mode 100644 index 0000000..d0f806e --- /dev/null +++ b/internal/endtoend/testdata/lower_switched_order/stdlib/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar string + Bat string +} diff --git a/internal/endtoend/testdata/lower_switched_order/stdlib/go/query.sql.go b/internal/endtoend/testdata/lower_switched_order/stdlib/go/query.sql.go new file mode 100644 index 0000000..b1dff8e --- /dev/null +++ b/internal/endtoend/testdata/lower_switched_order/stdlib/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const lowerSwitchedOrder = `-- name: LowerSwitchedOrder :many +SELECT bar FROM foo WHERE bar = $1 AND bat = LOWER($2) +` + +type LowerSwitchedOrderParams struct { + Bar string + Lower string +} + +func (q *Queries) LowerSwitchedOrder(ctx context.Context, arg LowerSwitchedOrderParams) ([]string, error) { + rows, err := q.db.QueryContext(ctx, lowerSwitchedOrder, arg.Bar, arg.Lower) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var bar string + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + 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/lower_switched_order/stdlib/query.sql b/internal/endtoend/testdata/lower_switched_order/stdlib/query.sql new file mode 100644 index 0000000..f4a9b83 --- /dev/null +++ b/internal/endtoend/testdata/lower_switched_order/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: LowerSwitchedOrder :many +SELECT bar FROM foo WHERE bar = $1 AND bat = LOWER($2); diff --git a/internal/endtoend/testdata/lower_switched_order/stdlib/schema.sql b/internal/endtoend/testdata/lower_switched_order/stdlib/schema.sql new file mode 100644 index 0000000..f9f4adf --- /dev/null +++ b/internal/endtoend/testdata/lower_switched_order/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text not null, bat text not null); + diff --git a/internal/endtoend/testdata/lower_switched_order/stdlib/sqlc.json b/internal/endtoend/testdata/lower_switched_order/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/lower_switched_order/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/materialized_views/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/materialized_views/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/materialized_views/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/materialized_views/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/materialized_views/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..3bf4c36 --- /dev/null +++ b/internal/endtoend/testdata/materialized_views/postgresql/pgx/v4/go/models.go @@ -0,0 +1,20 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString + Gender sql.NullInt32 +} + +type AuthorsName struct { + Name string +} diff --git a/internal/endtoend/testdata/materialized_views/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/materialized_views/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..39128f4 --- /dev/null +++ b/internal/endtoend/testdata/materialized_views/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,39 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name, bio, gender FROM authors +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.Query(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan( + &i.ID, + &i.Name, + &i.Bio, + &i.Gender, + ); 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/materialized_views/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/materialized_views/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..86636e2 --- /dev/null +++ b/internal/endtoend/testdata/materialized_views/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: ListAuthors :many +SELECT * FROM authors; diff --git a/internal/endtoend/testdata/materialized_views/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/materialized_views/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..cc05340 --- /dev/null +++ b/internal/endtoend/testdata/materialized_views/postgresql/pgx/v4/schema.sql @@ -0,0 +1,10 @@ +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name TEXT NOT NULL, + bio TEXT +); + +ALTER TABLE authors ADD COLUMN gender INTEGER NULL; + +CREATE MATERIALIZED VIEW authors_names as SELECT name from authors; + diff --git a/internal/endtoend/testdata/materialized_views/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/materialized_views/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/materialized_views/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/materialized_views/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/materialized_views/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/materialized_views/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/materialized_views/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/materialized_views/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..6e7c968 --- /dev/null +++ b/internal/endtoend/testdata/materialized_views/postgresql/pgx/v5/go/models.go @@ -0,0 +1,20 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Author struct { + ID int64 + Name string + Bio pgtype.Text + Gender pgtype.Int4 +} + +type AuthorsName struct { + Name string +} diff --git a/internal/endtoend/testdata/materialized_views/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/materialized_views/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..39128f4 --- /dev/null +++ b/internal/endtoend/testdata/materialized_views/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,39 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name, bio, gender FROM authors +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.Query(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan( + &i.ID, + &i.Name, + &i.Bio, + &i.Gender, + ); 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/materialized_views/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/materialized_views/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..86636e2 --- /dev/null +++ b/internal/endtoend/testdata/materialized_views/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: ListAuthors :many +SELECT * FROM authors; diff --git a/internal/endtoend/testdata/materialized_views/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/materialized_views/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..cc05340 --- /dev/null +++ b/internal/endtoend/testdata/materialized_views/postgresql/pgx/v5/schema.sql @@ -0,0 +1,10 @@ +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name TEXT NOT NULL, + bio TEXT +); + +ALTER TABLE authors ADD COLUMN gender INTEGER NULL; + +CREATE MATERIALIZED VIEW authors_names as SELECT name from authors; + diff --git a/internal/endtoend/testdata/materialized_views/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/materialized_views/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/materialized_views/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/materialized_views/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/materialized_views/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/materialized_views/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/materialized_views/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/materialized_views/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..3bf4c36 --- /dev/null +++ b/internal/endtoend/testdata/materialized_views/postgresql/stdlib/go/models.go @@ -0,0 +1,20 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString + Gender sql.NullInt32 +} + +type AuthorsName struct { + Name string +} diff --git a/internal/endtoend/testdata/materialized_views/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/materialized_views/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..1e62759 --- /dev/null +++ b/internal/endtoend/testdata/materialized_views/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name, bio, gender FROM authors +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan( + &i.ID, + &i.Name, + &i.Bio, + &i.Gender, + ); 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/materialized_views/postgresql/stdlib/query.sql b/internal/endtoend/testdata/materialized_views/postgresql/stdlib/query.sql new file mode 100644 index 0000000..86636e2 --- /dev/null +++ b/internal/endtoend/testdata/materialized_views/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: ListAuthors :many +SELECT * FROM authors; diff --git a/internal/endtoend/testdata/materialized_views/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/materialized_views/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..cc05340 --- /dev/null +++ b/internal/endtoend/testdata/materialized_views/postgresql/stdlib/schema.sql @@ -0,0 +1,10 @@ +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name TEXT NOT NULL, + bio TEXT +); + +ALTER TABLE authors ADD COLUMN gender INTEGER NULL; + +CREATE MATERIALIZED VIEW authors_names as SELECT name from authors; + diff --git a/internal/endtoend/testdata/materialized_views/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/materialized_views/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/materialized_views/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/mathmatical_operator/pgx/v4/go/db.go b/internal/endtoend/testdata/mathmatical_operator/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/mathmatical_operator/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/mathmatical_operator/pgx/v4/go/models.go b/internal/endtoend/testdata/mathmatical_operator/pgx/v4/go/models.go new file mode 100644 index 0000000..4835d70 --- /dev/null +++ b/internal/endtoend/testdata/mathmatical_operator/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Num int32 +} diff --git a/internal/endtoend/testdata/mathmatical_operator/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/mathmatical_operator/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..bcc1688 --- /dev/null +++ b/internal/endtoend/testdata/mathmatical_operator/pgx/v4/go/query.sql.go @@ -0,0 +1,39 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const math = `-- name: Math :many +SELECT num, num / 1024 as division FROM foo +` + +type MathRow struct { + Num int32 + Division int32 +} + +func (q *Queries) Math(ctx context.Context) ([]MathRow, error) { + rows, err := q.db.Query(ctx, math) + if err != nil { + return nil, err + } + defer rows.Close() + var items []MathRow + for rows.Next() { + var i MathRow + if err := rows.Scan(&i.Num, &i.Division); 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/mathmatical_operator/pgx/v4/query.sql b/internal/endtoend/testdata/mathmatical_operator/pgx/v4/query.sql new file mode 100644 index 0000000..a3655a3 --- /dev/null +++ b/internal/endtoend/testdata/mathmatical_operator/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Math :many +SELECT *, num / 1024 as division FROM foo; diff --git a/internal/endtoend/testdata/mathmatical_operator/pgx/v4/schema.sql b/internal/endtoend/testdata/mathmatical_operator/pgx/v4/schema.sql new file mode 100644 index 0000000..cfb1814 --- /dev/null +++ b/internal/endtoend/testdata/mathmatical_operator/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (num integer not null); + diff --git a/internal/endtoend/testdata/mathmatical_operator/pgx/v4/sqlc.json b/internal/endtoend/testdata/mathmatical_operator/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/mathmatical_operator/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/mathmatical_operator/pgx/v5/go/db.go b/internal/endtoend/testdata/mathmatical_operator/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/mathmatical_operator/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/mathmatical_operator/pgx/v5/go/models.go b/internal/endtoend/testdata/mathmatical_operator/pgx/v5/go/models.go new file mode 100644 index 0000000..4835d70 --- /dev/null +++ b/internal/endtoend/testdata/mathmatical_operator/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Num int32 +} diff --git a/internal/endtoend/testdata/mathmatical_operator/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/mathmatical_operator/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..bcc1688 --- /dev/null +++ b/internal/endtoend/testdata/mathmatical_operator/pgx/v5/go/query.sql.go @@ -0,0 +1,39 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const math = `-- name: Math :many +SELECT num, num / 1024 as division FROM foo +` + +type MathRow struct { + Num int32 + Division int32 +} + +func (q *Queries) Math(ctx context.Context) ([]MathRow, error) { + rows, err := q.db.Query(ctx, math) + if err != nil { + return nil, err + } + defer rows.Close() + var items []MathRow + for rows.Next() { + var i MathRow + if err := rows.Scan(&i.Num, &i.Division); 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/mathmatical_operator/pgx/v5/query.sql b/internal/endtoend/testdata/mathmatical_operator/pgx/v5/query.sql new file mode 100644 index 0000000..a3655a3 --- /dev/null +++ b/internal/endtoend/testdata/mathmatical_operator/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Math :many +SELECT *, num / 1024 as division FROM foo; diff --git a/internal/endtoend/testdata/mathmatical_operator/pgx/v5/schema.sql b/internal/endtoend/testdata/mathmatical_operator/pgx/v5/schema.sql new file mode 100644 index 0000000..cfb1814 --- /dev/null +++ b/internal/endtoend/testdata/mathmatical_operator/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (num integer not null); + diff --git a/internal/endtoend/testdata/mathmatical_operator/pgx/v5/sqlc.json b/internal/endtoend/testdata/mathmatical_operator/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/mathmatical_operator/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/mathmatical_operator/stdlib/go/db.go b/internal/endtoend/testdata/mathmatical_operator/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/mathmatical_operator/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/mathmatical_operator/stdlib/go/models.go b/internal/endtoend/testdata/mathmatical_operator/stdlib/go/models.go new file mode 100644 index 0000000..4835d70 --- /dev/null +++ b/internal/endtoend/testdata/mathmatical_operator/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Num int32 +} diff --git a/internal/endtoend/testdata/mathmatical_operator/stdlib/go/query.sql.go b/internal/endtoend/testdata/mathmatical_operator/stdlib/go/query.sql.go new file mode 100644 index 0000000..038047c --- /dev/null +++ b/internal/endtoend/testdata/mathmatical_operator/stdlib/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const math = `-- name: Math :many +SELECT num, num / 1024 as division FROM foo +` + +type MathRow struct { + Num int32 + Division int32 +} + +func (q *Queries) Math(ctx context.Context) ([]MathRow, error) { + rows, err := q.db.QueryContext(ctx, math) + if err != nil { + return nil, err + } + defer rows.Close() + var items []MathRow + for rows.Next() { + var i MathRow + if err := rows.Scan(&i.Num, &i.Division); 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/mathmatical_operator/stdlib/query.sql b/internal/endtoend/testdata/mathmatical_operator/stdlib/query.sql new file mode 100644 index 0000000..a3655a3 --- /dev/null +++ b/internal/endtoend/testdata/mathmatical_operator/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Math :many +SELECT *, num / 1024 as division FROM foo; diff --git a/internal/endtoend/testdata/mathmatical_operator/stdlib/schema.sql b/internal/endtoend/testdata/mathmatical_operator/stdlib/schema.sql new file mode 100644 index 0000000..cfb1814 --- /dev/null +++ b/internal/endtoend/testdata/mathmatical_operator/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (num integer not null); + diff --git a/internal/endtoend/testdata/mathmatical_operator/stdlib/sqlc.json b/internal/endtoend/testdata/mathmatical_operator/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/mathmatical_operator/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/min_max_date/issue.md b/internal/endtoend/testdata/min_max_date/issue.md new file mode 100644 index 0000000..73083e9 --- /dev/null +++ b/internal/endtoend/testdata/min_max_date/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1574 diff --git a/internal/endtoend/testdata/min_max_date/postgresql/pgx/exec.json b/internal/endtoend/testdata/min_max_date/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/min_max_date/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/min_max_date/postgresql/pgx/go/db.go b/internal/endtoend/testdata/min_max_date/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/min_max_date/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/min_max_date/postgresql/pgx/go/models.go b/internal/endtoend/testdata/min_max_date/postgresql/pgx/go/models.go new file mode 100644 index 0000000..a9219f8 --- /dev/null +++ b/internal/endtoend/testdata/min_max_date/postgresql/pgx/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Activity struct { + AccountID int64 + EventTime pgtype.Timestamptz +} diff --git a/internal/endtoend/testdata/min_max_date/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/min_max_date/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..49981b4 --- /dev/null +++ b/internal/endtoend/testdata/min_max_date/postgresql/pgx/go/query.sql.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const activityStats = `-- name: ActivityStats :one +SELECT COUNT(*) as NumOfActivities, + MIN(event_time) as MinDate, + MAX(event_time) as MaxDate +FROM activities +WHERE account_id = $1 +` + +type ActivityStatsRow struct { + Numofactivities int64 + Mindate pgtype.Timestamptz + Maxdate pgtype.Timestamptz +} + +func (q *Queries) ActivityStats(ctx context.Context, accountID int64) (ActivityStatsRow, error) { + row := q.db.QueryRow(ctx, activityStats, accountID) + var i ActivityStatsRow + err := row.Scan(&i.Numofactivities, &i.Mindate, &i.Maxdate) + return i, err +} diff --git a/internal/endtoend/testdata/min_max_date/postgresql/pgx/query.sql b/internal/endtoend/testdata/min_max_date/postgresql/pgx/query.sql new file mode 100644 index 0000000..19909d0 --- /dev/null +++ b/internal/endtoend/testdata/min_max_date/postgresql/pgx/query.sql @@ -0,0 +1,6 @@ +-- name: ActivityStats :one +SELECT COUNT(*) as NumOfActivities, + MIN(event_time) as MinDate, + MAX(event_time) as MaxDate +FROM activities +WHERE account_id = $1; diff --git a/internal/endtoend/testdata/min_max_date/postgresql/pgx/schema.sql b/internal/endtoend/testdata/min_max_date/postgresql/pgx/schema.sql new file mode 100644 index 0000000..c75fe28 --- /dev/null +++ b/internal/endtoend/testdata/min_max_date/postgresql/pgx/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE activities ( + account_id BIGINT NOT NULL, + event_time TIMESTAMP WITH TIME ZONE NOT NULL +); diff --git a/internal/endtoend/testdata/min_max_date/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/min_max_date/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/min_max_date/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/missing_semicolon/mysql/go/db.go b/internal/endtoend/testdata/missing_semicolon/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/missing_semicolon/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/missing_semicolon/mysql/go/models.go b/internal/endtoend/testdata/missing_semicolon/mysql/go/models.go new file mode 100644 index 0000000..4dbc5a5 --- /dev/null +++ b/internal/endtoend/testdata/missing_semicolon/mysql/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int32 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/missing_semicolon/mysql/go/query.sql.go b/internal/endtoend/testdata/missing_semicolon/mysql/go/query.sql.go new file mode 100644 index 0000000..9520697 --- /dev/null +++ b/internal/endtoend/testdata/missing_semicolon/mysql/go/query.sql.go @@ -0,0 +1,26 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const setAuthor = `-- name: SetAuthor :exec +UPDATE authors +SET name = ? +WHERE id = ? +` + +type SetAuthorParams struct { + Name string + ID int32 +} + +func (q *Queries) SetAuthor(ctx context.Context, arg SetAuthorParams) error { + _, err := q.db.ExecContext(ctx, setAuthor, arg.Name, arg.ID) + return err +} diff --git a/internal/endtoend/testdata/missing_semicolon/mysql/query.sql b/internal/endtoend/testdata/missing_semicolon/mysql/query.sql new file mode 100644 index 0000000..47500d5 --- /dev/null +++ b/internal/endtoend/testdata/missing_semicolon/mysql/query.sql @@ -0,0 +1,4 @@ +-- name: SetAuthor :exec +UPDATE authors +SET name = ? +WHERE id = ? diff --git a/internal/endtoend/testdata/missing_semicolon/mysql/schema.sql b/internal/endtoend/testdata/missing_semicolon/mysql/schema.sql new file mode 100644 index 0000000..4c11a9c --- /dev/null +++ b/internal/endtoend/testdata/missing_semicolon/mysql/schema.sql @@ -0,0 +1,7 @@ +-- https://github.com/sqlc-dev/sqlc/issues/1198 +CREATE TABLE authors ( + id INT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + bio text +); + diff --git a/internal/endtoend/testdata/missing_semicolon/mysql/sqlc.json b/internal/endtoend/testdata/missing_semicolon/mysql/sqlc.json new file mode 100644 index 0000000..0390f67 --- /dev/null +++ b/internal/endtoend/testdata/missing_semicolon/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/missing_semicolon/pgx/v4/query.sql b/internal/endtoend/testdata/missing_semicolon/pgx/v4/query.sql new file mode 100644 index 0000000..80c8354 --- /dev/null +++ b/internal/endtoend/testdata/missing_semicolon/pgx/v4/query.sql @@ -0,0 +1,5 @@ +-- name: FirstQuery :many +SELECT * FROM foo; + +-- name: SecondQuery :many +SELECT * FROM foo WHERE email = $1 diff --git a/internal/endtoend/testdata/missing_semicolon/pgx/v4/schema.sql b/internal/endtoend/testdata/missing_semicolon/pgx/v4/schema.sql new file mode 100644 index 0000000..e2b1d89 --- /dev/null +++ b/internal/endtoend/testdata/missing_semicolon/pgx/v4/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (email text not null); diff --git a/internal/endtoend/testdata/missing_semicolon/pgx/v4/sqlc.json b/internal/endtoend/testdata/missing_semicolon/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/missing_semicolon/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/missing_semicolon/pgx/v4/stderr.txt b/internal/endtoend/testdata/missing_semicolon/pgx/v4/stderr.txt new file mode 100644 index 0000000..7544904 --- /dev/null +++ b/internal/endtoend/testdata/missing_semicolon/pgx/v4/stderr.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:5:1: missing semicolon at end of file diff --git a/internal/endtoend/testdata/missing_semicolon/pgx/v5/query.sql b/internal/endtoend/testdata/missing_semicolon/pgx/v5/query.sql new file mode 100644 index 0000000..80c8354 --- /dev/null +++ b/internal/endtoend/testdata/missing_semicolon/pgx/v5/query.sql @@ -0,0 +1,5 @@ +-- name: FirstQuery :many +SELECT * FROM foo; + +-- name: SecondQuery :many +SELECT * FROM foo WHERE email = $1 diff --git a/internal/endtoend/testdata/missing_semicolon/pgx/v5/schema.sql b/internal/endtoend/testdata/missing_semicolon/pgx/v5/schema.sql new file mode 100644 index 0000000..28f5b2d --- /dev/null +++ b/internal/endtoend/testdata/missing_semicolon/pgx/v5/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (email text not null); \ No newline at end of file diff --git a/internal/endtoend/testdata/missing_semicolon/pgx/v5/sqlc.json b/internal/endtoend/testdata/missing_semicolon/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/missing_semicolon/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/missing_semicolon/pgx/v5/stderr.txt b/internal/endtoend/testdata/missing_semicolon/pgx/v5/stderr.txt new file mode 100644 index 0000000..7544904 --- /dev/null +++ b/internal/endtoend/testdata/missing_semicolon/pgx/v5/stderr.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:5:1: missing semicolon at end of file diff --git a/internal/endtoend/testdata/missing_semicolon/stdlib/query.sql b/internal/endtoend/testdata/missing_semicolon/stdlib/query.sql new file mode 100644 index 0000000..80c8354 --- /dev/null +++ b/internal/endtoend/testdata/missing_semicolon/stdlib/query.sql @@ -0,0 +1,5 @@ +-- name: FirstQuery :many +SELECT * FROM foo; + +-- name: SecondQuery :many +SELECT * FROM foo WHERE email = $1 diff --git a/internal/endtoend/testdata/missing_semicolon/stdlib/schema.sql b/internal/endtoend/testdata/missing_semicolon/stdlib/schema.sql new file mode 100644 index 0000000..28f5b2d --- /dev/null +++ b/internal/endtoend/testdata/missing_semicolon/stdlib/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (email text not null); \ No newline at end of file diff --git a/internal/endtoend/testdata/missing_semicolon/stdlib/sqlc.json b/internal/endtoend/testdata/missing_semicolon/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/missing_semicolon/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/missing_semicolon/stdlib/stderr.txt b/internal/endtoend/testdata/missing_semicolon/stdlib/stderr.txt new file mode 100644 index 0000000..7544904 --- /dev/null +++ b/internal/endtoend/testdata/missing_semicolon/stdlib/stderr.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:5:1: missing semicolon at end of file diff --git a/internal/endtoend/testdata/mix_param_types/mysql/go/db.go b/internal/endtoend/testdata/mix_param_types/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/mix_param_types/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/mix_param_types/mysql/go/models.go b/internal/endtoend/testdata/mix_param_types/mysql/go/models.go new file mode 100644 index 0000000..bf470d2 --- /dev/null +++ b/internal/endtoend/testdata/mix_param_types/mysql/go/models.go @@ -0,0 +1,11 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID uint64 + Name string + Phone string +} diff --git a/internal/endtoend/testdata/mix_param_types/mysql/go/test.sql.go b/internal/endtoend/testdata/mix_param_types/mysql/go/test.sql.go new file mode 100644 index 0000000..75ac6d3 --- /dev/null +++ b/internal/endtoend/testdata/mix_param_types/mysql/go/test.sql.go @@ -0,0 +1,59 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: test.sql + +package querytest + +import ( + "context" +) + +const countOne = `-- name: CountOne :one +SELECT count(1) FROM bar WHERE id = ? AND name <> ? +` + +type CountOneParams struct { + ID uint64 + Name string +} + +func (q *Queries) CountOne(ctx context.Context, arg CountOneParams) (int64, error) { + row := q.db.QueryRowContext(ctx, countOne, arg.ID, arg.Name) + var count int64 + err := row.Scan(&count) + return count, err +} + +const countThree = `-- name: CountThree :one +SELECT count(1) FROM bar WHERE id > ? AND phone <> ? AND name <> ? +` + +type CountThreeParams struct { + ID uint64 + Phone string + Name string +} + +func (q *Queries) CountThree(ctx context.Context, arg CountThreeParams) (int64, error) { + row := q.db.QueryRowContext(ctx, countThree, arg.ID, arg.Phone, arg.Name) + var count int64 + err := row.Scan(&count) + return count, err +} + +const countTwo = `-- name: CountTwo :one +SELECT count(1) FROM bar WHERE id = ? AND name <> ? +` + +type CountTwoParams struct { + ID uint64 + Name string +} + +func (q *Queries) CountTwo(ctx context.Context, arg CountTwoParams) (int64, error) { + row := q.db.QueryRowContext(ctx, countTwo, arg.ID, arg.Name) + var count int64 + err := row.Scan(&count) + return count, err +} diff --git a/internal/endtoend/testdata/mix_param_types/mysql/schema.sql b/internal/endtoend/testdata/mix_param_types/mysql/schema.sql new file mode 100644 index 0000000..b515bf8 --- /dev/null +++ b/internal/endtoend/testdata/mix_param_types/mysql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE bar ( + id serial not null, + name text not null, + phone text not null +); diff --git a/internal/endtoend/testdata/mix_param_types/mysql/sqlc.json b/internal/endtoend/testdata/mix_param_types/mysql/sqlc.json new file mode 100644 index 0000000..3e8d09d --- /dev/null +++ b/internal/endtoend/testdata/mix_param_types/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "test.sql", + "engine": "mysql" + } + ] +} diff --git a/internal/endtoend/testdata/mix_param_types/mysql/test.sql b/internal/endtoend/testdata/mix_param_types/mysql/test.sql new file mode 100644 index 0000000..e23f1dc --- /dev/null +++ b/internal/endtoend/testdata/mix_param_types/mysql/test.sql @@ -0,0 +1,8 @@ +-- name: CountOne :one +SELECT count(1) FROM bar WHERE id = sqlc.arg(id) AND name <> ?; + +-- name: CountTwo :one +SELECT count(1) FROM bar WHERE id = ? AND name <> sqlc.arg(name); + +-- name: CountThree :one +SELECT count(1) FROM bar WHERE id > ? AND phone <> sqlc.arg(phone) AND name <> ?; diff --git a/internal/endtoend/testdata/mix_param_types/postgresql/exec.json b/internal/endtoend/testdata/mix_param_types/postgresql/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/mix_param_types/postgresql/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/mix_param_types/postgresql/go/db.go b/internal/endtoend/testdata/mix_param_types/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/mix_param_types/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/mix_param_types/postgresql/go/models.go b/internal/endtoend/testdata/mix_param_types/postgresql/go/models.go new file mode 100644 index 0000000..27da234 --- /dev/null +++ b/internal/endtoend/testdata/mix_param_types/postgresql/go/models.go @@ -0,0 +1,11 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 + Name string + Phone string +} diff --git a/internal/endtoend/testdata/mix_param_types/postgresql/go/test.sql.go b/internal/endtoend/testdata/mix_param_types/postgresql/go/test.sql.go new file mode 100644 index 0000000..c38d8be --- /dev/null +++ b/internal/endtoend/testdata/mix_param_types/postgresql/go/test.sql.go @@ -0,0 +1,60 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: test.sql + +package querytest + +import ( + "context" +) + +const countOne = `-- name: CountOne :one +SELECT count(1) FROM bar WHERE id = $2 AND name <> $1 LIMIT $3 +` + +type CountOneParams struct { + Name string + ID int32 + Limit int32 +} + +func (q *Queries) CountOne(ctx context.Context, arg CountOneParams) (int64, error) { + row := q.db.QueryRowContext(ctx, countOne, arg.Name, arg.ID, arg.Limit) + var count int64 + err := row.Scan(&count) + return count, err +} + +const countThree = `-- name: CountThree :one +SELECT count(1) FROM bar WHERE id > $2 AND phone <> $3 AND name <> $1 +` + +type CountThreeParams struct { + Name string + ID int32 + Phone string +} + +func (q *Queries) CountThree(ctx context.Context, arg CountThreeParams) (int64, error) { + row := q.db.QueryRowContext(ctx, countThree, arg.Name, arg.ID, arg.Phone) + var count int64 + err := row.Scan(&count) + return count, err +} + +const countTwo = `-- name: CountTwo :one +SELECT count(1) FROM bar WHERE id = $1 AND name <> $2 +` + +type CountTwoParams struct { + ID int32 + Name string +} + +func (q *Queries) CountTwo(ctx context.Context, arg CountTwoParams) (int64, error) { + row := q.db.QueryRowContext(ctx, countTwo, arg.ID, arg.Name) + var count int64 + err := row.Scan(&count) + return count, err +} diff --git a/internal/endtoend/testdata/mix_param_types/postgresql/schema.sql b/internal/endtoend/testdata/mix_param_types/postgresql/schema.sql new file mode 100644 index 0000000..9e554c1 --- /dev/null +++ b/internal/endtoend/testdata/mix_param_types/postgresql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE bar ( + id serial not null, + name text not null, + phone text not null +); \ No newline at end of file diff --git a/internal/endtoend/testdata/mix_param_types/postgresql/sqlc.json b/internal/endtoend/testdata/mix_param_types/postgresql/sqlc.json new file mode 100644 index 0000000..2bb3f0d --- /dev/null +++ b/internal/endtoend/testdata/mix_param_types/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "test.sql", + "engine": "postgresql" + } + ] +} diff --git a/internal/endtoend/testdata/mix_param_types/postgresql/test.sql b/internal/endtoend/testdata/mix_param_types/postgresql/test.sql new file mode 100644 index 0000000..6811d1f --- /dev/null +++ b/internal/endtoend/testdata/mix_param_types/postgresql/test.sql @@ -0,0 +1,8 @@ +-- name: CountOne :one +SELECT count(1) FROM bar WHERE id = sqlc.arg(id) AND name <> $1 LIMIT sqlc.arg('limit'); + +-- name: CountTwo :one +SELECT count(1) FROM bar WHERE id = $1 AND name <> sqlc.arg(name); + +-- name: CountThree :one +SELECT count(1) FROM bar WHERE id > $2 AND phone <> sqlc.arg(phone) AND name <> $1; diff --git a/internal/endtoend/testdata/multibyte_comment/sqlite/go/db.go b/internal/endtoend/testdata/multibyte_comment/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/multibyte_comment/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/multibyte_comment/sqlite/go/models.go b/internal/endtoend/testdata/multibyte_comment/sqlite/go/models.go new file mode 100644 index 0000000..da152e2 --- /dev/null +++ b/internal/endtoend/testdata/multibyte_comment/sqlite/go/models.go @@ -0,0 +1,11 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Item struct { + ID int64 + Name string + CapRead string +} diff --git a/internal/endtoend/testdata/multibyte_comment/sqlite/go/query.sql.go b/internal/endtoend/testdata/multibyte_comment/sqlite/go/query.sql.go new file mode 100644 index 0000000..0ff9f72 --- /dev/null +++ b/internal/endtoend/testdata/multibyte_comment/sqlite/go/query.sql.go @@ -0,0 +1,87 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const createItem = `-- name: CreateItem :exec +INSERT INTO items (name, cap_read) +VALUES (?, ?) +` + +type CreateItemParams struct { + Name string + CapRead string +} + +// 当新建条目时,需要写入名称和权限 +func (q *Queries) CreateItem(ctx context.Context, arg CreateItemParams) error { + _, err := q.db.ExecContext(ctx, createItem, arg.Name, arg.CapRead) + return err +} + +const deleteItem = `-- name: DeleteItem :one +DELETE FROM items WHERE id = ? RETURNING id, name, cap_read +` + +func (q *Queries) DeleteItem(ctx context.Context, id int64) (Item, error) { + row := q.db.QueryRowContext(ctx, deleteItem, id) + var i Item + err := row.Scan(&i.ID, &i.Name, &i.CapRead) + return i, err +} + +const listItems = `-- name: ListItems :many + +SELECT id, name, cap_read +FROM items +WHERE cap_read = 'anonymous' +ORDER BY name +` + +// Multi-byte UTF-8 in comments must not shift the byte offsets used to slice +// query text out of the source file (#4523, #4235, #4372). +// an em dash right here — must not truncate the ORDER BY below +func (q *Queries) ListItems(ctx context.Context) ([]Item, error) { + rows, err := q.db.QueryContext(ctx, listItems) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Item + for rows.Next() { + var i Item + if err := rows.Scan(&i.ID, &i.Name, &i.CapRead); 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 updateItem = `-- name: UpdateItem :exec + +UPDATE items SET name = ? WHERE id = ? +` + +type UpdateItemParams struct { + Name string + ID int64 +} + +// section — divider between queries +func (q *Queries) UpdateItem(ctx context.Context, arg UpdateItemParams) error { + _, err := q.db.ExecContext(ctx, updateItem, arg.Name, arg.ID) + return err +} diff --git a/internal/endtoend/testdata/multibyte_comment/sqlite/query.sql b/internal/endtoend/testdata/multibyte_comment/sqlite/query.sql new file mode 100644 index 0000000..527d390 --- /dev/null +++ b/internal/endtoend/testdata/multibyte_comment/sqlite/query.sql @@ -0,0 +1,22 @@ +-- Multi-byte UTF-8 in comments must not shift the byte offsets used to slice +-- query text out of the source file (#4523, #4235, #4372). + +-- name: ListItems :many +-- an em dash right here — must not truncate the ORDER BY below +SELECT id, name, cap_read +FROM items +WHERE cap_read = 'anonymous' +ORDER BY name; + +-- section — divider between queries + +-- name: UpdateItem :exec +UPDATE items SET name = ? WHERE id = ?; + +-- name: CreateItem :exec +-- 当新建条目时,需要写入名称和权限 +INSERT INTO items (name, cap_read) +VALUES (?, ?); + +-- name: DeleteItem :one +DELETE FROM items WHERE id = ? RETURNING id, name, cap_read; diff --git a/internal/endtoend/testdata/multibyte_comment/sqlite/schema.sql b/internal/endtoend/testdata/multibyte_comment/sqlite/schema.sql new file mode 100644 index 0000000..cb0dedc --- /dev/null +++ b/internal/endtoend/testdata/multibyte_comment/sqlite/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE items ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL, + cap_read TEXT NOT NULL +); diff --git a/internal/endtoend/testdata/multibyte_comment/sqlite/sqlc.json b/internal/endtoend/testdata/multibyte_comment/sqlite/sqlc.json new file mode 100644 index 0000000..cd66df0 --- /dev/null +++ b/internal/endtoend/testdata/multibyte_comment/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/multidimension_array/pgx/v4/go/db.go b/internal/endtoend/testdata/multidimension_array/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/multidimension_array/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/multidimension_array/pgx/v4/go/models.go b/internal/endtoend/testdata/multidimension_array/pgx/v4/go/models.go new file mode 100644 index 0000000..edbfbc9 --- /dev/null +++ b/internal/endtoend/testdata/multidimension_array/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + Tags [][]string +} diff --git a/internal/endtoend/testdata/multidimension_array/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/multidimension_array/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..a61f4e8 --- /dev/null +++ b/internal/endtoend/testdata/multidimension_array/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const textArray = `-- name: TextArray :many +SELECT tags FROM bar +` + +func (q *Queries) TextArray(ctx context.Context) ([][][]string, error) { + rows, err := q.db.Query(ctx, textArray) + if err != nil { + return nil, err + } + defer rows.Close() + var items [][][]string + for rows.Next() { + var tags [][]string + if err := rows.Scan(&tags); err != nil { + return nil, err + } + items = append(items, tags) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/multidimension_array/pgx/v4/query.sql b/internal/endtoend/testdata/multidimension_array/pgx/v4/query.sql new file mode 100644 index 0000000..4c6b353 --- /dev/null +++ b/internal/endtoend/testdata/multidimension_array/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: TextArray :many +SELECT * FROM bar; diff --git a/internal/endtoend/testdata/multidimension_array/pgx/v4/schema.sql b/internal/endtoend/testdata/multidimension_array/pgx/v4/schema.sql new file mode 100644 index 0000000..d11d4bd --- /dev/null +++ b/internal/endtoend/testdata/multidimension_array/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (tags text[][] not null); + diff --git a/internal/endtoend/testdata/multidimension_array/pgx/v4/sqlc.json b/internal/endtoend/testdata/multidimension_array/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/multidimension_array/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/multidimension_array/pgx/v5/go/db.go b/internal/endtoend/testdata/multidimension_array/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/multidimension_array/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/multidimension_array/pgx/v5/go/models.go b/internal/endtoend/testdata/multidimension_array/pgx/v5/go/models.go new file mode 100644 index 0000000..edbfbc9 --- /dev/null +++ b/internal/endtoend/testdata/multidimension_array/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + Tags [][]string +} diff --git a/internal/endtoend/testdata/multidimension_array/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/multidimension_array/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..a61f4e8 --- /dev/null +++ b/internal/endtoend/testdata/multidimension_array/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const textArray = `-- name: TextArray :many +SELECT tags FROM bar +` + +func (q *Queries) TextArray(ctx context.Context) ([][][]string, error) { + rows, err := q.db.Query(ctx, textArray) + if err != nil { + return nil, err + } + defer rows.Close() + var items [][][]string + for rows.Next() { + var tags [][]string + if err := rows.Scan(&tags); err != nil { + return nil, err + } + items = append(items, tags) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/multidimension_array/pgx/v5/query.sql b/internal/endtoend/testdata/multidimension_array/pgx/v5/query.sql new file mode 100644 index 0000000..4c6b353 --- /dev/null +++ b/internal/endtoend/testdata/multidimension_array/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: TextArray :many +SELECT * FROM bar; diff --git a/internal/endtoend/testdata/multidimension_array/pgx/v5/schema.sql b/internal/endtoend/testdata/multidimension_array/pgx/v5/schema.sql new file mode 100644 index 0000000..d11d4bd --- /dev/null +++ b/internal/endtoend/testdata/multidimension_array/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (tags text[][] not null); + diff --git a/internal/endtoend/testdata/multidimension_array/pgx/v5/sqlc.json b/internal/endtoend/testdata/multidimension_array/pgx/v5/sqlc.json new file mode 100644 index 0000000..d5f0a3d --- /dev/null +++ b/internal/endtoend/testdata/multidimension_array/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/multidimension_array/stdlib/go/db.go b/internal/endtoend/testdata/multidimension_array/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/multidimension_array/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/multidimension_array/stdlib/go/models.go b/internal/endtoend/testdata/multidimension_array/stdlib/go/models.go new file mode 100644 index 0000000..edbfbc9 --- /dev/null +++ b/internal/endtoend/testdata/multidimension_array/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + Tags [][]string +} diff --git a/internal/endtoend/testdata/multidimension_array/stdlib/go/query.sql.go b/internal/endtoend/testdata/multidimension_array/stdlib/go/query.sql.go new file mode 100644 index 0000000..20104c7 --- /dev/null +++ b/internal/endtoend/testdata/multidimension_array/stdlib/go/query.sql.go @@ -0,0 +1,39 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/lib/pq" +) + +const textArray = `-- name: TextArray :many +SELECT tags FROM bar +` + +func (q *Queries) TextArray(ctx context.Context) ([][][]string, error) { + rows, err := q.db.QueryContext(ctx, textArray) + if err != nil { + return nil, err + } + defer rows.Close() + var items [][][]string + for rows.Next() { + var tags [][]string + if err := rows.Scan(pq.Array(&tags)); err != nil { + return nil, err + } + items = append(items, tags) + } + 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/multidimension_array/stdlib/query.sql b/internal/endtoend/testdata/multidimension_array/stdlib/query.sql new file mode 100644 index 0000000..4c6b353 --- /dev/null +++ b/internal/endtoend/testdata/multidimension_array/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: TextArray :many +SELECT * FROM bar; diff --git a/internal/endtoend/testdata/multidimension_array/stdlib/schema.sql b/internal/endtoend/testdata/multidimension_array/stdlib/schema.sql new file mode 100644 index 0000000..d11d4bd --- /dev/null +++ b/internal/endtoend/testdata/multidimension_array/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (tags text[][] not null); + diff --git a/internal/endtoend/testdata/multidimension_array/stdlib/sqlc.json b/internal/endtoend/testdata/multidimension_array/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/multidimension_array/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/multischema/pgx/v4/go/db.go b/internal/endtoend/testdata/multischema/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/multischema/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/multischema/pgx/v4/go/models.go b/internal/endtoend/testdata/multischema/pgx/v4/go/models.go new file mode 100644 index 0000000..b72efbb --- /dev/null +++ b/internal/endtoend/testdata/multischema/pgx/v4/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ID int32 +} + +type Foo struct { + ID int32 + Bar sql.NullInt32 +} diff --git a/internal/endtoend/testdata/multischema/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/multischema/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..5f30601 --- /dev/null +++ b/internal/endtoend/testdata/multischema/pgx/v4/go/query.sql.go @@ -0,0 +1,58 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listBar = `-- name: ListBar :many +SELECT id FROM bar +` + +func (q *Queries) ListBar(ctx context.Context) ([]int32, error) { + rows, err := q.db.Query(ctx, listBar) + 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 listFoo = `-- name: ListFoo :many +SELECT id, bar FROM foo +` + +func (q *Queries) ListFoo(ctx context.Context) ([]Foo, error) { + rows, err := q.db.Query(ctx, listFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.ID, &i.Bar); 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/multischema/pgx/v4/query.sql b/internal/endtoend/testdata/multischema/pgx/v4/query.sql new file mode 100644 index 0000000..926eec2 --- /dev/null +++ b/internal/endtoend/testdata/multischema/pgx/v4/query.sql @@ -0,0 +1,5 @@ +CREATE TABLE bar (id serial not null); +CREATE TABLE foo (id serial not null, bar serial); + +-- name: ListBar :many +SELECT * FROM bar; diff --git a/internal/endtoend/testdata/multischema/pgx/v4/sql/ignore.txt b/internal/endtoend/testdata/multischema/pgx/v4/sql/ignore.txt new file mode 100644 index 0000000..f4c35ce --- /dev/null +++ b/internal/endtoend/testdata/multischema/pgx/v4/sql/ignore.txt @@ -0,0 +1,3 @@ +Hello! + +This file should be ignored diff --git a/internal/endtoend/testdata/multischema/pgx/v4/sql/query.sql b/internal/endtoend/testdata/multischema/pgx/v4/sql/query.sql new file mode 100644 index 0000000..b475d29 --- /dev/null +++ b/internal/endtoend/testdata/multischema/pgx/v4/sql/query.sql @@ -0,0 +1,2 @@ +-- name: ListFoo :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/multischema/pgx/v4/sqlc.json b/internal/endtoend/testdata/multischema/pgx/v4/sqlc.json new file mode 100644 index 0000000..5f9f40e --- /dev/null +++ b/internal/endtoend/testdata/multischema/pgx/v4/sqlc.json @@ -0,0 +1,19 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": [ + "query.sql", + "sql" + ], + "queries": [ + "query.sql", + "sql" + ] + } + ] +} diff --git a/internal/endtoend/testdata/multischema/pgx/v5/go/db.go b/internal/endtoend/testdata/multischema/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/multischema/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/multischema/pgx/v5/go/models.go b/internal/endtoend/testdata/multischema/pgx/v5/go/models.go new file mode 100644 index 0000000..977ceaa --- /dev/null +++ b/internal/endtoend/testdata/multischema/pgx/v5/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Bar struct { + ID int32 +} + +type Foo struct { + ID int32 + Bar pgtype.Int4 +} diff --git a/internal/endtoend/testdata/multischema/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/multischema/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..5f30601 --- /dev/null +++ b/internal/endtoend/testdata/multischema/pgx/v5/go/query.sql.go @@ -0,0 +1,58 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listBar = `-- name: ListBar :many +SELECT id FROM bar +` + +func (q *Queries) ListBar(ctx context.Context) ([]int32, error) { + rows, err := q.db.Query(ctx, listBar) + 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 listFoo = `-- name: ListFoo :many +SELECT id, bar FROM foo +` + +func (q *Queries) ListFoo(ctx context.Context) ([]Foo, error) { + rows, err := q.db.Query(ctx, listFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.ID, &i.Bar); 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/multischema/pgx/v5/query.sql b/internal/endtoend/testdata/multischema/pgx/v5/query.sql new file mode 100644 index 0000000..926eec2 --- /dev/null +++ b/internal/endtoend/testdata/multischema/pgx/v5/query.sql @@ -0,0 +1,5 @@ +CREATE TABLE bar (id serial not null); +CREATE TABLE foo (id serial not null, bar serial); + +-- name: ListBar :many +SELECT * FROM bar; diff --git a/internal/endtoend/testdata/multischema/pgx/v5/sql/ignore.txt b/internal/endtoend/testdata/multischema/pgx/v5/sql/ignore.txt new file mode 100644 index 0000000..f4c35ce --- /dev/null +++ b/internal/endtoend/testdata/multischema/pgx/v5/sql/ignore.txt @@ -0,0 +1,3 @@ +Hello! + +This file should be ignored diff --git a/internal/endtoend/testdata/multischema/pgx/v5/sql/query.sql b/internal/endtoend/testdata/multischema/pgx/v5/sql/query.sql new file mode 100644 index 0000000..b475d29 --- /dev/null +++ b/internal/endtoend/testdata/multischema/pgx/v5/sql/query.sql @@ -0,0 +1,2 @@ +-- name: ListFoo :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/multischema/pgx/v5/sqlc.json b/internal/endtoend/testdata/multischema/pgx/v5/sqlc.json new file mode 100644 index 0000000..28fc49b --- /dev/null +++ b/internal/endtoend/testdata/multischema/pgx/v5/sqlc.json @@ -0,0 +1,19 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": [ + "query.sql", + "sql" + ], + "queries": [ + "query.sql", + "sql" + ] + } + ] +} diff --git a/internal/endtoend/testdata/multischema/stdlib/go/db.go b/internal/endtoend/testdata/multischema/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/multischema/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/multischema/stdlib/go/models.go b/internal/endtoend/testdata/multischema/stdlib/go/models.go new file mode 100644 index 0000000..b72efbb --- /dev/null +++ b/internal/endtoend/testdata/multischema/stdlib/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ID int32 +} + +type Foo struct { + ID int32 + Bar sql.NullInt32 +} diff --git a/internal/endtoend/testdata/multischema/stdlib/go/query.sql.go b/internal/endtoend/testdata/multischema/stdlib/go/query.sql.go new file mode 100644 index 0000000..0743124 --- /dev/null +++ b/internal/endtoend/testdata/multischema/stdlib/go/query.sql.go @@ -0,0 +1,64 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listBar = `-- name: ListBar :many +SELECT id FROM bar +` + +func (q *Queries) ListBar(ctx context.Context) ([]int32, error) { + rows, err := q.db.QueryContext(ctx, listBar) + 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 listFoo = `-- name: ListFoo :many +SELECT id, bar FROM foo +` + +func (q *Queries) ListFoo(ctx context.Context) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, listFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.ID, &i.Bar); 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/multischema/stdlib/query.sql b/internal/endtoend/testdata/multischema/stdlib/query.sql new file mode 100644 index 0000000..926eec2 --- /dev/null +++ b/internal/endtoend/testdata/multischema/stdlib/query.sql @@ -0,0 +1,5 @@ +CREATE TABLE bar (id serial not null); +CREATE TABLE foo (id serial not null, bar serial); + +-- name: ListBar :many +SELECT * FROM bar; diff --git a/internal/endtoend/testdata/multischema/stdlib/sql/ignore.txt b/internal/endtoend/testdata/multischema/stdlib/sql/ignore.txt new file mode 100644 index 0000000..f4c35ce --- /dev/null +++ b/internal/endtoend/testdata/multischema/stdlib/sql/ignore.txt @@ -0,0 +1,3 @@ +Hello! + +This file should be ignored diff --git a/internal/endtoend/testdata/multischema/stdlib/sql/query.sql b/internal/endtoend/testdata/multischema/stdlib/sql/query.sql new file mode 100644 index 0000000..b475d29 --- /dev/null +++ b/internal/endtoend/testdata/multischema/stdlib/sql/query.sql @@ -0,0 +1,2 @@ +-- name: ListFoo :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/multischema/stdlib/sqlc.json b/internal/endtoend/testdata/multischema/stdlib/sqlc.json new file mode 100644 index 0000000..ed961ba --- /dev/null +++ b/internal/endtoend/testdata/multischema/stdlib/sqlc.json @@ -0,0 +1,17 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": [ + "query.sql", + "sql" + ], + "queries": [ + "query.sql", + "sql" + ] + } + ] +} diff --git a/internal/endtoend/testdata/mysql_ddl_routines/mysql/go/db.go b/internal/endtoend/testdata/mysql_ddl_routines/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/mysql_ddl_routines/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/mysql_ddl_routines/mysql/go/models.go b/internal/endtoend/testdata/mysql_ddl_routines/mysql/go/models.go new file mode 100644 index 0000000..a058e12 --- /dev/null +++ b/internal/endtoend/testdata/mysql_ddl_routines/mysql/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "time" +) + +type Collection struct { + ID int64 + UpdatedAt time.Time +} diff --git a/internal/endtoend/testdata/mysql_ddl_routines/mysql/go/query.sql.go b/internal/endtoend/testdata/mysql_ddl_routines/mysql/go/query.sql.go new file mode 100644 index 0000000..f23260b --- /dev/null +++ b/internal/endtoend/testdata/mysql_ddl_routines/mysql/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getCollection = `-- name: GetCollection :one +SELECT id, updated_at FROM collections WHERE id = ? +` + +func (q *Queries) GetCollection(ctx context.Context, id int64) (Collection, error) { + row := q.db.QueryRowContext(ctx, getCollection, id) + var i Collection + err := row.Scan(&i.ID, &i.UpdatedAt) + return i, err +} diff --git a/internal/endtoend/testdata/mysql_ddl_routines/mysql/query.sql b/internal/endtoend/testdata/mysql_ddl_routines/mysql/query.sql new file mode 100644 index 0000000..f75433b --- /dev/null +++ b/internal/endtoend/testdata/mysql_ddl_routines/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: GetCollection :one +SELECT id, updated_at FROM collections WHERE id = ?; diff --git a/internal/endtoend/testdata/mysql_ddl_routines/mysql/schema.sql b/internal/endtoend/testdata/mysql_ddl_routines/mysql/schema.sql new file mode 100644 index 0000000..3c614e5 --- /dev/null +++ b/internal/endtoend/testdata/mysql_ddl_routines/mysql/schema.sql @@ -0,0 +1,12 @@ +CREATE TABLE collections ( + id BIGINT PRIMARY KEY, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE TRIGGER update_timestamp_collections BEFORE UPDATE ON collections FOR EACH ROW SET NEW.updated_at = CURRENT_TIMESTAMP; + +CREATE FUNCTION uuidv4() RETURNS CHAR(36) NO SQL RETURN LOWER(HEX(RANDOM_BYTES(4))); + +CREATE PROCEDURE touch_collections() UPDATE collections SET updated_at = NOW(); + +CREATE EVENT clear_stale_collections ON SCHEDULE EVERY 1 HOUR DO DELETE FROM collections WHERE updated_at < CURRENT_TIMESTAMP - INTERVAL 30 DAY; diff --git a/internal/endtoend/testdata/mysql_ddl_routines/mysql/sqlc.json b/internal/endtoend/testdata/mysql_ddl_routines/mysql/sqlc.json new file mode 100644 index 0000000..7dabfee --- /dev/null +++ b/internal/endtoend/testdata/mysql_ddl_routines/mysql/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "sql_package": "database/sql", + "sql_driver": "github.com/go-sql-driver/mysql", + "engine": "mysql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/mysql_default_expression/mysql/go/db.go b/internal/endtoend/testdata/mysql_default_expression/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/mysql_default_expression/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/mysql_default_expression/mysql/go/models.go b/internal/endtoend/testdata/mysql_default_expression/mysql/go/models.go new file mode 100644 index 0000000..87f7917 --- /dev/null +++ b/internal/endtoend/testdata/mysql_default_expression/mysql/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "time" +) + +type Expiration struct { + ID int32 + CreatedAt time.Time + Expiry time.Time +} diff --git a/internal/endtoend/testdata/mysql_default_expression/mysql/go/query.sql.go b/internal/endtoend/testdata/mysql_default_expression/mysql/go/query.sql.go new file mode 100644 index 0000000..1f73628 --- /dev/null +++ b/internal/endtoend/testdata/mysql_default_expression/mysql/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getExpiration = `-- name: GetExpiration :one +SELECT id, created_at, expiry FROM expirations WHERE id = ? +` + +func (q *Queries) GetExpiration(ctx context.Context, id int32) (Expiration, error) { + row := q.db.QueryRowContext(ctx, getExpiration, id) + var i Expiration + err := row.Scan(&i.ID, &i.CreatedAt, &i.Expiry) + return i, err +} diff --git a/internal/endtoend/testdata/mysql_default_expression/mysql/query.sql b/internal/endtoend/testdata/mysql_default_expression/mysql/query.sql new file mode 100644 index 0000000..62e0acd --- /dev/null +++ b/internal/endtoend/testdata/mysql_default_expression/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: GetExpiration :one +SELECT id, created_at, expiry FROM expirations WHERE id = ?; diff --git a/internal/endtoend/testdata/mysql_default_expression/mysql/schema.sql b/internal/endtoend/testdata/mysql_default_expression/mysql/schema.sql new file mode 100644 index 0000000..09a7a35 --- /dev/null +++ b/internal/endtoend/testdata/mysql_default_expression/mysql/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE expirations ( + id INT NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT (UTC_TIMESTAMP()), + expiry TIMESTAMP NOT NULL DEFAULT (CURRENT_TIMESTAMP + INTERVAL 30 DAY), + PRIMARY KEY (id) +); diff --git a/internal/endtoend/testdata/mysql_default_expression/mysql/sqlc.json b/internal/endtoend/testdata/mysql_default_expression/mysql/sqlc.json new file mode 100644 index 0000000..7dabfee --- /dev/null +++ b/internal/endtoend/testdata/mysql_default_expression/mysql/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "sql_package": "database/sql", + "sql_driver": "github.com/go-sql-driver/mysql", + "engine": "mysql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/mysql_default_value/mysql/go/db.go b/internal/endtoend/testdata/mysql_default_value/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/mysql_default_value/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/mysql_default_value/mysql/go/models.go b/internal/endtoend/testdata/mysql_default_value/mysql/go/models.go new file mode 100644 index 0000000..9187e54 --- /dev/null +++ b/internal/endtoend/testdata/mysql_default_value/mysql/go/models.go @@ -0,0 +1,12 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Author struct { + ID int32 + Name string + Bio string + Explanation string +} diff --git a/internal/endtoend/testdata/mysql_default_value/mysql/go/query.sql.go b/internal/endtoend/testdata/mysql_default_value/mysql/go/query.sql.go new file mode 100644 index 0000000..5878a5a --- /dev/null +++ b/internal/endtoend/testdata/mysql_default_value/mysql/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const selectAuthor = `-- name: SelectAuthor :many +SELECT id, name, bio, explanation FROM authors +` + +func (q *Queries) SelectAuthor(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, selectAuthor) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan( + &i.ID, + &i.Name, + &i.Bio, + &i.Explanation, + ); 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/mysql_default_value/mysql/query.sql b/internal/endtoend/testdata/mysql_default_value/mysql/query.sql new file mode 100644 index 0000000..00b1f3c --- /dev/null +++ b/internal/endtoend/testdata/mysql_default_value/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: SelectAuthor :many +SELECT * FROM authors; diff --git a/internal/endtoend/testdata/mysql_default_value/mysql/schema.sql b/internal/endtoend/testdata/mysql_default_value/mysql/schema.sql new file mode 100644 index 0000000..be66344 --- /dev/null +++ b/internal/endtoend/testdata/mysql_default_value/mysql/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE authors ( + id INT PRIMARY KEY, + name text NOT NULL, + bio text NOT NULL +); + +ALTER TABLE authors ADD COLUMN explanation text NOT NULL DEFAULT (''); diff --git a/internal/endtoend/testdata/mysql_default_value/mysql/sqlc.json b/internal/endtoend/testdata/mysql_default_value/mysql/sqlc.json new file mode 100644 index 0000000..7dabfee --- /dev/null +++ b/internal/endtoend/testdata/mysql_default_value/mysql/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "sql_package": "database/sql", + "sql_driver": "github.com/go-sql-driver/mysql", + "engine": "mysql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/mysql_json_table/mysql/go/db.go b/internal/endtoend/testdata/mysql_json_table/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/mysql_json_table/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/mysql_json_table/mysql/go/models.go b/internal/endtoend/testdata/mysql_json_table/mysql/go/models.go new file mode 100644 index 0000000..2e9aaeb --- /dev/null +++ b/internal/endtoend/testdata/mysql_json_table/mysql/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Person struct { + Emails string +} + +type PersonEmail struct { + Email string +} diff --git a/internal/endtoend/testdata/mysql_json_table/mysql/go/query.sql.go b/internal/endtoend/testdata/mysql_json_table/mysql/go/query.sql.go new file mode 100644 index 0000000..1089efb --- /dev/null +++ b/internal/endtoend/testdata/mysql_json_table/mysql/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getEmails = `-- name: GetEmails :many +SELECT email FROM person_email +` + +func (q *Queries) GetEmails(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, getEmails) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var email string + if err := rows.Scan(&email); err != nil { + return nil, err + } + items = append(items, email) + } + 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/mysql_json_table/mysql/query.sql b/internal/endtoend/testdata/mysql_json_table/mysql/query.sql new file mode 100644 index 0000000..8b22b52 --- /dev/null +++ b/internal/endtoend/testdata/mysql_json_table/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: GetEmails :many +SELECT email FROM person_email; diff --git a/internal/endtoend/testdata/mysql_json_table/mysql/schema.sql b/internal/endtoend/testdata/mysql_json_table/mysql/schema.sql new file mode 100644 index 0000000..7e4a730 --- /dev/null +++ b/internal/endtoend/testdata/mysql_json_table/mysql/schema.sql @@ -0,0 +1,12 @@ +CREATE TABLE person ( + emails TEXT NOT NULL +); + +CREATE TABLE person_email ( + email TEXT NOT NULL +); + +INSERT INTO person_email (`email`) + SELECT pe.email + FROM person AS p + JOIN JSON_TABLE(p.emails, '$[*]' COLUMNS(email TEXT PATH '$')) AS pe; diff --git a/internal/endtoend/testdata/mysql_json_table/mysql/sqlc.json b/internal/endtoend/testdata/mysql_json_table/mysql/sqlc.json new file mode 100644 index 0000000..7dabfee --- /dev/null +++ b/internal/endtoend/testdata/mysql_json_table/mysql/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "sql_package": "database/sql", + "sql_driver": "github.com/go-sql-driver/mysql", + "engine": "mysql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/mysql_optimizer_hints/mysql/go/db.go b/internal/endtoend/testdata/mysql_optimizer_hints/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/mysql_optimizer_hints/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/mysql_optimizer_hints/mysql/go/models.go b/internal/endtoend/testdata/mysql_optimizer_hints/mysql/go/models.go new file mode 100644 index 0000000..b5395d4 --- /dev/null +++ b/internal/endtoend/testdata/mysql_optimizer_hints/mysql/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString +} diff --git a/internal/endtoend/testdata/mysql_optimizer_hints/mysql/go/query.sql.go b/internal/endtoend/testdata/mysql_optimizer_hints/mysql/go/query.sql.go new file mode 100644 index 0000000..46febc1 --- /dev/null +++ b/internal/endtoend/testdata/mysql_optimizer_hints/mysql/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const inlineHint = `-- name: InlineHint :one +SELECT /*+ MAX_EXECUTION_TIME(1000) */ bar FROM foo LIMIT 1 +` + +func (q *Queries) InlineHint(ctx context.Context) (sql.NullString, error) { + row := q.db.QueryRowContext(ctx, inlineHint) + var bar sql.NullString + err := row.Scan(&bar) + return bar, err +} + +const multilineHint = `-- name: MultilineHint :one +SELECT +/*+ MAX_EXECUTION_TIME(1000) */ +bar +FROM foo +LIMIT 1 +` + +func (q *Queries) MultilineHint(ctx context.Context) (sql.NullString, error) { + row := q.db.QueryRowContext(ctx, multilineHint) + var bar sql.NullString + err := row.Scan(&bar) + return bar, err +} diff --git a/internal/endtoend/testdata/mysql_optimizer_hints/mysql/query.sql b/internal/endtoend/testdata/mysql_optimizer_hints/mysql/query.sql new file mode 100644 index 0000000..fa90093 --- /dev/null +++ b/internal/endtoend/testdata/mysql_optimizer_hints/mysql/query.sql @@ -0,0 +1,9 @@ +-- name: InlineHint :one +SELECT /*+ MAX_EXECUTION_TIME(1000) */ bar FROM foo LIMIT 1; + +-- name: MultilineHint :one +SELECT +/*+ MAX_EXECUTION_TIME(1000) */ +bar +FROM foo +LIMIT 1; diff --git a/internal/endtoend/testdata/mysql_optimizer_hints/mysql/schema.sql b/internal/endtoend/testdata/mysql_optimizer_hints/mysql/schema.sql new file mode 100644 index 0000000..d849628 --- /dev/null +++ b/internal/endtoend/testdata/mysql_optimizer_hints/mysql/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (bar text); diff --git a/internal/endtoend/testdata/mysql_optimizer_hints/mysql/sqlc.json b/internal/endtoend/testdata/mysql_optimizer_hints/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/mysql_optimizer_hints/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/mysql_reference_manual/README.md b/internal/endtoend/testdata/mysql_reference_manual/README.md new file mode 100644 index 0000000..95a4cbf --- /dev/null +++ b/internal/endtoend/testdata/mysql_reference_manual/README.md @@ -0,0 +1,2 @@ +All queries and examples in this directory come from the [MySQL Reference +Manual](https://dev.mysql.com/doc/refman/8.0/en/). diff --git a/internal/endtoend/testdata/mysql_reference_manual/aggregate_functions/go/db.go b/internal/endtoend/testdata/mysql_reference_manual/aggregate_functions/go/db.go new file mode 100644 index 0000000..60f0b8c --- /dev/null +++ b/internal/endtoend/testdata/mysql_reference_manual/aggregate_functions/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package aggregate_functions + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/mysql_reference_manual/aggregate_functions/go/group_concat.sql.go b/internal/endtoend/testdata/mysql_reference_manual/aggregate_functions/go/group_concat.sql.go new file mode 100644 index 0000000..d2e9e77 --- /dev/null +++ b/internal/endtoend/testdata/mysql_reference_manual/aggregate_functions/go/group_concat.sql.go @@ -0,0 +1,80 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: group_concat.sql + +package aggregate_functions + +import ( + "context" + "database/sql" +) + +const groupConcat = `-- name: GroupConcat :many +SELECT student_name, GROUP_CONCAT(test_score) +FROM student +GROUP BY student_name +` + +type GroupConcatRow struct { + StudentName sql.NullString + GroupConcat sql.NullString +} + +func (q *Queries) GroupConcat(ctx context.Context) ([]GroupConcatRow, error) { + rows, err := q.db.QueryContext(ctx, groupConcat) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GroupConcatRow + for rows.Next() { + var i GroupConcatRow + if err := rows.Scan(&i.StudentName, &i.GroupConcat); 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 groupConcatOrderBy = `-- name: GroupConcatOrderBy :many +SELECT student_name, + GROUP_CONCAT(DISTINCT test_score ORDER BY test_score DESC SEPARATOR ' ') +FROM student +GROUP BY student_name +` + +type GroupConcatOrderByRow struct { + StudentName sql.NullString + GroupConcat sql.NullString +} + +func (q *Queries) GroupConcatOrderBy(ctx context.Context) ([]GroupConcatOrderByRow, error) { + rows, err := q.db.QueryContext(ctx, groupConcatOrderBy) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GroupConcatOrderByRow + for rows.Next() { + var i GroupConcatOrderByRow + if err := rows.Scan(&i.StudentName, &i.GroupConcat); 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/mysql_reference_manual/aggregate_functions/go/models.go b/internal/endtoend/testdata/mysql_reference_manual/aggregate_functions/go/models.go new file mode 100644 index 0000000..f253c94 --- /dev/null +++ b/internal/endtoend/testdata/mysql_reference_manual/aggregate_functions/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package aggregate_functions + +import ( + "database/sql" +) + +type Student struct { + StudentName sql.NullString + TestScore sql.NullFloat64 +} diff --git a/internal/endtoend/testdata/mysql_reference_manual/aggregate_functions/group_concat.sql b/internal/endtoend/testdata/mysql_reference_manual/aggregate_functions/group_concat.sql new file mode 100644 index 0000000..4432538 --- /dev/null +++ b/internal/endtoend/testdata/mysql_reference_manual/aggregate_functions/group_concat.sql @@ -0,0 +1,10 @@ +-- name: GroupConcat :many +SELECT student_name, GROUP_CONCAT(test_score) +FROM student +GROUP BY student_name; + +-- name: GroupConcatOrderBy :many +SELECT student_name, + GROUP_CONCAT(DISTINCT test_score ORDER BY test_score DESC SEPARATOR ' ') +FROM student +GROUP BY student_name; diff --git a/internal/endtoend/testdata/mysql_reference_manual/date_and_time_functions/date_add.sql b/internal/endtoend/testdata/mysql_reference_manual/date_and_time_functions/date_add.sql new file mode 100644 index 0000000..299f20d --- /dev/null +++ b/internal/endtoend/testdata/mysql_reference_manual/date_and_time_functions/date_add.sql @@ -0,0 +1,24 @@ +-- https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-add + +-- name: DateAddOneDay :one +SELECT DATE_ADD('2018-05-01',INTERVAL 1 DAY); + +-- name: DateAddOneSecond :one +SELECT DATE_ADD('2020-12-31 23:59:59', + INTERVAL 1 SECOND); + +-- name: DateAddTimestampOneSecond :one +SELECT DATE_ADD('2018-12-31 23:59:59', + INTERVAL 1 DAY); + +-- name: DateAddMinuteSecond :one +SELECT DATE_ADD('2100-12-31 23:59:59', + INTERVAL '1:1' MINUTE_SECOND); + +-- name: DateAddDayHour :one +SELECT DATE_ADD('1900-01-01 00:00:00', + INTERVAL '-1 10' DAY_HOUR); + +-- name: DateAddSecondMicrosecond :one +SELECT DATE_ADD('1992-12-31 23:59:59.000002', + INTERVAL '1.999999' SECOND_MICROSECOND); diff --git a/internal/endtoend/testdata/mysql_reference_manual/date_and_time_functions/date_sub.sql b/internal/endtoend/testdata/mysql_reference_manual/date_and_time_functions/date_sub.sql new file mode 100644 index 0000000..0e1af3f --- /dev/null +++ b/internal/endtoend/testdata/mysql_reference_manual/date_and_time_functions/date_sub.sql @@ -0,0 +1,9 @@ +-- name: DateSubOneYear :one +SELECT DATE_SUB('2018-05-01',INTERVAL 1 YEAR); + +-- name: DateSubDaySecond :one +SELECT DATE_SUB('2025-01-01 00:00:00', + INTERVAL '1 1:1:1' DAY_SECOND); + +-- name: DateSub31Days :one +SELECT DATE_SUB('1998-01-02', INTERVAL 31 DAY); diff --git a/internal/endtoend/testdata/mysql_reference_manual/date_and_time_functions/go/date_add.sql.go b/internal/endtoend/testdata/mysql_reference_manual/date_and_time_functions/go/date_add.sql.go new file mode 100644 index 0000000..4c1bbda --- /dev/null +++ b/internal/endtoend/testdata/mysql_reference_manual/date_and_time_functions/go/date_add.sql.go @@ -0,0 +1,84 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: date_add.sql + +package date_and_time_functions + +import ( + "context" + "time" +) + +const dateAddDayHour = `-- name: DateAddDayHour :one +SELECT DATE_ADD('1900-01-01 00:00:00', + INTERVAL '-1 10' DAY_HOUR) +` + +func (q *Queries) DateAddDayHour(ctx context.Context) (time.Time, error) { + row := q.db.QueryRowContext(ctx, dateAddDayHour) + var date_add time.Time + err := row.Scan(&date_add) + return date_add, err +} + +const dateAddMinuteSecond = `-- name: DateAddMinuteSecond :one +SELECT DATE_ADD('2100-12-31 23:59:59', + INTERVAL '1:1' MINUTE_SECOND) +` + +func (q *Queries) DateAddMinuteSecond(ctx context.Context) (time.Time, error) { + row := q.db.QueryRowContext(ctx, dateAddMinuteSecond) + var date_add time.Time + err := row.Scan(&date_add) + return date_add, err +} + +const dateAddOneDay = `-- name: DateAddOneDay :one + +SELECT DATE_ADD('2018-05-01',INTERVAL 1 DAY) +` + +// https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-add +func (q *Queries) DateAddOneDay(ctx context.Context) (time.Time, error) { + row := q.db.QueryRowContext(ctx, dateAddOneDay) + var date_add time.Time + err := row.Scan(&date_add) + return date_add, err +} + +const dateAddOneSecond = `-- name: DateAddOneSecond :one +SELECT DATE_ADD('2020-12-31 23:59:59', + INTERVAL 1 SECOND) +` + +func (q *Queries) DateAddOneSecond(ctx context.Context) (time.Time, error) { + row := q.db.QueryRowContext(ctx, dateAddOneSecond) + var date_add time.Time + err := row.Scan(&date_add) + return date_add, err +} + +const dateAddSecondMicrosecond = `-- name: DateAddSecondMicrosecond :one +SELECT DATE_ADD('1992-12-31 23:59:59.000002', + INTERVAL '1.999999' SECOND_MICROSECOND) +` + +func (q *Queries) DateAddSecondMicrosecond(ctx context.Context) (time.Time, error) { + row := q.db.QueryRowContext(ctx, dateAddSecondMicrosecond) + var date_add time.Time + err := row.Scan(&date_add) + return date_add, err +} + +const dateAddTimestampOneSecond = `-- name: DateAddTimestampOneSecond :one +SELECT DATE_ADD('2018-12-31 23:59:59', + INTERVAL 1 DAY) +` + +func (q *Queries) DateAddTimestampOneSecond(ctx context.Context) (time.Time, error) { + row := q.db.QueryRowContext(ctx, dateAddTimestampOneSecond) + var date_add time.Time + err := row.Scan(&date_add) + return date_add, err +} diff --git a/internal/endtoend/testdata/mysql_reference_manual/date_and_time_functions/go/date_sub.sql.go b/internal/endtoend/testdata/mysql_reference_manual/date_and_time_functions/go/date_sub.sql.go new file mode 100644 index 0000000..66f91de --- /dev/null +++ b/internal/endtoend/testdata/mysql_reference_manual/date_and_time_functions/go/date_sub.sql.go @@ -0,0 +1,45 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: date_sub.sql + +package date_and_time_functions + +import ( + "context" + "time" +) + +const dateSub31Days = `-- name: DateSub31Days :one +SELECT DATE_SUB('1998-01-02', INTERVAL 31 DAY) +` + +func (q *Queries) DateSub31Days(ctx context.Context) (time.Time, error) { + row := q.db.QueryRowContext(ctx, dateSub31Days) + var date_sub time.Time + err := row.Scan(&date_sub) + return date_sub, err +} + +const dateSubDaySecond = `-- name: DateSubDaySecond :one +SELECT DATE_SUB('2025-01-01 00:00:00', + INTERVAL '1 1:1:1' DAY_SECOND) +` + +func (q *Queries) DateSubDaySecond(ctx context.Context) (time.Time, error) { + row := q.db.QueryRowContext(ctx, dateSubDaySecond) + var date_sub time.Time + err := row.Scan(&date_sub) + return date_sub, err +} + +const dateSubOneYear = `-- name: DateSubOneYear :one +SELECT DATE_SUB('2018-05-01',INTERVAL 1 YEAR) +` + +func (q *Queries) DateSubOneYear(ctx context.Context) (time.Time, error) { + row := q.db.QueryRowContext(ctx, dateSubOneYear) + var date_sub time.Time + err := row.Scan(&date_sub) + return date_sub, err +} diff --git a/internal/endtoend/testdata/mysql_reference_manual/date_and_time_functions/go/db.go b/internal/endtoend/testdata/mysql_reference_manual/date_and_time_functions/go/db.go new file mode 100644 index 0000000..b9a9f5d --- /dev/null +++ b/internal/endtoend/testdata/mysql_reference_manual/date_and_time_functions/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package date_and_time_functions + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/mysql_reference_manual/date_and_time_functions/go/models.go b/internal/endtoend/testdata/mysql_reference_manual/date_and_time_functions/go/models.go new file mode 100644 index 0000000..7080494 --- /dev/null +++ b/internal/endtoend/testdata/mysql_reference_manual/date_and_time_functions/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package date_and_time_functions + +import ( + "database/sql" +) + +type Student struct { + StudentName sql.NullString + TestScore sql.NullFloat64 +} diff --git a/internal/endtoend/testdata/mysql_reference_manual/schema.sql b/internal/endtoend/testdata/mysql_reference_manual/schema.sql new file mode 100644 index 0000000..5dcef48 --- /dev/null +++ b/internal/endtoend/testdata/mysql_reference_manual/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE student ( + student_name VARCHAR(255), + test_score DOUBLE +); diff --git a/internal/endtoend/testdata/mysql_reference_manual/sqlc.json b/internal/endtoend/testdata/mysql_reference_manual/sqlc.json new file mode 100644 index 0000000..71c8ff5 --- /dev/null +++ b/internal/endtoend/testdata/mysql_reference_manual/sqlc.json @@ -0,0 +1,19 @@ +{ + "version": "1", + "packages": [ + { + "name": "date_and_time_functions", + "path": "date_and_time_functions/go", + "schema": "schema.sql", + "queries": "date_and_time_functions", + "engine": "mysql" + }, + { + "name": "aggregate_functions", + "path": "aggregate_functions/go", + "schema": "schema.sql", + "queries": "aggregate_functions", + "engine": "mysql" + } + ] +} diff --git a/internal/endtoend/testdata/mysql_vector/mysql/go/db.go b/internal/endtoend/testdata/mysql_vector/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/mysql_vector/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/mysql_vector/mysql/go/models.go b/internal/endtoend/testdata/mysql_vector/mysql/go/models.go new file mode 100644 index 0000000..031c85d --- /dev/null +++ b/internal/endtoend/testdata/mysql_vector/mysql/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + ID int32 + Embedding any +} diff --git a/internal/endtoend/testdata/mysql_vector/mysql/go/query.sql.go b/internal/endtoend/testdata/mysql_vector/mysql/go/query.sql.go new file mode 100644 index 0000000..4c6e880 --- /dev/null +++ b/internal/endtoend/testdata/mysql_vector/mysql/go/query.sql.go @@ -0,0 +1,48 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const insertVector = `-- name: InsertVector :exec +INSERT INTO foo(embedding) VALUES (STRING_TO_VECTOR('[0.1, 0.2, 0.3, 0.4]')) +` + +func (q *Queries) InsertVector(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, insertVector) + return err +} + +const selectVector = `-- name: SelectVector :many +SELECT id FROM foo +ORDER BY DISTANCE(STRING_TO_VECTOR('[1.2, 3.4, 5.6]'), embedding, 'L2_squared') +LIMIT 10 +` + +func (q *Queries) SelectVector(ctx context.Context) ([]int32, error) { + rows, err := q.db.QueryContext(ctx, selectVector) + 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 +} diff --git a/internal/endtoend/testdata/mysql_vector/mysql/query.sql b/internal/endtoend/testdata/mysql_vector/mysql/query.sql new file mode 100644 index 0000000..358d691 --- /dev/null +++ b/internal/endtoend/testdata/mysql_vector/mysql/query.sql @@ -0,0 +1,7 @@ +-- name: InsertVector :exec +INSERT INTO foo(embedding) VALUES (STRING_TO_VECTOR('[0.1, 0.2, 0.3, 0.4]')); + +-- name: SelectVector :many +SELECT id FROM foo +ORDER BY DISTANCE(STRING_TO_VECTOR('[1.2, 3.4, 5.6]'), embedding, 'L2_squared') +LIMIT 10; diff --git a/internal/endtoend/testdata/mysql_vector/mysql/schema.sql b/internal/endtoend/testdata/mysql_vector/mysql/schema.sql new file mode 100644 index 0000000..da61ac5 --- /dev/null +++ b/internal/endtoend/testdata/mysql_vector/mysql/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE foo( + id INT PRIMARY KEY auto_increment, + embedding VECTOR(4) +); diff --git a/internal/endtoend/testdata/mysql_vector/mysql/sqlc.json b/internal/endtoend/testdata/mysql_vector/mysql/sqlc.json new file mode 100644 index 0000000..7dabfee --- /dev/null +++ b/internal/endtoend/testdata/mysql_vector/mysql/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "sql_package": "database/sql", + "sql_driver": "github.com/go-sql-driver/mysql", + "engine": "mysql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/named_param/pgx/v4/go/db.go b/internal/endtoend/testdata/named_param/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/named_param/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/named_param/pgx/v4/go/models.go b/internal/endtoend/testdata/named_param/pgx/v4/go/models.go new file mode 100644 index 0000000..34d5646 --- /dev/null +++ b/internal/endtoend/testdata/named_param/pgx/v4/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Name string + Bio string +} diff --git a/internal/endtoend/testdata/named_param/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/named_param/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..6bdbc78 --- /dev/null +++ b/internal/endtoend/testdata/named_param/pgx/v4/go/query.sql.go @@ -0,0 +1,122 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const atParams = `-- name: AtParams :many +SELECT name FROM foo WHERE name = $1 AND $2::bool +` + +type AtParamsParams struct { + Slug string + Filter bool +} + +func (q *Queries) AtParams(ctx context.Context, arg AtParamsParams) ([]string, error) { + rows, err := q.db.Query(ctx, atParams, arg.Slug, arg.Filter) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const funcParams = `-- name: FuncParams :many +SELECT name FROM foo WHERE name = $1 AND $2::bool +` + +type FuncParamsParams struct { + Slug string + Filter bool +} + +func (q *Queries) FuncParams(ctx context.Context, arg FuncParamsParams) ([]string, error) { + rows, err := q.db.Query(ctx, funcParams, arg.Slug, arg.Filter) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const insertAtParams = `-- name: InsertAtParams :one +INSERT INTO foo(name, bio) values ($1, $2) returning name +` + +type InsertAtParamsParams struct { + Name string + Bio string +} + +func (q *Queries) InsertAtParams(ctx context.Context, arg InsertAtParamsParams) (string, error) { + row := q.db.QueryRow(ctx, insertAtParams, arg.Name, arg.Bio) + var name string + err := row.Scan(&name) + return name, err +} + +const insertFuncParams = `-- name: InsertFuncParams :one +INSERT INTO foo(name, bio) values ($1, $2) returning name +` + +type InsertFuncParamsParams struct { + Name string + Bio string +} + +func (q *Queries) InsertFuncParams(ctx context.Context, arg InsertFuncParamsParams) (string, error) { + row := q.db.QueryRow(ctx, insertFuncParams, arg.Name, arg.Bio) + var name string + err := row.Scan(&name) + return name, err +} + +const update = `-- name: Update :one +UPDATE foo +SET + name = CASE WHEN $1::bool + THEN $2::text + ELSE name + END +RETURNING name, bio +` + +type UpdateParams struct { + SetName bool + Name string +} + +func (q *Queries) Update(ctx context.Context, arg UpdateParams) (Foo, error) { + row := q.db.QueryRow(ctx, update, arg.SetName, arg.Name) + var i Foo + err := row.Scan(&i.Name, &i.Bio) + return i, err +} diff --git a/internal/endtoend/testdata/named_param/pgx/v4/query.sql b/internal/endtoend/testdata/named_param/pgx/v4/query.sql new file mode 100644 index 0000000..9a2c906 --- /dev/null +++ b/internal/endtoend/testdata/named_param/pgx/v4/query.sql @@ -0,0 +1,21 @@ +-- name: FuncParams :many +SELECT name FROM foo WHERE name = sqlc.arg('slug') AND sqlc.arg(filter)::bool; + +-- name: AtParams :many +SELECT name FROM foo WHERE name = @slug AND @filter::bool; + +-- name: InsertFuncParams :one +INSERT INTO foo(name, bio) values (sqlc.arg('name'), sqlc.arg('bio')) returning name; + +-- name: InsertAtParams :one +INSERT INTO foo(name, bio) values (@name, @bio) returning name; + + +-- name: Update :one +UPDATE foo +SET + name = CASE WHEN @set_name::bool + THEN @name::text + ELSE name + END +RETURNING *; diff --git a/internal/endtoend/testdata/named_param/pgx/v4/schema.sql b/internal/endtoend/testdata/named_param/pgx/v4/schema.sql new file mode 100644 index 0000000..b4050d1 --- /dev/null +++ b/internal/endtoend/testdata/named_param/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (name text not null, bio text not null); + diff --git a/internal/endtoend/testdata/named_param/pgx/v4/sqlc.json b/internal/endtoend/testdata/named_param/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/named_param/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/named_param/pgx/v5/go/db.go b/internal/endtoend/testdata/named_param/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/named_param/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/named_param/pgx/v5/go/models.go b/internal/endtoend/testdata/named_param/pgx/v5/go/models.go new file mode 100644 index 0000000..34d5646 --- /dev/null +++ b/internal/endtoend/testdata/named_param/pgx/v5/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Name string + Bio string +} diff --git a/internal/endtoend/testdata/named_param/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/named_param/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..6bdbc78 --- /dev/null +++ b/internal/endtoend/testdata/named_param/pgx/v5/go/query.sql.go @@ -0,0 +1,122 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const atParams = `-- name: AtParams :many +SELECT name FROM foo WHERE name = $1 AND $2::bool +` + +type AtParamsParams struct { + Slug string + Filter bool +} + +func (q *Queries) AtParams(ctx context.Context, arg AtParamsParams) ([]string, error) { + rows, err := q.db.Query(ctx, atParams, arg.Slug, arg.Filter) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const funcParams = `-- name: FuncParams :many +SELECT name FROM foo WHERE name = $1 AND $2::bool +` + +type FuncParamsParams struct { + Slug string + Filter bool +} + +func (q *Queries) FuncParams(ctx context.Context, arg FuncParamsParams) ([]string, error) { + rows, err := q.db.Query(ctx, funcParams, arg.Slug, arg.Filter) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const insertAtParams = `-- name: InsertAtParams :one +INSERT INTO foo(name, bio) values ($1, $2) returning name +` + +type InsertAtParamsParams struct { + Name string + Bio string +} + +func (q *Queries) InsertAtParams(ctx context.Context, arg InsertAtParamsParams) (string, error) { + row := q.db.QueryRow(ctx, insertAtParams, arg.Name, arg.Bio) + var name string + err := row.Scan(&name) + return name, err +} + +const insertFuncParams = `-- name: InsertFuncParams :one +INSERT INTO foo(name, bio) values ($1, $2) returning name +` + +type InsertFuncParamsParams struct { + Name string + Bio string +} + +func (q *Queries) InsertFuncParams(ctx context.Context, arg InsertFuncParamsParams) (string, error) { + row := q.db.QueryRow(ctx, insertFuncParams, arg.Name, arg.Bio) + var name string + err := row.Scan(&name) + return name, err +} + +const update = `-- name: Update :one +UPDATE foo +SET + name = CASE WHEN $1::bool + THEN $2::text + ELSE name + END +RETURNING name, bio +` + +type UpdateParams struct { + SetName bool + Name string +} + +func (q *Queries) Update(ctx context.Context, arg UpdateParams) (Foo, error) { + row := q.db.QueryRow(ctx, update, arg.SetName, arg.Name) + var i Foo + err := row.Scan(&i.Name, &i.Bio) + return i, err +} diff --git a/internal/endtoend/testdata/named_param/pgx/v5/query.sql b/internal/endtoend/testdata/named_param/pgx/v5/query.sql new file mode 100644 index 0000000..9a2c906 --- /dev/null +++ b/internal/endtoend/testdata/named_param/pgx/v5/query.sql @@ -0,0 +1,21 @@ +-- name: FuncParams :many +SELECT name FROM foo WHERE name = sqlc.arg('slug') AND sqlc.arg(filter)::bool; + +-- name: AtParams :many +SELECT name FROM foo WHERE name = @slug AND @filter::bool; + +-- name: InsertFuncParams :one +INSERT INTO foo(name, bio) values (sqlc.arg('name'), sqlc.arg('bio')) returning name; + +-- name: InsertAtParams :one +INSERT INTO foo(name, bio) values (@name, @bio) returning name; + + +-- name: Update :one +UPDATE foo +SET + name = CASE WHEN @set_name::bool + THEN @name::text + ELSE name + END +RETURNING *; diff --git a/internal/endtoend/testdata/named_param/pgx/v5/schema.sql b/internal/endtoend/testdata/named_param/pgx/v5/schema.sql new file mode 100644 index 0000000..b4050d1 --- /dev/null +++ b/internal/endtoend/testdata/named_param/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (name text not null, bio text not null); + diff --git a/internal/endtoend/testdata/named_param/pgx/v5/sqlc.json b/internal/endtoend/testdata/named_param/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/named_param/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/named_param/sqlite/go/db.go b/internal/endtoend/testdata/named_param/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/named_param/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/named_param/sqlite/go/models.go b/internal/endtoend/testdata/named_param/sqlite/go/models.go new file mode 100644 index 0000000..34d5646 --- /dev/null +++ b/internal/endtoend/testdata/named_param/sqlite/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Name string + Bio string +} diff --git a/internal/endtoend/testdata/named_param/sqlite/go/query.sql.go b/internal/endtoend/testdata/named_param/sqlite/go/query.sql.go new file mode 100644 index 0000000..625e79a --- /dev/null +++ b/internal/endtoend/testdata/named_param/sqlite/go/query.sql.go @@ -0,0 +1,96 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const atParams = `-- name: AtParams :many +SELECT name FROM foo WHERE name = ?1 +` + +func (q *Queries) AtParams(ctx context.Context, slug string) ([]string, error) { + rows, err := q.db.QueryContext(ctx, atParams, slug) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const funcParams = `-- name: FuncParams :many +SELECT name FROM foo WHERE name = ?1 +` + +func (q *Queries) FuncParams(ctx context.Context, slug string) ([]string, error) { + rows, err := q.db.QueryContext(ctx, funcParams, slug) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const insertAtParams = `-- name: InsertAtParams :one +INSERT INTO foo(name, bio) values (?1, ?2) returning name +` + +type InsertAtParamsParams struct { + Name string + Bio string +} + +func (q *Queries) InsertAtParams(ctx context.Context, arg InsertAtParamsParams) (string, error) { + row := q.db.QueryRowContext(ctx, insertAtParams, arg.Name, arg.Bio) + var name string + err := row.Scan(&name) + return name, err +} + +const insertFuncParams = `-- name: InsertFuncParams :one +INSERT INTO foo(name, bio) values (?1, ?2) returning name +` + +type InsertFuncParamsParams struct { + Name string + Bio string +} + +func (q *Queries) InsertFuncParams(ctx context.Context, arg InsertFuncParamsParams) (string, error) { + row := q.db.QueryRowContext(ctx, insertFuncParams, arg.Name, arg.Bio) + var name string + err := row.Scan(&name) + return name, err +} diff --git a/internal/endtoend/testdata/named_param/sqlite/query.sql b/internal/endtoend/testdata/named_param/sqlite/query.sql new file mode 100644 index 0000000..7e19464 --- /dev/null +++ b/internal/endtoend/testdata/named_param/sqlite/query.sql @@ -0,0 +1,11 @@ +-- name: FuncParams :many +SELECT name FROM foo WHERE name = sqlc.arg('slug'); + +-- name: AtParams :many +SELECT name FROM foo WHERE name = @slug; + +-- name: InsertFuncParams :one +INSERT INTO foo(name, bio) values (sqlc.arg('name'), sqlc.arg('bio')) returning name; + +-- name: InsertAtParams :one +INSERT INTO foo(name, bio) values (@name, @bio) returning name; diff --git a/internal/endtoend/testdata/named_param/sqlite/schema.sql b/internal/endtoend/testdata/named_param/sqlite/schema.sql new file mode 100644 index 0000000..b4050d1 --- /dev/null +++ b/internal/endtoend/testdata/named_param/sqlite/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (name text not null, bio text not null); + diff --git a/internal/endtoend/testdata/named_param/sqlite/sqlc.json b/internal/endtoend/testdata/named_param/sqlite/sqlc.json new file mode 100644 index 0000000..cd66df0 --- /dev/null +++ b/internal/endtoend/testdata/named_param/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/named_param/stdlib/go/db.go b/internal/endtoend/testdata/named_param/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/named_param/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/named_param/stdlib/go/models.go b/internal/endtoend/testdata/named_param/stdlib/go/models.go new file mode 100644 index 0000000..34d5646 --- /dev/null +++ b/internal/endtoend/testdata/named_param/stdlib/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Name string + Bio string +} diff --git a/internal/endtoend/testdata/named_param/stdlib/go/query.sql.go b/internal/endtoend/testdata/named_param/stdlib/go/query.sql.go new file mode 100644 index 0000000..017f5be --- /dev/null +++ b/internal/endtoend/testdata/named_param/stdlib/go/query.sql.go @@ -0,0 +1,128 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const atParams = `-- name: AtParams :many +SELECT name FROM foo WHERE name = $1 AND $2::bool +` + +type AtParamsParams struct { + Slug string + Filter bool +} + +func (q *Queries) AtParams(ctx context.Context, arg AtParamsParams) ([]string, error) { + rows, err := q.db.QueryContext(ctx, atParams, arg.Slug, arg.Filter) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const funcParams = `-- name: FuncParams :many +SELECT name FROM foo WHERE name = $1 AND $2::bool +` + +type FuncParamsParams struct { + Slug string + Filter bool +} + +func (q *Queries) FuncParams(ctx context.Context, arg FuncParamsParams) ([]string, error) { + rows, err := q.db.QueryContext(ctx, funcParams, arg.Slug, arg.Filter) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const insertAtParams = `-- name: InsertAtParams :one +INSERT INTO foo(name, bio) values ($1, $2) returning name +` + +type InsertAtParamsParams struct { + Name string + Bio string +} + +func (q *Queries) InsertAtParams(ctx context.Context, arg InsertAtParamsParams) (string, error) { + row := q.db.QueryRowContext(ctx, insertAtParams, arg.Name, arg.Bio) + var name string + err := row.Scan(&name) + return name, err +} + +const insertFuncParams = `-- name: InsertFuncParams :one +INSERT INTO foo(name, bio) values ($1, $2) returning name +` + +type InsertFuncParamsParams struct { + Name string + Bio string +} + +func (q *Queries) InsertFuncParams(ctx context.Context, arg InsertFuncParamsParams) (string, error) { + row := q.db.QueryRowContext(ctx, insertFuncParams, arg.Name, arg.Bio) + var name string + err := row.Scan(&name) + return name, err +} + +const update = `-- name: Update :one +UPDATE foo +SET + name = CASE WHEN $1::bool + THEN $2::text + ELSE name + END +RETURNING name, bio +` + +type UpdateParams struct { + SetName bool + Name string +} + +func (q *Queries) Update(ctx context.Context, arg UpdateParams) (Foo, error) { + row := q.db.QueryRowContext(ctx, update, arg.SetName, arg.Name) + var i Foo + err := row.Scan(&i.Name, &i.Bio) + return i, err +} diff --git a/internal/endtoend/testdata/named_param/stdlib/query.sql b/internal/endtoend/testdata/named_param/stdlib/query.sql new file mode 100644 index 0000000..9a2c906 --- /dev/null +++ b/internal/endtoend/testdata/named_param/stdlib/query.sql @@ -0,0 +1,21 @@ +-- name: FuncParams :many +SELECT name FROM foo WHERE name = sqlc.arg('slug') AND sqlc.arg(filter)::bool; + +-- name: AtParams :many +SELECT name FROM foo WHERE name = @slug AND @filter::bool; + +-- name: InsertFuncParams :one +INSERT INTO foo(name, bio) values (sqlc.arg('name'), sqlc.arg('bio')) returning name; + +-- name: InsertAtParams :one +INSERT INTO foo(name, bio) values (@name, @bio) returning name; + + +-- name: Update :one +UPDATE foo +SET + name = CASE WHEN @set_name::bool + THEN @name::text + ELSE name + END +RETURNING *; diff --git a/internal/endtoend/testdata/named_param/stdlib/schema.sql b/internal/endtoend/testdata/named_param/stdlib/schema.sql new file mode 100644 index 0000000..b4050d1 --- /dev/null +++ b/internal/endtoend/testdata/named_param/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (name text not null, bio text not null); + diff --git a/internal/endtoend/testdata/named_param/stdlib/sqlc.json b/internal/endtoend/testdata/named_param/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/named_param/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/nested_select/issue.md b/internal/endtoend/testdata/nested_select/issue.md new file mode 100644 index 0000000..2c10d6d --- /dev/null +++ b/internal/endtoend/testdata/nested_select/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/708 diff --git a/internal/endtoend/testdata/nested_select/postgresql/pgx/exec.json b/internal/endtoend/testdata/nested_select/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/nested_select/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/nested_select/postgresql/pgx/go/db.go b/internal/endtoend/testdata/nested_select/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/nested_select/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/nested_select/postgresql/pgx/go/models.go b/internal/endtoend/testdata/nested_select/postgresql/pgx/go/models.go new file mode 100644 index 0000000..e114430 --- /dev/null +++ b/internal/endtoend/testdata/nested_select/postgresql/pgx/go/models.go @@ -0,0 +1,11 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Test struct { + ID int64 + UpdateTime int64 + Count int64 +} diff --git a/internal/endtoend/testdata/nested_select/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/nested_select/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..19e1864 --- /dev/null +++ b/internal/endtoend/testdata/nested_select/postgresql/pgx/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const nestedSelect = `-- name: NestedSelect :one +SELECT latest.id, t.count +FROM ( + SELECT id, max(update_time) AS update_time + FROM test + WHERE id = ANY ($1::bigint[]) + -- ERROR HERE on update_time + AND update_time >= $2 + GROUP BY id +) latest +INNER JOIN test t USING (id, update_time) +` + +type NestedSelectParams struct { + IDs []int64 + StartTime pgtype.Int8 +} + +type NestedSelectRow struct { + ID int64 + Count int64 +} + +func (q *Queries) NestedSelect(ctx context.Context, arg NestedSelectParams) (NestedSelectRow, error) { + row := q.db.QueryRow(ctx, nestedSelect, arg.IDs, arg.StartTime) + var i NestedSelectRow + err := row.Scan(&i.ID, &i.Count) + return i, err +} diff --git a/internal/endtoend/testdata/nested_select/postgresql/pgx/query.sql b/internal/endtoend/testdata/nested_select/postgresql/pgx/query.sql new file mode 100644 index 0000000..755521f --- /dev/null +++ b/internal/endtoend/testdata/nested_select/postgresql/pgx/query.sql @@ -0,0 +1,11 @@ +-- name: NestedSelect :one +SELECT latest.id, t.count +FROM ( + SELECT id, max(update_time) AS update_time + FROM test + WHERE id = ANY (sqlc.arg('IDs')::bigint[]) + -- ERROR HERE on update_time + AND update_time >= sqlc.arg('StartTime') + GROUP BY id +) latest +INNER JOIN test t USING (id, update_time); diff --git a/internal/endtoend/testdata/nested_select/postgresql/pgx/schema.sql b/internal/endtoend/testdata/nested_select/postgresql/pgx/schema.sql new file mode 100644 index 0000000..02f5f82 --- /dev/null +++ b/internal/endtoend/testdata/nested_select/postgresql/pgx/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE test ( + id bigint NOT NULL, + update_time bigint NOT NULL, + count bigint NOT NULL +); diff --git a/internal/endtoend/testdata/nested_select/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/nested_select/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..2f12715 --- /dev/null +++ b/internal/endtoend/testdata/nested_select/postgresql/pgx/sqlc.yaml @@ -0,0 +1,14 @@ +version: "2" +cloud: + project: "01HAQMMECEYQYKFJN8MP16QC41" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" + database: + managed: true diff --git a/internal/endtoend/testdata/nextval/postgresql/go/db.go b/internal/endtoend/testdata/nextval/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/nextval/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/nextval/postgresql/go/models.go b/internal/endtoend/testdata/nextval/postgresql/go/models.go new file mode 100644 index 0000000..b5763f0 --- /dev/null +++ b/internal/endtoend/testdata/nextval/postgresql/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Author struct { + ID int64 +} diff --git a/internal/endtoend/testdata/nextval/postgresql/go/query.sql.go b/internal/endtoend/testdata/nextval/postgresql/go/query.sql.go new file mode 100644 index 0000000..d6c7e29 --- /dev/null +++ b/internal/endtoend/testdata/nextval/postgresql/go/query.sql.go @@ -0,0 +1,27 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getNextID = `-- name: GetNextID :one +SELECT pk, pk FROM + (SELECT nextval('authors_id_seq') as pk) AS alias +` + +type GetNextIDRow struct { + Pk int64 + Pk_2 int64 +} + +func (q *Queries) GetNextID(ctx context.Context) (GetNextIDRow, error) { + row := q.db.QueryRowContext(ctx, getNextID) + var i GetNextIDRow + err := row.Scan(&i.Pk, &i.Pk_2) + return i, err +} diff --git a/internal/endtoend/testdata/nextval/postgresql/query.sql b/internal/endtoend/testdata/nextval/postgresql/query.sql new file mode 100644 index 0000000..606ac1e --- /dev/null +++ b/internal/endtoend/testdata/nextval/postgresql/query.sql @@ -0,0 +1,4 @@ +-- name: GetNextID :one +SELECT pk, pk FROM + (SELECT nextval('authors_id_seq') as pk) AS alias; + diff --git a/internal/endtoend/testdata/nextval/postgresql/schema.sql b/internal/endtoend/testdata/nextval/postgresql/schema.sql new file mode 100644 index 0000000..2ab37c0 --- /dev/null +++ b/internal/endtoend/testdata/nextval/postgresql/schema.sql @@ -0,0 +1,5 @@ +-- Simple table +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY +); + diff --git a/internal/endtoend/testdata/nextval/postgresql/sqlc.json b/internal/endtoend/testdata/nextval/postgresql/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/nextval/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/notifylisten/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/notifylisten/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/notifylisten/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/notifylisten/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/notifylisten/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/notifylisten/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/notifylisten/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/notifylisten/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..28ee1f1 --- /dev/null +++ b/internal/endtoend/testdata/notifylisten/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listenTest = `-- name: ListenTest :exec +LISTEN test +` + +func (q *Queries) ListenTest(ctx context.Context) error { + _, err := q.db.Exec(ctx, listenTest) + return err +} + +const notifyTest = `-- name: NotifyTest :exec +NOTIFY test +` + +func (q *Queries) NotifyTest(ctx context.Context) error { + _, err := q.db.Exec(ctx, notifyTest) + return err +} + +const notifyWithMessage = `-- name: NotifyWithMessage :exec +NOTIFY test, 'msg' +` + +func (q *Queries) NotifyWithMessage(ctx context.Context) error { + _, err := q.db.Exec(ctx, notifyWithMessage) + return err +} diff --git a/internal/endtoend/testdata/notifylisten/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/notifylisten/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..721da0a --- /dev/null +++ b/internal/endtoend/testdata/notifylisten/postgresql/pgx/v5/query.sql @@ -0,0 +1,8 @@ +-- name: NotifyTest :exec +NOTIFY test; + +-- name: NotifyWithMessage :exec +NOTIFY test, 'msg'; + +-- name: ListenTest :exec +LISTEN test; diff --git a/internal/endtoend/testdata/notifylisten/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/notifylisten/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/notifylisten/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/notifylisten/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/notifylisten/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/null_if_type/issue.md b/internal/endtoend/testdata/null_if_type/issue.md new file mode 100644 index 0000000..c83cc42 --- /dev/null +++ b/internal/endtoend/testdata/null_if_type/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/133 diff --git a/internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/db/db.go b/internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/null_if_type/postgresql/pganalyzer/db/models.go b/internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/db/models.go new file mode 100644 index 0000000..e0aedd9 --- /dev/null +++ b/internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/db/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +type Author struct { + ID int64 +} diff --git a/internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/db/query.sql.go b/internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/db/query.sql.go new file mode 100644 index 0000000..c10fa34 --- /dev/null +++ b/internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/db/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" +) + +const getRestrictedId = `-- name: GetRestrictedId :one +SELECT + NULLIF(id, $1) restricted_id +FROM + author +` + +func (q *Queries) GetRestrictedId(ctx context.Context, id int64) (int64, error) { + row := q.db.QueryRowContext(ctx, getRestrictedId, id) + var restricted_id int64 + err := row.Scan(&restricted_id) + return restricted_id, err +} diff --git a/internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/exec.json b/internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/query.sql b/internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/query.sql new file mode 100644 index 0000000..fc800b4 --- /dev/null +++ b/internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/query.sql @@ -0,0 +1,5 @@ +-- name: GetRestrictedId :one +SELECT + NULLIF(id, $1) restricted_id +FROM + author; diff --git a/internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/schema.sql b/internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/schema.sql new file mode 100644 index 0000000..c1afeca --- /dev/null +++ b/internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE author ( + id bigserial NOT NULL +); diff --git a/internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/sqlc.json b/internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/sqlc.json new file mode 100644 index 0000000..a682c52 --- /dev/null +++ b/internal/endtoend/testdata/null_if_type/postgresql/pganalyzer/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "db", + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} + diff --git a/internal/endtoend/testdata/null_if_type/postgresql/stdlib/db/db.go b/internal/endtoend/testdata/null_if_type/postgresql/stdlib/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/null_if_type/postgresql/stdlib/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/null_if_type/postgresql/stdlib/db/models.go b/internal/endtoend/testdata/null_if_type/postgresql/stdlib/db/models.go new file mode 100644 index 0000000..e0aedd9 --- /dev/null +++ b/internal/endtoend/testdata/null_if_type/postgresql/stdlib/db/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +type Author struct { + ID int64 +} diff --git a/internal/endtoend/testdata/null_if_type/postgresql/stdlib/db/query.sql.go b/internal/endtoend/testdata/null_if_type/postgresql/stdlib/db/query.sql.go new file mode 100644 index 0000000..46ab504 --- /dev/null +++ b/internal/endtoend/testdata/null_if_type/postgresql/stdlib/db/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" +) + +const getRestrictedId = `-- name: GetRestrictedId :one +SELECT + NULLIF(id, $1) restricted_id +FROM + author +` + +func (q *Queries) GetRestrictedId(ctx context.Context, id int64) (bool, error) { + row := q.db.QueryRowContext(ctx, getRestrictedId, id) + var restricted_id bool + err := row.Scan(&restricted_id) + return restricted_id, err +} diff --git a/internal/endtoend/testdata/null_if_type/postgresql/stdlib/exec.json b/internal/endtoend/testdata/null_if_type/postgresql/stdlib/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/null_if_type/postgresql/stdlib/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/null_if_type/postgresql/stdlib/query.sql b/internal/endtoend/testdata/null_if_type/postgresql/stdlib/query.sql new file mode 100644 index 0000000..fc800b4 --- /dev/null +++ b/internal/endtoend/testdata/null_if_type/postgresql/stdlib/query.sql @@ -0,0 +1,5 @@ +-- name: GetRestrictedId :one +SELECT + NULLIF(id, $1) restricted_id +FROM + author; diff --git a/internal/endtoend/testdata/null_if_type/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/null_if_type/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..c1afeca --- /dev/null +++ b/internal/endtoend/testdata/null_if_type/postgresql/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE author ( + id bigserial NOT NULL +); diff --git a/internal/endtoend/testdata/null_if_type/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/null_if_type/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..a682c52 --- /dev/null +++ b/internal/endtoend/testdata/null_if_type/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "db", + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} + diff --git a/internal/endtoend/testdata/omit_sqlc_version/db/db.go b/internal/endtoend/testdata/omit_sqlc_version/db/db.go new file mode 100644 index 0000000..e19c06c --- /dev/null +++ b/internal/endtoend/testdata/omit_sqlc_version/db/db.go @@ -0,0 +1,29 @@ +// Code generated by sqlc. DO NOT EDIT. + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/omit_sqlc_version/db/models.go b/internal/endtoend/testdata/omit_sqlc_version/db/models.go new file mode 100644 index 0000000..3bc4823 --- /dev/null +++ b/internal/endtoend/testdata/omit_sqlc_version/db/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. + +package db + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/omit_sqlc_version/db/query.sql.go b/internal/endtoend/testdata/omit_sqlc_version/db/query.sql.go new file mode 100644 index 0000000..147cb4b --- /dev/null +++ b/internal/endtoend/testdata/omit_sqlc_version/db/query.sql.go @@ -0,0 +1,80 @@ +// Code generated by sqlc. DO NOT EDIT. +// source: query.sql + +package db + +import ( + "context" + "database/sql" +) + +const createAuthor = `-- name: CreateAuthor :one +INSERT INTO authors ( + name, bio +) VALUES ( + $1, $2 +) +RETURNING id, name, bio +` + +type CreateAuthorParams struct { + Name string + Bio sql.NullString +} + +func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (Author, error) { + row := q.db.QueryRowContext(ctx, createAuthor, arg.Name, arg.Bio) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const deleteAuthor = `-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = $1 +` + +func (q *Queries) DeleteAuthor(ctx context.Context, id int64) error { + _, err := q.db.ExecContext(ctx, deleteAuthor, id) + return err +} + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, bio FROM authors +WHERE id = $1 LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name, bio FROM authors +ORDER BY name +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); 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/omit_sqlc_version/query.sql b/internal/endtoend/testdata/omit_sqlc_version/query.sql new file mode 100644 index 0000000..971b8f9 --- /dev/null +++ b/internal/endtoend/testdata/omit_sqlc_version/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/omit_sqlc_version/schema.sql b/internal/endtoend/testdata/omit_sqlc_version/schema.sql new file mode 100644 index 0000000..69b607d --- /dev/null +++ b/internal/endtoend/testdata/omit_sqlc_version/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/omit_sqlc_version/sqlc.json b/internal/endtoend/testdata/omit_sqlc_version/sqlc.json new file mode 100644 index 0000000..f86d2b7 --- /dev/null +++ b/internal/endtoend/testdata/omit_sqlc_version/sqlc.json @@ -0,0 +1,15 @@ +{ + "version": "2", + "sql": [{ + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql", + "gen": { + "go": { + "out": "db", + "omit_sqlc_version": true + } + } + }] +} + diff --git a/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/omit_unused_structs/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1d466f --- /dev/null +++ b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/models.go @@ -0,0 +1,325 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "database/sql/driver" + "fmt" +) + +type ArrayEnum string + +const ( + ArrayEnumO ArrayEnum = "o" + ArrayEnumP ArrayEnum = "p" +) + +func (e *ArrayEnum) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = ArrayEnum(s) + case string: + *e = ArrayEnum(s) + default: + return fmt.Errorf("unsupported scan type for ArrayEnum: %T", src) + } + return nil +} + +type NullArrayEnum struct { + ArrayEnum ArrayEnum + Valid bool // Valid is true if ArrayEnum is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullArrayEnum) Scan(value any) error { + if value == nil { + ns.ArrayEnum, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.ArrayEnum.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullArrayEnum) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.ArrayEnum), nil +} + +type QueryParamEnumTableEnum string + +const ( + QueryParamEnumTableEnumG QueryParamEnumTableEnum = "g" + QueryParamEnumTableEnumH QueryParamEnumTableEnum = "h" +) + +func (e *QueryParamEnumTableEnum) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = QueryParamEnumTableEnum(s) + case string: + *e = QueryParamEnumTableEnum(s) + default: + return fmt.Errorf("unsupported scan type for QueryParamEnumTableEnum: %T", src) + } + return nil +} + +type NullQueryParamEnumTableEnum struct { + QueryParamEnumTableEnum QueryParamEnumTableEnum + Valid bool // Valid is true if QueryParamEnumTableEnum is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullQueryParamEnumTableEnum) Scan(value any) error { + if value == nil { + ns.QueryParamEnumTableEnum, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.QueryParamEnumTableEnum.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullQueryParamEnumTableEnum) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.QueryParamEnumTableEnum), nil +} + +type QueryParamStructEnumTableEnum string + +const ( + QueryParamStructEnumTableEnumI QueryParamStructEnumTableEnum = "i" + QueryParamStructEnumTableEnumJ QueryParamStructEnumTableEnum = "j" +) + +func (e *QueryParamStructEnumTableEnum) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = QueryParamStructEnumTableEnum(s) + case string: + *e = QueryParamStructEnumTableEnum(s) + default: + return fmt.Errorf("unsupported scan type for QueryParamStructEnumTableEnum: %T", src) + } + return nil +} + +type NullQueryParamStructEnumTableEnum struct { + QueryParamStructEnumTableEnum QueryParamStructEnumTableEnum + Valid bool // Valid is true if QueryParamStructEnumTableEnum is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullQueryParamStructEnumTableEnum) Scan(value any) error { + if value == nil { + ns.QueryParamStructEnumTableEnum, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.QueryParamStructEnumTableEnum.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullQueryParamStructEnumTableEnum) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.QueryParamStructEnumTableEnum), nil +} + +type QueryReturnEnumTableEnum string + +const ( + QueryReturnEnumTableEnumK QueryReturnEnumTableEnum = "k" + QueryReturnEnumTableEnumL QueryReturnEnumTableEnum = "l" +) + +func (e *QueryReturnEnumTableEnum) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = QueryReturnEnumTableEnum(s) + case string: + *e = QueryReturnEnumTableEnum(s) + default: + return fmt.Errorf("unsupported scan type for QueryReturnEnumTableEnum: %T", src) + } + return nil +} + +type NullQueryReturnEnumTableEnum struct { + QueryReturnEnumTableEnum QueryReturnEnumTableEnum + Valid bool // Valid is true if QueryReturnEnumTableEnum is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullQueryReturnEnumTableEnum) Scan(value any) error { + if value == nil { + ns.QueryReturnEnumTableEnum, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.QueryReturnEnumTableEnum.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullQueryReturnEnumTableEnum) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.QueryReturnEnumTableEnum), nil +} + +type QueryReturnFullTableEnum string + +const ( + QueryReturnFullTableEnumE QueryReturnFullTableEnum = "e" + QueryReturnFullTableEnumF QueryReturnFullTableEnum = "f" +) + +func (e *QueryReturnFullTableEnum) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = QueryReturnFullTableEnum(s) + case string: + *e = QueryReturnFullTableEnum(s) + default: + return fmt.Errorf("unsupported scan type for QueryReturnFullTableEnum: %T", src) + } + return nil +} + +type NullQueryReturnFullTableEnum struct { + QueryReturnFullTableEnum QueryReturnFullTableEnum + Valid bool // Valid is true if QueryReturnFullTableEnum is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullQueryReturnFullTableEnum) Scan(value any) error { + if value == nil { + ns.QueryReturnFullTableEnum, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.QueryReturnFullTableEnum.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullQueryReturnFullTableEnum) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.QueryReturnFullTableEnum), nil +} + +type QueryReturnStructEnumTableEnum string + +const ( + QueryReturnStructEnumTableEnumK QueryReturnStructEnumTableEnum = "k" + QueryReturnStructEnumTableEnumL QueryReturnStructEnumTableEnum = "l" +) + +func (e *QueryReturnStructEnumTableEnum) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = QueryReturnStructEnumTableEnum(s) + case string: + *e = QueryReturnStructEnumTableEnum(s) + default: + return fmt.Errorf("unsupported scan type for QueryReturnStructEnumTableEnum: %T", src) + } + return nil +} + +type NullQueryReturnStructEnumTableEnum struct { + QueryReturnStructEnumTableEnum QueryReturnStructEnumTableEnum + Valid bool // Valid is true if QueryReturnStructEnumTableEnum is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullQueryReturnStructEnumTableEnum) Scan(value any) error { + if value == nil { + ns.QueryReturnStructEnumTableEnum, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.QueryReturnStructEnumTableEnum.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullQueryReturnStructEnumTableEnum) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.QueryReturnStructEnumTableEnum), nil +} + +type QuerySqlcEmbedEnum string + +const ( + QuerySqlcEmbedEnumM QuerySqlcEmbedEnum = "m" + QuerySqlcEmbedEnumN QuerySqlcEmbedEnum = "n" +) + +func (e *QuerySqlcEmbedEnum) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = QuerySqlcEmbedEnum(s) + case string: + *e = QuerySqlcEmbedEnum(s) + default: + return fmt.Errorf("unsupported scan type for QuerySqlcEmbedEnum: %T", src) + } + return nil +} + +type NullQuerySqlcEmbedEnum struct { + QuerySqlcEmbedEnum QuerySqlcEmbedEnum + Valid bool // Valid is true if QuerySqlcEmbedEnum is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullQuerySqlcEmbedEnum) Scan(value any) error { + if value == nil { + ns.QuerySqlcEmbedEnum, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.QuerySqlcEmbedEnum.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullQuerySqlcEmbedEnum) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.QuerySqlcEmbedEnum), nil +} + +type ArrayEnumTable struct { + ID int32 + Value []ArrayEnum +} + +type QueryParamEnumTable struct { + ID int32 + Other QueryParamEnumTableEnum + Value NullQueryParamEnumTableEnum +} + +type QueryReturnFullTable struct { + ID int32 + Value NullQueryReturnFullTableEnum +} + +type QuerySqlcEmbedTable struct { + ID int32 + Value NullQuerySqlcEmbedEnum +} diff --git a/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..91b4cef --- /dev/null +++ b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,136 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" + "database/sql" + + "github.com/lib/pq" +) + +const query_enum_array_table = `-- name: query_enum_array_table :many +SELECT id, value FROM array_enum_table +` + +func (q *Queries) query_enum_array_table(ctx context.Context) ([]ArrayEnumTable, error) { + rows, err := q.db.QueryContext(ctx, query_enum_array_table) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ArrayEnumTable + for rows.Next() { + var i ArrayEnumTable + if err := rows.Scan(&i.ID, pq.Array(&i.Value)); 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 query_param_enum_table = `-- name: query_param_enum_table :one +SELECT id, other, value FROM query_param_enum_table WHERE value = $1 +` + +func (q *Queries) query_param_enum_table(ctx context.Context, value NullQueryParamEnumTableEnum) (QueryParamEnumTable, error) { + row := q.db.QueryRowContext(ctx, query_param_enum_table, value) + var i QueryParamEnumTable + err := row.Scan(&i.ID, &i.Other, &i.Value) + return i, err +} + +const query_param_struct_enum_table = `-- name: query_param_struct_enum_table :one +SELECT id FROM query_param_struct_enum_table WHERE id = $1 AND value = $2 +` + +type query_param_struct_enum_tableParams struct { + ID int32 + Value NullQueryParamStructEnumTableEnum +} + +func (q *Queries) query_param_struct_enum_table(ctx context.Context, arg query_param_struct_enum_tableParams) (int32, error) { + row := q.db.QueryRowContext(ctx, query_param_struct_enum_table, arg.ID, arg.Value) + var id int32 + err := row.Scan(&id) + return id, err +} + +const query_return_enum_table = `-- name: query_return_enum_table :one +SELECT value FROM query_return_enum_table WHERE id = $1 +` + +func (q *Queries) query_return_enum_table(ctx context.Context, id int32) (NullQueryReturnEnumTableEnum, error) { + row := q.db.QueryRowContext(ctx, query_return_enum_table, id) + var value NullQueryReturnEnumTableEnum + err := row.Scan(&value) + return value, err +} + +const query_return_full_table = `-- name: query_return_full_table :many +SELECT id, value FROM query_return_full_table +` + +func (q *Queries) query_return_full_table(ctx context.Context) ([]QueryReturnFullTable, error) { + rows, err := q.db.QueryContext(ctx, query_return_full_table) + if err != nil { + return nil, err + } + defer rows.Close() + var items []QueryReturnFullTable + for rows.Next() { + var i QueryReturnFullTable + if err := rows.Scan(&i.ID, &i.Value); 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 query_return_struct_enum_table = `-- name: query_return_struct_enum_table :one +SELECT value, another FROM query_return_struct_enum_table WHERE id = $1 +` + +type query_return_struct_enum_tableRow struct { + Value NullQueryReturnStructEnumTableEnum + Another sql.NullInt32 +} + +func (q *Queries) query_return_struct_enum_table(ctx context.Context, id int32) (query_return_struct_enum_tableRow, error) { + row := q.db.QueryRowContext(ctx, query_return_struct_enum_table, id) + var i query_return_struct_enum_tableRow + err := row.Scan(&i.Value, &i.Another) + return i, err +} + +const query_sqlc_embed_table = `-- name: query_sqlc_embed_table :one +SELECT query_sqlc_embed_table.id, query_sqlc_embed_table.value FROM query_sqlc_embed_table WHERE id = $1 +` + +type query_sqlc_embed_tableRow struct { + QuerySqlcEmbedTable QuerySqlcEmbedTable +} + +func (q *Queries) query_sqlc_embed_table(ctx context.Context, id int32) (query_sqlc_embed_tableRow, error) { + row := q.db.QueryRowContext(ctx, query_sqlc_embed_table, id) + var i query_sqlc_embed_tableRow + err := row.Scan(&i.QuerySqlcEmbedTable.ID, &i.QuerySqlcEmbedTable.Value) + return i, err +} diff --git a/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/query.sql b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/query.sql new file mode 100644 index 0000000..60104c8 --- /dev/null +++ b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/query.sql @@ -0,0 +1,20 @@ +-- name: query_return_full_table :many +SELECT * FROM query_return_full_table; + +-- name: query_param_enum_table :one +SELECT * FROM query_param_enum_table WHERE value = $1; + +-- name: query_param_struct_enum_table :one +SELECT id FROM query_param_struct_enum_table WHERE id = $1 AND value = $2; + +-- name: query_return_enum_table :one +SELECT value FROM query_return_enum_table WHERE id = $1; + +-- name: query_return_struct_enum_table :one +SELECT value, another FROM query_return_struct_enum_table WHERE id = $1; + +-- name: query_sqlc_embed_table :one +SELECT sqlc.embed(query_sqlc_embed_table) FROM query_sqlc_embed_table WHERE id = $1; + +-- name: query_enum_array_table :many +SELECT * FROM array_enum_table; diff --git a/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..4ce5921 --- /dev/null +++ b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/schema.sql @@ -0,0 +1,69 @@ +CREATE TYPE unused_enum AS ENUM ( + 'a', 'b' +); + +CREATE TYPE unused_table_enum AS ENUM ( + 'c', 'd' +); +CREATE TABLE unused_table ( + id INTEGER PRIMARY KEY, + value unused_table_enum +); + +CREATE TYPE query_return_full_table_enum AS ENUM ( + 'e', 'f' +); +CREATE TABLE query_return_full_table ( + id INTEGER PRIMARY KEY, + value query_return_full_table_enum +); + +CREATE TYPE query_param_enum_table_enum AS ENUM ( + 'g', 'h' +); +CREATE TABLE query_param_enum_table ( + id INTEGER PRIMARY KEY, + other query_param_enum_table_enum NOT NULL, + value query_param_enum_table_enum +); + +CREATE TYPE query_param_struct_enum_table_enum AS ENUM ( + 'i', 'j' +); +CREATE TABLE query_param_struct_enum_table ( + id INTEGER PRIMARY KEY, + value query_param_struct_enum_table_enum +); + +CREATE TYPE query_return_enum_table_enum AS ENUM ( + 'k', 'l' +); +CREATE TABLE query_return_enum_table ( + id INTEGER PRIMARY KEY, + value query_return_enum_table_enum +); + +CREATE TYPE query_return_struct_enum_table_enum AS ENUM ( + 'k', 'l' +); +CREATE TABLE query_return_struct_enum_table ( + id INTEGER PRIMARY KEY, + value query_return_struct_enum_table_enum, + another INTEGER +); + +CREATE TYPE query_sqlc_embed_enum AS ENUM ( + 'm', 'n' +); +CREATE TABLE query_sqlc_embed_table ( + id INTEGER PRIMARY KEY, + value query_sqlc_embed_enum +); + +CREATE TYPE array_enum AS ENUM ( + 'o', 'p' +); +CREATE TABLE array_enum_table ( + id INTEGER PRIMARY KEY, + value array_enum[] +); diff --git a/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..a48c4d4 --- /dev/null +++ b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "db", + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "omit_unused_structs": true + } + ] +} diff --git a/internal/endtoend/testdata/on_duplicate_key_update/mysql/db/db.go b/internal/endtoend/testdata/on_duplicate_key_update/mysql/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/on_duplicate_key_update/mysql/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/on_duplicate_key_update/mysql/db/models.go b/internal/endtoend/testdata/on_duplicate_key_update/mysql/db/models.go new file mode 100644 index 0000000..56c9d4a --- /dev/null +++ b/internal/endtoend/testdata/on_duplicate_key_update/mysql/db/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/on_duplicate_key_update/mysql/db/query.sql.go b/internal/endtoend/testdata/on_duplicate_key_update/mysql/db/query.sql.go new file mode 100644 index 0000000..de3f8b4 --- /dev/null +++ b/internal/endtoend/testdata/on_duplicate_key_update/mysql/db/query.sql.go @@ -0,0 +1,46 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" + "database/sql" +) + +const upsertAuthor = `-- name: UpsertAuthor :exec +INSERT INTO authors (name, bio) +VALUES (?, ?) +ON DUPLICATE KEY + UPDATE bio = ? +` + +type UpsertAuthorParams struct { + Name string + Bio sql.NullString + Bio_2 sql.NullString +} + +func (q *Queries) UpsertAuthor(ctx context.Context, arg UpsertAuthorParams) error { + _, err := q.db.ExecContext(ctx, upsertAuthor, arg.Name, arg.Bio, arg.Bio_2) + return err +} + +const upsertAuthorNamed = `-- name: UpsertAuthorNamed :exec +INSERT INTO authors (name, bio) +VALUES (?, ?) +ON DUPLICATE KEY + UPDATE bio = ? +` + +type UpsertAuthorNamedParams struct { + Name string + Bio sql.NullString +} + +func (q *Queries) UpsertAuthorNamed(ctx context.Context, arg UpsertAuthorNamedParams) error { + _, err := q.db.ExecContext(ctx, upsertAuthorNamed, arg.Name, arg.Bio, arg.Bio) + return err +} diff --git a/internal/endtoend/testdata/on_duplicate_key_update/mysql/query.sql b/internal/endtoend/testdata/on_duplicate_key_update/mysql/query.sql new file mode 100644 index 0000000..7c54c43 --- /dev/null +++ b/internal/endtoend/testdata/on_duplicate_key_update/mysql/query.sql @@ -0,0 +1,11 @@ +-- name: UpsertAuthor :exec +INSERT INTO authors (name, bio) +VALUES (?, ?) +ON DUPLICATE KEY + UPDATE bio = ?; + +-- name: UpsertAuthorNamed :exec +INSERT INTO authors (name, bio) +VALUES (?, sqlc.arg(bio)) +ON DUPLICATE KEY + UPDATE bio = sqlc.arg(bio); diff --git a/internal/endtoend/testdata/on_duplicate_key_update/mysql/schema.sql b/internal/endtoend/testdata/on_duplicate_key_update/mysql/schema.sql new file mode 100644 index 0000000..581ecfe --- /dev/null +++ b/internal/endtoend/testdata/on_duplicate_key_update/mysql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE authors ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + name text NOT NULL, + bio text +); diff --git a/internal/endtoend/testdata/on_duplicate_key_update/mysql/sqlc.json b/internal/endtoend/testdata/on_duplicate_key_update/mysql/sqlc.json new file mode 100644 index 0000000..df10621 --- /dev/null +++ b/internal/endtoend/testdata/on_duplicate_key_update/mysql/sqlc.json @@ -0,0 +1,11 @@ +{ + "version":"1", + "packages":[ + { + "path":"db", + "engine":"mysql", + "schema":"schema.sql", + "queries":"query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/on_duplicate_key_update/postgresql/db/db.go b/internal/endtoend/testdata/on_duplicate_key_update/postgresql/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/on_duplicate_key_update/postgresql/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/on_duplicate_key_update/postgresql/db/models.go b/internal/endtoend/testdata/on_duplicate_key_update/postgresql/db/models.go new file mode 100644 index 0000000..56c9d4a --- /dev/null +++ b/internal/endtoend/testdata/on_duplicate_key_update/postgresql/db/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/on_duplicate_key_update/postgresql/db/query.sql.go b/internal/endtoend/testdata/on_duplicate_key_update/postgresql/db/query.sql.go new file mode 100644 index 0000000..cb3aa32 --- /dev/null +++ b/internal/endtoend/testdata/on_duplicate_key_update/postgresql/db/query.sql.go @@ -0,0 +1,45 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" + "database/sql" +) + +const upsertAuthor = `-- name: UpsertAuthor :exec +INSERT INTO authors (name, bio) +VALUES ($1, $2) +ON CONFLICT (name) DO UPDATE +SET bio = $2 +` + +type UpsertAuthorParams struct { + Name string + Bio sql.NullString +} + +func (q *Queries) UpsertAuthor(ctx context.Context, arg UpsertAuthorParams) error { + _, err := q.db.ExecContext(ctx, upsertAuthor, arg.Name, arg.Bio) + return err +} + +const upsertAuthorNamed = `-- name: UpsertAuthorNamed :exec +INSERT INTO authors (name, bio) +VALUES ($1, $2) +ON CONFLICT (name) DO UPDATE +SET bio = $2 +` + +type UpsertAuthorNamedParams struct { + Name string + Bio sql.NullString +} + +func (q *Queries) UpsertAuthorNamed(ctx context.Context, arg UpsertAuthorNamedParams) error { + _, err := q.db.ExecContext(ctx, upsertAuthorNamed, arg.Name, arg.Bio) + return err +} diff --git a/internal/endtoend/testdata/on_duplicate_key_update/postgresql/query.sql b/internal/endtoend/testdata/on_duplicate_key_update/postgresql/query.sql new file mode 100644 index 0000000..ad29e0e --- /dev/null +++ b/internal/endtoend/testdata/on_duplicate_key_update/postgresql/query.sql @@ -0,0 +1,11 @@ +-- name: UpsertAuthor :exec +INSERT INTO authors (name, bio) +VALUES ($1, $2) +ON CONFLICT (name) DO UPDATE +SET bio = $2; + +-- name: UpsertAuthorNamed :exec +INSERT INTO authors (name, bio) +VALUES ($1, sqlc.arg(bio)) +ON CONFLICT (name) DO UPDATE +SET bio = sqlc.arg(bio); diff --git a/internal/endtoend/testdata/on_duplicate_key_update/postgresql/schema.sql b/internal/endtoend/testdata/on_duplicate_key_update/postgresql/schema.sql new file mode 100644 index 0000000..b4fad78 --- /dev/null +++ b/internal/endtoend/testdata/on_duplicate_key_update/postgresql/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/on_duplicate_key_update/postgresql/sqlc.json b/internal/endtoend/testdata/on_duplicate_key_update/postgresql/sqlc.json new file mode 100644 index 0000000..58a7ee2 --- /dev/null +++ b/internal/endtoend/testdata/on_duplicate_key_update/postgresql/sqlc.json @@ -0,0 +1,11 @@ +{ + "version":"1", + "packages":[ + { + "path":"db", + "engine":"postgresql", + "schema":"schema.sql", + "queries":"query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/operator_string_concat/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..0ecbc7d --- /dev/null +++ b/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Demo struct { + Txt string +} diff --git a/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..7641d29 --- /dev/null +++ b/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const test2 = `-- name: Test2 :one +select txt from Demo +where txt like '%' || $1::text || '%' +` + +func (q *Queries) Test2(ctx context.Context, val string) (string, error) { + row := q.db.QueryRow(ctx, test2, val) + var txt string + err := row.Scan(&txt) + return txt, err +} + +const test3 = `-- name: Test3 :one +select txt from Demo +where txt like concat('%', $1::text, '%') +` + +func (q *Queries) Test3(ctx context.Context, val string) (string, error) { + row := q.db.QueryRow(ctx, test3, val) + var txt string + err := row.Scan(&txt) + return txt, err +} diff --git a/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..3133d4c --- /dev/null +++ b/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v4/query.sql @@ -0,0 +1,7 @@ +-- name: Test2 :one +select * from Demo +where txt like '%' || sqlc.arg('val')::text || '%'; + +-- name: Test3 :one +select * from Demo +where txt like concat('%', sqlc.arg('val')::text, '%'); diff --git a/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..8a50f1b --- /dev/null +++ b/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE demo (txt text not null); + diff --git a/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/operator_string_concat/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..0ecbc7d --- /dev/null +++ b/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Demo struct { + Txt string +} diff --git a/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..7641d29 --- /dev/null +++ b/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const test2 = `-- name: Test2 :one +select txt from Demo +where txt like '%' || $1::text || '%' +` + +func (q *Queries) Test2(ctx context.Context, val string) (string, error) { + row := q.db.QueryRow(ctx, test2, val) + var txt string + err := row.Scan(&txt) + return txt, err +} + +const test3 = `-- name: Test3 :one +select txt from Demo +where txt like concat('%', $1::text, '%') +` + +func (q *Queries) Test3(ctx context.Context, val string) (string, error) { + row := q.db.QueryRow(ctx, test3, val) + var txt string + err := row.Scan(&txt) + return txt, err +} diff --git a/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..3133d4c --- /dev/null +++ b/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v5/query.sql @@ -0,0 +1,7 @@ +-- name: Test2 :one +select * from Demo +where txt like '%' || sqlc.arg('val')::text || '%'; + +-- name: Test3 :one +select * from Demo +where txt like concat('%', sqlc.arg('val')::text, '%'); diff --git a/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..8a50f1b --- /dev/null +++ b/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE demo (txt text not null); + diff --git a/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/operator_string_concat/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/operator_string_concat/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/operator_string_concat/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/operator_string_concat/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/operator_string_concat/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/operator_string_concat/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..0ecbc7d --- /dev/null +++ b/internal/endtoend/testdata/operator_string_concat/postgresql/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Demo struct { + Txt string +} diff --git a/internal/endtoend/testdata/operator_string_concat/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/operator_string_concat/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..624aeef --- /dev/null +++ b/internal/endtoend/testdata/operator_string_concat/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const test2 = `-- name: Test2 :one +select txt from Demo +where txt like '%' || $1::text || '%' +` + +func (q *Queries) Test2(ctx context.Context, val string) (string, error) { + row := q.db.QueryRowContext(ctx, test2, val) + var txt string + err := row.Scan(&txt) + return txt, err +} + +const test3 = `-- name: Test3 :one +select txt from Demo +where txt like concat('%', $1::text, '%') +` + +func (q *Queries) Test3(ctx context.Context, val string) (string, error) { + row := q.db.QueryRowContext(ctx, test3, val) + var txt string + err := row.Scan(&txt) + return txt, err +} diff --git a/internal/endtoend/testdata/operator_string_concat/postgresql/stdlib/query.sql b/internal/endtoend/testdata/operator_string_concat/postgresql/stdlib/query.sql new file mode 100644 index 0000000..3133d4c --- /dev/null +++ b/internal/endtoend/testdata/operator_string_concat/postgresql/stdlib/query.sql @@ -0,0 +1,7 @@ +-- name: Test2 :one +select * from Demo +where txt like '%' || sqlc.arg('val')::text || '%'; + +-- name: Test3 :one +select * from Demo +where txt like concat('%', sqlc.arg('val')::text, '%'); diff --git a/internal/endtoend/testdata/operator_string_concat/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/operator_string_concat/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..8a50f1b --- /dev/null +++ b/internal/endtoend/testdata/operator_string_concat/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE demo (txt text not null); + diff --git a/internal/endtoend/testdata/operator_string_concat/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/operator_string_concat/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/operator_string_concat/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/order_by_binds/mysql/go/db.go b/internal/endtoend/testdata/order_by_binds/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/order_by_binds/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/order_by_binds/mysql/go/models.go b/internal/endtoend/testdata/order_by_binds/mysql/go/models.go new file mode 100644 index 0000000..2208139 --- /dev/null +++ b/internal/endtoend/testdata/order_by_binds/mysql/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/order_by_binds/mysql/go/query.sql.go b/internal/endtoend/testdata/order_by_binds/mysql/go/query.sql.go new file mode 100644 index 0000000..e135ade --- /dev/null +++ b/internal/endtoend/testdata/order_by_binds/mysql/go/query.sql.go @@ -0,0 +1,101 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listAuthorsColumnSort = `-- name: ListAuthorsColumnSort :many +SELECT id, name, bio FROM authors +WHERE id > ? +ORDER BY CASE WHEN ? = 'name' THEN name END +` + +type ListAuthorsColumnSortParams struct { + MinID int64 + SortColumn any +} + +func (q *Queries) ListAuthorsColumnSort(ctx context.Context, arg ListAuthorsColumnSortParams) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthorsColumnSort, arg.MinID, arg.SortColumn) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); 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 listAuthorsColumnSortFnWtihArg = `-- name: ListAuthorsColumnSortFnWtihArg :many +SELECT id, name, bio FROM authors +ORDER BY MOD(id, ?) +` + +func (q *Queries) ListAuthorsColumnSortFnWtihArg(ctx context.Context, modArg int64) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthorsColumnSortFnWtihArg, modArg) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); 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 listAuthorsNameSort = `-- name: ListAuthorsNameSort :many +SELECT id, name, bio FROM authors +WHERE id > ? +ORDER BY name ASC +` + +func (q *Queries) ListAuthorsNameSort(ctx context.Context, minID int64) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthorsNameSort, minID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); 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/order_by_binds/mysql/query.sql b/internal/endtoend/testdata/order_by_binds/mysql/query.sql new file mode 100644 index 0000000..c43763c --- /dev/null +++ b/internal/endtoend/testdata/order_by_binds/mysql/query.sql @@ -0,0 +1,13 @@ +-- name: ListAuthorsColumnSort :many +SELECT * FROM authors +WHERE id > sqlc.arg(min_id) +ORDER BY CASE WHEN sqlc.arg(sort_column) = 'name' THEN name END; + +-- name: ListAuthorsColumnSortFnWtihArg :many +SELECT * FROM authors +ORDER BY MOD(id, sqlc.arg(mod_arg)); + +-- name: ListAuthorsNameSort :many +SELECT * FROM authors +WHERE id > sqlc.arg(min_id) +ORDER BY name ASC; diff --git a/internal/endtoend/testdata/order_by_binds/mysql/schema.sql b/internal/endtoend/testdata/order_by_binds/mysql/schema.sql new file mode 100644 index 0000000..c3dfc1b --- /dev/null +++ b/internal/endtoend/testdata/order_by_binds/mysql/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE authors ( + id BIGINT PRIMARY KEY, + name text NOT NULL, + bio text +); + diff --git a/internal/endtoend/testdata/order_by_binds/mysql/sqlc.json b/internal/endtoend/testdata/order_by_binds/mysql/sqlc.json new file mode 100644 index 0000000..0390f67 --- /dev/null +++ b/internal/endtoend/testdata/order_by_binds/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/order_by_binds/pganalyze/exec.json b/internal/endtoend/testdata/order_by_binds/pganalyze/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/order_by_binds/pganalyze/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/order_by_binds/pganalyze/go/db.go b/internal/endtoend/testdata/order_by_binds/pganalyze/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/order_by_binds/pganalyze/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/order_by_binds/pganalyze/go/models.go b/internal/endtoend/testdata/order_by_binds/pganalyze/go/models.go new file mode 100644 index 0000000..2208139 --- /dev/null +++ b/internal/endtoend/testdata/order_by_binds/pganalyze/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/order_by_binds/pganalyze/go/query.sql.go b/internal/endtoend/testdata/order_by_binds/pganalyze/go/query.sql.go new file mode 100644 index 0000000..01b9d2f --- /dev/null +++ b/internal/endtoend/testdata/order_by_binds/pganalyze/go/query.sql.go @@ -0,0 +1,74 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const listAuthorsColumnSort = `-- name: ListAuthorsColumnSort :many +SELECT id, name, bio FROM authors +WHERE id > $1 +ORDER BY CASE WHEN $2 = 'name' THEN name END +` + +type ListAuthorsColumnSortParams struct { + MinID int64 + SortColumn sql.NullString +} + +func (q *Queries) ListAuthorsColumnSort(ctx context.Context, arg ListAuthorsColumnSortParams) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthorsColumnSort, arg.MinID, arg.SortColumn) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); 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 listAuthorsNameSort = `-- name: ListAuthorsNameSort :many +SELECT id, name, bio FROM authors +WHERE id > $1 +ORDER BY name ASC +` + +func (q *Queries) ListAuthorsNameSort(ctx context.Context, minID int64) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthorsNameSort, minID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); 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/order_by_binds/pganalyze/query.sql b/internal/endtoend/testdata/order_by_binds/pganalyze/query.sql new file mode 100644 index 0000000..e662d8f --- /dev/null +++ b/internal/endtoend/testdata/order_by_binds/pganalyze/query.sql @@ -0,0 +1,9 @@ +-- name: ListAuthorsColumnSort :many +SELECT * FROM authors +WHERE id > sqlc.arg(min_id) +ORDER BY CASE WHEN sqlc.arg(sort_column) = 'name' THEN name END; + +-- name: ListAuthorsNameSort :many +SELECT * FROM authors +WHERE id > sqlc.arg(min_id) +ORDER BY name ASC; diff --git a/internal/endtoend/testdata/order_by_binds/pganalyze/schema.sql b/internal/endtoend/testdata/order_by_binds/pganalyze/schema.sql new file mode 100644 index 0000000..f388f86 --- /dev/null +++ b/internal/endtoend/testdata/order_by_binds/pganalyze/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); + diff --git a/internal/endtoend/testdata/order_by_binds/pganalyze/sqlc.json b/internal/endtoend/testdata/order_by_binds/pganalyze/sqlc.json new file mode 100644 index 0000000..a590361 --- /dev/null +++ b/internal/endtoend/testdata/order_by_binds/pganalyze/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/order_by_binds/postgresql/exec.json b/internal/endtoend/testdata/order_by_binds/postgresql/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/order_by_binds/postgresql/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/order_by_binds/postgresql/go/db.go b/internal/endtoend/testdata/order_by_binds/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/order_by_binds/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/order_by_binds/postgresql/go/models.go b/internal/endtoend/testdata/order_by_binds/postgresql/go/models.go new file mode 100644 index 0000000..2208139 --- /dev/null +++ b/internal/endtoend/testdata/order_by_binds/postgresql/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/order_by_binds/postgresql/go/query.sql.go b/internal/endtoend/testdata/order_by_binds/postgresql/go/query.sql.go new file mode 100644 index 0000000..317e548 --- /dev/null +++ b/internal/endtoend/testdata/order_by_binds/postgresql/go/query.sql.go @@ -0,0 +1,101 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listAuthorsColumnSort = `-- name: ListAuthorsColumnSort :many +SELECT id, name, bio FROM authors +WHERE id > $1 +ORDER BY CASE WHEN $2 = 'name' THEN name END +` + +type ListAuthorsColumnSortParams struct { + MinID int64 + SortColumn any +} + +func (q *Queries) ListAuthorsColumnSort(ctx context.Context, arg ListAuthorsColumnSortParams) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthorsColumnSort, arg.MinID, arg.SortColumn) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); 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 listAuthorsColumnSortFnWtihArg = `-- name: ListAuthorsColumnSortFnWtihArg :many +SELECT id, name, bio FROM authors +ORDER BY MOD(id, $1) +` + +func (q *Queries) ListAuthorsColumnSortFnWtihArg(ctx context.Context, mod int64) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthorsColumnSortFnWtihArg, mod) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); 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 listAuthorsNameSort = `-- name: ListAuthorsNameSort :many +SELECT id, name, bio FROM authors +WHERE id > $1 +ORDER BY name ASC +` + +func (q *Queries) ListAuthorsNameSort(ctx context.Context, minID int64) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthorsNameSort, minID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); 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/order_by_binds/postgresql/query.sql b/internal/endtoend/testdata/order_by_binds/postgresql/query.sql new file mode 100644 index 0000000..961d3f4 --- /dev/null +++ b/internal/endtoend/testdata/order_by_binds/postgresql/query.sql @@ -0,0 +1,13 @@ +-- name: ListAuthorsColumnSort :many +SELECT * FROM authors +WHERE id > sqlc.arg(min_id) +ORDER BY CASE WHEN sqlc.arg(sort_column) = 'name' THEN name END; + +-- name: ListAuthorsColumnSortFnWtihArg :many +SELECT * FROM authors +ORDER BY MOD(id, $1); + +-- name: ListAuthorsNameSort :many +SELECT * FROM authors +WHERE id > sqlc.arg(min_id) +ORDER BY name ASC; diff --git a/internal/endtoend/testdata/order_by_binds/postgresql/schema.sql b/internal/endtoend/testdata/order_by_binds/postgresql/schema.sql new file mode 100644 index 0000000..f388f86 --- /dev/null +++ b/internal/endtoend/testdata/order_by_binds/postgresql/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); + diff --git a/internal/endtoend/testdata/order_by_binds/postgresql/sqlc.json b/internal/endtoend/testdata/order_by_binds/postgresql/sqlc.json new file mode 100644 index 0000000..a590361 --- /dev/null +++ b/internal/endtoend/testdata/order_by_binds/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/order_by_non_existing_column/postgresql/query.sql b/internal/endtoend/testdata/order_by_non_existing_column/postgresql/query.sql new file mode 100644 index 0000000..ba81cfd --- /dev/null +++ b/internal/endtoend/testdata/order_by_non_existing_column/postgresql/query.sql @@ -0,0 +1,3 @@ +-- name: ListAuthors :many +SELECT id FROM authors +ORDER BY adfadsf; \ No newline at end of file diff --git a/internal/endtoend/testdata/order_by_non_existing_column/postgresql/schema.sql b/internal/endtoend/testdata/order_by_non_existing_column/postgresql/schema.sql new file mode 100644 index 0000000..acba948 --- /dev/null +++ b/internal/endtoend/testdata/order_by_non_existing_column/postgresql/schema.sql @@ -0,0 +1,5 @@ +-- Example queries for sqlc +CREATE TABLE authors ( + id INT +); + diff --git a/internal/endtoend/testdata/order_by_non_existing_column/postgresql/sqlc.yaml b/internal/endtoend/testdata/order_by_non_existing_column/postgresql/sqlc.yaml new file mode 100644 index 0000000..9ae3fc0 --- /dev/null +++ b/internal/endtoend/testdata/order_by_non_existing_column/postgresql/sqlc.yaml @@ -0,0 +1,7 @@ +version: 1 +packages: + - path: "go" + name: "querytest" + engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" \ No newline at end of file diff --git a/internal/endtoend/testdata/order_by_non_existing_column/postgresql/stderr/base.txt b/internal/endtoend/testdata/order_by_non_existing_column/postgresql/stderr/base.txt new file mode 100644 index 0000000..5d9a674 --- /dev/null +++ b/internal/endtoend/testdata/order_by_non_existing_column/postgresql/stderr/base.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:1:1: column reference "adfadsf" not found: if you want to skip this validation, set 'strict_order_by' to false diff --git a/internal/endtoend/testdata/order_by_non_existing_column/postgresql/stderr/managed-db.txt b/internal/endtoend/testdata/order_by_non_existing_column/postgresql/stderr/managed-db.txt new file mode 100644 index 0000000..55cbb71 --- /dev/null +++ b/internal/endtoend/testdata/order_by_non_existing_column/postgresql/stderr/managed-db.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:3:10: column "adfadsf" does not exist diff --git a/internal/endtoend/testdata/order_by_union/mysql/go/db.go b/internal/endtoend/testdata/order_by_union/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/order_by_union/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/order_by_union/mysql/go/models.go b/internal/endtoend/testdata/order_by_union/mysql/go/models.go new file mode 100644 index 0000000..7b5042d --- /dev/null +++ b/internal/endtoend/testdata/order_by_union/mysql/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + Name string + Bio sql.NullString +} + +type Person struct { + FirstName string +} diff --git a/internal/endtoend/testdata/order_by_union/mysql/go/query.sql.go b/internal/endtoend/testdata/order_by_union/mysql/go/query.sql.go new file mode 100644 index 0000000..be47780 --- /dev/null +++ b/internal/endtoend/testdata/order_by_union/mysql/go/query.sql.go @@ -0,0 +1,40 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listAuthorsUnion = `-- name: ListAuthorsUnion :many +SELECT name as foo FROM authors +UNION +SELECT first_name as foo FROM people +ORDER BY foo +` + +func (q *Queries) ListAuthorsUnion(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, listAuthorsUnion) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var foo string + if err := rows.Scan(&foo); err != nil { + return nil, err + } + items = append(items, foo) + } + 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/order_by_union/mysql/query.sql b/internal/endtoend/testdata/order_by_union/mysql/query.sql new file mode 100644 index 0000000..bd034ef --- /dev/null +++ b/internal/endtoend/testdata/order_by_union/mysql/query.sql @@ -0,0 +1,5 @@ +-- name: ListAuthorsUnion :many +SELECT name as foo FROM authors +UNION +SELECT first_name as foo FROM people +ORDER BY foo; diff --git a/internal/endtoend/testdata/order_by_union/mysql/schema.sql b/internal/endtoend/testdata/order_by_union/mysql/schema.sql new file mode 100644 index 0000000..3cdb3a9 --- /dev/null +++ b/internal/endtoend/testdata/order_by_union/mysql/schema.sql @@ -0,0 +1,9 @@ +CREATE TABLE authors ( + name text NOT NULL, + bio text +); + +CREATE TABLE people ( + first_name text NOT NULL +); + diff --git a/internal/endtoend/testdata/order_by_union/mysql/sqlc.json b/internal/endtoend/testdata/order_by_union/mysql/sqlc.json new file mode 100644 index 0000000..0390f67 --- /dev/null +++ b/internal/endtoend/testdata/order_by_union/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/order_by_union/postgresql/go/db.go b/internal/endtoend/testdata/order_by_union/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/order_by_union/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/order_by_union/postgresql/go/models.go b/internal/endtoend/testdata/order_by_union/postgresql/go/models.go new file mode 100644 index 0000000..c5a0170 --- /dev/null +++ b/internal/endtoend/testdata/order_by_union/postgresql/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} + +type Person struct { + FirstName string +} diff --git a/internal/endtoend/testdata/order_by_union/postgresql/go/query.sql.go b/internal/endtoend/testdata/order_by_union/postgresql/go/query.sql.go new file mode 100644 index 0000000..be47780 --- /dev/null +++ b/internal/endtoend/testdata/order_by_union/postgresql/go/query.sql.go @@ -0,0 +1,40 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listAuthorsUnion = `-- name: ListAuthorsUnion :many +SELECT name as foo FROM authors +UNION +SELECT first_name as foo FROM people +ORDER BY foo +` + +func (q *Queries) ListAuthorsUnion(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, listAuthorsUnion) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var foo string + if err := rows.Scan(&foo); err != nil { + return nil, err + } + items = append(items, foo) + } + 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/order_by_union/postgresql/query.sql b/internal/endtoend/testdata/order_by_union/postgresql/query.sql new file mode 100644 index 0000000..bd034ef --- /dev/null +++ b/internal/endtoend/testdata/order_by_union/postgresql/query.sql @@ -0,0 +1,5 @@ +-- name: ListAuthorsUnion :many +SELECT name as foo FROM authors +UNION +SELECT first_name as foo FROM people +ORDER BY foo; diff --git a/internal/endtoend/testdata/order_by_union/postgresql/schema.sql b/internal/endtoend/testdata/order_by_union/postgresql/schema.sql new file mode 100644 index 0000000..2d646fd --- /dev/null +++ b/internal/endtoend/testdata/order_by_union/postgresql/schema.sql @@ -0,0 +1,10 @@ +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); + +CREATE TABLE people ( + first_name text NOT NULL +); + diff --git a/internal/endtoend/testdata/order_by_union/postgresql/sqlc.json b/internal/endtoend/testdata/order_by_union/postgresql/sqlc.json new file mode 100644 index 0000000..a590361 --- /dev/null +++ b/internal/endtoend/testdata/order_by_union/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/output_file_names/pgx/v4/go/batch_gen.go b/internal/endtoend/testdata/output_file_names/pgx/v4/go/batch_gen.go new file mode 100644 index 0000000..81bdf96 --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/pgx/v4/go/batch_gen.go @@ -0,0 +1,76 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: batch_gen.go + +package querytest + +import ( + "context" + "errors" + + "github.com/jackc/pgx/v4" +) + +var ( + ErrBatchAlreadyClosed = errors.New("batch already closed") +) + +const usersB = `-- name: UsersB :batchmany +SELECT id FROM "user" +WHERE id = $1 +` + +type UsersBBatchResults struct { + br pgx.BatchResults + tot int + closed bool +} + +func (q *Queries) UsersB(ctx context.Context, id []int64) *UsersBBatchResults { + batch := &pgx.Batch{} + for _, a := range id { + vals := []any{ + a, + } + batch.Queue(usersB, vals...) + } + br := q.db.SendBatch(ctx, batch) + return &UsersBBatchResults{br, len(id), false} +} + +func (b *UsersBBatchResults) Query(f func(int, []int64, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + var items []int64 + if b.closed { + if f != nil { + f(t, items, ErrBatchAlreadyClosed) + } + continue + } + err := func() error { + rows, err := b.br.Query() + if err != nil { + return err + } + defer rows.Close() + for rows.Next() { + var id int64 + if err := rows.Scan(&id); err != nil { + return err + } + items = append(items, id) + } + return rows.Err() + }() + if f != nil { + f(t, items, err) + } + } +} + +func (b *UsersBBatchResults) Close() error { + b.closed = true + return b.br.Close() +} diff --git a/internal/endtoend/testdata/output_file_names/pgx/v4/go/copyfrom_gen.go b/internal/endtoend/testdata/output_file_names/pgx/v4/go/copyfrom_gen.go new file mode 100644 index 0000000..672ccfd --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/pgx/v4/go/copyfrom_gen.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: copyfrom_gen.go + +package querytest + +import ( + "context" +) + +// iteratorForUsersC implements pgx.CopyFromSource. +type iteratorForUsersC struct { + rows []int64 + skippedFirstNextCall bool +} + +func (r *iteratorForUsersC) Next() bool { + if len(r.rows) == 0 { + return false + } + if !r.skippedFirstNextCall { + r.skippedFirstNextCall = true + return true + } + r.rows = r.rows[1:] + return len(r.rows) > 0 +} + +func (r iteratorForUsersC) Values() ([]any, error) { + return []any{ + r.rows[0], + }, nil +} + +func (r iteratorForUsersC) Err() error { + return nil +} + +func (q *Queries) UsersC(ctx context.Context, id []int64) (int64, error) { + return q.db.CopyFrom(ctx, []string{"user"}, []string{"id"}, &iteratorForUsersC{rows: id}) +} diff --git a/internal/endtoend/testdata/output_file_names/pgx/v4/go/db_gen.go b/internal/endtoend/testdata/output_file_names/pgx/v4/go/db_gen.go new file mode 100644 index 0000000..a331016 --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/pgx/v4/go/db_gen.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row + CopyFrom(ctx context.Context, tableName pgx.Identifier, columnNames []string, rowSrc pgx.CopyFromSource) (int64, error) + SendBatch(context.Context, *pgx.Batch) pgx.BatchResults +} + +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/output_file_names/pgx/v4/go/models_gen.go b/internal/endtoend/testdata/output_file_names/pgx/v4/go/models_gen.go new file mode 100644 index 0000000..4af57ab --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/pgx/v4/go/models_gen.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type User struct { + ID int64 +} diff --git a/internal/endtoend/testdata/output_file_names/pgx/v4/go/querier_gen.go b/internal/endtoend/testdata/output_file_names/pgx/v4/go/querier_gen.go new file mode 100644 index 0000000..287259c --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/pgx/v4/go/querier_gen.go @@ -0,0 +1,17 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" +) + +type Querier interface { + User(ctx context.Context) ([]int64, error) + UsersB(ctx context.Context, id []int64) *UsersBBatchResults + UsersC(ctx context.Context, id []int64) (int64, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/output_file_names/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/output_file_names/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..34274a0 --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const user = `-- name: User :many +SELECT "user".id FROM "user" +` + +func (q *Queries) User(ctx context.Context) ([]int64, error) { + rows, err := q.db.Query(ctx, user) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var id int64 + 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 +} diff --git a/internal/endtoend/testdata/output_file_names/pgx/v4/query.sql b/internal/endtoend/testdata/output_file_names/pgx/v4/query.sql new file mode 100644 index 0000000..0b14d20 --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/pgx/v4/query.sql @@ -0,0 +1,12 @@ +-- name: User :many +SELECT "user".* FROM "user"; + +-- name: UsersB :batchmany +SELECT * FROM "user" +WHERE id = $1; + +-- name: UsersC :copyfrom +INSERT INTO "user" +(id) +VALUES +($1); diff --git a/internal/endtoend/testdata/output_file_names/pgx/v4/schema.sql b/internal/endtoend/testdata/output_file_names/pgx/v4/schema.sql new file mode 100644 index 0000000..7fd1e59 --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE "user" (id bigserial not null); + diff --git a/internal/endtoend/testdata/output_file_names/pgx/v4/sqlc.json b/internal/endtoend/testdata/output_file_names/pgx/v4/sqlc.json new file mode 100644 index 0000000..b92274a --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/pgx/v4/sqlc.json @@ -0,0 +1,19 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_interface": true, + "output_batch_file_name": "batch_gen.go", + "output_db_file_name": "db_gen.go", + "output_models_file_name": "models_gen.go", + "output_querier_file_name": "querier_gen.go", + "output_copyfrom_file_name": "copyfrom_gen.go" + } + ] +} diff --git a/internal/endtoend/testdata/output_file_names/pgx/v5/go/batch_gen.go b/internal/endtoend/testdata/output_file_names/pgx/v5/go/batch_gen.go new file mode 100644 index 0000000..569eee2 --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/pgx/v5/go/batch_gen.go @@ -0,0 +1,76 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: batch_gen.go + +package querytest + +import ( + "context" + "errors" + + "github.com/jackc/pgx/v5" +) + +var ( + ErrBatchAlreadyClosed = errors.New("batch already closed") +) + +const usersB = `-- name: UsersB :batchmany +SELECT id FROM "user" +WHERE id = $1 +` + +type UsersBBatchResults struct { + br pgx.BatchResults + tot int + closed bool +} + +func (q *Queries) UsersB(ctx context.Context, id []int64) *UsersBBatchResults { + batch := &pgx.Batch{} + for _, a := range id { + vals := []any{ + a, + } + batch.Queue(usersB, vals...) + } + br := q.db.SendBatch(ctx, batch) + return &UsersBBatchResults{br, len(id), false} +} + +func (b *UsersBBatchResults) Query(f func(int, []int64, error)) { + defer b.br.Close() + for t := 0; t < b.tot; t++ { + var items []int64 + if b.closed { + if f != nil { + f(t, items, ErrBatchAlreadyClosed) + } + continue + } + err := func() error { + rows, err := b.br.Query() + if err != nil { + return err + } + defer rows.Close() + for rows.Next() { + var id int64 + if err := rows.Scan(&id); err != nil { + return err + } + items = append(items, id) + } + return rows.Err() + }() + if f != nil { + f(t, items, err) + } + } +} + +func (b *UsersBBatchResults) Close() error { + b.closed = true + return b.br.Close() +} diff --git a/internal/endtoend/testdata/output_file_names/pgx/v5/go/copyfrom_gen.go b/internal/endtoend/testdata/output_file_names/pgx/v5/go/copyfrom_gen.go new file mode 100644 index 0000000..672ccfd --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/pgx/v5/go/copyfrom_gen.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: copyfrom_gen.go + +package querytest + +import ( + "context" +) + +// iteratorForUsersC implements pgx.CopyFromSource. +type iteratorForUsersC struct { + rows []int64 + skippedFirstNextCall bool +} + +func (r *iteratorForUsersC) Next() bool { + if len(r.rows) == 0 { + return false + } + if !r.skippedFirstNextCall { + r.skippedFirstNextCall = true + return true + } + r.rows = r.rows[1:] + return len(r.rows) > 0 +} + +func (r iteratorForUsersC) Values() ([]any, error) { + return []any{ + r.rows[0], + }, nil +} + +func (r iteratorForUsersC) Err() error { + return nil +} + +func (q *Queries) UsersC(ctx context.Context, id []int64) (int64, error) { + return q.db.CopyFrom(ctx, []string{"user"}, []string{"id"}, &iteratorForUsersC{rows: id}) +} diff --git a/internal/endtoend/testdata/output_file_names/pgx/v5/go/db_gen.go b/internal/endtoend/testdata/output_file_names/pgx/v5/go/db_gen.go new file mode 100644 index 0000000..185bd2a --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/pgx/v5/go/db_gen.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) pgx.Row + CopyFrom(ctx context.Context, tableName pgx.Identifier, columnNames []string, rowSrc pgx.CopyFromSource) (int64, error) + SendBatch(context.Context, *pgx.Batch) pgx.BatchResults +} + +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/output_file_names/pgx/v5/go/models_gen.go b/internal/endtoend/testdata/output_file_names/pgx/v5/go/models_gen.go new file mode 100644 index 0000000..4af57ab --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/pgx/v5/go/models_gen.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type User struct { + ID int64 +} diff --git a/internal/endtoend/testdata/output_file_names/pgx/v5/go/querier_gen.go b/internal/endtoend/testdata/output_file_names/pgx/v5/go/querier_gen.go new file mode 100644 index 0000000..287259c --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/pgx/v5/go/querier_gen.go @@ -0,0 +1,17 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" +) + +type Querier interface { + User(ctx context.Context) ([]int64, error) + UsersB(ctx context.Context, id []int64) *UsersBBatchResults + UsersC(ctx context.Context, id []int64) (int64, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/output_file_names/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/output_file_names/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..34274a0 --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const user = `-- name: User :many +SELECT "user".id FROM "user" +` + +func (q *Queries) User(ctx context.Context) ([]int64, error) { + rows, err := q.db.Query(ctx, user) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var id int64 + 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 +} diff --git a/internal/endtoend/testdata/output_file_names/pgx/v5/query.sql b/internal/endtoend/testdata/output_file_names/pgx/v5/query.sql new file mode 100644 index 0000000..7d59a79 --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/pgx/v5/query.sql @@ -0,0 +1,12 @@ +-- name: User :many +SELECT "user".* FROM "user"; + +-- name: UsersB :batchmany +SELECT * FROM "user" +WHERE id = $1; + +-- name: UsersC :copyfrom +INSERT INTO "user" +(id) +VALUES + ($1); diff --git a/internal/endtoend/testdata/output_file_names/pgx/v5/schema.sql b/internal/endtoend/testdata/output_file_names/pgx/v5/schema.sql new file mode 100644 index 0000000..7fd1e59 --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE "user" (id bigserial not null); + diff --git a/internal/endtoend/testdata/output_file_names/pgx/v5/sqlc.json b/internal/endtoend/testdata/output_file_names/pgx/v5/sqlc.json new file mode 100644 index 0000000..958c874 --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/pgx/v5/sqlc.json @@ -0,0 +1,19 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_interface": true, + "output_batch_file_name": "batch_gen.go", + "output_db_file_name": "db_gen.go", + "output_models_file_name": "models_gen.go", + "output_querier_file_name": "querier_gen.go", + "output_copyfrom_file_name": "copyfrom_gen.go" + } + ] +} diff --git a/internal/endtoend/testdata/output_file_names/stdlib/go/db_gen.go b/internal/endtoend/testdata/output_file_names/stdlib/go/db_gen.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/stdlib/go/db_gen.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/output_file_names/stdlib/go/models_gen.go b/internal/endtoend/testdata/output_file_names/stdlib/go/models_gen.go new file mode 100644 index 0000000..4af57ab --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/stdlib/go/models_gen.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type User struct { + ID int64 +} diff --git a/internal/endtoend/testdata/output_file_names/stdlib/go/querier_gen.go b/internal/endtoend/testdata/output_file_names/stdlib/go/querier_gen.go new file mode 100644 index 0000000..e1caa4f --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/stdlib/go/querier_gen.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" +) + +type Querier interface { + User(ctx context.Context) ([]int64, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/output_file_names/stdlib/go/query.sql.go b/internal/endtoend/testdata/output_file_names/stdlib/go/query.sql.go new file mode 100644 index 0000000..7cd0ecd --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const user = `-- name: User :many +SELECT "user".id FROM "user" +` + +func (q *Queries) User(ctx context.Context) ([]int64, error) { + rows, err := q.db.QueryContext(ctx, user) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var id int64 + 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 +} diff --git a/internal/endtoend/testdata/output_file_names/stdlib/query.sql b/internal/endtoend/testdata/output_file_names/stdlib/query.sql new file mode 100644 index 0000000..6449356 --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: User :many +SELECT "user".* FROM "user"; diff --git a/internal/endtoend/testdata/output_file_names/stdlib/schema.sql b/internal/endtoend/testdata/output_file_names/stdlib/schema.sql new file mode 100644 index 0000000..7fd1e59 --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE "user" (id bigserial not null); + diff --git a/internal/endtoend/testdata/output_file_names/stdlib/sqlc.json b/internal/endtoend/testdata/output_file_names/stdlib/sqlc.json new file mode 100644 index 0000000..677f10a --- /dev/null +++ b/internal/endtoend/testdata/output_file_names/stdlib/sqlc.json @@ -0,0 +1,16 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_interface": true, + "output_db_file_name": "db_gen.go", + "output_models_file_name": "models_gen.go", + "output_querier_file_name": "querier_gen.go", + "output_copyfrom_file_name": "copyfrom_gen.go" + } + ] +} diff --git a/internal/endtoend/testdata/output_files_suffix/pgx/v4/go/db.go b/internal/endtoend/testdata/output_files_suffix/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/output_files_suffix/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/output_files_suffix/pgx/v4/go/models.go b/internal/endtoend/testdata/output_files_suffix/pgx/v4/go/models.go new file mode 100644 index 0000000..4af57ab --- /dev/null +++ b/internal/endtoend/testdata/output_files_suffix/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type User struct { + ID int64 +} diff --git a/internal/endtoend/testdata/output_files_suffix/pgx/v4/go/query.sql_gen.go b/internal/endtoend/testdata/output_files_suffix/pgx/v4/go/query.sql_gen.go new file mode 100644 index 0000000..34274a0 --- /dev/null +++ b/internal/endtoend/testdata/output_files_suffix/pgx/v4/go/query.sql_gen.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const user = `-- name: User :many +SELECT "user".id FROM "user" +` + +func (q *Queries) User(ctx context.Context) ([]int64, error) { + rows, err := q.db.Query(ctx, user) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var id int64 + 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 +} diff --git a/internal/endtoend/testdata/output_files_suffix/pgx/v4/query.sql b/internal/endtoend/testdata/output_files_suffix/pgx/v4/query.sql new file mode 100644 index 0000000..6449356 --- /dev/null +++ b/internal/endtoend/testdata/output_files_suffix/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: User :many +SELECT "user".* FROM "user"; diff --git a/internal/endtoend/testdata/output_files_suffix/pgx/v4/schema.sql b/internal/endtoend/testdata/output_files_suffix/pgx/v4/schema.sql new file mode 100644 index 0000000..7fd1e59 --- /dev/null +++ b/internal/endtoend/testdata/output_files_suffix/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE "user" (id bigserial not null); + diff --git a/internal/endtoend/testdata/output_files_suffix/pgx/v4/sqlc.json b/internal/endtoend/testdata/output_files_suffix/pgx/v4/sqlc.json new file mode 100644 index 0000000..966fad6 --- /dev/null +++ b/internal/endtoend/testdata/output_files_suffix/pgx/v4/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "output_files_suffix": "_gen.go" + } + ] +} diff --git a/internal/endtoend/testdata/output_files_suffix/pgx/v5/go/db.go b/internal/endtoend/testdata/output_files_suffix/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/output_files_suffix/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/output_files_suffix/pgx/v5/go/models.go b/internal/endtoend/testdata/output_files_suffix/pgx/v5/go/models.go new file mode 100644 index 0000000..4af57ab --- /dev/null +++ b/internal/endtoend/testdata/output_files_suffix/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type User struct { + ID int64 +} diff --git a/internal/endtoend/testdata/output_files_suffix/pgx/v5/go/query.sql_gen.go b/internal/endtoend/testdata/output_files_suffix/pgx/v5/go/query.sql_gen.go new file mode 100644 index 0000000..34274a0 --- /dev/null +++ b/internal/endtoend/testdata/output_files_suffix/pgx/v5/go/query.sql_gen.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const user = `-- name: User :many +SELECT "user".id FROM "user" +` + +func (q *Queries) User(ctx context.Context) ([]int64, error) { + rows, err := q.db.Query(ctx, user) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var id int64 + 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 +} diff --git a/internal/endtoend/testdata/output_files_suffix/pgx/v5/query.sql b/internal/endtoend/testdata/output_files_suffix/pgx/v5/query.sql new file mode 100644 index 0000000..6449356 --- /dev/null +++ b/internal/endtoend/testdata/output_files_suffix/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: User :many +SELECT "user".* FROM "user"; diff --git a/internal/endtoend/testdata/output_files_suffix/pgx/v5/schema.sql b/internal/endtoend/testdata/output_files_suffix/pgx/v5/schema.sql new file mode 100644 index 0000000..7fd1e59 --- /dev/null +++ b/internal/endtoend/testdata/output_files_suffix/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE "user" (id bigserial not null); + diff --git a/internal/endtoend/testdata/output_files_suffix/pgx/v5/sqlc.json b/internal/endtoend/testdata/output_files_suffix/pgx/v5/sqlc.json new file mode 100644 index 0000000..9d64831 --- /dev/null +++ b/internal/endtoend/testdata/output_files_suffix/pgx/v5/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "output_files_suffix": "_gen.go" + } + ] +} diff --git a/internal/endtoend/testdata/output_files_suffix/stdlib/go/db.go b/internal/endtoend/testdata/output_files_suffix/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/output_files_suffix/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/output_files_suffix/stdlib/go/models.go b/internal/endtoend/testdata/output_files_suffix/stdlib/go/models.go new file mode 100644 index 0000000..4af57ab --- /dev/null +++ b/internal/endtoend/testdata/output_files_suffix/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type User struct { + ID int64 +} diff --git a/internal/endtoend/testdata/output_files_suffix/stdlib/go/query.sql_gen.go b/internal/endtoend/testdata/output_files_suffix/stdlib/go/query.sql_gen.go new file mode 100644 index 0000000..7cd0ecd --- /dev/null +++ b/internal/endtoend/testdata/output_files_suffix/stdlib/go/query.sql_gen.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const user = `-- name: User :many +SELECT "user".id FROM "user" +` + +func (q *Queries) User(ctx context.Context) ([]int64, error) { + rows, err := q.db.QueryContext(ctx, user) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var id int64 + 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 +} diff --git a/internal/endtoend/testdata/output_files_suffix/stdlib/query.sql b/internal/endtoend/testdata/output_files_suffix/stdlib/query.sql new file mode 100644 index 0000000..6449356 --- /dev/null +++ b/internal/endtoend/testdata/output_files_suffix/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: User :many +SELECT "user".* FROM "user"; diff --git a/internal/endtoend/testdata/output_files_suffix/stdlib/schema.sql b/internal/endtoend/testdata/output_files_suffix/stdlib/schema.sql new file mode 100644 index 0000000..7fd1e59 --- /dev/null +++ b/internal/endtoend/testdata/output_files_suffix/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE "user" (id bigserial not null); + diff --git a/internal/endtoend/testdata/output_files_suffix/stdlib/sqlc.json b/internal/endtoend/testdata/output_files_suffix/stdlib/sqlc.json new file mode 100644 index 0000000..73ff897 --- /dev/null +++ b/internal/endtoend/testdata/output_files_suffix/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "output_files_suffix": "_gen.go" + } + ] +} diff --git a/internal/endtoend/testdata/output_models_path/postgresql/db/db.go b/internal/endtoend/testdata/output_models_path/postgresql/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/output_models_path/postgresql/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/output_models_path/postgresql/db/querier.go b/internal/endtoend/testdata/output_models_path/postgresql/db/querier.go new file mode 100644 index 0000000..18d562c --- /dev/null +++ b/internal/endtoend/testdata/output_models_path/postgresql/db/querier.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + + models "github.com/sqlc-dev/sqlc/endtoend/output_models_path/postgresql/model" +) + +type Querier interface { + CreateAuthor(ctx context.Context, arg CreateAuthorParams) (models.Author, error) + GetAuthor(ctx context.Context, id int64) (models.Author, error) + GetBook(ctx context.Context, id int64) (models.Book, error) + ListAuthors(ctx context.Context) ([]models.Author, error) + ListAuthorsByStatus(ctx context.Context, status models.Status) ([]models.Author, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/output_models_path/postgresql/db/query.sql.go b/internal/endtoend/testdata/output_models_path/postgresql/db/query.sql.go new file mode 100644 index 0000000..2e25613 --- /dev/null +++ b/internal/endtoend/testdata/output_models_path/postgresql/db/query.sql.go @@ -0,0 +1,126 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" + "database/sql" + + models "github.com/sqlc-dev/sqlc/endtoend/output_models_path/postgresql/model" +) + +const createAuthor = `-- name: CreateAuthor :one +INSERT INTO authors (name, bio, status) VALUES ($1, $2, $3) RETURNING id, name, bio, status +` + +type CreateAuthorParams struct { + Name string + Bio sql.NullString + Status models.Status +} + +func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (models.Author, error) { + row := q.db.QueryRowContext(ctx, createAuthor, arg.Name, arg.Bio, arg.Status) + var i models.Author + err := row.Scan( + &i.ID, + &i.Name, + &i.Bio, + &i.Status, + ) + return i, err +} + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, bio, status FROM authors WHERE id = $1 LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (models.Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i models.Author + err := row.Scan( + &i.ID, + &i.Name, + &i.Bio, + &i.Status, + ) + return i, err +} + +const getBook = `-- name: GetBook :one +SELECT id, author_id, title FROM books WHERE id = $1 LIMIT 1 +` + +func (q *Queries) GetBook(ctx context.Context, id int64) (models.Book, error) { + row := q.db.QueryRowContext(ctx, getBook, id) + var i models.Book + err := row.Scan(&i.ID, &i.AuthorID, &i.Title) + return i, err +} + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name, bio, status FROM authors ORDER BY name +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]models.Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []models.Author + for rows.Next() { + var i models.Author + if err := rows.Scan( + &i.ID, + &i.Name, + &i.Bio, + &i.Status, + ); 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 listAuthorsByStatus = `-- name: ListAuthorsByStatus :many +SELECT id, name, bio, status FROM authors WHERE status = $1 ORDER BY name +` + +func (q *Queries) ListAuthorsByStatus(ctx context.Context, status models.Status) ([]models.Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthorsByStatus, status) + if err != nil { + return nil, err + } + defer rows.Close() + var items []models.Author + for rows.Next() { + var i models.Author + if err := rows.Scan( + &i.ID, + &i.Name, + &i.Bio, + &i.Status, + ); 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/output_models_path/postgresql/model/models.go b/internal/endtoend/testdata/output_models_path/postgresql/model/models.go new file mode 100644 index 0000000..82fc33d --- /dev/null +++ b/internal/endtoend/testdata/output_models_path/postgresql/model/models.go @@ -0,0 +1,67 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package model + +import ( + "database/sql" + "database/sql/driver" + "fmt" +) + +type Status string + +const ( + StatusActive Status = "active" + StatusInactive Status = "inactive" + StatusPending Status = "pending" +) + +func (e *Status) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = Status(s) + case string: + *e = Status(s) + default: + return fmt.Errorf("unsupported scan type for Status: %T", src) + } + return nil +} + +type NullStatus struct { + Status Status + Valid bool // Valid is true if Status is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullStatus) Scan(value any) error { + if value == nil { + ns.Status, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.Status.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullStatus) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.Status), nil +} + +type Author struct { + ID int64 + Name string + Bio sql.NullString + Status Status +} + +type Book struct { + ID int64 + AuthorID int64 + Title string +} diff --git a/internal/endtoend/testdata/output_models_path/postgresql/query.sql b/internal/endtoend/testdata/output_models_path/postgresql/query.sql new file mode 100644 index 0000000..5c7c377 --- /dev/null +++ b/internal/endtoend/testdata/output_models_path/postgresql/query.sql @@ -0,0 +1,14 @@ +-- 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, status) VALUES ($1, $2, $3) RETURNING *; + +-- name: ListAuthorsByStatus :many +SELECT * FROM authors WHERE status = $1 ORDER BY name; + +-- name: GetBook :one +SELECT * FROM books WHERE id = $1 LIMIT 1; diff --git a/internal/endtoend/testdata/output_models_path/postgresql/schema.sql b/internal/endtoend/testdata/output_models_path/postgresql/schema.sql new file mode 100644 index 0000000..2d85828 --- /dev/null +++ b/internal/endtoend/testdata/output_models_path/postgresql/schema.sql @@ -0,0 +1,14 @@ +CREATE TYPE status AS ENUM ('active', 'inactive', 'pending'); + +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text, + status status NOT NULL DEFAULT 'active' +); + +CREATE TABLE books ( + id BIGSERIAL PRIMARY KEY, + author_id BIGINT NOT NULL REFERENCES authors(id), + title text NOT NULL +); diff --git a/internal/endtoend/testdata/output_models_path/postgresql/sqlc.json b/internal/endtoend/testdata/output_models_path/postgresql/sqlc.json new file mode 100644 index 0000000..9fa8540 --- /dev/null +++ b/internal/endtoend/testdata/output_models_path/postgresql/sqlc.json @@ -0,0 +1,19 @@ +{ + "version": "2", + "sql": [ + { + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql", + "gen": { + "go": { + "out": "db", + "package": "db", + "emit_interface": true, + "output_models_path": "model", + "output_models_import": "github.com/sqlc-dev/sqlc/endtoend/output_models_path/postgresql/model" + } + } + } + ] +} diff --git a/internal/endtoend/testdata/output_models_shared/postgresql/model/models.go b/internal/endtoend/testdata/output_models_shared/postgresql/model/models.go new file mode 100644 index 0000000..ac322bd --- /dev/null +++ b/internal/endtoend/testdata/output_models_shared/postgresql/model/models.go @@ -0,0 +1,58 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package model + +import ( + "database/sql/driver" + "fmt" +) + +type Status string + +const ( + StatusActive Status = "active" + StatusInactive Status = "inactive" +) + +func (e *Status) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = Status(s) + case string: + *e = Status(s) + default: + return fmt.Errorf("unsupported scan type for Status: %T", src) + } + return nil +} + +type NullStatus struct { + Status Status + Valid bool // Valid is true if Status is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullStatus) Scan(value any) error { + if value == nil { + ns.Status, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.Status.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullStatus) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.Status), nil +} + +type Author struct { + ID int64 + Name string + Status Status +} diff --git a/internal/endtoend/testdata/output_models_shared/postgresql/primary/db.go b/internal/endtoend/testdata/output_models_shared/postgresql/primary/db.go new file mode 100644 index 0000000..19e576d --- /dev/null +++ b/internal/endtoend/testdata/output_models_shared/postgresql/primary/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package primary + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/output_models_shared/postgresql/primary/query.sql.go b/internal/endtoend/testdata/output_models_shared/postgresql/primary/query.sql.go new file mode 100644 index 0000000..555d405 --- /dev/null +++ b/internal/endtoend/testdata/output_models_shared/postgresql/primary/query.sql.go @@ -0,0 +1,39 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package primary + +import ( + "context" + + models "github.com/sqlc-dev/sqlc/endtoend/output_models_shared/postgresql/model" +) + +const createAuthor = `-- name: CreateAuthor :one +INSERT INTO authors (name, status) VALUES ($1, $2) RETURNING id, name, status +` + +type CreateAuthorParams struct { + Name string + Status models.Status +} + +func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (models.Author, error) { + row := q.db.QueryRowContext(ctx, createAuthor, arg.Name, arg.Status) + var i models.Author + err := row.Scan(&i.ID, &i.Name, &i.Status) + return i, err +} + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, status FROM authors WHERE id = $1 LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (models.Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i models.Author + err := row.Scan(&i.ID, &i.Name, &i.Status) + return i, err +} diff --git a/internal/endtoend/testdata/output_models_shared/postgresql/queries/primary/query.sql b/internal/endtoend/testdata/output_models_shared/postgresql/queries/primary/query.sql new file mode 100644 index 0000000..b8646b5 --- /dev/null +++ b/internal/endtoend/testdata/output_models_shared/postgresql/queries/primary/query.sql @@ -0,0 +1,5 @@ +-- name: CreateAuthor :one +INSERT INTO authors (name, status) VALUES ($1, $2) RETURNING *; + +-- name: GetAuthor :one +SELECT * FROM authors WHERE id = $1 LIMIT 1; diff --git a/internal/endtoend/testdata/output_models_shared/postgresql/queries/replica/query.sql b/internal/endtoend/testdata/output_models_shared/postgresql/queries/replica/query.sql new file mode 100644 index 0000000..b533fea --- /dev/null +++ b/internal/endtoend/testdata/output_models_shared/postgresql/queries/replica/query.sql @@ -0,0 +1,5 @@ +-- name: ListAuthors :many +SELECT * FROM authors ORDER BY name; + +-- name: ListAuthorsByStatus :many +SELECT * FROM authors WHERE status = $1 ORDER BY name; diff --git a/internal/endtoend/testdata/output_models_shared/postgresql/replica/db.go b/internal/endtoend/testdata/output_models_shared/postgresql/replica/db.go new file mode 100644 index 0000000..3e0b2c2 --- /dev/null +++ b/internal/endtoend/testdata/output_models_shared/postgresql/replica/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package replica + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/output_models_shared/postgresql/replica/query.sql.go b/internal/endtoend/testdata/output_models_shared/postgresql/replica/query.sql.go new file mode 100644 index 0000000..4831f5c --- /dev/null +++ b/internal/endtoend/testdata/output_models_shared/postgresql/replica/query.sql.go @@ -0,0 +1,66 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package replica + +import ( + "context" + + models "github.com/sqlc-dev/sqlc/endtoend/output_models_shared/postgresql/model" +) + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name, status FROM authors ORDER BY name +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]models.Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []models.Author + for rows.Next() { + var i models.Author + if err := rows.Scan(&i.ID, &i.Name, &i.Status); 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 listAuthorsByStatus = `-- name: ListAuthorsByStatus :many +SELECT id, name, status FROM authors WHERE status = $1 ORDER BY name +` + +func (q *Queries) ListAuthorsByStatus(ctx context.Context, status models.Status) ([]models.Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthorsByStatus, status) + if err != nil { + return nil, err + } + defer rows.Close() + var items []models.Author + for rows.Next() { + var i models.Author + if err := rows.Scan(&i.ID, &i.Name, &i.Status); 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/output_models_shared/postgresql/schema.sql b/internal/endtoend/testdata/output_models_shared/postgresql/schema.sql new file mode 100644 index 0000000..afb9a4e --- /dev/null +++ b/internal/endtoend/testdata/output_models_shared/postgresql/schema.sql @@ -0,0 +1,7 @@ +CREATE TYPE status AS ENUM ('active', 'inactive'); + +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + status status NOT NULL DEFAULT 'active' +); diff --git a/internal/endtoend/testdata/output_models_shared/postgresql/sqlc.json b/internal/endtoend/testdata/output_models_shared/postgresql/sqlc.json new file mode 100644 index 0000000..98d60f8 --- /dev/null +++ b/internal/endtoend/testdata/output_models_shared/postgresql/sqlc.json @@ -0,0 +1,31 @@ +{ + "version": "2", + "sql": [ + { + "schema": "schema.sql", + "queries": "queries/primary", + "engine": "postgresql", + "gen": { + "go": { + "out": "primary", + "package": "primary", + "output_models_path": "model", + "output_models_import": "github.com/sqlc-dev/sqlc/endtoend/output_models_shared/postgresql/model" + } + } + }, + { + "schema": "schema.sql", + "queries": "queries/replica", + "engine": "postgresql", + "gen": { + "go": { + "out": "replica", + "package": "replica", + "output_models_import": "github.com/sqlc-dev/sqlc/endtoend/output_models_shared/postgresql/model", + "output_models_emit": false + } + } + } + ] +} diff --git a/internal/endtoend/testdata/overrides/mysql/go/db.go b/internal/endtoend/testdata/overrides/mysql/go/db.go new file mode 100644 index 0000000..3e4ebb9 --- /dev/null +++ b/internal/endtoend/testdata/overrides/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/overrides/mysql/go/models.go b/internal/endtoend/testdata/overrides/mysql/go/models.go new file mode 100644 index 0000000..b538582 --- /dev/null +++ b/internal/endtoend/testdata/overrides/mysql/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "github.com/sqlc-dev/sqlc-testdata/pkg" +) + +type Foo struct { + Other string + Total int64 + Retyped pkg.CustomType +} diff --git a/internal/endtoend/testdata/overrides/mysql/go/query.sql.go b/internal/endtoend/testdata/overrides/mysql/go/query.sql.go new file mode 100644 index 0000000..0a94a43 --- /dev/null +++ b/internal/endtoend/testdata/overrides/mysql/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package override + +import ( + "context" +) + +const test = `-- name: Test :one +SELECT 1 +` + +func (q *Queries) Test(ctx context.Context) (int32, error) { + row := q.db.QueryRowContext(ctx, test) + var column_1 int32 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/overrides/mysql/query.sql b/internal/endtoend/testdata/overrides/mysql/query.sql new file mode 100644 index 0000000..9da604b --- /dev/null +++ b/internal/endtoend/testdata/overrides/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT 1; diff --git a/internal/endtoend/testdata/overrides/mysql/schema.sql b/internal/endtoend/testdata/overrides/mysql/schema.sql new file mode 100644 index 0000000..c0c5fc4 --- /dev/null +++ b/internal/endtoend/testdata/overrides/mysql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE foo ( + other text NOT NULL, + total bigint NOT NULL, + retyped text NOT NULL +); diff --git a/internal/endtoend/testdata/overrides/mysql/sqlc.json b/internal/endtoend/testdata/overrides/mysql/sqlc.json new file mode 100644 index 0000000..5e0c8b6 --- /dev/null +++ b/internal/endtoend/testdata/overrides/mysql/sqlc.json @@ -0,0 +1,18 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "override", + "engine": "mysql", + "schema": "schema.sql", + "queries": "query.sql", + "overrides": [ + { + "go_type": "github.com/sqlc-dev/sqlc-testdata/pkg.CustomType", + "column": "foo.retyped" + } + ] + } + ] +} diff --git a/internal/endtoend/testdata/overrides/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/overrides/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..6e1aea1 --- /dev/null +++ b/internal/endtoend/testdata/overrides/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/overrides/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/overrides/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..94d1878 --- /dev/null +++ b/internal/endtoend/testdata/overrides/postgresql/pgx/v4/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "github.com/lib/pq" + "github.com/sqlc-dev/sqlc-testdata/pkg" +) + +type Foo struct { + Other string + Total int64 + Tags []string + ByteSeq []byte + Retyped pkg.CustomType + Langs pq.StringArray +} diff --git a/internal/endtoend/testdata/overrides/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/overrides/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..422e04a --- /dev/null +++ b/internal/endtoend/testdata/overrides/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package override + +import ( + "context" +) + +const test = `-- name: Test :one +SELECT 1 +` + +func (q *Queries) Test(ctx context.Context) (int32, error) { + row := q.db.QueryRow(ctx, test) + var column_1 int32 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/overrides/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/overrides/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..9da604b --- /dev/null +++ b/internal/endtoend/testdata/overrides/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT 1; diff --git a/internal/endtoend/testdata/overrides/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/overrides/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..fc3a13e --- /dev/null +++ b/internal/endtoend/testdata/overrides/postgresql/pgx/v4/schema.sql @@ -0,0 +1,8 @@ +CREATE TABLE foo ( + other text NOT NULL, + total bigint NOT NULL, + tags text[] NOT NULL, + byte_seq bytea NOT NULL, + retyped text NOT NULL, + langs text[] +); diff --git a/internal/endtoend/testdata/overrides/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/overrides/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..db76a9d --- /dev/null +++ b/internal/endtoend/testdata/overrides/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,23 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "override", + "schema": "schema.sql", + "queries": "query.sql", + "overrides": [ + { + "go_type": "github.com/sqlc-dev/sqlc-testdata/pkg.CustomType", + "column": "foo.retyped" + }, + { + "go_type": "github.com/lib/pq.StringArray", + "column": "foo.langs" + } + ] + } + ] +} diff --git a/internal/endtoend/testdata/overrides/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/overrides/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..9b9f9ee --- /dev/null +++ b/internal/endtoend/testdata/overrides/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/overrides/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/overrides/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..94d1878 --- /dev/null +++ b/internal/endtoend/testdata/overrides/postgresql/pgx/v5/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "github.com/lib/pq" + "github.com/sqlc-dev/sqlc-testdata/pkg" +) + +type Foo struct { + Other string + Total int64 + Tags []string + ByteSeq []byte + Retyped pkg.CustomType + Langs pq.StringArray +} diff --git a/internal/endtoend/testdata/overrides/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/overrides/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..422e04a --- /dev/null +++ b/internal/endtoend/testdata/overrides/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package override + +import ( + "context" +) + +const test = `-- name: Test :one +SELECT 1 +` + +func (q *Queries) Test(ctx context.Context) (int32, error) { + row := q.db.QueryRow(ctx, test) + var column_1 int32 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/overrides/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/overrides/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..9da604b --- /dev/null +++ b/internal/endtoend/testdata/overrides/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT 1; diff --git a/internal/endtoend/testdata/overrides/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/overrides/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..fc3a13e --- /dev/null +++ b/internal/endtoend/testdata/overrides/postgresql/pgx/v5/schema.sql @@ -0,0 +1,8 @@ +CREATE TABLE foo ( + other text NOT NULL, + total bigint NOT NULL, + tags text[] NOT NULL, + byte_seq bytea NOT NULL, + retyped text NOT NULL, + langs text[] +); diff --git a/internal/endtoend/testdata/overrides/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/overrides/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..109d41a --- /dev/null +++ b/internal/endtoend/testdata/overrides/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,23 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "override", + "schema": "schema.sql", + "queries": "query.sql", + "overrides": [ + { + "go_type": "github.com/sqlc-dev/sqlc-testdata/pkg.CustomType", + "column": "foo.retyped" + }, + { + "go_type": "github.com/lib/pq.StringArray", + "column": "foo.langs" + } + ] + } + ] +} diff --git a/internal/endtoend/testdata/overrides/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/overrides/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..3e4ebb9 --- /dev/null +++ b/internal/endtoend/testdata/overrides/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/overrides/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/overrides/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..94d1878 --- /dev/null +++ b/internal/endtoend/testdata/overrides/postgresql/stdlib/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "github.com/lib/pq" + "github.com/sqlc-dev/sqlc-testdata/pkg" +) + +type Foo struct { + Other string + Total int64 + Tags []string + ByteSeq []byte + Retyped pkg.CustomType + Langs pq.StringArray +} diff --git a/internal/endtoend/testdata/overrides/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/overrides/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..0a94a43 --- /dev/null +++ b/internal/endtoend/testdata/overrides/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package override + +import ( + "context" +) + +const test = `-- name: Test :one +SELECT 1 +` + +func (q *Queries) Test(ctx context.Context) (int32, error) { + row := q.db.QueryRowContext(ctx, test) + var column_1 int32 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/overrides/postgresql/stdlib/query.sql b/internal/endtoend/testdata/overrides/postgresql/stdlib/query.sql new file mode 100644 index 0000000..9da604b --- /dev/null +++ b/internal/endtoend/testdata/overrides/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT 1; diff --git a/internal/endtoend/testdata/overrides/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/overrides/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..fc3a13e --- /dev/null +++ b/internal/endtoend/testdata/overrides/postgresql/stdlib/schema.sql @@ -0,0 +1,8 @@ +CREATE TABLE foo ( + other text NOT NULL, + total bigint NOT NULL, + tags text[] NOT NULL, + byte_seq bytea NOT NULL, + retyped text NOT NULL, + langs text[] +); diff --git a/internal/endtoend/testdata/overrides/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/overrides/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..28e58c9 --- /dev/null +++ b/internal/endtoend/testdata/overrides/postgresql/stdlib/sqlc.json @@ -0,0 +1,22 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "override", + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "overrides": [ + { + "go_type": "github.com/sqlc-dev/sqlc-testdata/pkg.CustomType", + "column": "foo.retyped" + }, + { + "go_type": "github.com/lib/pq.StringArray", + "column": "foo.langs" + } + ] + } + ] +} diff --git a/internal/endtoend/testdata/overrides/sqlite/go/db.go b/internal/endtoend/testdata/overrides/sqlite/go/db.go new file mode 100644 index 0000000..3e4ebb9 --- /dev/null +++ b/internal/endtoend/testdata/overrides/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/overrides/sqlite/go/models.go b/internal/endtoend/testdata/overrides/sqlite/go/models.go new file mode 100644 index 0000000..b538582 --- /dev/null +++ b/internal/endtoend/testdata/overrides/sqlite/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "github.com/sqlc-dev/sqlc-testdata/pkg" +) + +type Foo struct { + Other string + Total int64 + Retyped pkg.CustomType +} diff --git a/internal/endtoend/testdata/overrides/sqlite/go/query.sql.go b/internal/endtoend/testdata/overrides/sqlite/go/query.sql.go new file mode 100644 index 0000000..185ff73 --- /dev/null +++ b/internal/endtoend/testdata/overrides/sqlite/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package override + +import ( + "context" +) + +const test = `-- name: Test :one +SELECT 1 +` + +func (q *Queries) Test(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, test) + var column_1 int64 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/overrides/sqlite/query.sql b/internal/endtoend/testdata/overrides/sqlite/query.sql new file mode 100644 index 0000000..9da604b --- /dev/null +++ b/internal/endtoend/testdata/overrides/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT 1; diff --git a/internal/endtoend/testdata/overrides/sqlite/schema.sql b/internal/endtoend/testdata/overrides/sqlite/schema.sql new file mode 100644 index 0000000..c0c5fc4 --- /dev/null +++ b/internal/endtoend/testdata/overrides/sqlite/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE foo ( + other text NOT NULL, + total bigint NOT NULL, + retyped text NOT NULL +); diff --git a/internal/endtoend/testdata/overrides/sqlite/sqlc.json b/internal/endtoend/testdata/overrides/sqlite/sqlc.json new file mode 100644 index 0000000..3b22097 --- /dev/null +++ b/internal/endtoend/testdata/overrides/sqlite/sqlc.json @@ -0,0 +1,18 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "override", + "engine": "sqlite", + "schema": "schema.sql", + "queries": "query.sql", + "overrides": [ + { + "go_type": "github.com/sqlc-dev/sqlc-testdata/pkg.CustomType", + "column": "foo.retyped" + } + ] + } + ] +} diff --git a/internal/endtoend/testdata/overrides_array/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/overrides_array/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6c0b1c8 --- /dev/null +++ b/internal/endtoend/testdata/overrides_array/postgresql/pgx/v4/query.sql @@ -0,0 +1,3 @@ +-- name: GetAuthor :one +SELECT * FROM authors +WHERE id = $1 LIMIT 1; diff --git a/internal/endtoend/testdata/overrides_array/postgresql/pgx/v4/query/db.go b/internal/endtoend/testdata/overrides_array/postgresql/pgx/v4/query/db.go new file mode 100644 index 0000000..5bda287 --- /dev/null +++ b/internal/endtoend/testdata/overrides_array/postgresql/pgx/v4/query/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package query + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/overrides_array/postgresql/pgx/v4/query/models.go b/internal/endtoend/testdata/overrides_array/postgresql/pgx/v4/query/models.go new file mode 100644 index 0000000..d7e10e5 --- /dev/null +++ b/internal/endtoend/testdata/overrides_array/postgresql/pgx/v4/query/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package query + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString + Tags []sql.NullInt64 +} diff --git a/internal/endtoend/testdata/overrides_array/postgresql/pgx/v4/query/query.sql.go b/internal/endtoend/testdata/overrides_array/postgresql/pgx/v4/query/query.sql.go new file mode 100644 index 0000000..b054454 --- /dev/null +++ b/internal/endtoend/testdata/overrides_array/postgresql/pgx/v4/query/query.sql.go @@ -0,0 +1,27 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package query + +import ( + "context" +) + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, bio, tags FROM authors +WHERE id = $1 LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRow(ctx, getAuthor, id) + var i Author + err := row.Scan( + &i.ID, + &i.Name, + &i.Bio, + &i.Tags, + ) + return i, err +} diff --git a/internal/endtoend/testdata/overrides_array/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/overrides_array/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..f0ca77b --- /dev/null +++ b/internal/endtoend/testdata/overrides_array/postgresql/pgx/v4/schema.sql @@ -0,0 +1,8 @@ +-- Example queries for sqlc +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text, + tags text[] +); + diff --git a/internal/endtoend/testdata/overrides_array/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/overrides_array/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..3aaed50 --- /dev/null +++ b/internal/endtoend/testdata/overrides_array/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,23 @@ +{ + "version": "2", + "sql": [{ + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql", + "gen": { + "go": { + "sql_package": "pgx/v4", + "package": "query", + "out": "query", + "overrides": [{ + "column": "authors.tags", + "go_type": { + "type": "NullInt64", + "import": "database/sql", + "slice": true + } + }] + } + } + }] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/overrides_array/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/overrides_array/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6c0b1c8 --- /dev/null +++ b/internal/endtoend/testdata/overrides_array/postgresql/pgx/v5/query.sql @@ -0,0 +1,3 @@ +-- name: GetAuthor :one +SELECT * FROM authors +WHERE id = $1 LIMIT 1; diff --git a/internal/endtoend/testdata/overrides_array/postgresql/pgx/v5/query/db.go b/internal/endtoend/testdata/overrides_array/postgresql/pgx/v5/query/db.go new file mode 100644 index 0000000..f7cf1a6 --- /dev/null +++ b/internal/endtoend/testdata/overrides_array/postgresql/pgx/v5/query/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package query + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/overrides_array/postgresql/pgx/v5/query/models.go b/internal/endtoend/testdata/overrides_array/postgresql/pgx/v5/query/models.go new file mode 100644 index 0000000..1358922 --- /dev/null +++ b/internal/endtoend/testdata/overrides_array/postgresql/pgx/v5/query/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package query + +import ( + "database/sql" + + "github.com/jackc/pgx/v5/pgtype" +) + +type Author struct { + ID int64 + Name string + Bio pgtype.Text + Tags []sql.NullInt64 +} diff --git a/internal/endtoend/testdata/overrides_array/postgresql/pgx/v5/query/query.sql.go b/internal/endtoend/testdata/overrides_array/postgresql/pgx/v5/query/query.sql.go new file mode 100644 index 0000000..b054454 --- /dev/null +++ b/internal/endtoend/testdata/overrides_array/postgresql/pgx/v5/query/query.sql.go @@ -0,0 +1,27 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package query + +import ( + "context" +) + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, bio, tags FROM authors +WHERE id = $1 LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRow(ctx, getAuthor, id) + var i Author + err := row.Scan( + &i.ID, + &i.Name, + &i.Bio, + &i.Tags, + ) + return i, err +} diff --git a/internal/endtoend/testdata/overrides_array/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/overrides_array/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..f0ca77b --- /dev/null +++ b/internal/endtoend/testdata/overrides_array/postgresql/pgx/v5/schema.sql @@ -0,0 +1,8 @@ +-- Example queries for sqlc +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text, + tags text[] +); + diff --git a/internal/endtoend/testdata/overrides_array/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/overrides_array/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..f75e700 --- /dev/null +++ b/internal/endtoend/testdata/overrides_array/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,23 @@ +{ + "version": "2", + "sql": [{ + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql", + "gen": { + "go": { + "sql_package": "pgx/v5", + "package": "query", + "out": "query", + "overrides": [{ + "column": "authors.tags", + "go_type": { + "type": "NullInt64", + "import": "database/sql", + "slice": true + } + }] + } + } + }] + } \ No newline at end of file diff --git a/internal/endtoend/testdata/overrides_array/postgresql/stdlib/query.sql b/internal/endtoend/testdata/overrides_array/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6c0b1c8 --- /dev/null +++ b/internal/endtoend/testdata/overrides_array/postgresql/stdlib/query.sql @@ -0,0 +1,3 @@ +-- name: GetAuthor :one +SELECT * FROM authors +WHERE id = $1 LIMIT 1; diff --git a/internal/endtoend/testdata/overrides_array/postgresql/stdlib/query/db.go b/internal/endtoend/testdata/overrides_array/postgresql/stdlib/query/db.go new file mode 100644 index 0000000..095a0a7 --- /dev/null +++ b/internal/endtoend/testdata/overrides_array/postgresql/stdlib/query/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package query + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/overrides_array/postgresql/stdlib/query/models.go b/internal/endtoend/testdata/overrides_array/postgresql/stdlib/query/models.go new file mode 100644 index 0000000..d7e10e5 --- /dev/null +++ b/internal/endtoend/testdata/overrides_array/postgresql/stdlib/query/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package query + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString + Tags []sql.NullInt64 +} diff --git a/internal/endtoend/testdata/overrides_array/postgresql/stdlib/query/query.sql.go b/internal/endtoend/testdata/overrides_array/postgresql/stdlib/query/query.sql.go new file mode 100644 index 0000000..d86dd18 --- /dev/null +++ b/internal/endtoend/testdata/overrides_array/postgresql/stdlib/query/query.sql.go @@ -0,0 +1,29 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package query + +import ( + "context" + + "github.com/lib/pq" +) + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, bio, tags FROM authors +WHERE id = $1 LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Author + err := row.Scan( + &i.ID, + &i.Name, + &i.Bio, + pq.Array(&i.Tags), + ) + return i, err +} diff --git a/internal/endtoend/testdata/overrides_array/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/overrides_array/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..f0ca77b --- /dev/null +++ b/internal/endtoend/testdata/overrides_array/postgresql/stdlib/schema.sql @@ -0,0 +1,8 @@ +-- Example queries for sqlc +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text, + tags text[] +); + diff --git a/internal/endtoend/testdata/overrides_array/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/overrides_array/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..8b02b46 --- /dev/null +++ b/internal/endtoend/testdata/overrides_array/postgresql/stdlib/sqlc.json @@ -0,0 +1,22 @@ +{ + "version": "2", + "sql": [{ + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql", + "gen": { + "go": { + "package": "query", + "out": "query", + "overrides": [{ + "column": "authors.tags", + "go_type": { + "type": "NullInt64", + "import": "database/sql", + "slice": true + } + }] + } + } + }] + } \ No newline at end of file diff --git a/internal/endtoend/testdata/overrides_config/query.sql b/internal/endtoend/testdata/overrides_config/query.sql new file mode 100644 index 0000000..9da604b --- /dev/null +++ b/internal/endtoend/testdata/overrides_config/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT 1; diff --git a/internal/endtoend/testdata/overrides_config/schema.sql b/internal/endtoend/testdata/overrides_config/schema.sql new file mode 100644 index 0000000..03d90e1 --- /dev/null +++ b/internal/endtoend/testdata/overrides_config/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE overrides ( + one text NOT NULL, + two bigint NOT NULL, + three text[] NOT NULL, + four bytea NOT NULL, + five text[] +); diff --git a/internal/endtoend/testdata/overrides_config/v2/yaml/global/db/db.go b/internal/endtoend/testdata/overrides_config/v2/yaml/global/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/overrides_config/v2/yaml/global/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/overrides_config/v2/yaml/global/db/models.go b/internal/endtoend/testdata/overrides_config/v2/yaml/global/db/models.go new file mode 100644 index 0000000..261e14b --- /dev/null +++ b/internal/endtoend/testdata/overrides_config/v2/yaml/global/db/models.go @@ -0,0 +1,17 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "github.com/sqlc-dev/sqlc-testdata/pkg" +) + +type Override struct { + ONE pkg.CustomType + Two int64 + Three pkg.CustomType + Four []byte + Five []pkg.CustomType +} diff --git a/internal/endtoend/testdata/overrides_config/v2/yaml/global/db/query.sql.go b/internal/endtoend/testdata/overrides_config/v2/yaml/global/db/query.sql.go new file mode 100644 index 0000000..5b09ecb --- /dev/null +++ b/internal/endtoend/testdata/overrides_config/v2/yaml/global/db/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" +) + +const test = `-- name: Test :one +SELECT 1 +` + +func (q *Queries) Test(ctx context.Context) (int32, error) { + row := q.db.QueryRowContext(ctx, test) + var column_1 int32 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/overrides_config/v2/yaml/global/sqlc.yaml b/internal/endtoend/testdata/overrides_config/v2/yaml/global/sqlc.yaml new file mode 100644 index 0000000..335759c --- /dev/null +++ b/internal/endtoend/testdata/overrides_config/v2/yaml/global/sqlc.yaml @@ -0,0 +1,19 @@ +version: "2" +overrides: + go: + rename: + one: "ONE" + overrides: + - db_type: "text" + go_type: "github.com/sqlc-dev/sqlc-testdata/pkg.CustomType" + - column: "overrides.three" + go_type: + import: "github.com/sqlc-dev/sqlc-testdata/pkg" + type: "CustomType" +sql: +- schema: "../../../schema.sql" + queries: "../../../query.sql" + engine: "postgresql" + gen: + go: + out: "db" diff --git a/internal/endtoend/testdata/overrides_config/v2/yaml/global_and_queryset/db/db.go b/internal/endtoend/testdata/overrides_config/v2/yaml/global_and_queryset/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/overrides_config/v2/yaml/global_and_queryset/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/overrides_config/v2/yaml/global_and_queryset/db/models.go b/internal/endtoend/testdata/overrides_config/v2/yaml/global_and_queryset/db/models.go new file mode 100644 index 0000000..261e14b --- /dev/null +++ b/internal/endtoend/testdata/overrides_config/v2/yaml/global_and_queryset/db/models.go @@ -0,0 +1,17 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "github.com/sqlc-dev/sqlc-testdata/pkg" +) + +type Override struct { + ONE pkg.CustomType + Two int64 + Three pkg.CustomType + Four []byte + Five []pkg.CustomType +} diff --git a/internal/endtoend/testdata/overrides_config/v2/yaml/global_and_queryset/db/query.sql.go b/internal/endtoend/testdata/overrides_config/v2/yaml/global_and_queryset/db/query.sql.go new file mode 100644 index 0000000..5b09ecb --- /dev/null +++ b/internal/endtoend/testdata/overrides_config/v2/yaml/global_and_queryset/db/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" +) + +const test = `-- name: Test :one +SELECT 1 +` + +func (q *Queries) Test(ctx context.Context) (int32, error) { + row := q.db.QueryRowContext(ctx, test) + var column_1 int32 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/overrides_config/v2/yaml/global_and_queryset/sqlc.yaml b/internal/endtoend/testdata/overrides_config/v2/yaml/global_and_queryset/sqlc.yaml new file mode 100644 index 0000000..62ef7e7 --- /dev/null +++ b/internal/endtoend/testdata/overrides_config/v2/yaml/global_and_queryset/sqlc.yaml @@ -0,0 +1,26 @@ +version: "2" +overrides: + go: + rename: + one: "ONE" + overrides: + - db_type: "text" + go_type: "github.com/sqlc-dev/sqlc-testdata/pkg.CustomType" + - column: "overrides.three" + go_type: + import: "github.com/sqlc-dev/sqlc-testdata/pkg" + type: "CustomType" +sql: +- schema: "../../../schema.sql" + queries: "../../../query.sql" + engine: "postgresql" + gen: + go: + out: "db" + rename: + one: "ONE" + overrides: + - column: "overrides.three" + go_type: + import: "invalid/import" + type: "ShouldNotSeeThis" diff --git a/internal/endtoend/testdata/overrides_config/v2/yaml/queryset/db/db.go b/internal/endtoend/testdata/overrides_config/v2/yaml/queryset/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/overrides_config/v2/yaml/queryset/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/overrides_config/v2/yaml/queryset/db/models.go b/internal/endtoend/testdata/overrides_config/v2/yaml/queryset/db/models.go new file mode 100644 index 0000000..261e14b --- /dev/null +++ b/internal/endtoend/testdata/overrides_config/v2/yaml/queryset/db/models.go @@ -0,0 +1,17 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "github.com/sqlc-dev/sqlc-testdata/pkg" +) + +type Override struct { + ONE pkg.CustomType + Two int64 + Three pkg.CustomType + Four []byte + Five []pkg.CustomType +} diff --git a/internal/endtoend/testdata/overrides_config/v2/yaml/queryset/db/query.sql.go b/internal/endtoend/testdata/overrides_config/v2/yaml/queryset/db/query.sql.go new file mode 100644 index 0000000..5b09ecb --- /dev/null +++ b/internal/endtoend/testdata/overrides_config/v2/yaml/queryset/db/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" +) + +const test = `-- name: Test :one +SELECT 1 +` + +func (q *Queries) Test(ctx context.Context) (int32, error) { + row := q.db.QueryRowContext(ctx, test) + var column_1 int32 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/overrides_config/v2/yaml/queryset/sqlc.yaml b/internal/endtoend/testdata/overrides_config/v2/yaml/queryset/sqlc.yaml new file mode 100644 index 0000000..7847f6d --- /dev/null +++ b/internal/endtoend/testdata/overrides_config/v2/yaml/queryset/sqlc.yaml @@ -0,0 +1,17 @@ +version: "2" +sql: +- schema: "../../../schema.sql" + queries: "../../../query.sql" + engine: "postgresql" + gen: + go: + out: "db" + rename: + one: "ONE" + overrides: + - db_type: "text" + go_type: "github.com/sqlc-dev/sqlc-testdata/pkg.CustomType" + - column: "overrides.three" + go_type: + import: "github.com/sqlc-dev/sqlc-testdata/pkg" + type: "CustomType" diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/invalid_tags/query.sql b/internal/endtoend/testdata/overrides_go_struct_tags/invalid_tags/query.sql new file mode 100644 index 0000000..9da604b --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/invalid_tags/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT 1; diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/invalid_tags/schema.sql b/internal/endtoend/testdata/overrides_go_struct_tags/invalid_tags/schema.sql new file mode 100644 index 0000000..4d5233c --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/invalid_tags/schema.sql @@ -0,0 +1,14 @@ +CREATE TABLE foo ( + other text NOT NULL, + tagged text NOT NULL +); + +CREATE TABLE bar ( + other text NOT NULL, + also_tagged text NOT NULL +); + +CREATE TABLE baz ( + other text NOT NULL, + also_tagged text NOT NULL +); diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/invalid_tags/sqlc.json b/internal/endtoend/testdata/overrides_go_struct_tags/invalid_tags/sqlc.json new file mode 100644 index 0000000..f3cb66e --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/invalid_tags/sqlc.json @@ -0,0 +1,22 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "override", + "engine": "mysql", + "schema": "schema.sql", + "queries": "query.sql", + "overrides": [ + { + "go_struct_tag": "abc", + "column": "foo.tagged" + }, + { + "go_struct_tag": "a:b", + "column": "*.also_tagged" + } + ] + } + ] +} diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/invalid_tags/stderr.txt b/internal/endtoend/testdata/overrides_go_struct_tags/invalid_tags/stderr.txt new file mode 100644 index 0000000..c6891c1 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/invalid_tags/stderr.txt @@ -0,0 +1,2 @@ +# package override +error generating code: bad syntax for struct tag pair diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/mysql/go/db.go b/internal/endtoend/testdata/overrides_go_struct_tags/mysql/go/db.go new file mode 100644 index 0000000..3e4ebb9 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/overrides_go_struct_tags/mysql/go/models.go b/internal/endtoend/testdata/overrides_go_struct_tags/mysql/go/models.go new file mode 100644 index 0000000..7fc2d30 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/mysql/go/models.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +type Bar struct { + Other string `utype:"notnull_text"` + AlsoTagged string `also:"tagged" utype:"notnull_text"` +} + +type Baz struct { + Other string `utype:"notnull_text"` + AlsoTagged string `also:"tagged" utype:"notnull_text"` +} + +type Foo struct { + Other string `utype:"notnull_text"` + Tagged string `a:"b" utype:"notnull_text" x:"y,z"` + Nulltext string `utype:"nullable_text"` +} diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/mysql/go/query.sql.go b/internal/endtoend/testdata/overrides_go_struct_tags/mysql/go/query.sql.go new file mode 100644 index 0000000..0a94a43 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/mysql/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package override + +import ( + "context" +) + +const test = `-- name: Test :one +SELECT 1 +` + +func (q *Queries) Test(ctx context.Context) (int32, error) { + row := q.db.QueryRowContext(ctx, test) + var column_1 int32 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/mysql/query.sql b/internal/endtoend/testdata/overrides_go_struct_tags/mysql/query.sql new file mode 100644 index 0000000..9da604b --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT 1; diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/mysql/schema.sql b/internal/endtoend/testdata/overrides_go_struct_tags/mysql/schema.sql new file mode 100644 index 0000000..5c9ce85 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/mysql/schema.sql @@ -0,0 +1,15 @@ +CREATE TABLE foo ( + other text NOT NULL, + tagged text NOT NULL, + nulltext text +); + +CREATE TABLE bar ( + other text NOT NULL, + also_tagged text NOT NULL +); + +CREATE TABLE baz ( + other text NOT NULL, + also_tagged text NOT NULL +); diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/mysql/sqlc.json b/internal/endtoend/testdata/overrides_go_struct_tags/mysql/sqlc.json new file mode 100644 index 0000000..697fe05 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/mysql/sqlc.json @@ -0,0 +1,32 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "override", + "engine": "mysql", + "schema": "schema.sql", + "queries": "query.sql", + "overrides": [ + { + "go_struct_tag": "a:\"b\" x:\"y,z\"", + "column": "foo.tagged" + }, + { + "go_struct_tag": "also:\"tagged\"", + "column": "*.also_tagged" + }, + { + "db_type": "text", + "go_struct_tag": "utype:\"notnull_text\"" + }, + { + "db_type": "text", + "go_type": "string", + "nullable": true, + "go_struct_tag": "utype:\"nullable_text\"" + } + ] + } + ] +} diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..6e1aea1 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/overrides_go_struct_tags/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..5c01d22 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v4/go/models.go @@ -0,0 +1,20 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +type Bar struct { + ID string `type:"id" utype:"nullable_text"` + OtherID string `type:"other_id" utype:"nullable_text"` + About string `utype:"nullable_text"` + Other string `type:"other" utype:"nullable_text"` +} + +type Foo struct { + ID string `source:"foo" type:"id" utype:"nullable_text"` + OtherID string `type:"other_id" utype:"nullable_text"` + About string `type:"about" utype:"nullable_text"` + Other string `type:"this" utype:"nullable_text"` + Notnulltext string `utype:"notnull_text"` +} diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..422e04a --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package override + +import ( + "context" +) + +const test = `-- name: Test :one +SELECT 1 +` + +func (q *Queries) Test(ctx context.Context) (int32, error) { + row := q.db.QueryRow(ctx, test) + var column_1 int32 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..9da604b --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT 1; diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..30b7182 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v4/schema.sql @@ -0,0 +1,14 @@ +CREATE TABLE foo ( + id text, + other_id text, + about text, + other text, + notnulltext text not null +); + +CREATE TABLE bar ( + id text, + other_id text, + about text, + other text +); diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..bc583cd --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,49 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "override", + "schema": "schema.sql", + "queries": "query.sql", + "overrides": [ + { + "column": "*.id", + "go_struct_tag": "type:\"id\"" + }, + { + "column": "*.*_id", + "go_struct_tag": "type:\"other_id\"" + }, + { + "column": "foo.about", + "go_struct_tag": "type:\"about\"" + }, + { + "column": "foo.id", + "go_struct_tag": "source:\"foo\"" + }, + { + "column": "*.other", + "go_struct_tag": "type:\"other\"" + }, + { + "column": "foo.other", + "go_struct_tag": "type:\"this\"" + }, + { + "db_type": "text", + "go_struct_tag": "utype:\"notnull_text\"" + }, + { + "db_type": "text", + "go_type": "string", + "nullable": true, + "go_struct_tag": "utype:\"nullable_text\"" + } + ] + } + ] +} diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..9b9f9ee --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/overrides_go_struct_tags/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..5c01d22 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v5/go/models.go @@ -0,0 +1,20 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +type Bar struct { + ID string `type:"id" utype:"nullable_text"` + OtherID string `type:"other_id" utype:"nullable_text"` + About string `utype:"nullable_text"` + Other string `type:"other" utype:"nullable_text"` +} + +type Foo struct { + ID string `source:"foo" type:"id" utype:"nullable_text"` + OtherID string `type:"other_id" utype:"nullable_text"` + About string `type:"about" utype:"nullable_text"` + Other string `type:"this" utype:"nullable_text"` + Notnulltext string `utype:"notnull_text"` +} diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..422e04a --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package override + +import ( + "context" +) + +const test = `-- name: Test :one +SELECT 1 +` + +func (q *Queries) Test(ctx context.Context) (int32, error) { + row := q.db.QueryRow(ctx, test) + var column_1 int32 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..9da604b --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT 1; diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..30b7182 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v5/schema.sql @@ -0,0 +1,14 @@ +CREATE TABLE foo ( + id text, + other_id text, + about text, + other text, + notnulltext text not null +); + +CREATE TABLE bar ( + id text, + other_id text, + about text, + other text +); diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..df8c9de --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,49 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "override", + "schema": "schema.sql", + "queries": "query.sql", + "overrides": [ + { + "column": "*.id", + "go_struct_tag": "type:\"id\"" + }, + { + "column": "*.*_id", + "go_struct_tag": "type:\"other_id\"" + }, + { + "column": "foo.about", + "go_struct_tag": "type:\"about\"" + }, + { + "column": "foo.id", + "go_struct_tag": "source:\"foo\"" + }, + { + "column": "*.other", + "go_struct_tag": "type:\"other\"" + }, + { + "column": "foo.other", + "go_struct_tag": "type:\"this\"" + }, + { + "db_type": "text", + "go_struct_tag": "utype:\"notnull_text\"" + }, + { + "db_type": "text", + "go_type": "string", + "nullable": true, + "go_struct_tag": "utype:\"nullable_text\"" + } + ] + } + ] +} diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..3e4ebb9 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/overrides_go_struct_tags/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..1e0f9e2 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/stdlib/go/models.go @@ -0,0 +1,11 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +type Foo struct { + ID string `utype:"nullable_text" x:"y"` + OtherID string `utype:"nullable_text"` + Notnulltext string `utype:"notnull_text"` +} diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..0a94a43 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package override + +import ( + "context" +) + +const test = `-- name: Test :one +SELECT 1 +` + +func (q *Queries) Test(ctx context.Context) (int32, error) { + row := q.db.QueryRowContext(ctx, test) + var column_1 int32 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/stdlib/query.sql b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/stdlib/query.sql new file mode 100644 index 0000000..9da604b --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT 1; diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..82698ec --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/stdlib/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE foo ( + id text, + other_id text, + notnulltext text not null +); diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f1171fc --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/postgresql/stdlib/sqlc.json @@ -0,0 +1,28 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "override", + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "overrides": [ + { + "column": "foo.id", + "go_struct_tag": "x:\"y\"" + }, + { + "db_type": "text", + "go_struct_tag": "utype:\"notnull_text\"" + }, + { + "db_type": "text", + "go_type": "string", + "nullable": true, + "go_struct_tag": "utype:\"nullable_text\"" + } + ] + } + ] +} diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/sqlite/go/db.go b/internal/endtoend/testdata/overrides_go_struct_tags/sqlite/go/db.go new file mode 100644 index 0000000..3e4ebb9 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/overrides_go_struct_tags/sqlite/go/models.go b/internal/endtoend/testdata/overrides_go_struct_tags/sqlite/go/models.go new file mode 100644 index 0000000..0e0c9aa --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/sqlite/go/models.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +type Bar struct { + Other string `utype:"notnull_text"` + AlsoTagged string `also:"tagged" utype:"notnull_text"` + Tag3 string `tag_with_space:" it's legal!" utype:"notnull_text"` +} + +type Baz struct { + Other string `utype:"notnull_text"` + AlsoTagged string `also:"tagged" utype:"notnull_text"` + Tag3 string `tag_with_space:" it's legal!" utype:"notnull_text"` +} + +type Foo struct { + Other string `utype:"notnull_text"` + Tagged string `a:"b" utype:"notnull_text" x:"y,z"` + Tag3 string `tag_with_space:" it's legal!" utype:"notnull_text"` + Nulltext string `utype:"nullable_text"` +} diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/sqlite/go/query.sql.go b/internal/endtoend/testdata/overrides_go_struct_tags/sqlite/go/query.sql.go new file mode 100644 index 0000000..185ff73 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/sqlite/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package override + +import ( + "context" +) + +const test = `-- name: Test :one +SELECT 1 +` + +func (q *Queries) Test(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, test) + var column_1 int64 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/sqlite/query.sql b/internal/endtoend/testdata/overrides_go_struct_tags/sqlite/query.sql new file mode 100644 index 0000000..9da604b --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT 1; diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/sqlite/schema.sql b/internal/endtoend/testdata/overrides_go_struct_tags/sqlite/schema.sql new file mode 100644 index 0000000..e9aa9bd --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/sqlite/schema.sql @@ -0,0 +1,18 @@ +CREATE TABLE foo ( + other text NOT NULL, + tagged text NOT NULL, + tag3 text NOT NULL, + nulltext text +); + +CREATE TABLE bar ( + other text NOT NULL, + also_tagged text NOT NULL, + tag3 text NOT NULL +); + +CREATE TABLE baz ( + other text NOT NULL, + also_tagged text NOT NULL, + tag3 text NOT NULL +); diff --git a/internal/endtoend/testdata/overrides_go_struct_tags/sqlite/sqlc.json b/internal/endtoend/testdata/overrides_go_struct_tags/sqlite/sqlc.json new file mode 100644 index 0000000..a4ca853 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_struct_tags/sqlite/sqlc.json @@ -0,0 +1,36 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "override", + "engine": "sqlite", + "schema": "schema.sql", + "queries": "query.sql", + "overrides": [ + { + "go_struct_tag": "a:\"b\" x:\"y,z\"", + "column": "foo.tagged" + }, + { + "go_struct_tag": "also:\"tagged\"", + "column": "*.also_tagged" + }, + { + "go_struct_tag": "tag_with_space:\" it's legal!\"", + "column": "*.tag3" + }, + { + "db_type": "text", + "go_struct_tag": "utype:\"notnull_text\"" + }, + { + "db_type": "text", + "go_type": "string", + "nullable": true, + "go_struct_tag": "utype:\"nullable_text\"" + } + ] + } + ] +} diff --git a/internal/endtoend/testdata/overrides_go_types/mysql/go/db.go b/internal/endtoend/testdata/overrides_go_types/mysql/go/db.go new file mode 100644 index 0000000..3e4ebb9 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/overrides_go_types/mysql/go/models.go b/internal/endtoend/testdata/overrides_go_types/mysql/go/models.go new file mode 100644 index 0000000..aa041ac --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/mysql/go/models.go @@ -0,0 +1,27 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "github.com/sqlc-dev/sqlc-testdata/pkg" +) + +type Bar struct { + Other string + Total int64 + AlsoRetyped pkg.CustomType +} + +type Baz struct { + Other string + Total int64 + AlsoRetyped pkg.CustomType +} + +type Foo struct { + Other string + Total int64 + Retyped pkg.CustomType +} diff --git a/internal/endtoend/testdata/overrides_go_types/mysql/go/query.sql.go b/internal/endtoend/testdata/overrides_go_types/mysql/go/query.sql.go new file mode 100644 index 0000000..570aca6 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/mysql/go/query.sql.go @@ -0,0 +1,50 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package override + +import ( + "context" + "strings" + + "github.com/sqlc-dev/sqlc-testdata/pkg" +) + +const testIN = `-- name: TestIN :many +SELECT other, total, retyped FROM foo WHERE retyped IN (/*SLICE:paramname*/?) +` + +func (q *Queries) TestIN(ctx context.Context, paramname []pkg.CustomType) ([]Foo, error) { + query := testIN + var queryParams []any + if len(paramname) > 0 { + for _, v := range paramname { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:paramname*/?", strings.Repeat(",?", len(paramname))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:paramname*/?", "NULL", 1) + } + rows, err := q.db.QueryContext(ctx, query, queryParams...) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.Other, &i.Total, &i.Retyped); 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/overrides_go_types/mysql/query.sql b/internal/endtoend/testdata/overrides_go_types/mysql/query.sql new file mode 100644 index 0000000..6b6fb86 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: TestIN :many +SELECT * FROM foo WHERE retyped IN (sqlc.slice(paramName)); diff --git a/internal/endtoend/testdata/overrides_go_types/mysql/schema.sql b/internal/endtoend/testdata/overrides_go_types/mysql/schema.sql new file mode 100644 index 0000000..31b183a --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/mysql/schema.sql @@ -0,0 +1,17 @@ +CREATE TABLE foo ( + other text NOT NULL, + total bigint NOT NULL, + retyped text NOT NULL +); + +CREATE TABLE bar ( + other text NOT NULL, + total bigint NOT NULL, + also_retyped text NOT NULL +); + +CREATE TABLE baz ( + other text NOT NULL, + total bigint NOT NULL, + also_retyped text NOT NULL +); diff --git a/internal/endtoend/testdata/overrides_go_types/mysql/sqlc.json b/internal/endtoend/testdata/overrides_go_types/mysql/sqlc.json new file mode 100644 index 0000000..75730b2 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/mysql/sqlc.json @@ -0,0 +1,22 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "override", + "engine": "mysql", + "schema": "schema.sql", + "queries": "query.sql", + "overrides": [ + { + "go_type": "github.com/sqlc-dev/sqlc-testdata/pkg.CustomType", + "column": "foo.retyped" + }, + { + "go_type": "github.com/sqlc-dev/sqlc-testdata/pkg.CustomType", + "column": "*.also_retyped" + } + ] + } + ] +} diff --git a/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..6e1aea1 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/overrides_go_types/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..8d98c03 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v4/go/models.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "database/sql" + + orm "database/sql" + fuid "github.com/gofrs/uuid" + uuid "github.com/gofrs/uuid" + null "github.com/volatiletech/null/v8" + null_v4 "gopkg.in/guregu/null.v4" +) + +type Bar struct { + ID uuid.UUID + OtherID fuid.UUID + MoreID fuid.UUID + Age sql.NullInt32 + Balance sql.NullFloat64 + Bio sql.NullString + About sql.NullString +} + +type Foo struct { + ID uuid.UUID + OtherID fuid.UUID + Age orm.NullInt32 + Balance null.Float32 + Bio null_v4.String + About *string +} diff --git a/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..951c4c4 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,95 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package override + +import ( + "context" + + orm "database/sql" + fuid "github.com/gofrs/uuid" + uuid "github.com/gofrs/uuid" + null "github.com/volatiletech/null/v8" + null_v4 "gopkg.in/guregu/null.v4" +) + +const loadFoo = `-- name: LoadFoo :many +SELECT id, other_id, age, balance, bio, about FROM foo WHERE id = $1 +` + +func (q *Queries) LoadFoo(ctx context.Context, id uuid.UUID) ([]Foo, error) { + rows, err := q.db.Query(ctx, loadFoo, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan( + &i.ID, + &i.OtherID, + &i.Age, + &i.Balance, + &i.Bio, + &i.About, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const loadFooWithAliases = `-- name: LoadFooWithAliases :many +SELECT + id AS aliased_id, + other_id AS aliased_other_id, + age AS aliased_age, + balance AS aliased_balance, + bio AS aliased_bio, + about AS aliased_about +FROM foo +WHERE id = $1 +` + +type LoadFooWithAliasesRow struct { + AliasedID uuid.UUID + AliasedOtherID fuid.UUID + AliasedAge orm.NullInt32 + AliasedBalance null.Float32 + AliasedBio null_v4.String + AliasedAbout *string +} + +func (q *Queries) LoadFooWithAliases(ctx context.Context, namedParameterID uuid.UUID) ([]LoadFooWithAliasesRow, error) { + rows, err := q.db.Query(ctx, loadFooWithAliases, namedParameterID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []LoadFooWithAliasesRow + for rows.Next() { + var i LoadFooWithAliasesRow + if err := rows.Scan( + &i.AliasedID, + &i.AliasedOtherID, + &i.AliasedAge, + &i.AliasedBalance, + &i.AliasedBio, + &i.AliasedAbout, + ); 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/overrides_go_types/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..b439829 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v4/query.sql @@ -0,0 +1,13 @@ +-- name: LoadFoo :many +SELECT * FROM foo WHERE id = $1; + +-- name: LoadFooWithAliases :many +SELECT + id AS aliased_id, + other_id AS aliased_other_id, + age AS aliased_age, + balance AS aliased_balance, + bio AS aliased_bio, + about AS aliased_about +FROM foo +WHERE id = @named_parameter_id; diff --git a/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..68d2f83 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v4/schema.sql @@ -0,0 +1,18 @@ +CREATE TABLE foo ( + id uuid NOT NULL, + other_id uuid NOT NULL, + age integer, + balance double precision, + bio text, + about text +); + +CREATE TABLE bar ( + id uuid NOT NULL, + other_id uuid NOT NULL, + more_id uuid NOT NULL, + age integer, + balance double precision, + bio text, + about text +); diff --git a/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..80f4577 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,64 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "override", + "schema": "schema.sql", + "queries": "query.sql", + "overrides": [ + { + "column": "*.id", + "go_type": { + "import": "github.com/gofrs/uuid", + "package": "uuid", + "type": "UUID" + } + }, + { + "column": "*.*_id", + "go_type": { + "import": "github.com/gofrs/uuid", + "package": "fuid", + "type": "UUID" + } + }, + { + "column": "foo.age", + "nullable": true, + "go_type": { + "import": "database/sql", + "package": "orm", + "type": "NullInt32" + } + }, + { + "column": "foo.balance", + "nullable": true, + "go_type": { + "import": "github.com/volatiletech/null/v8", + "type": "Float32" + } + }, + { + "column": "foo.bio", + "nullable": true, + "go_type": { + "import": "gopkg.in/guregu/null.v4", + "type": "String" + } + }, + { + "column": "foo.about", + "nullable": true, + "go_type": { + "type": "string", + "pointer": true + } + } + ] + } + ] +} diff --git a/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..9b9f9ee --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/overrides_go_types/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..8421708 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v5/go/models.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + orm "database/sql" + fuid "github.com/gofrs/uuid" + uuid "github.com/gofrs/uuid" + "github.com/jackc/pgx/v5/pgtype" + null "github.com/volatiletech/null/v8" + null_v4 "gopkg.in/guregu/null.v4" +) + +type Bar struct { + ID uuid.UUID + OtherID fuid.UUID + MoreID fuid.UUID + Age pgtype.Int4 + Balance pgtype.Float8 + Bio pgtype.Text + About pgtype.Text +} + +type Foo struct { + ID uuid.UUID + OtherID fuid.UUID + Age orm.NullInt32 + Balance null.Float32 + Bio null_v4.String + About *string +} diff --git a/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..332661e --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,43 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package override + +import ( + "context" + + uuid "github.com/gofrs/uuid" +) + +const loadFoo = `-- name: LoadFoo :many +SELECT id, other_id, age, balance, bio, about FROM foo WHERE id = $1 +` + +func (q *Queries) LoadFoo(ctx context.Context, id uuid.UUID) ([]Foo, error) { + rows, err := q.db.Query(ctx, loadFoo, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan( + &i.ID, + &i.OtherID, + &i.Age, + &i.Balance, + &i.Bio, + &i.About, + ); 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/overrides_go_types/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..192dc6c --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: LoadFoo :many +SELECT * FROM foo WHERE id = $1; diff --git a/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..68d2f83 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v5/schema.sql @@ -0,0 +1,18 @@ +CREATE TABLE foo ( + id uuid NOT NULL, + other_id uuid NOT NULL, + age integer, + balance double precision, + bio text, + about text +); + +CREATE TABLE bar ( + id uuid NOT NULL, + other_id uuid NOT NULL, + more_id uuid NOT NULL, + age integer, + balance double precision, + bio text, + about text +); diff --git a/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..5baf328 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,64 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "override", + "schema": "schema.sql", + "queries": "query.sql", + "overrides": [ + { + "column": "*.id", + "go_type": { + "import": "github.com/gofrs/uuid", + "package": "uuid", + "type": "UUID" + } + }, + { + "column": "*.*_id", + "go_type": { + "import": "github.com/gofrs/uuid", + "package": "fuid", + "type": "UUID" + } + }, + { + "column": "foo.age", + "nullable": true, + "go_type": { + "import": "database/sql", + "package": "orm", + "type": "NullInt32" + } + }, + { + "column": "foo.balance", + "nullable": true, + "go_type": { + "import": "github.com/volatiletech/null/v8", + "type": "Float32" + } + }, + { + "column": "foo.bio", + "nullable": true, + "go_type": { + "import": "gopkg.in/guregu/null.v4", + "type": "String" + } + }, + { + "column": "foo.about", + "nullable": true, + "go_type": { + "type": "string", + "pointer": true + } + } + ] + } + ] +} diff --git a/internal/endtoend/testdata/overrides_go_types/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/overrides_go_types/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..3e4ebb9 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/overrides_go_types/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/overrides_go_types/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..bc258d9 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/postgresql/stdlib/go/models.go @@ -0,0 +1,22 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + orm "database/sql" + "github.com/gofrs/uuid" + fuid "github.com/gofrs/uuid" + null "github.com/volatiletech/null/v8" + null_v4 "gopkg.in/guregu/null.v4" +) + +type Foo struct { + ID uuid.UUID + OtherID fuid.UUID + Age orm.NullInt32 + Balance null.Float32 + Bio null_v4.String + About *string +} diff --git a/internal/endtoend/testdata/overrides_go_types/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/overrides_go_types/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..de6dbef --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,46 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package override + +import ( + "context" + + "github.com/gofrs/uuid" +) + +const loadFoo = `-- name: LoadFoo :many +SELECT id, other_id, age, balance, bio, about FROM foo WHERE id = $1 +` + +func (q *Queries) LoadFoo(ctx context.Context, id uuid.UUID) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, loadFoo, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan( + &i.ID, + &i.OtherID, + &i.Age, + &i.Balance, + &i.Bio, + &i.About, + ); 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/overrides_go_types/postgresql/stdlib/query.sql b/internal/endtoend/testdata/overrides_go_types/postgresql/stdlib/query.sql new file mode 100644 index 0000000..192dc6c --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: LoadFoo :many +SELECT * FROM foo WHERE id = $1; diff --git a/internal/endtoend/testdata/overrides_go_types/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/overrides_go_types/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..6e33abf --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/postgresql/stdlib/schema.sql @@ -0,0 +1,8 @@ +CREATE TABLE foo ( + id uuid NOT NULL, + other_id uuid NOT NULL, + age integer, + balance double precision, + bio text, + about text +); diff --git a/internal/endtoend/testdata/overrides_go_types/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/overrides_go_types/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..c97894f --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/postgresql/stdlib/sqlc.json @@ -0,0 +1,62 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "override", + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "overrides": [ + { + "column": "foo.id", + "go_type": { + "import": "github.com/gofrs/uuid", + "type": "UUID" + } + }, + { + "column": "foo.other_id", + "go_type": { + "import": "github.com/gofrs/uuid", + "package": "fuid", + "type": "UUID" + } + }, + { + "column": "foo.age", + "nullable": true, + "go_type": { + "import": "database/sql", + "package": "orm", + "type": "NullInt32" + } + }, + { + "column": "foo.balance", + "nullable": true, + "go_type": { + "import": "github.com/volatiletech/null/v8", + "type": "Float32" + } + }, + { + "column": "foo.bio", + "nullable": true, + "go_type": { + "import": "gopkg.in/guregu/null.v4", + "type": "String" + } + }, + { + "column": "foo.about", + "nullable": true, + "go_type": { + "type": "string", + "pointer": true + } + } + ] + } + ] +} diff --git a/internal/endtoend/testdata/overrides_go_types/sqlite/go/db.go b/internal/endtoend/testdata/overrides_go_types/sqlite/go/db.go new file mode 100644 index 0000000..3e4ebb9 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/overrides_go_types/sqlite/go/models.go b/internal/endtoend/testdata/overrides_go_types/sqlite/go/models.go new file mode 100644 index 0000000..aa041ac --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/sqlite/go/models.go @@ -0,0 +1,27 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "github.com/sqlc-dev/sqlc-testdata/pkg" +) + +type Bar struct { + Other string + Total int64 + AlsoRetyped pkg.CustomType +} + +type Baz struct { + Other string + Total int64 + AlsoRetyped pkg.CustomType +} + +type Foo struct { + Other string + Total int64 + Retyped pkg.CustomType +} diff --git a/internal/endtoend/testdata/overrides_go_types/sqlite/go/query.sql.go b/internal/endtoend/testdata/overrides_go_types/sqlite/go/query.sql.go new file mode 100644 index 0000000..185ff73 --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/sqlite/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package override + +import ( + "context" +) + +const test = `-- name: Test :one +SELECT 1 +` + +func (q *Queries) Test(ctx context.Context) (int64, error) { + row := q.db.QueryRowContext(ctx, test) + var column_1 int64 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/overrides_go_types/sqlite/query.sql b/internal/endtoend/testdata/overrides_go_types/sqlite/query.sql new file mode 100644 index 0000000..9da604b --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT 1; diff --git a/internal/endtoend/testdata/overrides_go_types/sqlite/schema.sql b/internal/endtoend/testdata/overrides_go_types/sqlite/schema.sql new file mode 100644 index 0000000..31b183a --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/sqlite/schema.sql @@ -0,0 +1,17 @@ +CREATE TABLE foo ( + other text NOT NULL, + total bigint NOT NULL, + retyped text NOT NULL +); + +CREATE TABLE bar ( + other text NOT NULL, + total bigint NOT NULL, + also_retyped text NOT NULL +); + +CREATE TABLE baz ( + other text NOT NULL, + total bigint NOT NULL, + also_retyped text NOT NULL +); diff --git a/internal/endtoend/testdata/overrides_go_types/sqlite/sqlc.json b/internal/endtoend/testdata/overrides_go_types/sqlite/sqlc.json new file mode 100644 index 0000000..212161c --- /dev/null +++ b/internal/endtoend/testdata/overrides_go_types/sqlite/sqlc.json @@ -0,0 +1,22 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "override", + "engine": "sqlite", + "schema": "schema.sql", + "queries": "query.sql", + "overrides": [ + { + "go_type": "github.com/sqlc-dev/sqlc-testdata/pkg.CustomType", + "column": "foo.retyped" + }, + { + "go_type": "github.com/sqlc-dev/sqlc-testdata/pkg.CustomType", + "column": "*.also_retyped" + } + ] + } + ] +} diff --git a/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/overrides_nullable/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..2137629 --- /dev/null +++ b/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v4/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgtype" +) + +type Foo struct { + Bar pgtype.Text + Bam pgtype.Name + Baz pgtype.Name +} diff --git a/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..4a2a7d1 --- /dev/null +++ b/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listFoo = `-- name: ListFoo :many +SELECT bar, bam, baz FROM foo +` + +func (q *Queries) ListFoo(ctx context.Context) ([]Foo, error) { + rows, err := q.db.Query(ctx, listFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.Bar, &i.Bam, &i.Baz); 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/overrides_nullable/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..b475d29 --- /dev/null +++ b/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: ListFoo :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..b9579b3 --- /dev/null +++ b/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v4/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE foo ( + bar text, + bam name, + baz name not null +); + diff --git a/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..c3f4e17 --- /dev/null +++ b/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,29 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ], + "overrides": [ + { + "db_type": "name", + "go_type": "github.com/jackc/pgtype.Name" + }, + { + "db_type": "name", + "go_type": "github.com/jackc/pgtype.Name", + "nullable": true + }, + { + "db_type": "text", + "go_type": "github.com/jackc/pgtype.Text", + "null": true + } + ] +} diff --git a/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/overrides_nullable/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..78d65bb --- /dev/null +++ b/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v5/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + Bar pgtype.UndecodedBytes + Bam pgtype.DriverBytes + Baz pgtype.Text +} diff --git a/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..4a2a7d1 --- /dev/null +++ b/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listFoo = `-- name: ListFoo :many +SELECT bar, bam, baz FROM foo +` + +func (q *Queries) ListFoo(ctx context.Context) ([]Foo, error) { + rows, err := q.db.Query(ctx, listFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.Bar, &i.Bam, &i.Baz); 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/overrides_nullable/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..b475d29 --- /dev/null +++ b/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: ListFoo :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..a59f631 --- /dev/null +++ b/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v5/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE foo ( + bar text, + bam jsonb, + baz jsonb not null +); + diff --git a/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..04508b4 --- /dev/null +++ b/internal/endtoend/testdata/overrides_nullable/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,29 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ], + "overrides": [ + { + "db_type": "jsonb", + "go_type": "github.com/jackc/pgx/v5/pgtype.Text" + }, + { + "db_type": "jsonb", + "go_type": "github.com/jackc/pgx/v5/pgtype.DriverBytes", + "nullable": true + }, + { + "db_type": "text", + "go_type": "github.com/jackc/pgx/v5/pgtype.UndecodedBytes", + "null": true + } + ] +} diff --git a/internal/endtoend/testdata/overrides_nullable/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/overrides_nullable/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/overrides_nullable/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/overrides_nullable/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/overrides_nullable/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..2137629 --- /dev/null +++ b/internal/endtoend/testdata/overrides_nullable/postgresql/stdlib/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgtype" +) + +type Foo struct { + Bar pgtype.Text + Bam pgtype.Name + Baz pgtype.Name +} diff --git a/internal/endtoend/testdata/overrides_nullable/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/overrides_nullable/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..bd82726 --- /dev/null +++ b/internal/endtoend/testdata/overrides_nullable/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listFoo = `-- name: ListFoo :many +SELECT bar, bam, baz FROM foo +` + +func (q *Queries) ListFoo(ctx context.Context) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, listFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.Bar, &i.Bam, &i.Baz); 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/overrides_nullable/postgresql/stdlib/query.sql b/internal/endtoend/testdata/overrides_nullable/postgresql/stdlib/query.sql new file mode 100644 index 0000000..b475d29 --- /dev/null +++ b/internal/endtoend/testdata/overrides_nullable/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: ListFoo :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/overrides_nullable/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/overrides_nullable/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..b9579b3 --- /dev/null +++ b/internal/endtoend/testdata/overrides_nullable/postgresql/stdlib/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE foo ( + bar text, + bam name, + baz name not null +); + diff --git a/internal/endtoend/testdata/overrides_nullable/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/overrides_nullable/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..d59d867 --- /dev/null +++ b/internal/endtoend/testdata/overrides_nullable/postgresql/stdlib/sqlc.json @@ -0,0 +1,28 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ], + "overrides": [ + { + "db_type": "name", + "go_type": "github.com/jackc/pgtype.Name" + }, + { + "db_type": "name", + "go_type": "github.com/jackc/pgtype.Name", + "nullable": true + }, + { + "db_type": "text", + "go_type": "github.com/jackc/pgtype.Text", + "null": true + } + ] +} diff --git a/internal/endtoend/testdata/overrides_pointers/mysql/go/db.go b/internal/endtoend/testdata/overrides_pointers/mysql/go/db.go new file mode 100644 index 0000000..3e4ebb9 --- /dev/null +++ b/internal/endtoend/testdata/overrides_pointers/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/overrides_pointers/mysql/go/models.go b/internal/endtoend/testdata/overrides_pointers/mysql/go/models.go new file mode 100644 index 0000000..1ba6645 --- /dev/null +++ b/internal/endtoend/testdata/overrides_pointers/mysql/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + t "github.com/jackc/pgtype" +) + +type Foo struct { + Other string + Total int64 + Retyped *t.Text +} diff --git a/internal/endtoend/testdata/overrides_pointers/mysql/go/query.sql.go b/internal/endtoend/testdata/overrides_pointers/mysql/go/query.sql.go new file mode 100644 index 0000000..3e0d5a6 --- /dev/null +++ b/internal/endtoend/testdata/overrides_pointers/mysql/go/query.sql.go @@ -0,0 +1,26 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package override + +import ( + "context" + + t "github.com/jackc/pgtype" +) + +const test = `-- name: test :exec +SELECT other, total, retyped FROM foo WHERE other = ? and retyped = ? +` + +type testParams struct { + Other string + Retyped *t.Text +} + +func (q *Queries) test(ctx context.Context, arg testParams) error { + _, err := q.db.ExecContext(ctx, test, arg.Other, arg.Retyped) + return err +} diff --git a/internal/endtoend/testdata/overrides_pointers/mysql/query.sql b/internal/endtoend/testdata/overrides_pointers/mysql/query.sql new file mode 100644 index 0000000..d2733d7 --- /dev/null +++ b/internal/endtoend/testdata/overrides_pointers/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: test :exec +SELECT * FROM foo WHERE other = ? and retyped = ?; \ No newline at end of file diff --git a/internal/endtoend/testdata/overrides_pointers/mysql/schema.sql b/internal/endtoend/testdata/overrides_pointers/mysql/schema.sql new file mode 100644 index 0000000..c0c5fc4 --- /dev/null +++ b/internal/endtoend/testdata/overrides_pointers/mysql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE foo ( + other text NOT NULL, + total bigint NOT NULL, + retyped text NOT NULL +); diff --git a/internal/endtoend/testdata/overrides_pointers/mysql/sqlc.json b/internal/endtoend/testdata/overrides_pointers/mysql/sqlc.json new file mode 100644 index 0000000..cff9b5a --- /dev/null +++ b/internal/endtoend/testdata/overrides_pointers/mysql/sqlc.json @@ -0,0 +1,23 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "override", + "engine": "mysql", + "schema": "schema.sql", + "queries": "query.sql", + "overrides": [ + { + "go_type": { + "import": "github.com/jackc/pgtype", + "type": "Text", + "package": "t", + "pointer": true + }, + "column": "foo.retyped" + } + ] + } + ] +} diff --git a/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..6e1aea1 --- /dev/null +++ b/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/overrides_pointers/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..4f2c215 --- /dev/null +++ b/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v4/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + t "github.com/jackc/pgtype" +) + +type Foo struct { + Other string + Total int64 + Tags []string + ByteSeq []byte + Retyped string + Langs *t.Text +} diff --git a/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..6e328f6 --- /dev/null +++ b/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package override + +import ( + "context" + + t "github.com/jackc/pgtype" +) + +const test = `-- name: test :exec +UPDATE foo SET langs = $1 +` + +func (q *Queries) test(ctx context.Context, langs *t.Text) error { + _, err := q.db.Exec(ctx, test, langs) + return err +} diff --git a/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..989c99f --- /dev/null +++ b/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: test :exec +UPDATE foo SET langs = $1; \ No newline at end of file diff --git a/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..fc3a13e --- /dev/null +++ b/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v4/schema.sql @@ -0,0 +1,8 @@ +CREATE TABLE foo ( + other text NOT NULL, + total bigint NOT NULL, + tags text[] NOT NULL, + byte_seq bytea NOT NULL, + retyped text NOT NULL, + langs text[] +); diff --git a/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..7f9b92f --- /dev/null +++ b/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,24 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "override", + "schema": "schema.sql", + "queries": "query.sql", + "overrides": [ + { + "go_type": { + "import": "github.com/jackc/pgtype", + "type": "Text", + "package": "t", + "pointer": true + }, + "column": "foo.langs" + } + ] + } + ] +} diff --git a/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..9b9f9ee --- /dev/null +++ b/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/overrides_pointers/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..4f2c215 --- /dev/null +++ b/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v5/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + t "github.com/jackc/pgtype" +) + +type Foo struct { + Other string + Total int64 + Tags []string + ByteSeq []byte + Retyped string + Langs *t.Text +} diff --git a/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..6e328f6 --- /dev/null +++ b/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package override + +import ( + "context" + + t "github.com/jackc/pgtype" +) + +const test = `-- name: test :exec +UPDATE foo SET langs = $1 +` + +func (q *Queries) test(ctx context.Context, langs *t.Text) error { + _, err := q.db.Exec(ctx, test, langs) + return err +} diff --git a/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..989c99f --- /dev/null +++ b/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: test :exec +UPDATE foo SET langs = $1; \ No newline at end of file diff --git a/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..fc3a13e --- /dev/null +++ b/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v5/schema.sql @@ -0,0 +1,8 @@ +CREATE TABLE foo ( + other text NOT NULL, + total bigint NOT NULL, + tags text[] NOT NULL, + byte_seq bytea NOT NULL, + retyped text NOT NULL, + langs text[] +); diff --git a/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..9bbaf45 --- /dev/null +++ b/internal/endtoend/testdata/overrides_pointers/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,24 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "override", + "schema": "schema.sql", + "queries": "query.sql", + "overrides": [ + { + "go_type": { + "import": "github.com/jackc/pgtype", + "type": "Text", + "package": "t", + "pointer": true + }, + "column": "foo.langs" + } + ] + } + ] +} diff --git a/internal/endtoend/testdata/overrides_pointers/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/overrides_pointers/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..3e4ebb9 --- /dev/null +++ b/internal/endtoend/testdata/overrides_pointers/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/overrides_pointers/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/overrides_pointers/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..4f2c215 --- /dev/null +++ b/internal/endtoend/testdata/overrides_pointers/postgresql/stdlib/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + t "github.com/jackc/pgtype" +) + +type Foo struct { + Other string + Total int64 + Tags []string + ByteSeq []byte + Retyped string + Langs *t.Text +} diff --git a/internal/endtoend/testdata/overrides_pointers/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/overrides_pointers/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..25d47d9 --- /dev/null +++ b/internal/endtoend/testdata/overrides_pointers/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package override + +import ( + "context" + + t "github.com/jackc/pgtype" +) + +const test = `-- name: test :exec +UPDATE foo SET langs = $1 +` + +func (q *Queries) test(ctx context.Context, langs *t.Text) error { + _, err := q.db.ExecContext(ctx, test, langs) + return err +} diff --git a/internal/endtoend/testdata/overrides_pointers/postgresql/stdlib/query.sql b/internal/endtoend/testdata/overrides_pointers/postgresql/stdlib/query.sql new file mode 100644 index 0000000..c3da7cc --- /dev/null +++ b/internal/endtoend/testdata/overrides_pointers/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: test :exec +UPDATE foo SET langs = $1; diff --git a/internal/endtoend/testdata/overrides_pointers/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/overrides_pointers/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..fc3a13e --- /dev/null +++ b/internal/endtoend/testdata/overrides_pointers/postgresql/stdlib/schema.sql @@ -0,0 +1,8 @@ +CREATE TABLE foo ( + other text NOT NULL, + total bigint NOT NULL, + tags text[] NOT NULL, + byte_seq bytea NOT NULL, + retyped text NOT NULL, + langs text[] +); diff --git a/internal/endtoend/testdata/overrides_pointers/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/overrides_pointers/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..a251249 --- /dev/null +++ b/internal/endtoend/testdata/overrides_pointers/postgresql/stdlib/sqlc.json @@ -0,0 +1,23 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "override", + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "overrides": [ + { + "go_type": { + "import": "github.com/jackc/pgtype", + "type": "Text", + "package": "t", + "pointer": true + }, + "column": "foo.langs" + } + ] + } + ] +} diff --git a/internal/endtoend/testdata/overrides_result_tag/stdlib/go/db.go b/internal/endtoend/testdata/overrides_result_tag/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/overrides_result_tag/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/overrides_result_tag/stdlib/go/models.go b/internal/endtoend/testdata/overrides_result_tag/stdlib/go/models.go new file mode 100644 index 0000000..227745d --- /dev/null +++ b/internal/endtoend/testdata/overrides_result_tag/stdlib/go/models.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + + "github.com/google/uuid" +) + +type Account struct { + ID uuid.UUID `sometagtype:"some_value"` + State sql.NullString +} + +type UsersAccount struct { + Id2 uuid.UUID + Name sql.NullString +} diff --git a/internal/endtoend/testdata/overrides_result_tag/stdlib/go/query.sql.go b/internal/endtoend/testdata/overrides_result_tag/stdlib/go/query.sql.go new file mode 100644 index 0000000..3c41c7f --- /dev/null +++ b/internal/endtoend/testdata/overrides_result_tag/stdlib/go/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" + + "github.com/google/uuid" +) + +const findAccount = `-- name: FindAccount :one +SELECT + a.id, a.state, + ua.name + -- other fields +FROM + accounts a + INNER JOIN users_accounts ua ON a.id = ua.id2 +WHERE + a.id = $1 +` + +type FindAccountRow struct { + ID uuid.UUID `sometagtype:"some_value"` + State sql.NullString + Name sql.NullString +} + +func (q *Queries) FindAccount(ctx context.Context, accountID uuid.UUID) (FindAccountRow, error) { + row := q.db.QueryRowContext(ctx, findAccount, accountID) + var i FindAccountRow + err := row.Scan(&i.ID, &i.State, &i.Name) + return i, err +} diff --git a/internal/endtoend/testdata/overrides_result_tag/stdlib/query.sql b/internal/endtoend/testdata/overrides_result_tag/stdlib/query.sql new file mode 100644 index 0000000..4ca1dd8 --- /dev/null +++ b/internal/endtoend/testdata/overrides_result_tag/stdlib/query.sql @@ -0,0 +1,10 @@ +-- name: FindAccount :one +SELECT + a.*, + ua.name + -- other fields +FROM + accounts a + INNER JOIN users_accounts ua ON a.id = ua.id2 +WHERE + a.id = @account_id; diff --git a/internal/endtoend/testdata/overrides_result_tag/stdlib/schema.sql b/internal/endtoend/testdata/overrides_result_tag/stdlib/schema.sql new file mode 100644 index 0000000..ebd8d00 --- /dev/null +++ b/internal/endtoend/testdata/overrides_result_tag/stdlib/schema.sql @@ -0,0 +1,12 @@ +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; + +CREATE TABLE public.accounts ( + id uuid DEFAULT public.uuid_generate_v4() NOT NULL, + state character varying +); + +CREATE TABLE public.users_accounts ( + ID2 uuid DEFAULT public.uuid_generate_v4() NOT NULL, + name character varying +); + diff --git a/internal/endtoend/testdata/overrides_result_tag/stdlib/sqlc.yaml b/internal/endtoend/testdata/overrides_result_tag/stdlib/sqlc.yaml new file mode 100644 index 0000000..bbfc3b1 --- /dev/null +++ b/internal/endtoend/testdata/overrides_result_tag/stdlib/sqlc.yaml @@ -0,0 +1,12 @@ +version: "2" +sql: + - schema: "schema.sql" + queries: "query.sql" + engine: "postgresql" + gen: + go: + package: "querytest" + out: "go" + overrides: + - column: accounts.id + go_struct_tag: sometagtype:"some_value" \ No newline at end of file diff --git a/internal/endtoend/testdata/overrides_unsigned/mysql/go/db.go b/internal/endtoend/testdata/overrides_unsigned/mysql/go/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/overrides_unsigned/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/overrides_unsigned/mysql/go/models.go b/internal/endtoend/testdata/overrides_unsigned/mysql/go/models.go new file mode 100644 index 0000000..17a3e7b --- /dev/null +++ b/internal/endtoend/testdata/overrides_unsigned/mysql/go/models.go @@ -0,0 +1,17 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Rating int64 + Score uint32 + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/overrides_unsigned/mysql/go/query.sql.go b/internal/endtoend/testdata/overrides_unsigned/mysql/go/query.sql.go new file mode 100644 index 0000000..626c64e --- /dev/null +++ b/internal/endtoend/testdata/overrides_unsigned/mysql/go/query.sql.go @@ -0,0 +1,91 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" + "database/sql" +) + +const createAuthor = `-- name: CreateAuthor :exec +INSERT INTO authors ( + name, bio +) VALUES ( + ?, ? +) +` + +type CreateAuthorParams struct { + Name string + Bio sql.NullString +} + +func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) error { + _, err := q.db.ExecContext(ctx, createAuthor, arg.Name, arg.Bio) + return err +} + +const deleteAuthor = `-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = ? +` + +func (q *Queries) DeleteAuthor(ctx context.Context, id int64) error { + _, err := q.db.ExecContext(ctx, deleteAuthor, id) + return err +} + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, rating, score, bio FROM authors +WHERE id = ? LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Author + err := row.Scan( + &i.ID, + &i.Name, + &i.Rating, + &i.Score, + &i.Bio, + ) + return i, err +} + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name, rating, score, bio FROM authors +ORDER BY name +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan( + &i.ID, + &i.Name, + &i.Rating, + &i.Score, + &i.Bio, + ); 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/overrides_unsigned/mysql/query.sql b/internal/endtoend/testdata/overrides_unsigned/mysql/query.sql new file mode 100644 index 0000000..348b2c6 --- /dev/null +++ b/internal/endtoend/testdata/overrides_unsigned/mysql/query.sql @@ -0,0 +1,18 @@ +-- name: ListAuthors :many +SELECT * FROM authors +ORDER BY name; + +-- name: GetAuthor :one +SELECT * FROM authors +WHERE id = ? LIMIT 1; + +-- name: CreateAuthor :exec +INSERT INTO authors ( + name, bio +) VALUES ( + ?, ? +); + +-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = ?; \ No newline at end of file diff --git a/internal/endtoend/testdata/overrides_unsigned/mysql/schema.sql b/internal/endtoend/testdata/overrides_unsigned/mysql/schema.sql new file mode 100644 index 0000000..70567ea --- /dev/null +++ b/internal/endtoend/testdata/overrides_unsigned/mysql/schema.sql @@ -0,0 +1,8 @@ +CREATE TABLE authors ( + id SERIAL, + name text NOT NULL, + rating bigint NOT NULL, + score int UNSIGNED NOT NULL, + bio text +); + diff --git a/internal/endtoend/testdata/overrides_unsigned/mysql/sqlc.json b/internal/endtoend/testdata/overrides_unsigned/mysql/sqlc.json new file mode 100644 index 0000000..400518f --- /dev/null +++ b/internal/endtoend/testdata/overrides_unsigned/mysql/sqlc.json @@ -0,0 +1,23 @@ +{ + "version": "2", + "sql": [ + { + "schema": "schema.sql", + "queries": "query.sql", + "engine": "mysql", + "gen": { + "go": { + "package": "db", + "out": "go", + "overrides": [ + { + "db_type": "bigint", + "go_type": "int64", + "unsigned": true + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/params_duplicate/mysql/go/db.go b/internal/endtoend/testdata/params_duplicate/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/params_duplicate/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/params_duplicate/mysql/go/models.go b/internal/endtoend/testdata/params_duplicate/mysql/go/models.go new file mode 100644 index 0000000..828a2c3 --- /dev/null +++ b/internal/endtoend/testdata/params_duplicate/mysql/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID int32 + FirstName sql.NullString + LastName sql.NullString + Age sql.NullInt32 +} diff --git a/internal/endtoend/testdata/params_duplicate/mysql/go/query.sql.go b/internal/endtoend/testdata/params_duplicate/mysql/go/query.sql.go new file mode 100644 index 0000000..562981c --- /dev/null +++ b/internal/endtoend/testdata/params_duplicate/mysql/go/query.sql.go @@ -0,0 +1,143 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const selectUserByAgeCast = `-- name: SelectUserByAgeCast :many +SELECT first_name FROM users +WHERE age > CAST(? AS SIGNED) + OR age < CAST(? AS SIGNED) +` + +type SelectUserByAgeCastParams struct { + Threshold int64 +} + +func (q *Queries) SelectUserByAgeCast(ctx context.Context, arg SelectUserByAgeCastParams) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, selectUserByAgeCast, arg.Threshold, arg.Threshold) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var first_name sql.NullString + if err := rows.Scan(&first_name); err != nil { + return nil, err + } + items = append(items, first_name) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const selectUserByID = `-- name: SelectUserByID :many +SELECT first_name from +users where (? = id OR ? = 0) +` + +type SelectUserByIDParams struct { + ID int32 +} + +func (q *Queries) SelectUserByID(ctx context.Context, arg SelectUserByIDParams) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, selectUserByID, arg.ID, arg.ID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var first_name sql.NullString + if err := rows.Scan(&first_name); err != nil { + return nil, err + } + items = append(items, first_name) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const selectUserByName = `-- name: SelectUserByName :many +SELECT first_name +FROM users +WHERE first_name = ? + OR last_name = ? +` + +type SelectUserByNameParams struct { + Name sql.NullString +} + +func (q *Queries) SelectUserByName(ctx context.Context, arg SelectUserByNameParams) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, selectUserByName, arg.Name, arg.Name) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var first_name sql.NullString + if err := rows.Scan(&first_name); err != nil { + return nil, err + } + items = append(items, first_name) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const selectUserQuestion = `-- name: SelectUserQuestion :many +SELECT first_name from +users where (? = id OR ? = 0) +` + +type SelectUserQuestionParams struct { + ID int32 + Column2 any +} + +func (q *Queries) SelectUserQuestion(ctx context.Context, arg SelectUserQuestionParams) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, selectUserQuestion, arg.ID, arg.Column2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var first_name sql.NullString + if err := rows.Scan(&first_name); err != nil { + return nil, err + } + items = append(items, first_name) + } + 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/params_duplicate/mysql/query.sql b/internal/endtoend/testdata/params_duplicate/mysql/query.sql new file mode 100644 index 0000000..3924f57 --- /dev/null +++ b/internal/endtoend/testdata/params_duplicate/mysql/query.sql @@ -0,0 +1,18 @@ +/* name: SelectUserByID :many */ +SELECT first_name from +users where (sqlc.arg(id) = id OR sqlc.arg(id) = 0); + +/* name: SelectUserByName :many */ +SELECT first_name +FROM users +WHERE first_name = sqlc.arg(name) + OR last_name = sqlc.arg(name); + +/* name: SelectUserQuestion :many */ +SELECT first_name from +users where (? = id OR ? = 0); + +/* name: SelectUserByAgeCast :many */ +SELECT first_name FROM users +WHERE age > CAST(sqlc.arg(threshold) AS SIGNED) + OR age < CAST(sqlc.arg(threshold) AS SIGNED); diff --git a/internal/endtoend/testdata/params_duplicate/mysql/schema.sql b/internal/endtoend/testdata/params_duplicate/mysql/schema.sql new file mode 100644 index 0000000..497fa29 --- /dev/null +++ b/internal/endtoend/testdata/params_duplicate/mysql/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + id integer NOT NULL AUTO_INCREMENT PRIMARY KEY, + first_name varchar(255), + last_name varchar(255), + age int +) ENGINE=InnoDB; diff --git a/internal/endtoend/testdata/params_duplicate/mysql/sqlc.json b/internal/endtoend/testdata/params_duplicate/mysql/sqlc.json new file mode 100644 index 0000000..1f70415 --- /dev/null +++ b/internal/endtoend/testdata/params_duplicate/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "schema.sql", + "queries": "query.sql", + "engine": "mysql" + } + ] +} diff --git a/internal/endtoend/testdata/params_duplicate/postgresql/go/db.go b/internal/endtoend/testdata/params_duplicate/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/params_duplicate/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/params_duplicate/postgresql/go/models.go b/internal/endtoend/testdata/params_duplicate/postgresql/go/models.go new file mode 100644 index 0000000..16d7ae2 --- /dev/null +++ b/internal/endtoend/testdata/params_duplicate/postgresql/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID int32 + FirstName sql.NullString + LastName sql.NullString +} diff --git a/internal/endtoend/testdata/params_duplicate/postgresql/go/query.sql.go b/internal/endtoend/testdata/params_duplicate/postgresql/go/query.sql.go new file mode 100644 index 0000000..56fc2d3 --- /dev/null +++ b/internal/endtoend/testdata/params_duplicate/postgresql/go/query.sql.go @@ -0,0 +1,97 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const selectUserByID = `-- name: SelectUserByID :many +SELECT first_name from +users where ($1 = id OR $1 = 0) +` + +func (q *Queries) SelectUserByID(ctx context.Context, id int32) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, selectUserByID, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var first_name sql.NullString + if err := rows.Scan(&first_name); err != nil { + return nil, err + } + items = append(items, first_name) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const selectUserByName = `-- name: SelectUserByName :many +SELECT first_name +FROM users +WHERE first_name = $1 + OR last_name = $1 +` + +func (q *Queries) SelectUserByName(ctx context.Context, name sql.NullString) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, selectUserByName, name) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var first_name sql.NullString + if err := rows.Scan(&first_name); err != nil { + return nil, err + } + items = append(items, first_name) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const selectUserQuestion = `-- name: SelectUserQuestion :many +SELECT first_name from +users where ($1 = id OR $1 = 0) +` + +func (q *Queries) SelectUserQuestion(ctx context.Context, id int32) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, selectUserQuestion, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var first_name sql.NullString + if err := rows.Scan(&first_name); err != nil { + return nil, err + } + items = append(items, first_name) + } + 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/params_duplicate/postgresql/query.sql b/internal/endtoend/testdata/params_duplicate/postgresql/query.sql new file mode 100644 index 0000000..8a75624 --- /dev/null +++ b/internal/endtoend/testdata/params_duplicate/postgresql/query.sql @@ -0,0 +1,13 @@ +/* name: SelectUserByID :many */ +SELECT first_name from +users where (sqlc.arg(id) = id OR sqlc.arg(id) = 0); + +/* name: SelectUserByName :many */ +SELECT first_name +FROM users +WHERE first_name = sqlc.arg(name) + OR last_name = sqlc.arg(name); + +/* name: SelectUserQuestion :many */ +SELECT first_name from +users where ($1 = id OR $1 = 0); diff --git a/internal/endtoend/testdata/params_duplicate/postgresql/schema.sql b/internal/endtoend/testdata/params_duplicate/postgresql/schema.sql new file mode 100644 index 0000000..554581b --- /dev/null +++ b/internal/endtoend/testdata/params_duplicate/postgresql/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + id INT PRIMARY KEY, + first_name varchar(255), + last_name varchar(255) +); + diff --git a/internal/endtoend/testdata/params_duplicate/postgresql/sqlc.json b/internal/endtoend/testdata/params_duplicate/postgresql/sqlc.json new file mode 100644 index 0000000..2fc79a9 --- /dev/null +++ b/internal/endtoend/testdata/params_duplicate/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql" + } + ] +} diff --git a/internal/endtoend/testdata/params_go_keywords/issue.md b/internal/endtoend/testdata/params_go_keywords/issue.md new file mode 100644 index 0000000..f87f5c1 --- /dev/null +++ b/internal/endtoend/testdata/params_go_keywords/issue.md @@ -0,0 +1 @@ +# TODO \ No newline at end of file diff --git a/internal/endtoend/testdata/params_go_keywords/postgresql/go/db.go b/internal/endtoend/testdata/params_go_keywords/postgresql/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/params_go_keywords/postgresql/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/params_go_keywords/postgresql/go/models.go b/internal/endtoend/testdata/params_go_keywords/postgresql/go/models.go new file mode 100644 index 0000000..9af4bf3 --- /dev/null +++ b/internal/endtoend/testdata/params_go_keywords/postgresql/go/models.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type GoKeyword struct { + Break pgtype.Text + Default pgtype.Text + Func pgtype.Text + Interface pgtype.Text + Select pgtype.Text + Case pgtype.Text + Defer pgtype.Text + Go pgtype.Text + Map pgtype.Text + Struct pgtype.Text + Chan pgtype.Text + Else pgtype.Text + Goto pgtype.Text + Package pgtype.Text + Switch pgtype.Text + Const pgtype.Text + Fallthrough pgtype.Text + If pgtype.Text + Range pgtype.Text + Type pgtype.Text + Continue pgtype.Text + For pgtype.Text + Import pgtype.Text + Return pgtype.Text + Var pgtype.Text + Q pgtype.Text +} diff --git a/internal/endtoend/testdata/params_go_keywords/postgresql/go/query.sql.go b/internal/endtoend/testdata/params_go_keywords/postgresql/go/query.sql.go new file mode 100644 index 0000000..d659225 --- /dev/null +++ b/internal/endtoend/testdata/params_go_keywords/postgresql/go/query.sql.go @@ -0,0 +1,532 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const keywordBreak = `-- name: KeywordBreak :exec +SELECT $1::text +` + +func (q *Queries) KeywordBreak(ctx context.Context, break_ string) error { + _, err := q.db.Exec(ctx, keywordBreak, break_) + return err +} + +const keywordCase = `-- name: KeywordCase :exec +SELECT $1::text +` + +func (q *Queries) KeywordCase(ctx context.Context, case_ string) error { + _, err := q.db.Exec(ctx, keywordCase, case_) + return err +} + +const keywordChan = `-- name: KeywordChan :exec +SELECT $1::text +` + +func (q *Queries) KeywordChan(ctx context.Context, chan_ string) error { + _, err := q.db.Exec(ctx, keywordChan, chan_) + return err +} + +const keywordConst = `-- name: KeywordConst :exec +SELECT $1::text +` + +func (q *Queries) KeywordConst(ctx context.Context, const_ string) error { + _, err := q.db.Exec(ctx, keywordConst, const_) + return err +} + +const keywordContinue = `-- name: KeywordContinue :exec +SELECT $1::text +` + +func (q *Queries) KeywordContinue(ctx context.Context, continue_ string) error { + _, err := q.db.Exec(ctx, keywordContinue, continue_) + return err +} + +const keywordDefault = `-- name: KeywordDefault :exec +SELECT $1::text +` + +func (q *Queries) KeywordDefault(ctx context.Context, default_ string) error { + _, err := q.db.Exec(ctx, keywordDefault, default_) + return err +} + +const keywordDefer = `-- name: KeywordDefer :exec +SELECT $1::text +` + +func (q *Queries) KeywordDefer(ctx context.Context, defer_ string) error { + _, err := q.db.Exec(ctx, keywordDefer, defer_) + return err +} + +const keywordElse = `-- name: KeywordElse :exec +SELECT $1::text +` + +func (q *Queries) KeywordElse(ctx context.Context, else_ string) error { + _, err := q.db.Exec(ctx, keywordElse, else_) + return err +} + +const keywordFallthrough = `-- name: KeywordFallthrough :exec +SELECT $1::text +` + +func (q *Queries) KeywordFallthrough(ctx context.Context, fallthrough_ string) error { + _, err := q.db.Exec(ctx, keywordFallthrough, fallthrough_) + return err +} + +const keywordFor = `-- name: KeywordFor :exec +SELECT $1::text +` + +func (q *Queries) KeywordFor(ctx context.Context, for_ string) error { + _, err := q.db.Exec(ctx, keywordFor, for_) + return err +} + +const keywordFunc = `-- name: KeywordFunc :exec +SELECT $1::text +` + +func (q *Queries) KeywordFunc(ctx context.Context, func_ string) error { + _, err := q.db.Exec(ctx, keywordFunc, func_) + return err +} + +const keywordGo = `-- name: KeywordGo :exec +SELECT $1::text +` + +func (q *Queries) KeywordGo(ctx context.Context, go_ string) error { + _, err := q.db.Exec(ctx, keywordGo, go_) + return err +} + +const keywordGoto = `-- name: KeywordGoto :exec +SELECT $1::text +` + +func (q *Queries) KeywordGoto(ctx context.Context, goto_ string) error { + _, err := q.db.Exec(ctx, keywordGoto, goto_) + return err +} + +const keywordIf = `-- name: KeywordIf :exec +SELECT $1::text +` + +func (q *Queries) KeywordIf(ctx context.Context, if_ string) error { + _, err := q.db.Exec(ctx, keywordIf, if_) + return err +} + +const keywordImport = `-- name: KeywordImport :exec +SELECT $1::text +` + +func (q *Queries) KeywordImport(ctx context.Context, import_ string) error { + _, err := q.db.Exec(ctx, keywordImport, import_) + return err +} + +const keywordInterface = `-- name: KeywordInterface :exec +SELECT $1::text +` + +func (q *Queries) KeywordInterface(ctx context.Context, interface_ string) error { + _, err := q.db.Exec(ctx, keywordInterface, interface_) + return err +} + +const keywordMap = `-- name: KeywordMap :exec +SELECT $1::text +` + +func (q *Queries) KeywordMap(ctx context.Context, map_ string) error { + _, err := q.db.Exec(ctx, keywordMap, map_) + return err +} + +const keywordPackage = `-- name: KeywordPackage :exec +SELECT $1::text +` + +func (q *Queries) KeywordPackage(ctx context.Context, package_ string) error { + _, err := q.db.Exec(ctx, keywordPackage, package_) + return err +} + +const keywordQ = `-- name: KeywordQ :exec +SELECT $1::text +` + +func (q *Queries) KeywordQ(ctx context.Context, q_ string) error { + _, err := q.db.Exec(ctx, keywordQ, q_) + return err +} + +const keywordRange = `-- name: KeywordRange :exec +SELECT $1::text +` + +func (q *Queries) KeywordRange(ctx context.Context, range_ string) error { + _, err := q.db.Exec(ctx, keywordRange, range_) + return err +} + +const keywordReturn = `-- name: KeywordReturn :exec +SELECT $1::text +` + +func (q *Queries) KeywordReturn(ctx context.Context, return_ string) error { + _, err := q.db.Exec(ctx, keywordReturn, return_) + return err +} + +const keywordSelect = `-- name: KeywordSelect :exec +SELECT $1::text +` + +func (q *Queries) KeywordSelect(ctx context.Context, select_ string) error { + _, err := q.db.Exec(ctx, keywordSelect, select_) + return err +} + +const keywordStruct = `-- name: KeywordStruct :exec +SELECT $1::text +` + +func (q *Queries) KeywordStruct(ctx context.Context, struct_ string) error { + _, err := q.db.Exec(ctx, keywordStruct, struct_) + return err +} + +const keywordSwitch = `-- name: KeywordSwitch :exec +SELECT $1::text +` + +func (q *Queries) KeywordSwitch(ctx context.Context, switch_ string) error { + _, err := q.db.Exec(ctx, keywordSwitch, switch_) + return err +} + +const keywordType = `-- name: KeywordType :exec +SELECT $1::text +` + +func (q *Queries) KeywordType(ctx context.Context, type_ string) error { + _, err := q.db.Exec(ctx, keywordType, type_) + return err +} + +const keywordVar = `-- name: KeywordVar :exec +SELECT $1::text +` + +func (q *Queries) KeywordVar(ctx context.Context, var_ string) error { + _, err := q.db.Exec(ctx, keywordVar, var_) + return err +} + +const selectBreak = `-- name: SelectBreak :one +SELECT "break" FROM go_keywords +` + +func (q *Queries) SelectBreak(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectBreak) + var break_ pgtype.Text + err := row.Scan(&break_) + return break_, err +} + +const selectCase = `-- name: SelectCase :one +SELECT "case" FROM go_keywords +` + +func (q *Queries) SelectCase(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectCase) + var case_ pgtype.Text + err := row.Scan(&case_) + return case_, err +} + +const selectChan = `-- name: SelectChan :one +SELECT "chan" FROM go_keywords +` + +func (q *Queries) SelectChan(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectChan) + var chan_ pgtype.Text + err := row.Scan(&chan_) + return chan_, err +} + +const selectConst = `-- name: SelectConst :one +SELECT "const" FROM go_keywords +` + +func (q *Queries) SelectConst(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectConst) + var const_ pgtype.Text + err := row.Scan(&const_) + return const_, err +} + +const selectContinue = `-- name: SelectContinue :one +SELECT "continue" FROM go_keywords +` + +func (q *Queries) SelectContinue(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectContinue) + var continue_ pgtype.Text + err := row.Scan(&continue_) + return continue_, err +} + +const selectDefault = `-- name: SelectDefault :one +SELECT "default" FROM go_keywords +` + +func (q *Queries) SelectDefault(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectDefault) + var default_ pgtype.Text + err := row.Scan(&default_) + return default_, err +} + +const selectDefer = `-- name: SelectDefer :one +SELECT "defer" FROM go_keywords +` + +func (q *Queries) SelectDefer(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectDefer) + var defer_ pgtype.Text + err := row.Scan(&defer_) + return defer_, err +} + +const selectElse = `-- name: SelectElse :one +SELECT "else" FROM go_keywords +` + +func (q *Queries) SelectElse(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectElse) + var else_ pgtype.Text + err := row.Scan(&else_) + return else_, err +} + +const selectFallthrough = `-- name: SelectFallthrough :one +SELECT "fallthrough" FROM go_keywords +` + +func (q *Queries) SelectFallthrough(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectFallthrough) + var fallthrough_ pgtype.Text + err := row.Scan(&fallthrough_) + return fallthrough_, err +} + +const selectFor = `-- name: SelectFor :one +SELECT "for" FROM go_keywords +` + +func (q *Queries) SelectFor(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectFor) + var for_ pgtype.Text + err := row.Scan(&for_) + return for_, err +} + +const selectFunc = `-- name: SelectFunc :one +SELECT "func" FROM go_keywords +` + +func (q *Queries) SelectFunc(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectFunc) + var func_ pgtype.Text + err := row.Scan(&func_) + return func_, err +} + +const selectGo = `-- name: SelectGo :one +SELECT "go" FROM go_keywords +` + +func (q *Queries) SelectGo(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectGo) + var go_ pgtype.Text + err := row.Scan(&go_) + return go_, err +} + +const selectGoto = `-- name: SelectGoto :one +SELECT "goto" FROM go_keywords +` + +func (q *Queries) SelectGoto(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectGoto) + var goto_ pgtype.Text + err := row.Scan(&goto_) + return goto_, err +} + +const selectIf = `-- name: SelectIf :one +SELECT "if" FROM go_keywords +` + +func (q *Queries) SelectIf(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectIf) + var if_ pgtype.Text + err := row.Scan(&if_) + return if_, err +} + +const selectImport = `-- name: SelectImport :one +SELECT "import" FROM go_keywords +` + +func (q *Queries) SelectImport(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectImport) + var import_ pgtype.Text + err := row.Scan(&import_) + return import_, err +} + +const selectInterface = `-- name: SelectInterface :one +SELECT "interface" FROM go_keywords +` + +func (q *Queries) SelectInterface(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectInterface) + var interface_ pgtype.Text + err := row.Scan(&interface_) + return interface_, err +} + +const selectMap = `-- name: SelectMap :one +SELECT "map" FROM go_keywords +` + +func (q *Queries) SelectMap(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectMap) + var map_ pgtype.Text + err := row.Scan(&map_) + return map_, err +} + +const selectPackage = `-- name: SelectPackage :one +SELECT "package" FROM go_keywords +` + +func (q *Queries) SelectPackage(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectPackage) + var package_ pgtype.Text + err := row.Scan(&package_) + return package_, err +} + +const selectQ = `-- name: SelectQ :one +SELECT "q" FROM go_keywords +` + +func (q *Queries) SelectQ(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectQ) + var q_ pgtype.Text + err := row.Scan(&q_) + return q_, err +} + +const selectRange = `-- name: SelectRange :one +SELECT "range" FROM go_keywords +` + +func (q *Queries) SelectRange(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectRange) + var range_ pgtype.Text + err := row.Scan(&range_) + return range_, err +} + +const selectReturn = `-- name: SelectReturn :one +SELECT "return" FROM go_keywords +` + +func (q *Queries) SelectReturn(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectReturn) + var return_ pgtype.Text + err := row.Scan(&return_) + return return_, err +} + +const selectSelect = `-- name: SelectSelect :one +SELECT "select" FROM go_keywords +` + +func (q *Queries) SelectSelect(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectSelect) + var select_ pgtype.Text + err := row.Scan(&select_) + return select_, err +} + +const selectStruct = `-- name: SelectStruct :one +SELECT "struct" FROM go_keywords +` + +func (q *Queries) SelectStruct(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectStruct) + var struct_ pgtype.Text + err := row.Scan(&struct_) + return struct_, err +} + +const selectSwitch = `-- name: SelectSwitch :one +SELECT "switch" FROM go_keywords +` + +func (q *Queries) SelectSwitch(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectSwitch) + var switch_ pgtype.Text + err := row.Scan(&switch_) + return switch_, err +} + +const selectType = `-- name: SelectType :one +SELECT "type" FROM go_keywords +` + +func (q *Queries) SelectType(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectType) + var type_ pgtype.Text + err := row.Scan(&type_) + return type_, err +} + +const selectVar = `-- name: SelectVar :one +SELECT "var" FROM go_keywords +` + +func (q *Queries) SelectVar(ctx context.Context) (pgtype.Text, error) { + row := q.db.QueryRow(ctx, selectVar) + var var_ pgtype.Text + err := row.Scan(&var_) + return var_, err +} diff --git a/internal/endtoend/testdata/params_go_keywords/postgresql/query.sql b/internal/endtoend/testdata/params_go_keywords/postgresql/query.sql new file mode 100644 index 0000000..bc45b11 --- /dev/null +++ b/internal/endtoend/testdata/params_go_keywords/postgresql/query.sql @@ -0,0 +1,155 @@ +-- name: KeywordBreak :exec +SELECT sqlc.arg('break')::text; + +-- name: KeywordDefault :exec +SELECT sqlc.arg('default')::text; + +-- name: KeywordFunc :exec +SELECT sqlc.arg('func')::text; + +-- name: KeywordInterface :exec +SELECT sqlc.arg('interface')::text; + +-- name: KeywordSelect :exec +SELECT sqlc.arg('select')::text; + +-- name: KeywordCase :exec +SELECT sqlc.arg('case')::text; + +-- name: KeywordDefer :exec +SELECT sqlc.arg('defer')::text; + +-- name: KeywordGo :exec +SELECT sqlc.arg('go')::text; + +-- name: KeywordMap :exec +SELECT sqlc.arg('map')::text; + +-- name: KeywordStruct :exec +SELECT sqlc.arg('struct')::text; + +-- name: KeywordChan :exec +SELECT sqlc.arg('chan')::text; + +-- name: KeywordElse :exec +SELECT sqlc.arg('else')::text; + +-- name: KeywordGoto :exec +SELECT sqlc.arg('goto')::text; + +-- name: KeywordPackage :exec +SELECT sqlc.arg('package')::text; + +-- name: KeywordSwitch :exec +SELECT sqlc.arg('switch')::text; + +-- name: KeywordConst :exec +SELECT sqlc.arg('const')::text; + +-- name: KeywordFallthrough :exec +SELECT sqlc.arg('fallthrough')::text; + +-- name: KeywordIf :exec +SELECT sqlc.arg('if')::text; + +-- name: KeywordRange :exec +SELECT sqlc.arg('range')::text; + +-- name: KeywordType :exec +SELECT sqlc.arg('type')::text; + +-- name: KeywordContinue :exec +SELECT sqlc.arg('continue')::text; + +-- name: KeywordFor :exec +SELECT sqlc.arg('for')::text; + +-- name: KeywordImport :exec +SELECT sqlc.arg('import')::text; + +-- name: KeywordReturn :exec +SELECT sqlc.arg('return')::text; + +-- name: KeywordVar :exec +SELECT sqlc.arg('var')::text; + +-- name: KeywordQ :exec +SELECT sqlc.arg('q')::text; + +-- name: SelectBreak :one +SELECT "break" FROM go_keywords; + +-- name: SelectDefault :one +SELECT "default" FROM go_keywords; + +-- name: SelectFunc :one +SELECT "func" FROM go_keywords; + +-- name: SelectInterface :one +SELECT "interface" FROM go_keywords; + +-- name: SelectSelect :one +SELECT "select" FROM go_keywords; + +-- name: SelectCase :one +SELECT "case" FROM go_keywords; + +-- name: SelectDefer :one +SELECT "defer" FROM go_keywords; + +-- name: SelectGo :one +SELECT "go" FROM go_keywords; + +-- name: SelectMap :one +SELECT "map" FROM go_keywords; + +-- name: SelectStruct :one +SELECT "struct" FROM go_keywords; + +-- name: SelectChan :one +SELECT "chan" FROM go_keywords; + +-- name: SelectElse :one +SELECT "else" FROM go_keywords; + +-- name: SelectGoto :one +SELECT "goto" FROM go_keywords; + +-- name: SelectPackage :one +SELECT "package" FROM go_keywords; + +-- name: SelectSwitch :one +SELECT "switch" FROM go_keywords; + +-- name: SelectConst :one +SELECT "const" FROM go_keywords; + +-- name: SelectFallthrough :one +SELECT "fallthrough" FROM go_keywords; + +-- name: SelectIf :one +SELECT "if" FROM go_keywords; + +-- name: SelectRange :one +SELECT "range" FROM go_keywords; + +-- name: SelectType :one +SELECT "type" FROM go_keywords; + +-- name: SelectContinue :one +SELECT "continue" FROM go_keywords; + +-- name: SelectFor :one +SELECT "for" FROM go_keywords; + +-- name: SelectImport :one +SELECT "import" FROM go_keywords; + +-- name: SelectReturn :one +SELECT "return" FROM go_keywords; + +-- name: SelectVar :one +SELECT "var" FROM go_keywords; + +-- name: SelectQ :one +SELECT "q" FROM go_keywords; diff --git a/internal/endtoend/testdata/params_go_keywords/postgresql/schema.sql b/internal/endtoend/testdata/params_go_keywords/postgresql/schema.sql new file mode 100644 index 0000000..100be50 --- /dev/null +++ b/internal/endtoend/testdata/params_go_keywords/postgresql/schema.sql @@ -0,0 +1,28 @@ +CREATE TABLE go_keywords ( + "break" TEXT, + "default" TEXT, + "func" TEXT, + "interface" TEXT, + "select" TEXT, + "case" TEXT, + "defer" TEXT, + "go" TEXT, + "map" TEXT, + "struct" TEXT, + "chan" TEXT, + "else" TEXT, + "goto" TEXT, + "package" TEXT, + "switch" TEXT, + "const" TEXT, + "fallthrough" TEXT, + "if" TEXT, + "range" TEXT, + "type" TEXT, + "continue" TEXT, + "for" TEXT, + "import" TEXT, + "return" TEXT, + "var" TEXT, + "q" TEXT +); diff --git a/internal/endtoend/testdata/params_go_keywords/postgresql/sqlc.yaml b/internal/endtoend/testdata/params_go_keywords/postgresql/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/params_go_keywords/postgresql/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/params_in_nested_func/mysql/db/db.go b/internal/endtoend/testdata/params_in_nested_func/mysql/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/params_in_nested_func/mysql/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/params_in_nested_func/mysql/db/models.go b/internal/endtoend/testdata/params_in_nested_func/mysql/db/models.go new file mode 100644 index 0000000..5028056 --- /dev/null +++ b/internal/endtoend/testdata/params_in_nested_func/mysql/db/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "database/sql" +) + +type Routergroup struct { + Groupid uint32 + Groupname string + Defaultconfigid sql.NullInt32 + Defaultfirmwareversion sql.NullString + Parentgroupid sql.NullInt32 + Firmwarepolicy sql.NullString + Styles sql.NullString +} diff --git a/internal/endtoend/testdata/params_in_nested_func/mysql/db/query.sql.go b/internal/endtoend/testdata/params_in_nested_func/mysql/db/query.sql.go new file mode 100644 index 0000000..9cdd1a5 --- /dev/null +++ b/internal/endtoend/testdata/params_in_nested_func/mysql/db/query.sql.go @@ -0,0 +1,55 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" + "database/sql" +) + +const getGroups = `-- name: GetGroups :many +SELECT + rg.groupId, + rg.groupName +FROM + RouterGroup rg +WHERE + rg.groupName LIKE CONCAT('%', COALESCE(?, rg.groupName), '%') AND + rg.groupId = COALESCE(?, rg.groupId) +` + +type GetGroupsParams struct { + GroupName any + GroupId sql.NullInt32 +} + +type GetGroupsRow struct { + Groupid uint32 + Groupname string +} + +func (q *Queries) GetGroups(ctx context.Context, arg GetGroupsParams) ([]GetGroupsRow, error) { + rows, err := q.db.QueryContext(ctx, getGroups, arg.GroupName, arg.GroupId) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetGroupsRow + for rows.Next() { + var i GetGroupsRow + if err := rows.Scan(&i.Groupid, &i.Groupname); 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/params_in_nested_func/mysql/query.sql b/internal/endtoend/testdata/params_in_nested_func/mysql/query.sql new file mode 100644 index 0000000..8a2a78f --- /dev/null +++ b/internal/endtoend/testdata/params_in_nested_func/mysql/query.sql @@ -0,0 +1,9 @@ +-- name: GetGroups :many +SELECT + rg.groupId, + rg.groupName +FROM + RouterGroup rg +WHERE + rg.groupName LIKE CONCAT('%', COALESCE(sqlc.narg('groupName'), rg.groupName), '%') AND + rg.groupId = COALESCE(sqlc.narg('groupId'), rg.groupId); diff --git a/internal/endtoend/testdata/params_in_nested_func/mysql/schema.sql b/internal/endtoend/testdata/params_in_nested_func/mysql/schema.sql new file mode 100644 index 0000000..12e0fb3 --- /dev/null +++ b/internal/endtoend/testdata/params_in_nested_func/mysql/schema.sql @@ -0,0 +1,10 @@ +create table RouterGroup +( + groupId int unsigned auto_increment primary key, + groupName varchar(100) not null, + defaultConfigId int unsigned null, + defaultFirmwareVersion varchar(12) null, + parentGroupId int unsigned null, + firmwarePolicy varchar(45) null, + styles text null +); diff --git a/internal/endtoend/testdata/params_in_nested_func/mysql/sqlc.yaml b/internal/endtoend/testdata/params_in_nested_func/mysql/sqlc.yaml new file mode 100644 index 0000000..e8b45d3 --- /dev/null +++ b/internal/endtoend/testdata/params_in_nested_func/mysql/sqlc.yaml @@ -0,0 +1,8 @@ +version: '2' +sql: +- schema: schema.sql + queries: query.sql + engine: mysql + gen: + go: + out: db diff --git a/internal/endtoend/testdata/params_in_nested_func/postgresql/db/db.go b/internal/endtoend/testdata/params_in_nested_func/postgresql/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/params_in_nested_func/postgresql/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/params_in_nested_func/postgresql/db/models.go b/internal/endtoend/testdata/params_in_nested_func/postgresql/db/models.go new file mode 100644 index 0000000..2c8d1b7 --- /dev/null +++ b/internal/endtoend/testdata/params_in_nested_func/postgresql/db/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "database/sql" +) + +type Routergroup struct { + Groupid int32 + Groupname string + Defaultconfigid sql.NullInt32 + Defaultfirmwareversion sql.NullString + Parentgroupid sql.NullInt32 + Firmwarepolicy sql.NullString + Styles sql.NullString +} diff --git a/internal/endtoend/testdata/params_in_nested_func/postgresql/db/query.sql.go b/internal/endtoend/testdata/params_in_nested_func/postgresql/db/query.sql.go new file mode 100644 index 0000000..695d59f --- /dev/null +++ b/internal/endtoend/testdata/params_in_nested_func/postgresql/db/query.sql.go @@ -0,0 +1,55 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" + "database/sql" +) + +const getGroups = `-- name: GetGroups :many +SELECT + rg.groupId, + rg.groupName +FROM + RouterGroup rg +WHERE + rg.groupName LIKE CONCAT('%', COALESCE($1::text, rg.groupName), '%') AND + rg.groupId = COALESCE($2, rg.groupId) +` + +type GetGroupsParams struct { + GroupName sql.NullString + GroupId sql.NullInt32 +} + +type GetGroupsRow struct { + Groupid int32 + Groupname string +} + +func (q *Queries) GetGroups(ctx context.Context, arg GetGroupsParams) ([]GetGroupsRow, error) { + rows, err := q.db.QueryContext(ctx, getGroups, arg.GroupName, arg.GroupId) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetGroupsRow + for rows.Next() { + var i GetGroupsRow + if err := rows.Scan(&i.Groupid, &i.Groupname); 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/params_in_nested_func/postgresql/query.sql b/internal/endtoend/testdata/params_in_nested_func/postgresql/query.sql new file mode 100644 index 0000000..7732269 --- /dev/null +++ b/internal/endtoend/testdata/params_in_nested_func/postgresql/query.sql @@ -0,0 +1,9 @@ +-- name: GetGroups :many +SELECT + rg.groupId, + rg.groupName +FROM + RouterGroup rg +WHERE + rg.groupName LIKE CONCAT('%', COALESCE(sqlc.narg('groupName')::text, rg.groupName), '%') AND + rg.groupId = COALESCE(sqlc.narg('groupId'), rg.groupId); diff --git a/internal/endtoend/testdata/params_in_nested_func/postgresql/schema.sql b/internal/endtoend/testdata/params_in_nested_func/postgresql/schema.sql new file mode 100644 index 0000000..66cfd02 --- /dev/null +++ b/internal/endtoend/testdata/params_in_nested_func/postgresql/schema.sql @@ -0,0 +1,10 @@ +create table RouterGroup +( + groupId serial primary key, + groupName varchar(100) not null, + defaultConfigId int null, + defaultFirmwareVersion varchar(12) null, + parentGroupId int null, + firmwarePolicy varchar(45) null, + styles text null +); diff --git a/internal/endtoend/testdata/params_in_nested_func/postgresql/sqlc.yaml b/internal/endtoend/testdata/params_in_nested_func/postgresql/sqlc.yaml new file mode 100644 index 0000000..936b017 --- /dev/null +++ b/internal/endtoend/testdata/params_in_nested_func/postgresql/sqlc.yaml @@ -0,0 +1,8 @@ +version: '2' +sql: +- schema: schema.sql + queries: query.sql + engine: postgresql + gen: + go: + out: db diff --git a/internal/endtoend/testdata/params_location/mysql/go/db.go b/internal/endtoend/testdata/params_location/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/params_location/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/params_location/mysql/go/models.go b/internal/endtoend/testdata/params_location/mysql/go/models.go new file mode 100644 index 0000000..eee0c6d --- /dev/null +++ b/internal/endtoend/testdata/params_location/mysql/go/models.go @@ -0,0 +1,23 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Order struct { + ID int32 + Price string + UserID int32 +} + +type User struct { + ID int32 + FirstName string + LastName sql.NullString + Age int32 + JobStatus string +} diff --git a/internal/endtoend/testdata/params_location/mysql/go/query.sql.go b/internal/endtoend/testdata/params_location/mysql/go/query.sql.go new file mode 100644 index 0000000..9449c9d --- /dev/null +++ b/internal/endtoend/testdata/params_location/mysql/go/query.sql.go @@ -0,0 +1,257 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const getUserByID = `-- name: GetUserByID :one +SELECT first_name, id, last_name FROM users WHERE id = ? +` + +type GetUserByIDRow struct { + FirstName string + ID int32 + LastName sql.NullString +} + +func (q *Queries) GetUserByID(ctx context.Context, targetID int32) (GetUserByIDRow, error) { + row := q.db.QueryRowContext(ctx, getUserByID, targetID) + var i GetUserByIDRow + err := row.Scan(&i.FirstName, &i.ID, &i.LastName) + return i, err +} + +const insertNewUser = `-- name: InsertNewUser :exec +INSERT INTO users (first_name, last_name) VALUES (?, ?) +` + +type InsertNewUserParams struct { + FirstName string + LastName sql.NullString +} + +func (q *Queries) InsertNewUser(ctx context.Context, arg InsertNewUserParams) error { + _, err := q.db.ExecContext(ctx, insertNewUser, arg.FirstName, arg.LastName) + return err +} + +const limitSQLCArg = `-- name: LimitSQLCArg :many +select first_name, id FROM users LIMIT ? +` + +type LimitSQLCArgRow struct { + FirstName string + ID int32 +} + +func (q *Queries) LimitSQLCArg(ctx context.Context, limit int32) ([]LimitSQLCArgRow, error) { + rows, err := q.db.QueryContext(ctx, limitSQLCArg, limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []LimitSQLCArgRow + for rows.Next() { + var i LimitSQLCArgRow + if err := rows.Scan(&i.FirstName, &i.ID); 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 listUserOrders = `-- name: ListUserOrders :many +SELECT + users.id, + users.first_name, + orders.price +FROM + orders +LEFT JOIN users ON orders.user_id = users.id +WHERE orders.price > ? +` + +type ListUserOrdersRow struct { + ID sql.NullInt32 + FirstName sql.NullString + Price string +} + +func (q *Queries) ListUserOrders(ctx context.Context, minPrice string) ([]ListUserOrdersRow, error) { + rows, err := q.db.QueryContext(ctx, listUserOrders, minPrice) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUserOrdersRow + for rows.Next() { + var i ListUserOrdersRow + if err := rows.Scan(&i.ID, &i.FirstName, &i.Price); 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 listUserParenExpr = `-- name: ListUserParenExpr :many +SELECT id, first_name, last_name, age, job_status FROM users WHERE (job_status = 'APPLIED' OR job_status = 'PENDING') +AND id > ? +ORDER BY id +LIMIT ? +` + +type ListUserParenExprParams struct { + ID int32 + Limit int32 +} + +func (q *Queries) ListUserParenExpr(ctx context.Context, arg ListUserParenExprParams) ([]User, error) { + rows, err := q.db.QueryContext(ctx, listUserParenExpr, arg.ID, arg.Limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + &i.JobStatus, + ); 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 listUsersByFamily = `-- name: ListUsersByFamily :many +SELECT first_name, last_name FROM users WHERE age < ? AND last_name = ? +` + +type ListUsersByFamilyParams struct { + MaxAge int32 + InFamily sql.NullString +} + +type ListUsersByFamilyRow struct { + FirstName string + LastName sql.NullString +} + +func (q *Queries) ListUsersByFamily(ctx context.Context, arg ListUsersByFamilyParams) ([]ListUsersByFamilyRow, error) { + rows, err := q.db.QueryContext(ctx, listUsersByFamily, arg.MaxAge, arg.InFamily) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUsersByFamilyRow + for rows.Next() { + var i ListUsersByFamilyRow + if err := rows.Scan(&i.FirstName, &i.LastName); 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 listUsersByID = `-- name: ListUsersByID :many +SELECT first_name, id, last_name FROM users WHERE id < ? +` + +type ListUsersByIDRow struct { + FirstName string + ID int32 + LastName sql.NullString +} + +func (q *Queries) ListUsersByID(ctx context.Context, id int32) ([]ListUsersByIDRow, error) { + rows, err := q.db.QueryContext(ctx, listUsersByID, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUsersByIDRow + for rows.Next() { + var i ListUsersByIDRow + if err := rows.Scan(&i.FirstName, &i.ID, &i.LastName); 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 listUsersWithLimit = `-- name: ListUsersWithLimit :many +SELECT first_name, last_name FROM users LIMIT ? +` + +type ListUsersWithLimitRow struct { + FirstName string + LastName sql.NullString +} + +func (q *Queries) ListUsersWithLimit(ctx context.Context, limit int32) ([]ListUsersWithLimitRow, error) { + rows, err := q.db.QueryContext(ctx, listUsersWithLimit, limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUsersWithLimitRow + for rows.Next() { + var i ListUsersWithLimitRow + if err := rows.Scan(&i.FirstName, &i.LastName); 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/params_location/mysql/query.sql b/internal/endtoend/testdata/params_location/mysql/query.sql new file mode 100644 index 0000000..cfa804c --- /dev/null +++ b/internal/endtoend/testdata/params_location/mysql/query.sql @@ -0,0 +1,33 @@ +/* name: ListUsersByID :many */ +SELECT first_name, id, last_name FROM users WHERE id < ?; + +/* name: ListUserOrders :many */ +SELECT + users.id, + users.first_name, + orders.price +FROM + orders +LEFT JOIN users ON orders.user_id = users.id +WHERE orders.price > sqlc.arg('min_price'); + +/* name: GetUserByID :one */ +SELECT first_name, id, last_name FROM users WHERE id = sqlc.arg('target_id'); + +/* name: ListUsersByFamily :many */ +SELECT first_name, last_name FROM users WHERE age < sqlc.arg('max_age') AND last_name = sqlc.arg('in_family'); + +/* name: ListUsersWithLimit :many */ +SELECT first_name, last_name FROM users LIMIT ?; + +/* name: LimitSQLCArg :many */ +select first_name, id FROM users LIMIT ?; + +/* name: InsertNewUser :exec */ +INSERT INTO users (first_name, last_name) VALUES (?, ?); + +/* name: ListUserParenExpr :many */ +SELECT * FROM users WHERE (job_status = 'APPLIED' OR job_status = 'PENDING') +AND id > ? +ORDER BY id +LIMIT ?; diff --git a/internal/endtoend/testdata/params_location/mysql/schema.sql b/internal/endtoend/testdata/params_location/mysql/schema.sql new file mode 100644 index 0000000..5df4b6c --- /dev/null +++ b/internal/endtoend/testdata/params_location/mysql/schema.sql @@ -0,0 +1,14 @@ +CREATE TABLE users ( + id integer NOT NULL AUTO_INCREMENT PRIMARY KEY, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL, + job_status varchar(10) NOT NULL +) ENGINE=InnoDB; + +CREATE TABLE orders ( + id integer NOT NULL AUTO_INCREMENT PRIMARY KEY, + price DECIMAL(13, 4) NOT NULL, + user_id integer NOT NULL +) ENGINE=InnoDB; + diff --git a/internal/endtoend/testdata/params_location/mysql/sqlc.json b/internal/endtoend/testdata/params_location/mysql/sqlc.json new file mode 100644 index 0000000..a9e7b05 --- /dev/null +++ b/internal/endtoend/testdata/params_location/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "schema.sql", + "queries": "query.sql", + "engine": "mysql" + } + ] +} diff --git a/internal/endtoend/testdata/params_location/postgresql/pgx/v4/exec.json b/internal/endtoend/testdata/params_location/postgresql/pgx/v4/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/params_location/postgresql/pgx/v4/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/params_location/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/params_location/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/params_location/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/params_location/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/params_location/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..20494b0 --- /dev/null +++ b/internal/endtoend/testdata/params_location/postgresql/pgx/v4/go/models.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + + "github.com/jackc/pgtype" +) + +type Order struct { + ID int32 + Price pgtype.Numeric + UserID int32 +} + +type User struct { + ID int32 + FirstName string + LastName sql.NullString + Age int32 + JobStatus string +} diff --git a/internal/endtoend/testdata/params_location/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/params_location/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..01addb8 --- /dev/null +++ b/internal/endtoend/testdata/params_location/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,241 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" + + "github.com/jackc/pgtype" +) + +const getUserByID = `-- name: GetUserByID :one +SELECT first_name, id, last_name FROM users WHERE id = $1 +` + +type GetUserByIDRow struct { + FirstName string + ID int32 + LastName sql.NullString +} + +func (q *Queries) GetUserByID(ctx context.Context, targetID int32) (GetUserByIDRow, error) { + row := q.db.QueryRow(ctx, getUserByID, targetID) + var i GetUserByIDRow + err := row.Scan(&i.FirstName, &i.ID, &i.LastName) + return i, err +} + +const insertNewUser = `-- name: InsertNewUser :exec +INSERT INTO users (first_name, last_name) VALUES ($1, $2) +` + +type InsertNewUserParams struct { + FirstName string + LastName sql.NullString +} + +func (q *Queries) InsertNewUser(ctx context.Context, arg InsertNewUserParams) error { + _, err := q.db.Exec(ctx, insertNewUser, arg.FirstName, arg.LastName) + return err +} + +const limitSQLCArg = `-- name: LimitSQLCArg :many +select first_name, id FROM users LIMIT $1 +` + +type LimitSQLCArgRow struct { + FirstName string + ID int32 +} + +func (q *Queries) LimitSQLCArg(ctx context.Context, limit int32) ([]LimitSQLCArgRow, error) { + rows, err := q.db.Query(ctx, limitSQLCArg, limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []LimitSQLCArgRow + for rows.Next() { + var i LimitSQLCArgRow + if err := rows.Scan(&i.FirstName, &i.ID); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listUserOrders = `-- name: ListUserOrders :many +SELECT + users.id, + users.first_name, + orders.price +FROM + orders +LEFT JOIN users ON orders.user_id = users.id +WHERE orders.price > $1 +` + +type ListUserOrdersRow struct { + ID sql.NullInt32 + FirstName sql.NullString + Price pgtype.Numeric +} + +func (q *Queries) ListUserOrders(ctx context.Context, minPrice pgtype.Numeric) ([]ListUserOrdersRow, error) { + rows, err := q.db.Query(ctx, listUserOrders, minPrice) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUserOrdersRow + for rows.Next() { + var i ListUserOrdersRow + if err := rows.Scan(&i.ID, &i.FirstName, &i.Price); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listUserParenExpr = `-- name: ListUserParenExpr :many +SELECT id, first_name, last_name, age, job_status FROM users WHERE (job_status = 'APPLIED' OR job_status = 'PENDING') +AND id > $1 +ORDER BY id +LIMIT $2 +` + +type ListUserParenExprParams struct { + ID int32 + Limit int32 +} + +func (q *Queries) ListUserParenExpr(ctx context.Context, arg ListUserParenExprParams) ([]User, error) { + rows, err := q.db.Query(ctx, listUserParenExpr, arg.ID, arg.Limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + &i.JobStatus, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listUsersByFamily = `-- name: ListUsersByFamily :many +SELECT first_name, last_name FROM users WHERE age < $1 AND last_name = $2 +` + +type ListUsersByFamilyParams struct { + MaxAge int32 + InFamily sql.NullString +} + +type ListUsersByFamilyRow struct { + FirstName string + LastName sql.NullString +} + +func (q *Queries) ListUsersByFamily(ctx context.Context, arg ListUsersByFamilyParams) ([]ListUsersByFamilyRow, error) { + rows, err := q.db.Query(ctx, listUsersByFamily, arg.MaxAge, arg.InFamily) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUsersByFamilyRow + for rows.Next() { + var i ListUsersByFamilyRow + if err := rows.Scan(&i.FirstName, &i.LastName); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listUsersByID = `-- name: ListUsersByID :many +SELECT first_name, id, last_name FROM users WHERE id < $1 +` + +type ListUsersByIDRow struct { + FirstName string + ID int32 + LastName sql.NullString +} + +func (q *Queries) ListUsersByID(ctx context.Context, id int32) ([]ListUsersByIDRow, error) { + rows, err := q.db.Query(ctx, listUsersByID, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUsersByIDRow + for rows.Next() { + var i ListUsersByIDRow + if err := rows.Scan(&i.FirstName, &i.ID, &i.LastName); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listUsersWithLimit = `-- name: ListUsersWithLimit :many +SELECT first_name, last_name FROM users LIMIT $1 +` + +type ListUsersWithLimitRow struct { + FirstName string + LastName sql.NullString +} + +func (q *Queries) ListUsersWithLimit(ctx context.Context, limit int32) ([]ListUsersWithLimitRow, error) { + rows, err := q.db.Query(ctx, listUsersWithLimit, limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUsersWithLimitRow + for rows.Next() { + var i ListUsersWithLimitRow + if err := rows.Scan(&i.FirstName, &i.LastName); 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/params_location/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/params_location/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..7f973bf --- /dev/null +++ b/internal/endtoend/testdata/params_location/postgresql/pgx/v4/query.sql @@ -0,0 +1,33 @@ +/* name: ListUsersByID :many */ +SELECT first_name, id, last_name FROM users WHERE id < $1; + +/* name: ListUserOrders :many */ +SELECT + users.id, + users.first_name, + orders.price +FROM + orders +LEFT JOIN users ON orders.user_id = users.id +WHERE orders.price > sqlc.arg('min_price'); + +/* name: GetUserByID :one */ +SELECT first_name, id, last_name FROM users WHERE id = sqlc.arg('target_id'); + +/* name: ListUsersByFamily :many */ +SELECT first_name, last_name FROM users WHERE age < sqlc.arg('max_age') AND last_name = sqlc.arg('in_family'); + +/* name: ListUsersWithLimit :many */ +SELECT first_name, last_name FROM users LIMIT $1; + +/* name: LimitSQLCArg :many */ +select first_name, id FROM users LIMIT $1; + +/* name: InsertNewUser :exec */ +INSERT INTO users (first_name, last_name) VALUES ($1, $2); + +/* name: ListUserParenExpr :many */ +SELECT * FROM users WHERE (job_status = 'APPLIED' OR job_status = 'PENDING') +AND id > $1 +ORDER BY id +LIMIT $2; diff --git a/internal/endtoend/testdata/params_location/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/params_location/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..a150e2a --- /dev/null +++ b/internal/endtoend/testdata/params_location/postgresql/pgx/v4/schema.sql @@ -0,0 +1,14 @@ +CREATE TABLE users ( + id SERIAL NOT NULL, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL, + job_status varchar(10) NOT NULL +); + +CREATE TABLE orders ( + id SERIAL NOT NULL, + price DECIMAL(13, 4) NOT NULL, + user_id integer NOT NULL +); + diff --git a/internal/endtoend/testdata/params_location/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/params_location/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/params_location/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/params_location/postgresql/pgx/v5/exec.json b/internal/endtoend/testdata/params_location/postgresql/pgx/v5/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/params_location/postgresql/pgx/v5/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/params_location/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/params_location/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/params_location/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/params_location/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/params_location/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..e2a0512 --- /dev/null +++ b/internal/endtoend/testdata/params_location/postgresql/pgx/v5/go/models.go @@ -0,0 +1,23 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Order struct { + ID int32 + Price pgtype.Numeric + UserID int32 +} + +type User struct { + ID int32 + FirstName string + LastName pgtype.Text + Age int32 + JobStatus string +} diff --git a/internal/endtoend/testdata/params_location/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/params_location/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..7eeb1ff --- /dev/null +++ b/internal/endtoend/testdata/params_location/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,240 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const getUserByID = `-- name: GetUserByID :one +SELECT first_name, id, last_name FROM users WHERE id = $1 +` + +type GetUserByIDRow struct { + FirstName string + ID int32 + LastName pgtype.Text +} + +func (q *Queries) GetUserByID(ctx context.Context, targetID int32) (GetUserByIDRow, error) { + row := q.db.QueryRow(ctx, getUserByID, targetID) + var i GetUserByIDRow + err := row.Scan(&i.FirstName, &i.ID, &i.LastName) + return i, err +} + +const insertNewUser = `-- name: InsertNewUser :exec +INSERT INTO users (first_name, last_name) VALUES ($1, $2) +` + +type InsertNewUserParams struct { + FirstName string + LastName pgtype.Text +} + +func (q *Queries) InsertNewUser(ctx context.Context, arg InsertNewUserParams) error { + _, err := q.db.Exec(ctx, insertNewUser, arg.FirstName, arg.LastName) + return err +} + +const limitSQLCArg = `-- name: LimitSQLCArg :many +select first_name, id FROM users LIMIT $1 +` + +type LimitSQLCArgRow struct { + FirstName string + ID int32 +} + +func (q *Queries) LimitSQLCArg(ctx context.Context, limit int32) ([]LimitSQLCArgRow, error) { + rows, err := q.db.Query(ctx, limitSQLCArg, limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []LimitSQLCArgRow + for rows.Next() { + var i LimitSQLCArgRow + if err := rows.Scan(&i.FirstName, &i.ID); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listUserOrders = `-- name: ListUserOrders :many +SELECT + users.id, + users.first_name, + orders.price +FROM + orders +LEFT JOIN users ON orders.user_id = users.id +WHERE orders.price > $1 +` + +type ListUserOrdersRow struct { + ID pgtype.Int4 + FirstName pgtype.Text + Price pgtype.Numeric +} + +func (q *Queries) ListUserOrders(ctx context.Context, minPrice pgtype.Numeric) ([]ListUserOrdersRow, error) { + rows, err := q.db.Query(ctx, listUserOrders, minPrice) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUserOrdersRow + for rows.Next() { + var i ListUserOrdersRow + if err := rows.Scan(&i.ID, &i.FirstName, &i.Price); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listUserParenExpr = `-- name: ListUserParenExpr :many +SELECT id, first_name, last_name, age, job_status FROM users WHERE (job_status = 'APPLIED' OR job_status = 'PENDING') +AND id > $1 +ORDER BY id +LIMIT $2 +` + +type ListUserParenExprParams struct { + ID int32 + Limit int32 +} + +func (q *Queries) ListUserParenExpr(ctx context.Context, arg ListUserParenExprParams) ([]User, error) { + rows, err := q.db.Query(ctx, listUserParenExpr, arg.ID, arg.Limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + &i.JobStatus, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listUsersByFamily = `-- name: ListUsersByFamily :many +SELECT first_name, last_name FROM users WHERE age < $1 AND last_name = $2 +` + +type ListUsersByFamilyParams struct { + MaxAge int32 + InFamily pgtype.Text +} + +type ListUsersByFamilyRow struct { + FirstName string + LastName pgtype.Text +} + +func (q *Queries) ListUsersByFamily(ctx context.Context, arg ListUsersByFamilyParams) ([]ListUsersByFamilyRow, error) { + rows, err := q.db.Query(ctx, listUsersByFamily, arg.MaxAge, arg.InFamily) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUsersByFamilyRow + for rows.Next() { + var i ListUsersByFamilyRow + if err := rows.Scan(&i.FirstName, &i.LastName); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listUsersByID = `-- name: ListUsersByID :many +SELECT first_name, id, last_name FROM users WHERE id < $1 +` + +type ListUsersByIDRow struct { + FirstName string + ID int32 + LastName pgtype.Text +} + +func (q *Queries) ListUsersByID(ctx context.Context, id int32) ([]ListUsersByIDRow, error) { + rows, err := q.db.Query(ctx, listUsersByID, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUsersByIDRow + for rows.Next() { + var i ListUsersByIDRow + if err := rows.Scan(&i.FirstName, &i.ID, &i.LastName); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listUsersWithLimit = `-- name: ListUsersWithLimit :many +SELECT first_name, last_name FROM users LIMIT $1 +` + +type ListUsersWithLimitRow struct { + FirstName string + LastName pgtype.Text +} + +func (q *Queries) ListUsersWithLimit(ctx context.Context, limit int32) ([]ListUsersWithLimitRow, error) { + rows, err := q.db.Query(ctx, listUsersWithLimit, limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUsersWithLimitRow + for rows.Next() { + var i ListUsersWithLimitRow + if err := rows.Scan(&i.FirstName, &i.LastName); 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/params_location/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/params_location/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..7f973bf --- /dev/null +++ b/internal/endtoend/testdata/params_location/postgresql/pgx/v5/query.sql @@ -0,0 +1,33 @@ +/* name: ListUsersByID :many */ +SELECT first_name, id, last_name FROM users WHERE id < $1; + +/* name: ListUserOrders :many */ +SELECT + users.id, + users.first_name, + orders.price +FROM + orders +LEFT JOIN users ON orders.user_id = users.id +WHERE orders.price > sqlc.arg('min_price'); + +/* name: GetUserByID :one */ +SELECT first_name, id, last_name FROM users WHERE id = sqlc.arg('target_id'); + +/* name: ListUsersByFamily :many */ +SELECT first_name, last_name FROM users WHERE age < sqlc.arg('max_age') AND last_name = sqlc.arg('in_family'); + +/* name: ListUsersWithLimit :many */ +SELECT first_name, last_name FROM users LIMIT $1; + +/* name: LimitSQLCArg :many */ +select first_name, id FROM users LIMIT $1; + +/* name: InsertNewUser :exec */ +INSERT INTO users (first_name, last_name) VALUES ($1, $2); + +/* name: ListUserParenExpr :many */ +SELECT * FROM users WHERE (job_status = 'APPLIED' OR job_status = 'PENDING') +AND id > $1 +ORDER BY id +LIMIT $2; diff --git a/internal/endtoend/testdata/params_location/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/params_location/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..a150e2a --- /dev/null +++ b/internal/endtoend/testdata/params_location/postgresql/pgx/v5/schema.sql @@ -0,0 +1,14 @@ +CREATE TABLE users ( + id SERIAL NOT NULL, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL, + job_status varchar(10) NOT NULL +); + +CREATE TABLE orders ( + id SERIAL NOT NULL, + price DECIMAL(13, 4) NOT NULL, + user_id integer NOT NULL +); + diff --git a/internal/endtoend/testdata/params_location/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/params_location/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/params_location/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/params_location/postgresql/stdlib/exec.json b/internal/endtoend/testdata/params_location/postgresql/stdlib/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/params_location/postgresql/stdlib/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/params_location/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/params_location/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/params_location/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/params_location/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/params_location/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..eee0c6d --- /dev/null +++ b/internal/endtoend/testdata/params_location/postgresql/stdlib/go/models.go @@ -0,0 +1,23 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Order struct { + ID int32 + Price string + UserID int32 +} + +type User struct { + ID int32 + FirstName string + LastName sql.NullString + Age int32 + JobStatus string +} diff --git a/internal/endtoend/testdata/params_location/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/params_location/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..d532e30 --- /dev/null +++ b/internal/endtoend/testdata/params_location/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,257 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const getUserByID = `-- name: GetUserByID :one +SELECT first_name, id, last_name FROM users WHERE id = $1 +` + +type GetUserByIDRow struct { + FirstName string + ID int32 + LastName sql.NullString +} + +func (q *Queries) GetUserByID(ctx context.Context, targetID int32) (GetUserByIDRow, error) { + row := q.db.QueryRowContext(ctx, getUserByID, targetID) + var i GetUserByIDRow + err := row.Scan(&i.FirstName, &i.ID, &i.LastName) + return i, err +} + +const insertNewUser = `-- name: InsertNewUser :exec +INSERT INTO users (first_name, last_name) VALUES ($1, $2) +` + +type InsertNewUserParams struct { + FirstName string + LastName sql.NullString +} + +func (q *Queries) InsertNewUser(ctx context.Context, arg InsertNewUserParams) error { + _, err := q.db.ExecContext(ctx, insertNewUser, arg.FirstName, arg.LastName) + return err +} + +const limitSQLCArg = `-- name: LimitSQLCArg :many +select first_name, id FROM users LIMIT $1 +` + +type LimitSQLCArgRow struct { + FirstName string + ID int32 +} + +func (q *Queries) LimitSQLCArg(ctx context.Context, limit int32) ([]LimitSQLCArgRow, error) { + rows, err := q.db.QueryContext(ctx, limitSQLCArg, limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []LimitSQLCArgRow + for rows.Next() { + var i LimitSQLCArgRow + if err := rows.Scan(&i.FirstName, &i.ID); 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 listUserOrders = `-- name: ListUserOrders :many +SELECT + users.id, + users.first_name, + orders.price +FROM + orders +LEFT JOIN users ON orders.user_id = users.id +WHERE orders.price > $1 +` + +type ListUserOrdersRow struct { + ID sql.NullInt32 + FirstName sql.NullString + Price string +} + +func (q *Queries) ListUserOrders(ctx context.Context, minPrice string) ([]ListUserOrdersRow, error) { + rows, err := q.db.QueryContext(ctx, listUserOrders, minPrice) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUserOrdersRow + for rows.Next() { + var i ListUserOrdersRow + if err := rows.Scan(&i.ID, &i.FirstName, &i.Price); 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 listUserParenExpr = `-- name: ListUserParenExpr :many +SELECT id, first_name, last_name, age, job_status FROM users WHERE (job_status = 'APPLIED' OR job_status = 'PENDING') +AND id > $1 +ORDER BY id +LIMIT $2 +` + +type ListUserParenExprParams struct { + ID int32 + Limit int32 +} + +func (q *Queries) ListUserParenExpr(ctx context.Context, arg ListUserParenExprParams) ([]User, error) { + rows, err := q.db.QueryContext(ctx, listUserParenExpr, arg.ID, arg.Limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + &i.JobStatus, + ); 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 listUsersByFamily = `-- name: ListUsersByFamily :many +SELECT first_name, last_name FROM users WHERE age < $1 AND last_name = $2 +` + +type ListUsersByFamilyParams struct { + MaxAge int32 + InFamily sql.NullString +} + +type ListUsersByFamilyRow struct { + FirstName string + LastName sql.NullString +} + +func (q *Queries) ListUsersByFamily(ctx context.Context, arg ListUsersByFamilyParams) ([]ListUsersByFamilyRow, error) { + rows, err := q.db.QueryContext(ctx, listUsersByFamily, arg.MaxAge, arg.InFamily) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUsersByFamilyRow + for rows.Next() { + var i ListUsersByFamilyRow + if err := rows.Scan(&i.FirstName, &i.LastName); 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 listUsersByID = `-- name: ListUsersByID :many +SELECT first_name, id, last_name FROM users WHERE id < $1 +` + +type ListUsersByIDRow struct { + FirstName string + ID int32 + LastName sql.NullString +} + +func (q *Queries) ListUsersByID(ctx context.Context, id int32) ([]ListUsersByIDRow, error) { + rows, err := q.db.QueryContext(ctx, listUsersByID, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUsersByIDRow + for rows.Next() { + var i ListUsersByIDRow + if err := rows.Scan(&i.FirstName, &i.ID, &i.LastName); 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 listUsersWithLimit = `-- name: ListUsersWithLimit :many +SELECT first_name, last_name FROM users LIMIT $1 +` + +type ListUsersWithLimitRow struct { + FirstName string + LastName sql.NullString +} + +func (q *Queries) ListUsersWithLimit(ctx context.Context, limit int32) ([]ListUsersWithLimitRow, error) { + rows, err := q.db.QueryContext(ctx, listUsersWithLimit, limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUsersWithLimitRow + for rows.Next() { + var i ListUsersWithLimitRow + if err := rows.Scan(&i.FirstName, &i.LastName); 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/params_location/postgresql/stdlib/query.sql b/internal/endtoend/testdata/params_location/postgresql/stdlib/query.sql new file mode 100644 index 0000000..7f973bf --- /dev/null +++ b/internal/endtoend/testdata/params_location/postgresql/stdlib/query.sql @@ -0,0 +1,33 @@ +/* name: ListUsersByID :many */ +SELECT first_name, id, last_name FROM users WHERE id < $1; + +/* name: ListUserOrders :many */ +SELECT + users.id, + users.first_name, + orders.price +FROM + orders +LEFT JOIN users ON orders.user_id = users.id +WHERE orders.price > sqlc.arg('min_price'); + +/* name: GetUserByID :one */ +SELECT first_name, id, last_name FROM users WHERE id = sqlc.arg('target_id'); + +/* name: ListUsersByFamily :many */ +SELECT first_name, last_name FROM users WHERE age < sqlc.arg('max_age') AND last_name = sqlc.arg('in_family'); + +/* name: ListUsersWithLimit :many */ +SELECT first_name, last_name FROM users LIMIT $1; + +/* name: LimitSQLCArg :many */ +select first_name, id FROM users LIMIT $1; + +/* name: InsertNewUser :exec */ +INSERT INTO users (first_name, last_name) VALUES ($1, $2); + +/* name: ListUserParenExpr :many */ +SELECT * FROM users WHERE (job_status = 'APPLIED' OR job_status = 'PENDING') +AND id > $1 +ORDER BY id +LIMIT $2; diff --git a/internal/endtoend/testdata/params_location/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/params_location/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..a150e2a --- /dev/null +++ b/internal/endtoend/testdata/params_location/postgresql/stdlib/schema.sql @@ -0,0 +1,14 @@ +CREATE TABLE users ( + id SERIAL NOT NULL, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL, + job_status varchar(10) NOT NULL +); + +CREATE TABLE orders ( + id SERIAL NOT NULL, + price DECIMAL(13, 4) NOT NULL, + user_id integer NOT NULL +); + diff --git a/internal/endtoend/testdata/params_location/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/params_location/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f5a835c --- /dev/null +++ b/internal/endtoend/testdata/params_location/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql" + } + ] +} diff --git a/internal/endtoend/testdata/params_placeholder_in_left_expr/mysql/go/db.go b/internal/endtoend/testdata/params_placeholder_in_left_expr/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/params_placeholder_in_left_expr/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/params_placeholder_in_left_expr/mysql/go/models.go b/internal/endtoend/testdata/params_placeholder_in_left_expr/mysql/go/models.go new file mode 100644 index 0000000..04930c9 --- /dev/null +++ b/internal/endtoend/testdata/params_placeholder_in_left_expr/mysql/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID int32 + Name sql.NullString +} diff --git a/internal/endtoend/testdata/params_placeholder_in_left_expr/mysql/go/query.sql.go b/internal/endtoend/testdata/params_placeholder_in_left_expr/mysql/go/query.sql.go new file mode 100644 index 0000000..76436e3 --- /dev/null +++ b/internal/endtoend/testdata/params_placeholder_in_left_expr/mysql/go/query.sql.go @@ -0,0 +1,70 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const findByID = `-- name: FindByID :many +SELECT id, name FROM users WHERE ? = id +` + +func (q *Queries) FindByID(ctx context.Context, id int32) ([]User, error) { + rows, err := q.db.QueryContext(ctx, findByID, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan(&i.ID, &i.Name); 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 findByIDAndName = `-- name: FindByIDAndName :many +SELECT id, name FROM users WHERE ? = id AND ? = name +` + +type FindByIDAndNameParams struct { + ID int32 + Name sql.NullString +} + +func (q *Queries) FindByIDAndName(ctx context.Context, arg FindByIDAndNameParams) ([]User, error) { + rows, err := q.db.QueryContext(ctx, findByIDAndName, arg.ID, arg.Name) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan(&i.ID, &i.Name); 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/params_placeholder_in_left_expr/mysql/query.sql b/internal/endtoend/testdata/params_placeholder_in_left_expr/mysql/query.sql new file mode 100644 index 0000000..e241f76 --- /dev/null +++ b/internal/endtoend/testdata/params_placeholder_in_left_expr/mysql/query.sql @@ -0,0 +1,5 @@ +-- name: FindByID :many +SELECT * FROM users WHERE ? = id; + +-- name: FindByIDAndName :many +SELECT * FROM users WHERE ? = id AND ? = name; diff --git a/internal/endtoend/testdata/params_placeholder_in_left_expr/mysql/schema.sql b/internal/endtoend/testdata/params_placeholder_in_left_expr/mysql/schema.sql new file mode 100644 index 0000000..b2c6d8d --- /dev/null +++ b/internal/endtoend/testdata/params_placeholder_in_left_expr/mysql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE users ( + id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) +) ENGINE=InnoDB; + diff --git a/internal/endtoend/testdata/params_placeholder_in_left_expr/mysql/sqlc.json b/internal/endtoend/testdata/params_placeholder_in_left_expr/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/params_placeholder_in_left_expr/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/params_placeholder_in_left_expr/postgresql/exec.json b/internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/go/db.go b/internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/params_placeholder_in_left_expr/postgresql/go/models.go b/internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/go/models.go new file mode 100644 index 0000000..04930c9 --- /dev/null +++ b/internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID int32 + Name sql.NullString +} diff --git a/internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/go/query.sql.go b/internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/go/query.sql.go new file mode 100644 index 0000000..f117fc9 --- /dev/null +++ b/internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/go/query.sql.go @@ -0,0 +1,64 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const findByID = `-- name: FindByID :many +SELECT id, name FROM users WHERE $1 = id +` + +func (q *Queries) FindByID(ctx context.Context, id int32) ([]User, error) { + rows, err := q.db.QueryContext(ctx, findByID, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan(&i.ID, &i.Name); 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 findByIDAndName = `-- name: FindByIDAndName :many +SELECT id, name FROM users WHERE $1 = id AND $1 = name +` + +func (q *Queries) FindByIDAndName(ctx context.Context, id int32) ([]User, error) { + rows, err := q.db.QueryContext(ctx, findByIDAndName, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan(&i.ID, &i.Name); 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/params_placeholder_in_left_expr/postgresql/query.sql b/internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/query.sql new file mode 100644 index 0000000..50b95ea --- /dev/null +++ b/internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/query.sql @@ -0,0 +1,5 @@ +-- name: FindByID :many +SELECT * FROM users WHERE $1 = id; + +-- name: FindByIDAndName :many +SELECT * FROM users WHERE $1 = id AND $1 = name; diff --git a/internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/schema.sql b/internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/schema.sql new file mode 100644 index 0000000..33ca489 --- /dev/null +++ b/internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE users ( + id INT PRIMARY KEY, + name VARCHAR(255) +); + diff --git a/internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/sqlc.json b/internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/params_placeholder_in_left_expr/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/params_two/mysql/go/db.go b/internal/endtoend/testdata/params_two/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/params_two/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/params_two/mysql/go/models.go b/internal/endtoend/testdata/params_two/mysql/go/models.go new file mode 100644 index 0000000..a26317d --- /dev/null +++ b/internal/endtoend/testdata/params_two/mysql/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString + B sql.NullString +} diff --git a/internal/endtoend/testdata/params_two/mysql/go/query.sql.go b/internal/endtoend/testdata/params_two/mysql/go/query.sql.go new file mode 100644 index 0000000..72a9991 --- /dev/null +++ b/internal/endtoend/testdata/params_two/mysql/go/query.sql.go @@ -0,0 +1,44 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const fooByAandB = `-- name: FooByAandB :many +SELECT a, b FROM foo +WHERE a = ? and b = ? +` + +type FooByAandBParams struct { + A sql.NullString + B sql.NullString +} + +func (q *Queries) FooByAandB(ctx context.Context, arg FooByAandBParams) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, fooByAandB, arg.A, arg.B) + 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/params_two/mysql/query.sql b/internal/endtoend/testdata/params_two/mysql/query.sql new file mode 100644 index 0000000..6693709 --- /dev/null +++ b/internal/endtoend/testdata/params_two/mysql/query.sql @@ -0,0 +1,3 @@ +/* name: FooByAandB :many */ +SELECT a, b FROM foo +WHERE a = ? and b = ?; diff --git a/internal/endtoend/testdata/params_two/mysql/schema.sql b/internal/endtoend/testdata/params_two/mysql/schema.sql new file mode 100644 index 0000000..a68a0e4 --- /dev/null +++ b/internal/endtoend/testdata/params_two/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b text); + diff --git a/internal/endtoend/testdata/params_two/mysql/sqlc.json b/internal/endtoend/testdata/params_two/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/params_two/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/params_two/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/params_two/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/params_two/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/params_two/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/params_two/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a26317d --- /dev/null +++ b/internal/endtoend/testdata/params_two/postgresql/pgx/v4/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString + B sql.NullString +} diff --git a/internal/endtoend/testdata/params_two/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/params_two/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8294904 --- /dev/null +++ b/internal/endtoend/testdata/params_two/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,41 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const fooByAandB = `-- name: FooByAandB :many +SELECT a, b FROM foo +WHERE a = $1 and b = $2 +` + +type FooByAandBParams struct { + A sql.NullString + B sql.NullString +} + +func (q *Queries) FooByAandB(ctx context.Context, arg FooByAandBParams) ([]Foo, error) { + rows, err := q.db.Query(ctx, fooByAandB, arg.A, arg.B) + 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/params_two/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/params_two/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..83fd1ea --- /dev/null +++ b/internal/endtoend/testdata/params_two/postgresql/pgx/v4/query.sql @@ -0,0 +1,3 @@ +-- name: FooByAandB :many +SELECT a, b FROM foo +WHERE a = $1 and b = $2; diff --git a/internal/endtoend/testdata/params_two/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/params_two/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..a68a0e4 --- /dev/null +++ b/internal/endtoend/testdata/params_two/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b text); + diff --git a/internal/endtoend/testdata/params_two/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/params_two/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/params_two/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/params_two/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/params_two/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/params_two/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/params_two/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/params_two/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..463744d --- /dev/null +++ b/internal/endtoend/testdata/params_two/postgresql/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + A pgtype.Text + B pgtype.Text +} diff --git a/internal/endtoend/testdata/params_two/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/params_two/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..870986a --- /dev/null +++ b/internal/endtoend/testdata/params_two/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const fooByAandB = `-- name: FooByAandB :many +SELECT a, b FROM foo +WHERE a = $1 and b = $2 +` + +type FooByAandBParams struct { + A pgtype.Text + B pgtype.Text +} + +func (q *Queries) FooByAandB(ctx context.Context, arg FooByAandBParams) ([]Foo, error) { + rows, err := q.db.Query(ctx, fooByAandB, arg.A, arg.B) + 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/params_two/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/params_two/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..83fd1ea --- /dev/null +++ b/internal/endtoend/testdata/params_two/postgresql/pgx/v5/query.sql @@ -0,0 +1,3 @@ +-- name: FooByAandB :many +SELECT a, b FROM foo +WHERE a = $1 and b = $2; diff --git a/internal/endtoend/testdata/params_two/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/params_two/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..a68a0e4 --- /dev/null +++ b/internal/endtoend/testdata/params_two/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b text); + diff --git a/internal/endtoend/testdata/params_two/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/params_two/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/params_two/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/params_two/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/params_two/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/params_two/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/params_two/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/params_two/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a26317d --- /dev/null +++ b/internal/endtoend/testdata/params_two/postgresql/stdlib/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString + B sql.NullString +} diff --git a/internal/endtoend/testdata/params_two/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/params_two/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..0db559a --- /dev/null +++ b/internal/endtoend/testdata/params_two/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,44 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const fooByAandB = `-- name: FooByAandB :many +SELECT a, b FROM foo +WHERE a = $1 and b = $2 +` + +type FooByAandBParams struct { + A sql.NullString + B sql.NullString +} + +func (q *Queries) FooByAandB(ctx context.Context, arg FooByAandBParams) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, fooByAandB, arg.A, arg.B) + 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/params_two/postgresql/stdlib/query.sql b/internal/endtoend/testdata/params_two/postgresql/stdlib/query.sql new file mode 100644 index 0000000..83fd1ea --- /dev/null +++ b/internal/endtoend/testdata/params_two/postgresql/stdlib/query.sql @@ -0,0 +1,3 @@ +-- name: FooByAandB :many +SELECT a, b FROM foo +WHERE a = $1 and b = $2; diff --git a/internal/endtoend/testdata/params_two/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/params_two/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..a68a0e4 --- /dev/null +++ b/internal/endtoend/testdata/params_two/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b text); + diff --git a/internal/endtoend/testdata/params_two/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/params_two/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..cd51867 --- /dev/null +++ b/internal/endtoend/testdata/params_two/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/parse_basic/clickhouse/exec.json b/internal/endtoend/testdata/parse_basic/clickhouse/exec.json new file mode 100644 index 0000000..9481db4 --- /dev/null +++ b/internal/endtoend/testdata/parse_basic/clickhouse/exec.json @@ -0,0 +1,5 @@ +{ + "command": "parse", + "args": ["--dialect", "clickhouse", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/parse_basic/clickhouse/query.sql b/internal/endtoend/testdata/parse_basic/clickhouse/query.sql new file mode 100644 index 0000000..11dff59 --- /dev/null +++ b/internal/endtoend/testdata/parse_basic/clickhouse/query.sql @@ -0,0 +1,2 @@ +-- name: GetValue :one +SELECT 1; diff --git a/internal/endtoend/testdata/parse_basic/clickhouse/stdout.txt b/internal/endtoend/testdata/parse_basic/clickhouse/stdout.txt new file mode 100644 index 0000000..0344534 --- /dev/null +++ b/internal/endtoend/testdata/parse_basic/clickhouse/stdout.txt @@ -0,0 +1,34 @@ +[ + { + "name": "GetValue", + "cmd": ":one", + "ast": { + "tag": "RawStmt", + "stmt": { + "tag": "SelectStmt", + "target_list": { + "tag": "List", + "items": [ + { + "tag": "ResTarget", + "name": "1", + "val": { + "tag": "A_Const", + "val": { + "tag": "Integer", + "ival": 1 + }, + "location": 30 + }, + "location": 30 + } + ] + }, + "op": 0, + "all": false + }, + "stmt_location": 0, + "stmt_len": 32 + } + } +] diff --git a/internal/endtoend/testdata/parse_basic/duckdb/exec.json b/internal/endtoend/testdata/parse_basic/duckdb/exec.json new file mode 100644 index 0000000..078d8d0 --- /dev/null +++ b/internal/endtoend/testdata/parse_basic/duckdb/exec.json @@ -0,0 +1,5 @@ +{ + "command": "parse", + "args": ["--dialect", "duckdb", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/parse_basic/duckdb/query.sql b/internal/endtoend/testdata/parse_basic/duckdb/query.sql new file mode 100644 index 0000000..11dff59 --- /dev/null +++ b/internal/endtoend/testdata/parse_basic/duckdb/query.sql @@ -0,0 +1,2 @@ +-- name: GetValue :one +SELECT 1; diff --git a/internal/endtoend/testdata/parse_basic/duckdb/stdout.txt b/internal/endtoend/testdata/parse_basic/duckdb/stdout.txt new file mode 100644 index 0000000..9c48f6b --- /dev/null +++ b/internal/endtoend/testdata/parse_basic/duckdb/stdout.txt @@ -0,0 +1,33 @@ +[ + { + "name": "GetValue", + "cmd": ":one", + "ast": { + "tag": "RawStmt", + "stmt": { + "tag": "SelectStmt", + "target_list": { + "tag": "List", + "items": [ + { + "tag": "ResTarget", + "val": { + "tag": "A_Const", + "val": { + "tag": "Integer", + "ival": 1 + }, + "location": 30 + }, + "location": 30 + } + ] + }, + "op": 0, + "all": false + }, + "stmt_location": 0, + "stmt_len": 33 + } + } +] diff --git a/internal/endtoend/testdata/parse_basic/googlesql/exec.json b/internal/endtoend/testdata/parse_basic/googlesql/exec.json new file mode 100644 index 0000000..6931f13 --- /dev/null +++ b/internal/endtoend/testdata/parse_basic/googlesql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "parse", + "args": ["--dialect", "googlesql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/parse_basic/googlesql/query.sql b/internal/endtoend/testdata/parse_basic/googlesql/query.sql new file mode 100644 index 0000000..11dff59 --- /dev/null +++ b/internal/endtoend/testdata/parse_basic/googlesql/query.sql @@ -0,0 +1,2 @@ +-- name: GetValue :one +SELECT 1; diff --git a/internal/endtoend/testdata/parse_basic/googlesql/stdout.txt b/internal/endtoend/testdata/parse_basic/googlesql/stdout.txt new file mode 100644 index 0000000..f1d5434 --- /dev/null +++ b/internal/endtoend/testdata/parse_basic/googlesql/stdout.txt @@ -0,0 +1,33 @@ +[ + { + "name": "GetValue", + "cmd": ":one", + "ast": { + "tag": "RawStmt", + "stmt": { + "tag": "SelectStmt", + "target_list": { + "tag": "List", + "items": [ + { + "tag": "ResTarget", + "val": { + "tag": "A_Const", + "val": { + "tag": "Integer", + "ival": 1 + }, + "location": 30 + }, + "location": 30 + } + ] + }, + "op": 0, + "all": false + }, + "stmt_location": 0, + "stmt_len": 31 + } + } +] diff --git a/internal/endtoend/testdata/parse_basic/mssql/exec.json b/internal/endtoend/testdata/parse_basic/mssql/exec.json new file mode 100644 index 0000000..fb49754 --- /dev/null +++ b/internal/endtoend/testdata/parse_basic/mssql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "parse", + "args": ["--dialect", "mssql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/parse_basic/mssql/query.sql b/internal/endtoend/testdata/parse_basic/mssql/query.sql new file mode 100644 index 0000000..11dff59 --- /dev/null +++ b/internal/endtoend/testdata/parse_basic/mssql/query.sql @@ -0,0 +1,2 @@ +-- name: GetValue :one +SELECT 1; diff --git a/internal/endtoend/testdata/parse_basic/mssql/stdout.txt b/internal/endtoend/testdata/parse_basic/mssql/stdout.txt new file mode 100644 index 0000000..a317604 --- /dev/null +++ b/internal/endtoend/testdata/parse_basic/mssql/stdout.txt @@ -0,0 +1,33 @@ +[ + { + "name": "GetValue", + "cmd": ":one", + "ast": { + "tag": "RawStmt", + "stmt": { + "tag": "SelectStmt", + "target_list": { + "tag": "List", + "items": [ + { + "tag": "ResTarget", + "val": { + "tag": "A_Const", + "val": { + "tag": "Integer", + "ival": 1 + }, + "location": 30 + }, + "location": 30 + } + ] + }, + "op": 0, + "all": false + }, + "stmt_location": 0, + "stmt_len": 32 + } + } +] diff --git a/internal/endtoend/testdata/parse_basic/mysql/exec.json b/internal/endtoend/testdata/parse_basic/mysql/exec.json new file mode 100644 index 0000000..b3326c0 --- /dev/null +++ b/internal/endtoend/testdata/parse_basic/mysql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "parse", + "args": ["--dialect", "mysql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/parse_basic/mysql/query.sql b/internal/endtoend/testdata/parse_basic/mysql/query.sql new file mode 100644 index 0000000..11dff59 --- /dev/null +++ b/internal/endtoend/testdata/parse_basic/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: GetValue :one +SELECT 1; diff --git a/internal/endtoend/testdata/parse_basic/mysql/stdout.txt b/internal/endtoend/testdata/parse_basic/mysql/stdout.txt new file mode 100644 index 0000000..baad161 --- /dev/null +++ b/internal/endtoend/testdata/parse_basic/mysql/stdout.txt @@ -0,0 +1,42 @@ +[ + { + "name": "GetValue", + "cmd": ":one", + "ast": { + "tag": "RawStmt", + "stmt": { + "tag": "SelectStmt", + "target_list": { + "tag": "List", + "items": [ + { + "tag": "ResTarget", + "val": { + "tag": "A_Const", + "val": { + "tag": "Integer", + "ival": 1 + }, + "location": 30 + }, + "location": 30 + } + ] + }, + "from_clause": { + "tag": "List" + }, + "group_clause": { + "tag": "List" + }, + "window_clause": { + "tag": "List" + }, + "op": 0, + "all": false + }, + "stmt_location": 0, + "stmt_len": 31 + } + } +] diff --git a/internal/endtoend/testdata/parse_basic/postgresql/exec.json b/internal/endtoend/testdata/parse_basic/postgresql/exec.json new file mode 100644 index 0000000..0a75ff4 --- /dev/null +++ b/internal/endtoend/testdata/parse_basic/postgresql/exec.json @@ -0,0 +1,5 @@ +{ + "command": "parse", + "args": ["--dialect", "postgresql", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/parse_basic/postgresql/query.sql b/internal/endtoend/testdata/parse_basic/postgresql/query.sql new file mode 100644 index 0000000..11dff59 --- /dev/null +++ b/internal/endtoend/testdata/parse_basic/postgresql/query.sql @@ -0,0 +1,2 @@ +-- name: GetValue :one +SELECT 1; diff --git a/internal/endtoend/testdata/parse_basic/postgresql/stdout.txt b/internal/endtoend/testdata/parse_basic/postgresql/stdout.txt new file mode 100644 index 0000000..da9c2f9 --- /dev/null +++ b/internal/endtoend/testdata/parse_basic/postgresql/stdout.txt @@ -0,0 +1,69 @@ +[ + { + "name": "GetValue", + "cmd": ":one", + "ast": { + "tag": "RawStmt", + "stmt": { + "tag": "SelectStmt", + "distinct_clause": { + "tag": "List" + }, + "target_list": { + "tag": "List", + "items": [ + { + "tag": "ResTarget", + "indirection": { + "tag": "List" + }, + "val": { + "tag": "A_Const", + "val": { + "tag": "Integer", + "ival": 1 + }, + "location": 30 + }, + "location": 30 + } + ] + }, + "from_clause": { + "tag": "List" + }, + "where_clause": { + "tag": "TODO" + }, + "group_clause": { + "tag": "List" + }, + "having_clause": { + "tag": "TODO" + }, + "window_clause": { + "tag": "List" + }, + "values_lists": { + "tag": "List" + }, + "sort_clause": { + "tag": "List" + }, + "limit_offset": { + "tag": "TODO" + }, + "limit_count": { + "tag": "TODO" + }, + "locking_clause": { + "tag": "List" + }, + "op": 0, + "all": false + }, + "stmt_location": 0, + "stmt_len": 31 + } + } +] diff --git a/internal/endtoend/testdata/parse_basic/sqlite/exec.json b/internal/endtoend/testdata/parse_basic/sqlite/exec.json new file mode 100644 index 0000000..13abc58 --- /dev/null +++ b/internal/endtoend/testdata/parse_basic/sqlite/exec.json @@ -0,0 +1,5 @@ +{ + "command": "parse", + "args": ["--dialect", "sqlite", "query.sql"], + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/parse_basic/sqlite/query.sql b/internal/endtoend/testdata/parse_basic/sqlite/query.sql new file mode 100644 index 0000000..11dff59 --- /dev/null +++ b/internal/endtoend/testdata/parse_basic/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: GetValue :one +SELECT 1; diff --git a/internal/endtoend/testdata/parse_basic/sqlite/stdout.txt b/internal/endtoend/testdata/parse_basic/sqlite/stdout.txt new file mode 100644 index 0000000..8cbf077 --- /dev/null +++ b/internal/endtoend/testdata/parse_basic/sqlite/stdout.txt @@ -0,0 +1,45 @@ +[ + { + "name": "GetValue", + "cmd": ":one", + "ast": { + "tag": "RawStmt", + "stmt": { + "tag": "SelectStmt", + "target_list": { + "tag": "List", + "items": [ + { + "tag": "ResTarget", + "val": { + "tag": "A_Const", + "val": { + "tag": "Integer", + "ival": 1 + }, + "location": 30 + }, + "location": 30 + } + ] + }, + "from_clause": { + "tag": "List" + }, + "group_clause": { + "tag": "List" + }, + "window_clause": { + "tag": "List" + }, + "values_lists": { + "tag": "List" + }, + "op": 0, + "all": false + }, + "stmt_location": 0, + "stmt_len": 31 + } + } +] diff --git a/internal/endtoend/testdata/pattern_in_expr/mysql/go/db.go b/internal/endtoend/testdata/pattern_in_expr/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/pattern_in_expr/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/pattern_in_expr/mysql/go/models.go b/internal/endtoend/testdata/pattern_in_expr/mysql/go/models.go new file mode 100644 index 0000000..a3b9f9c --- /dev/null +++ b/internal/endtoend/testdata/pattern_in_expr/mysql/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +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/pattern_in_expr/mysql/go/query.sql.go b/internal/endtoend/testdata/pattern_in_expr/mysql/go/query.sql.go new file mode 100644 index 0000000..5fc53b3 --- /dev/null +++ b/internal/endtoend/testdata/pattern_in_expr/mysql/go/query.sql.go @@ -0,0 +1,129 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const fooByBarB = `-- name: FooByBarB :many +SELECT a, b from foo where foo.a in (select a from bar where bar.b = ?) +` + +func (q *Queries) FooByBarB(ctx context.Context, b sql.NullString) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, fooByBarB, b) + 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 fooByList = `-- name: FooByList :many +SELECT a, b from foo where foo.a in (?, ?) +` + +type FooByListParams struct { + A sql.NullString + A_2 sql.NullString +} + +func (q *Queries) FooByList(ctx context.Context, arg FooByListParams) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, fooByList, arg.A, arg.A_2) + 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 fooByNotList = `-- name: FooByNotList :many +SELECT a, b from foo where foo.a not in (?, ?) +` + +type FooByNotListParams struct { + A sql.NullString + A_2 sql.NullString +} + +func (q *Queries) FooByNotList(ctx context.Context, arg FooByNotListParams) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, fooByNotList, arg.A, arg.A_2) + 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 fooByParamList = `-- name: FooByParamList :many +SELECT a, b from foo where ? in (foo.a, foo.b) +` + +func (q *Queries) FooByParamList(ctx context.Context, a sql.NullString) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, fooByParamList, a) + 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/pattern_in_expr/mysql/query.sql b/internal/endtoend/testdata/pattern_in_expr/mysql/query.sql new file mode 100644 index 0000000..f2c3783 --- /dev/null +++ b/internal/endtoend/testdata/pattern_in_expr/mysql/query.sql @@ -0,0 +1,11 @@ +/* name: FooByBarB :many */ +SELECT a, b from foo where foo.a in (select a from bar where bar.b = ?); + +/* name: FooByList :many */ +SELECT a, b from foo where foo.a in (?, ?); + +/* name: FooByNotList :many */ +SELECT a, b from foo where foo.a not in (?, ?); + +/* name: FooByParamList :many */ +SELECT a, b from foo where ? in (foo.a, foo.b); diff --git a/internal/endtoend/testdata/pattern_in_expr/mysql/schema.sql b/internal/endtoend/testdata/pattern_in_expr/mysql/schema.sql new file mode 100644 index 0000000..98a197f --- /dev/null +++ b/internal/endtoend/testdata/pattern_in_expr/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b text); +CREATE TABLE bar (a text, b text); diff --git a/internal/endtoend/testdata/pattern_in_expr/mysql/sqlc.json b/internal/endtoend/testdata/pattern_in_expr/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/pattern_in_expr/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/pattern_matching/mysql/go/db.go b/internal/endtoend/testdata/pattern_matching/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/pattern_matching/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/pattern_matching/mysql/go/models.go b/internal/endtoend/testdata/pattern_matching/mysql/go/models.go new file mode 100644 index 0000000..027ea49 --- /dev/null +++ b/internal/endtoend/testdata/pattern_matching/mysql/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Pet struct { + Name sql.NullString +} diff --git a/internal/endtoend/testdata/pattern_matching/mysql/go/query.sql.go b/internal/endtoend/testdata/pattern_matching/mysql/go/query.sql.go new file mode 100644 index 0000000..d0314c8 --- /dev/null +++ b/internal/endtoend/testdata/pattern_matching/mysql/go/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const petsByName = `-- name: PetsByName :many +SELECT name FROM pet WHERE name LIKE ? +` + +func (q *Queries) PetsByName(ctx context.Context, name sql.NullString) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, petsByName, name) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var name sql.NullString + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + 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/pattern_matching/mysql/query.sql b/internal/endtoend/testdata/pattern_matching/mysql/query.sql new file mode 100644 index 0000000..02327ed --- /dev/null +++ b/internal/endtoend/testdata/pattern_matching/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: PetsByName :many +SELECT * FROM pet WHERE name LIKE ?; diff --git a/internal/endtoend/testdata/pattern_matching/mysql/schema.sql b/internal/endtoend/testdata/pattern_matching/mysql/schema.sql new file mode 100644 index 0000000..8133f35 --- /dev/null +++ b/internal/endtoend/testdata/pattern_matching/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE pet (name text); + diff --git a/internal/endtoend/testdata/pattern_matching/mysql/sqlc.json b/internal/endtoend/testdata/pattern_matching/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/pattern_matching/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/pattern_matching/postgresql/go/db.go b/internal/endtoend/testdata/pattern_matching/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/pattern_matching/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/pattern_matching/postgresql/go/models.go b/internal/endtoend/testdata/pattern_matching/postgresql/go/models.go new file mode 100644 index 0000000..027ea49 --- /dev/null +++ b/internal/endtoend/testdata/pattern_matching/postgresql/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Pet struct { + Name sql.NullString +} diff --git a/internal/endtoend/testdata/pattern_matching/postgresql/go/query.sql.go b/internal/endtoend/testdata/pattern_matching/postgresql/go/query.sql.go new file mode 100644 index 0000000..c7e0223 --- /dev/null +++ b/internal/endtoend/testdata/pattern_matching/postgresql/go/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const petsByName = `-- name: PetsByName :many +SELECT name FROM pet WHERE name LIKE $1 +` + +func (q *Queries) PetsByName(ctx context.Context, name sql.NullString) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, petsByName, name) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var name sql.NullString + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + 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/pattern_matching/postgresql/query.sql b/internal/endtoend/testdata/pattern_matching/postgresql/query.sql new file mode 100644 index 0000000..6fef93e --- /dev/null +++ b/internal/endtoend/testdata/pattern_matching/postgresql/query.sql @@ -0,0 +1,2 @@ +-- name: PetsByName :many +SELECT * FROM pet WHERE name LIKE $1; diff --git a/internal/endtoend/testdata/pattern_matching/postgresql/schema.sql b/internal/endtoend/testdata/pattern_matching/postgresql/schema.sql new file mode 100644 index 0000000..8133f35 --- /dev/null +++ b/internal/endtoend/testdata/pattern_matching/postgresql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE pet (name text); + diff --git a/internal/endtoend/testdata/pattern_matching/postgresql/sqlc.json b/internal/endtoend/testdata/pattern_matching/postgresql/sqlc.json new file mode 100644 index 0000000..cd51867 --- /dev/null +++ b/internal/endtoend/testdata/pattern_matching/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/exec.sql b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/exec.sql new file mode 100644 index 0000000..3f032b3 --- /dev/null +++ b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/exec.sql @@ -0,0 +1,5 @@ +-- name: AdvisoryLockExec :exec +SELECT pg_advisory_lock($1); + +-- name: AdvisoryLockExecRows :execrows +SELECT pg_advisory_lock($1); diff --git a/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/pg_advisory_xact_lock/postgresql/pgx/v4/go/exec.sql.go b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/go/exec.sql.go new file mode 100644 index 0000000..c0e470e --- /dev/null +++ b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/go/exec.sql.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: exec.sql + +package querytest + +import ( + "context" +) + +const advisoryLockExec = `-- name: AdvisoryLockExec :exec +SELECT pg_advisory_lock($1) +` + +func (q *Queries) AdvisoryLockExec(ctx context.Context, pgAdvisoryLock int64) error { + _, err := q.db.Exec(ctx, advisoryLockExec, pgAdvisoryLock) + return err +} + +const advisoryLockExecRows = `-- name: AdvisoryLockExecRows :execrows +SELECT pg_advisory_lock($1) +` + +func (q *Queries) AdvisoryLockExecRows(ctx context.Context, pgAdvisoryLock int64) (int64, error) { + result, err := q.db.Exec(ctx, advisoryLockExecRows, pgAdvisoryLock) + if err != nil { + return 0, err + } + return result.RowsAffected(), nil +} diff --git a/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..774c62f --- /dev/null +++ b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,55 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" +) + +const advisoryLockExecResult = `-- name: AdvisoryLockExecResult :execresult +SELECT pg_advisory_lock($1) +` + +func (q *Queries) AdvisoryLockExecResult(ctx context.Context, pgAdvisoryLock int64) (pgconn.CommandTag, error) { + return q.db.Exec(ctx, advisoryLockExecResult, pgAdvisoryLock) +} + +const advisoryLockOne = `-- name: AdvisoryLockOne :one +SELECT pg_advisory_lock($1) +` + +func (q *Queries) AdvisoryLockOne(ctx context.Context, pgAdvisoryLock int64) (any, error) { + row := q.db.QueryRow(ctx, advisoryLockOne, pgAdvisoryLock) + var pg_advisory_lock any + err := row.Scan(&pg_advisory_lock) + return pg_advisory_lock, err +} + +const advisoryUnlock = `-- name: AdvisoryUnlock :many +SELECT pg_advisory_unlock($1) +` + +func (q *Queries) AdvisoryUnlock(ctx context.Context, pgAdvisoryUnlock int64) ([]bool, error) { + rows, err := q.db.Query(ctx, advisoryUnlock, pgAdvisoryUnlock) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var pg_advisory_unlock bool + if err := rows.Scan(&pg_advisory_unlock); err != nil { + return nil, err + } + items = append(items, pg_advisory_unlock) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..aeb36c8 --- /dev/null +++ b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/query.sql @@ -0,0 +1,8 @@ +-- name: AdvisoryLockOne :one +SELECT pg_advisory_lock($1); + +-- name: AdvisoryUnlock :many +SELECT pg_advisory_unlock($1); + +-- name: AdvisoryLockExecResult :execresult +SELECT pg_advisory_lock($1); diff --git a/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..a632d53 --- /dev/null +++ b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": ["query.sql", "exec.sql"] + } + ] +} diff --git a/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/exec.sql b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/exec.sql new file mode 100644 index 0000000..3f032b3 --- /dev/null +++ b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/exec.sql @@ -0,0 +1,5 @@ +-- name: AdvisoryLockExec :exec +SELECT pg_advisory_lock($1); + +-- name: AdvisoryLockExecRows :execrows +SELECT pg_advisory_lock($1); diff --git a/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/pg_advisory_xact_lock/postgresql/pgx/v5/go/exec.sql.go b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/go/exec.sql.go new file mode 100644 index 0000000..c0e470e --- /dev/null +++ b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/go/exec.sql.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: exec.sql + +package querytest + +import ( + "context" +) + +const advisoryLockExec = `-- name: AdvisoryLockExec :exec +SELECT pg_advisory_lock($1) +` + +func (q *Queries) AdvisoryLockExec(ctx context.Context, pgAdvisoryLock int64) error { + _, err := q.db.Exec(ctx, advisoryLockExec, pgAdvisoryLock) + return err +} + +const advisoryLockExecRows = `-- name: AdvisoryLockExecRows :execrows +SELECT pg_advisory_lock($1) +` + +func (q *Queries) AdvisoryLockExecRows(ctx context.Context, pgAdvisoryLock int64) (int64, error) { + result, err := q.db.Exec(ctx, advisoryLockExecRows, pgAdvisoryLock) + if err != nil { + return 0, err + } + return result.RowsAffected(), nil +} diff --git a/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..a8d448b --- /dev/null +++ b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,55 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgconn" +) + +const advisoryLockExecResult = `-- name: AdvisoryLockExecResult :execresult +SELECT pg_advisory_lock($1) +` + +func (q *Queries) AdvisoryLockExecResult(ctx context.Context, pgAdvisoryLock int64) (pgconn.CommandTag, error) { + return q.db.Exec(ctx, advisoryLockExecResult, pgAdvisoryLock) +} + +const advisoryLockOne = `-- name: AdvisoryLockOne :one +SELECT pg_advisory_lock($1) +` + +func (q *Queries) AdvisoryLockOne(ctx context.Context, pgAdvisoryLock int64) (any, error) { + row := q.db.QueryRow(ctx, advisoryLockOne, pgAdvisoryLock) + var pg_advisory_lock any + err := row.Scan(&pg_advisory_lock) + return pg_advisory_lock, err +} + +const advisoryUnlock = `-- name: AdvisoryUnlock :many +SELECT pg_advisory_unlock($1) +` + +func (q *Queries) AdvisoryUnlock(ctx context.Context, pgAdvisoryUnlock int64) ([]bool, error) { + rows, err := q.db.Query(ctx, advisoryUnlock, pgAdvisoryUnlock) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var pg_advisory_unlock bool + if err := rows.Scan(&pg_advisory_unlock); err != nil { + return nil, err + } + items = append(items, pg_advisory_unlock) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..aeb36c8 --- /dev/null +++ b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/query.sql @@ -0,0 +1,8 @@ +-- name: AdvisoryLockOne :one +SELECT pg_advisory_lock($1); + +-- name: AdvisoryUnlock :many +SELECT pg_advisory_unlock($1); + +-- name: AdvisoryLockExecResult :execresult +SELECT pg_advisory_lock($1); diff --git a/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..a780e05 --- /dev/null +++ b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": ["query.sql", "exec.sql"] + } + ] +} diff --git a/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/exec.sql b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/exec.sql new file mode 100644 index 0000000..3f032b3 --- /dev/null +++ b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/exec.sql @@ -0,0 +1,5 @@ +-- name: AdvisoryLockExec :exec +SELECT pg_advisory_lock($1); + +-- name: AdvisoryLockExecRows :execrows +SELECT pg_advisory_lock($1); diff --git a/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/pg_advisory_xact_lock/postgresql/stdlib/go/exec.sql.go b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/go/exec.sql.go new file mode 100644 index 0000000..77bc72e --- /dev/null +++ b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/go/exec.sql.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: exec.sql + +package querytest + +import ( + "context" +) + +const advisoryLockExec = `-- name: AdvisoryLockExec :exec +SELECT pg_advisory_lock($1) +` + +func (q *Queries) AdvisoryLockExec(ctx context.Context, pgAdvisoryLock int64) error { + _, err := q.db.ExecContext(ctx, advisoryLockExec, pgAdvisoryLock) + return err +} + +const advisoryLockExecRows = `-- name: AdvisoryLockExecRows :execrows +SELECT pg_advisory_lock($1) +` + +func (q *Queries) AdvisoryLockExecRows(ctx context.Context, pgAdvisoryLock int64) (int64, error) { + result, err := q.db.ExecContext(ctx, advisoryLockExecRows, pgAdvisoryLock) + if err != nil { + return 0, err + } + return result.RowsAffected() +} diff --git a/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..76cb08e --- /dev/null +++ b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,57 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const advisoryLockExecResult = `-- name: AdvisoryLockExecResult :execresult +SELECT pg_advisory_lock($1) +` + +func (q *Queries) AdvisoryLockExecResult(ctx context.Context, pgAdvisoryLock int64) (sql.Result, error) { + return q.db.ExecContext(ctx, advisoryLockExecResult, pgAdvisoryLock) +} + +const advisoryLockOne = `-- name: AdvisoryLockOne :one +SELECT pg_advisory_lock($1) +` + +func (q *Queries) AdvisoryLockOne(ctx context.Context, pgAdvisoryLock int64) (any, error) { + row := q.db.QueryRowContext(ctx, advisoryLockOne, pgAdvisoryLock) + var pg_advisory_lock any + err := row.Scan(&pg_advisory_lock) + return pg_advisory_lock, err +} + +const advisoryUnlock = `-- name: AdvisoryUnlock :many +SELECT pg_advisory_unlock($1) +` + +func (q *Queries) AdvisoryUnlock(ctx context.Context, pgAdvisoryUnlock int64) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, advisoryUnlock, pgAdvisoryUnlock) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var pg_advisory_unlock bool + if err := rows.Scan(&pg_advisory_unlock); err != nil { + return nil, err + } + items = append(items, pg_advisory_unlock) + } + 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/pg_advisory_xact_lock/postgresql/stdlib/query.sql b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/query.sql new file mode 100644 index 0000000..aeb36c8 --- /dev/null +++ b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/query.sql @@ -0,0 +1,8 @@ +-- name: AdvisoryLockOne :one +SELECT pg_advisory_lock($1); + +-- name: AdvisoryUnlock :many +SELECT pg_advisory_unlock($1); + +-- name: AdvisoryLockExecResult :execresult +SELECT pg_advisory_lock($1); diff --git a/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..af1dbd0 --- /dev/null +++ b/internal/endtoend/testdata/pg_advisory_xact_lock/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": ["query.sql", "exec.sql"] + } + ] +} diff --git a/internal/endtoend/testdata/pg_dump/db/db.go b/internal/endtoend/testdata/pg_dump/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/pg_dump/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/pg_dump/db/models.go b/internal/endtoend/testdata/pg_dump/db/models.go new file mode 100644 index 0000000..56c9d4a --- /dev/null +++ b/internal/endtoend/testdata/pg_dump/db/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/pg_dump/db/query.sql.go b/internal/endtoend/testdata/pg_dump/db/query.sql.go new file mode 100644 index 0000000..703f751 --- /dev/null +++ b/internal/endtoend/testdata/pg_dump/db/query.sql.go @@ -0,0 +1,82 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" + "database/sql" +) + +const createAuthor = `-- name: CreateAuthor :one +INSERT INTO authors ( + name, bio +) VALUES ( + $1, $2 +) +RETURNING id, name, bio +` + +type CreateAuthorParams struct { + Name string + Bio sql.NullString +} + +func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (Author, error) { + row := q.db.QueryRowContext(ctx, createAuthor, arg.Name, arg.Bio) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const deleteAuthor = `-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = $1 +` + +func (q *Queries) DeleteAuthor(ctx context.Context, id int64) error { + _, err := q.db.ExecContext(ctx, deleteAuthor, id) + return err +} + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, bio FROM authors +WHERE id = $1 LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name, bio FROM authors +ORDER BY name +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); 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/pg_dump/exec.json b/internal/endtoend/testdata/pg_dump/exec.json new file mode 100644 index 0000000..c85ca2d --- /dev/null +++ b/internal/endtoend/testdata/pg_dump/exec.json @@ -0,0 +1,6 @@ +{ + "contexts": ["base"], + "meta": { + "invalid_schema": true + } +} diff --git a/internal/endtoend/testdata/pg_dump/query.sql b/internal/endtoend/testdata/pg_dump/query.sql new file mode 100644 index 0000000..75e38b2 --- /dev/null +++ b/internal/endtoend/testdata/pg_dump/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/pg_dump/schema.sql b/internal/endtoend/testdata/pg_dump/schema.sql new file mode 100644 index 0000000..ef1ab49 --- /dev/null +++ b/internal/endtoend/testdata/pg_dump/schema.sql @@ -0,0 +1,93 @@ +-- +-- PostgreSQL database dump +-- + +-- Dumped from database version 15.3 (Debian 15.3-1.pgdg120+1) +-- Dumped by pg_dump version 15.3 + +\restrict auwherpfqaiuwrhgp + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +-- +-- Name: public; Type: SCHEMA; Schema: -; Owner: pg_database_owner +-- + +CREATE SCHEMA public; + + +ALTER SCHEMA public OWNER TO pg_database_owner; + +-- +-- Name: SCHEMA public; Type: COMMENT; Schema: -; Owner: pg_database_owner +-- + +COMMENT ON SCHEMA public IS 'standard public schema'; + + +SET default_table_access_method = heap; + +-- +-- Name: authors; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.authors ( + id bigint NOT NULL, + name text NOT NULL, + bio text +); + + +ALTER TABLE public.authors OWNER TO postgres; + +-- +-- Name: authors_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE public.authors_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.authors_id_seq OWNER TO postgres; + +-- +-- Name: authors_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE public.authors_id_seq OWNED BY public.authors.id; + + +-- +-- Name: authors id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.authors ALTER COLUMN id SET DEFAULT nextval('public.authors_id_seq'::regclass); + + +-- +-- Name: authors authors_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.authors + ADD CONSTRAINT authors_pkey PRIMARY KEY (id); + + +\unrestrict auwherpfqaiuwrhgp + +-- +-- PostgreSQL database dump complete +-- + diff --git a/internal/endtoend/testdata/pg_dump/sqlc.json b/internal/endtoend/testdata/pg_dump/sqlc.json new file mode 100644 index 0000000..a682c52 --- /dev/null +++ b/internal/endtoend/testdata/pg_dump/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "db", + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} + diff --git a/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/pg_ext_ltree/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..824658e --- /dev/null +++ b/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v4/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + QualifiedName sql.NullString + NameQuery sql.NullString + FtsNameQuery sql.NullString +} diff --git a/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..7fd7c3a --- /dev/null +++ b/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listFoo = `-- name: ListFoo :many +SELECT qualified_name, name_query, fts_name_query FROM foo +` + +func (q *Queries) ListFoo(ctx context.Context) ([]Foo, error) { + rows, err := q.db.Query(ctx, listFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.QualifiedName, &i.NameQuery, &i.FtsNameQuery); 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/pg_ext_ltree/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..b475d29 --- /dev/null +++ b/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: ListFoo :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..82fb9b2 --- /dev/null +++ b/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v4/schema.sql @@ -0,0 +1,8 @@ +CREATE EXTENSION IF NOT EXISTS ltree; + +CREATE TABLE foo ( + qualified_name ltree, + name_query lquery, + fts_name_query ltxtquery +); + diff --git a/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/pg_ext_ltree/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..1b4affe --- /dev/null +++ b/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v5/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + QualifiedName pgtype.Text + NameQuery pgtype.Text + FtsNameQuery pgtype.Text +} diff --git a/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..7fd7c3a --- /dev/null +++ b/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listFoo = `-- name: ListFoo :many +SELECT qualified_name, name_query, fts_name_query FROM foo +` + +func (q *Queries) ListFoo(ctx context.Context) ([]Foo, error) { + rows, err := q.db.Query(ctx, listFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.QualifiedName, &i.NameQuery, &i.FtsNameQuery); 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/pg_ext_ltree/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..b475d29 --- /dev/null +++ b/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: ListFoo :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..82fb9b2 --- /dev/null +++ b/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v5/schema.sql @@ -0,0 +1,8 @@ +CREATE EXTENSION IF NOT EXISTS ltree; + +CREATE TABLE foo ( + qualified_name ltree, + name_query lquery, + fts_name_query ltxtquery +); + diff --git a/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/pg_ext_ltree/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/pg_ext_ltree/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/pg_ext_ltree/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/pg_ext_ltree/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/pg_ext_ltree/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/pg_ext_ltree/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..824658e --- /dev/null +++ b/internal/endtoend/testdata/pg_ext_ltree/postgresql/stdlib/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + QualifiedName sql.NullString + NameQuery sql.NullString + FtsNameQuery sql.NullString +} diff --git a/internal/endtoend/testdata/pg_ext_ltree/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/pg_ext_ltree/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..efc1920 --- /dev/null +++ b/internal/endtoend/testdata/pg_ext_ltree/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listFoo = `-- name: ListFoo :many +SELECT qualified_name, name_query, fts_name_query FROM foo +` + +func (q *Queries) ListFoo(ctx context.Context) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, listFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.QualifiedName, &i.NameQuery, &i.FtsNameQuery); 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/pg_ext_ltree/postgresql/stdlib/query.sql b/internal/endtoend/testdata/pg_ext_ltree/postgresql/stdlib/query.sql new file mode 100644 index 0000000..b475d29 --- /dev/null +++ b/internal/endtoend/testdata/pg_ext_ltree/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: ListFoo :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/pg_ext_ltree/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/pg_ext_ltree/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..82fb9b2 --- /dev/null +++ b/internal/endtoend/testdata/pg_ext_ltree/postgresql/stdlib/schema.sql @@ -0,0 +1,8 @@ +CREATE EXTENSION IF NOT EXISTS ltree; + +CREATE TABLE foo ( + qualified_name ltree, + name_query lquery, + fts_name_query ltxtquery +); + diff --git a/internal/endtoend/testdata/pg_ext_ltree/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/pg_ext_ltree/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/pg_ext_ltree/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/pg_extensions/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/go/pg_trgm.sql.go b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/go/pg_trgm.sql.go new file mode 100644 index 0000000..ba7b612 --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/go/pg_trgm.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: pg_trgm.sql + +package querytest + +import ( + "context" +) + +const wordSimilarity = `-- name: WordSimilarity :one +SELECT word_similarity('word', 'two words') +` + +func (q *Queries) WordSimilarity(ctx context.Context) (float32, error) { + row := q.db.QueryRow(ctx, wordSimilarity) + var word_similarity float32 + err := row.Scan(&word_similarity) + return word_similarity, err +} diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/go/pgcrypto.sql.go b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/go/pgcrypto.sql.go new file mode 100644 index 0000000..5dbd345 --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/go/pgcrypto.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: pgcrypto.sql + +package querytest + +import ( + "context" +) + +const encodeDigest = `-- name: EncodeDigest :one +SELECT encode(digest($1, 'sha1'), 'hex') +` + +func (q *Queries) EncodeDigest(ctx context.Context, digest string) (string, error) { + row := q.db.QueryRow(ctx, encodeDigest, digest) + var encode string + err := row.Scan(&encode) + return encode, err +} diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/go/uuid_ossp.sql.go b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/go/uuid_ossp.sql.go new file mode 100644 index 0000000..448810e --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/go/uuid_ossp.sql.go @@ -0,0 +1,23 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: uuid_ossp.sql + +package querytest + +import ( + "context" + + "github.com/google/uuid" +) + +const generateUUID = `-- name: GenerateUUID :one +SELECT uuid_generate_v4() +` + +func (q *Queries) GenerateUUID(ctx context.Context) (uuid.UUID, error) { + row := q.db.QueryRow(ctx, generateUUID) + var uuid_generate_v4 uuid.UUID + err := row.Scan(&uuid_generate_v4) + return uuid_generate_v4, err +} diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..bf80206 --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE EXTENSION IF NOT EXISTS "pg_trgm"; +CREATE EXTENSION IF NOT EXISTS "pgcrypto"; +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; \ No newline at end of file diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/sql/pg_trgm.sql b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/sql/pg_trgm.sql new file mode 100644 index 0000000..f0edf09 --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/sql/pg_trgm.sql @@ -0,0 +1,2 @@ +-- name: WordSimilarity :one +SELECT word_similarity('word', 'two words'); diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/sql/pgcrypto.sql b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/sql/pgcrypto.sql new file mode 100644 index 0000000..f1045a4 --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/sql/pgcrypto.sql @@ -0,0 +1,3 @@ +-- name: EncodeDigest :one +SELECT encode(digest($1, 'sha1'), 'hex'); + diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/sql/uuid_ossp.sql b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/sql/uuid_ossp.sql new file mode 100644 index 0000000..1716962 --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/sql/uuid_ossp.sql @@ -0,0 +1,2 @@ +-- name: GenerateUUID :one +SELECT uuid_generate_v4(); diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..520995c --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "sql" + } + ] +} diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/pg_extensions/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/go/pg_trgm.sql.go b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/go/pg_trgm.sql.go new file mode 100644 index 0000000..ba7b612 --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/go/pg_trgm.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: pg_trgm.sql + +package querytest + +import ( + "context" +) + +const wordSimilarity = `-- name: WordSimilarity :one +SELECT word_similarity('word', 'two words') +` + +func (q *Queries) WordSimilarity(ctx context.Context) (float32, error) { + row := q.db.QueryRow(ctx, wordSimilarity) + var word_similarity float32 + err := row.Scan(&word_similarity) + return word_similarity, err +} diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/go/pgcrypto.sql.go b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/go/pgcrypto.sql.go new file mode 100644 index 0000000..5dbd345 --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/go/pgcrypto.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: pgcrypto.sql + +package querytest + +import ( + "context" +) + +const encodeDigest = `-- name: EncodeDigest :one +SELECT encode(digest($1, 'sha1'), 'hex') +` + +func (q *Queries) EncodeDigest(ctx context.Context, digest string) (string, error) { + row := q.db.QueryRow(ctx, encodeDigest, digest) + var encode string + err := row.Scan(&encode) + return encode, err +} diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/go/uuid_ossp.sql.go b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/go/uuid_ossp.sql.go new file mode 100644 index 0000000..836f0d2 --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/go/uuid_ossp.sql.go @@ -0,0 +1,23 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: uuid_ossp.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const generateUUID = `-- name: GenerateUUID :one +SELECT uuid_generate_v4() +` + +func (q *Queries) GenerateUUID(ctx context.Context) (pgtype.UUID, error) { + row := q.db.QueryRow(ctx, generateUUID) + var uuid_generate_v4 pgtype.UUID + err := row.Scan(&uuid_generate_v4) + return uuid_generate_v4, err +} diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..bf80206 --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE EXTENSION IF NOT EXISTS "pg_trgm"; +CREATE EXTENSION IF NOT EXISTS "pgcrypto"; +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; \ No newline at end of file diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/sql/pg_trgm.sql b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/sql/pg_trgm.sql new file mode 100644 index 0000000..f0edf09 --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/sql/pg_trgm.sql @@ -0,0 +1,2 @@ +-- name: WordSimilarity :one +SELECT word_similarity('word', 'two words'); diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/sql/pgcrypto.sql b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/sql/pgcrypto.sql new file mode 100644 index 0000000..f1045a4 --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/sql/pgcrypto.sql @@ -0,0 +1,3 @@ +-- name: EncodeDigest :one +SELECT encode(digest($1, 'sha1'), 'hex'); + diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/sql/uuid_ossp.sql b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/sql/uuid_ossp.sql new file mode 100644 index 0000000..1716962 --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/sql/uuid_ossp.sql @@ -0,0 +1,2 @@ +-- name: GenerateUUID :one +SELECT uuid_generate_v4(); diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..7fcfe04 --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "sql" + } + ] +} diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/pg_extensions/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/go/pg_trgm.sql.go b/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/go/pg_trgm.sql.go new file mode 100644 index 0000000..564b9eb --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/go/pg_trgm.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: pg_trgm.sql + +package querytest + +import ( + "context" +) + +const wordSimilarity = `-- name: WordSimilarity :one +SELECT word_similarity('word', 'two words') +` + +func (q *Queries) WordSimilarity(ctx context.Context) (float32, error) { + row := q.db.QueryRowContext(ctx, wordSimilarity) + var word_similarity float32 + err := row.Scan(&word_similarity) + return word_similarity, err +} diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/go/pgcrypto.sql.go b/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/go/pgcrypto.sql.go new file mode 100644 index 0000000..4676430 --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/go/pgcrypto.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: pgcrypto.sql + +package querytest + +import ( + "context" +) + +const encodeDigest = `-- name: EncodeDigest :one +SELECT encode(digest($1, 'sha1'), 'hex') +` + +func (q *Queries) EncodeDigest(ctx context.Context, digest string) (string, error) { + row := q.db.QueryRowContext(ctx, encodeDigest, digest) + var encode string + err := row.Scan(&encode) + return encode, err +} diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/go/uuid_ossp.sql.go b/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/go/uuid_ossp.sql.go new file mode 100644 index 0000000..0bd737e --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/go/uuid_ossp.sql.go @@ -0,0 +1,23 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: uuid_ossp.sql + +package querytest + +import ( + "context" + + "github.com/google/uuid" +) + +const generateUUID = `-- name: GenerateUUID :one +SELECT uuid_generate_v4() +` + +func (q *Queries) GenerateUUID(ctx context.Context) (uuid.UUID, error) { + row := q.db.QueryRowContext(ctx, generateUUID) + var uuid_generate_v4 uuid.UUID + err := row.Scan(&uuid_generate_v4) + return uuid_generate_v4, err +} diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..bf80206 --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE EXTENSION IF NOT EXISTS "pg_trgm"; +CREATE EXTENSION IF NOT EXISTS "pgcrypto"; +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; \ No newline at end of file diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/sql/pg_trgm.sql b/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/sql/pg_trgm.sql new file mode 100644 index 0000000..f0edf09 --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/sql/pg_trgm.sql @@ -0,0 +1,2 @@ +-- name: WordSimilarity :one +SELECT word_similarity('word', 'two words'); diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/sql/pgcrypto.sql b/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/sql/pgcrypto.sql new file mode 100644 index 0000000..f1045a4 --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/sql/pgcrypto.sql @@ -0,0 +1,3 @@ +-- name: EncodeDigest :one +SELECT encode(digest($1, 'sha1'), 'hex'); + diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/sql/uuid_ossp.sql b/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/sql/uuid_ossp.sql new file mode 100644 index 0000000..1716962 --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/sql/uuid_ossp.sql @@ -0,0 +1,2 @@ +-- name: GenerateUUID :one +SELECT uuid_generate_v4(); diff --git a/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..c78a329 --- /dev/null +++ b/internal/endtoend/testdata/pg_extensions/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "sql" + } + ] +} diff --git a/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/exec.json b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/pg_generate_series/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..4502d2a --- /dev/null +++ b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,40 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "time" +) + +const generateSeries = `-- name: GenerateSeries :many +SELECT generate_series($1::timestamp, $2::timestamp, '10 hours') +` + +type GenerateSeriesParams struct { + Column1 time.Time `json:"column_1"` + Column2 time.Time `json:"column_2"` +} + +func (q *Queries) GenerateSeries(ctx context.Context, arg GenerateSeriesParams) ([]int64, error) { + rows, err := q.db.Query(ctx, generateSeries, arg.Column1, arg.Column2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var generate_series int64 + if err := rows.Scan(&generate_series); err != nil { + return nil, err + } + items = append(items, generate_series) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..3d483e8 --- /dev/null +++ b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: GenerateSeries :many +SELECT generate_series($1::timestamp, $2::timestamp, '10 hours'); diff --git a/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..a1dead4 --- /dev/null +++ b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_json_tags": true + } + ] +} diff --git a/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/exec.json b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/pg_generate_series/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..d0f1c56 --- /dev/null +++ b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,41 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const generateSeries = `-- name: GenerateSeries :many +SELECT generate_series($1::timestamp, $2::timestamp, '10 hours') +` + +type GenerateSeriesParams struct { + Column1 pgtype.Timestamp `json:"column_1"` + Column2 pgtype.Timestamp `json:"column_2"` +} + +func (q *Queries) GenerateSeries(ctx context.Context, arg GenerateSeriesParams) ([]int64, error) { + rows, err := q.db.Query(ctx, generateSeries, arg.Column1, arg.Column2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var generate_series int64 + if err := rows.Scan(&generate_series); err != nil { + return nil, err + } + items = append(items, generate_series) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..3d483e8 --- /dev/null +++ b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: GenerateSeries :many +SELECT generate_series($1::timestamp, $2::timestamp, '10 hours'); diff --git a/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..fff8b19 --- /dev/null +++ b/internal/endtoend/testdata/pg_generate_series/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_json_tags": true + } + ] +} diff --git a/internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/exec.json b/internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/pg_generate_series/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..a386f76 --- /dev/null +++ b/internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,43 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "time" +) + +const generateSeries = `-- name: GenerateSeries :many +SELECT generate_series($1::timestamp, $2::timestamp, '10 hours') +` + +type GenerateSeriesParams struct { + Column1 time.Time `json:"column_1"` + Column2 time.Time `json:"column_2"` +} + +func (q *Queries) GenerateSeries(ctx context.Context, arg GenerateSeriesParams) ([]int64, error) { + rows, err := q.db.QueryContext(ctx, generateSeries, arg.Column1, arg.Column2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var generate_series int64 + if err := rows.Scan(&generate_series); err != nil { + return nil, err + } + items = append(items, generate_series) + } + 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/pg_generate_series/postgresql/stdlib/query.sql b/internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/query.sql new file mode 100644 index 0000000..3d483e8 --- /dev/null +++ b/internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: GenerateSeries :many +SELECT generate_series($1::timestamp, $2::timestamp, '10 hours'); diff --git a/internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..bb6ecf4 --- /dev/null +++ b/internal/endtoend/testdata/pg_generate_series/postgresql/stdlib/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_json_tags": true + } + ] +} diff --git a/internal/endtoend/testdata/pg_timezone_names/go_pgx/v4/db.go b/internal/endtoend/testdata/pg_timezone_names/go_pgx/v4/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/pg_timezone_names/go_pgx/v4/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/pg_timezone_names/go_pgx/v4/models.go b/internal/endtoend/testdata/pg_timezone_names/go_pgx/v4/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/pg_timezone_names/go_pgx/v4/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/pg_timezone_names/go_pgx/v4/query.sql.go b/internal/endtoend/testdata/pg_timezone_names/go_pgx/v4/query.sql.go new file mode 100644 index 0000000..f263950 --- /dev/null +++ b/internal/endtoend/testdata/pg_timezone_names/go_pgx/v4/query.sql.go @@ -0,0 +1,100 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const getColumns = `-- name: GetColumns :many +SELECT table_name::text, column_name::text from information_schema.columns +` + +type GetColumnsRow struct { + TableName string + ColumnName string +} + +func (q *Queries) GetColumns(ctx context.Context) ([]GetColumnsRow, error) { + rows, err := q.db.Query(ctx, getColumns) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetColumnsRow + for rows.Next() { + var i GetColumnsRow + if err := rows.Scan(&i.TableName, &i.ColumnName); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getTables = `-- name: GetTables :many +SELECT table_name::text from information_schema.tables +` + +func (q *Queries) GetTables(ctx context.Context) ([]string, error) { + rows, err := q.db.Query(ctx, getTables) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var table_name string + if err := rows.Scan(&table_name); err != nil { + return nil, err + } + items = append(items, table_name) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getTimezones = `-- name: GetTimezones :many +SELECT name, abbrev, utc_offset, is_dst from pg_catalog.pg_timezone_names +` + +type GetTimezonesRow struct { + Name sql.NullString + Abbrev sql.NullString + UtcOffset sql.NullInt64 + IsDst sql.NullBool +} + +func (q *Queries) GetTimezones(ctx context.Context) ([]GetTimezonesRow, error) { + rows, err := q.db.Query(ctx, getTimezones) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetTimezonesRow + for rows.Next() { + var i GetTimezonesRow + if err := rows.Scan( + &i.Name, + &i.Abbrev, + &i.UtcOffset, + &i.IsDst, + ); 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/pg_timezone_names/go_pgx/v5/db.go b/internal/endtoend/testdata/pg_timezone_names/go_pgx/v5/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/pg_timezone_names/go_pgx/v5/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/pg_timezone_names/go_pgx/v5/models.go b/internal/endtoend/testdata/pg_timezone_names/go_pgx/v5/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/pg_timezone_names/go_pgx/v5/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/pg_timezone_names/go_pgx/v5/query.sql.go b/internal/endtoend/testdata/pg_timezone_names/go_pgx/v5/query.sql.go new file mode 100644 index 0000000..0eb1011 --- /dev/null +++ b/internal/endtoend/testdata/pg_timezone_names/go_pgx/v5/query.sql.go @@ -0,0 +1,101 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const getColumns = `-- name: GetColumns :many +SELECT table_name::text, column_name::text from information_schema.columns +` + +type GetColumnsRow struct { + TableName string + ColumnName string +} + +func (q *Queries) GetColumns(ctx context.Context) ([]GetColumnsRow, error) { + rows, err := q.db.Query(ctx, getColumns) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetColumnsRow + for rows.Next() { + var i GetColumnsRow + if err := rows.Scan(&i.TableName, &i.ColumnName); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getTables = `-- name: GetTables :many +SELECT table_name::text from information_schema.tables +` + +func (q *Queries) GetTables(ctx context.Context) ([]string, error) { + rows, err := q.db.Query(ctx, getTables) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var table_name string + if err := rows.Scan(&table_name); err != nil { + return nil, err + } + items = append(items, table_name) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getTimezones = `-- name: GetTimezones :many +SELECT name, abbrev, utc_offset, is_dst from pg_catalog.pg_timezone_names +` + +type GetTimezonesRow struct { + Name pgtype.Text + Abbrev pgtype.Text + UtcOffset pgtype.Interval + IsDst pgtype.Bool +} + +func (q *Queries) GetTimezones(ctx context.Context) ([]GetTimezonesRow, error) { + rows, err := q.db.Query(ctx, getTimezones) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetTimezonesRow + for rows.Next() { + var i GetTimezonesRow + if err := rows.Scan( + &i.Name, + &i.Abbrev, + &i.UtcOffset, + &i.IsDst, + ); 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/pg_timezone_names/go_stdlib/db.go b/internal/endtoend/testdata/pg_timezone_names/go_stdlib/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/pg_timezone_names/go_stdlib/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/pg_timezone_names/go_stdlib/models.go b/internal/endtoend/testdata/pg_timezone_names/go_stdlib/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/pg_timezone_names/go_stdlib/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/pg_timezone_names/go_stdlib/query.sql.go b/internal/endtoend/testdata/pg_timezone_names/go_stdlib/query.sql.go new file mode 100644 index 0000000..5579308 --- /dev/null +++ b/internal/endtoend/testdata/pg_timezone_names/go_stdlib/query.sql.go @@ -0,0 +1,109 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const getColumns = `-- name: GetColumns :many +SELECT table_name::text, column_name::text from information_schema.columns +` + +type GetColumnsRow struct { + TableName string + ColumnName string +} + +func (q *Queries) GetColumns(ctx context.Context) ([]GetColumnsRow, error) { + rows, err := q.db.QueryContext(ctx, getColumns) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetColumnsRow + for rows.Next() { + var i GetColumnsRow + if err := rows.Scan(&i.TableName, &i.ColumnName); 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 getTables = `-- name: GetTables :many +SELECT table_name::text from information_schema.tables +` + +func (q *Queries) GetTables(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, getTables) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var table_name string + if err := rows.Scan(&table_name); err != nil { + return nil, err + } + items = append(items, table_name) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getTimezones = `-- name: GetTimezones :many +SELECT name, abbrev, utc_offset, is_dst from pg_catalog.pg_timezone_names +` + +type GetTimezonesRow struct { + Name sql.NullString + Abbrev sql.NullString + UtcOffset sql.NullInt64 + IsDst sql.NullBool +} + +func (q *Queries) GetTimezones(ctx context.Context) ([]GetTimezonesRow, error) { + rows, err := q.db.QueryContext(ctx, getTimezones) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetTimezonesRow + for rows.Next() { + var i GetTimezonesRow + if err := rows.Scan( + &i.Name, + &i.Abbrev, + &i.UtcOffset, + &i.IsDst, + ); 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/pg_timezone_names/query.sql b/internal/endtoend/testdata/pg_timezone_names/query.sql new file mode 100644 index 0000000..dc4310f --- /dev/null +++ b/internal/endtoend/testdata/pg_timezone_names/query.sql @@ -0,0 +1,8 @@ +-- name: GetTimezones :many +SELECT * from pg_catalog.pg_timezone_names; + +-- name: GetTables :many +SELECT table_name::text from information_schema.tables; + +-- name: GetColumns :many +SELECT table_name::text, column_name::text from information_schema.columns; diff --git a/internal/endtoend/testdata/pg_timezone_names/schema.sql b/internal/endtoend/testdata/pg_timezone_names/schema.sql new file mode 100644 index 0000000..e0ac49d --- /dev/null +++ b/internal/endtoend/testdata/pg_timezone_names/schema.sql @@ -0,0 +1 @@ +SELECT 1; diff --git a/internal/endtoend/testdata/pg_timezone_names/sqlc.json b/internal/endtoend/testdata/pg_timezone_names/sqlc.json new file mode 100644 index 0000000..1f0b8cd --- /dev/null +++ b/internal/endtoend/testdata/pg_timezone_names/sqlc.json @@ -0,0 +1,40 @@ +{ + "version": "2", + "sql": [ + { + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "gen": { + "go": { + "sql_package": "pgx/v4", + "package": "querytest", + "out": "go_pgx/v4" + } + } + }, + { + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "gen": { + "go": { + "sql_package": "pgx/v5", + "package": "querytest", + "out": "go_pgx/v5" + } + } + }, + { + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "gen": { + "go": { + "package": "querytest", + "out": "go_stdlib" + } + } + } + ] +} diff --git a/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/pg_user_table/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..4af57ab --- /dev/null +++ b/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type User struct { + ID int64 +} diff --git a/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..34274a0 --- /dev/null +++ b/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const user = `-- name: User :many +SELECT "user".id FROM "user" +` + +func (q *Queries) User(ctx context.Context) ([]int64, error) { + rows, err := q.db.Query(ctx, user) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var id int64 + 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 +} diff --git a/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..6449356 --- /dev/null +++ b/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: User :many +SELECT "user".* FROM "user"; diff --git a/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..7fd1e59 --- /dev/null +++ b/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE "user" (id bigserial not null); + diff --git a/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/pg_user_table/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..4af57ab --- /dev/null +++ b/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type User struct { + ID int64 +} diff --git a/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..34274a0 --- /dev/null +++ b/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const user = `-- name: User :many +SELECT "user".id FROM "user" +` + +func (q *Queries) User(ctx context.Context) ([]int64, error) { + rows, err := q.db.Query(ctx, user) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var id int64 + 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 +} diff --git a/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..6449356 --- /dev/null +++ b/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: User :many +SELECT "user".* FROM "user"; diff --git a/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..7fd1e59 --- /dev/null +++ b/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE "user" (id bigserial not null); + diff --git a/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/pg_user_table/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/pg_user_table/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/pg_user_table/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/pg_user_table/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/pg_user_table/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/pg_user_table/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..4af57ab --- /dev/null +++ b/internal/endtoend/testdata/pg_user_table/postgresql/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type User struct { + ID int64 +} diff --git a/internal/endtoend/testdata/pg_user_table/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/pg_user_table/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..7cd0ecd --- /dev/null +++ b/internal/endtoend/testdata/pg_user_table/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const user = `-- name: User :many +SELECT "user".id FROM "user" +` + +func (q *Queries) User(ctx context.Context) ([]int64, error) { + rows, err := q.db.QueryContext(ctx, user) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var id int64 + 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 +} diff --git a/internal/endtoend/testdata/pg_user_table/postgresql/stdlib/query.sql b/internal/endtoend/testdata/pg_user_table/postgresql/stdlib/query.sql new file mode 100644 index 0000000..6449356 --- /dev/null +++ b/internal/endtoend/testdata/pg_user_table/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: User :many +SELECT "user".* FROM "user"; diff --git a/internal/endtoend/testdata/pg_user_table/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/pg_user_table/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..7fd1e59 --- /dev/null +++ b/internal/endtoend/testdata/pg_user_table/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE "user" (id bigserial not null); + diff --git a/internal/endtoend/testdata/pg_user_table/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/pg_user_table/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/pg_user_table/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/pg_vector/postgresql/pgx/exec.json b/internal/endtoend/testdata/pg_vector/postgresql/pgx/exec.json new file mode 100644 index 0000000..c85ca2d --- /dev/null +++ b/internal/endtoend/testdata/pg_vector/postgresql/pgx/exec.json @@ -0,0 +1,6 @@ +{ + "contexts": ["base"], + "meta": { + "invalid_schema": true + } +} diff --git a/internal/endtoend/testdata/pg_vector/postgresql/pgx/go/db.go b/internal/endtoend/testdata/pg_vector/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/pg_vector/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/pg_vector/postgresql/pgx/go/models.go b/internal/endtoend/testdata/pg_vector/postgresql/pgx/go/models.go new file mode 100644 index 0000000..f6a0dc3 --- /dev/null +++ b/internal/endtoend/testdata/pg_vector/postgresql/pgx/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/pgvector/pgvector-go" +) + +type Item struct { + ID int64 + Embedding pgvector.Vector +} diff --git a/internal/endtoend/testdata/pg_vector/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/pg_vector/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..d7c54c1 --- /dev/null +++ b/internal/endtoend/testdata/pg_vector/postgresql/pgx/go/query.sql.go @@ -0,0 +1,48 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/pgvector/pgvector-go" +) + +const insertVector = `-- name: InsertVector :exec +INSERT INTO items (embedding) VALUES ($1) +` + +func (q *Queries) InsertVector(ctx context.Context, embedding pgvector.Vector) error { + _, err := q.db.Exec(ctx, insertVector, embedding) + return err +} + +const nearestNeighbor = `-- name: NearestNeighbor :many +SELECT id, embedding +FROM items +ORDER BY embedding <-> $1 +LIMIT 5 +` + +func (q *Queries) NearestNeighbor(ctx context.Context, embedding pgvector.Vector) ([]Item, error) { + rows, err := q.db.Query(ctx, nearestNeighbor, embedding) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Item + for rows.Next() { + var i Item + if err := rows.Scan(&i.ID, &i.Embedding); 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/pg_vector/postgresql/pgx/query.sql b/internal/endtoend/testdata/pg_vector/postgresql/pgx/query.sql new file mode 100644 index 0000000..5bcc539 --- /dev/null +++ b/internal/endtoend/testdata/pg_vector/postgresql/pgx/query.sql @@ -0,0 +1,8 @@ +-- name: InsertVector :exec +INSERT INTO items (embedding) VALUES ($1); + +-- name: NearestNeighbor :many +SELECT * +FROM items +ORDER BY embedding <-> $1 +LIMIT 5; diff --git a/internal/endtoend/testdata/pg_vector/postgresql/pgx/schema.sql b/internal/endtoend/testdata/pg_vector/postgresql/pgx/schema.sql new file mode 100644 index 0000000..a078405 --- /dev/null +++ b/internal/endtoend/testdata/pg_vector/postgresql/pgx/schema.sql @@ -0,0 +1,3 @@ +CREATE EXTENSION IF NOT EXISTS "vector"; + +CREATE TABLE items (id bigserial PRIMARY KEY, embedding vector(3)); diff --git a/internal/endtoend/testdata/pg_vector/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/pg_vector/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/pg_vector/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..5cc19ed --- /dev/null +++ b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package datatype + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/pointer_type_import/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..35ffc14 --- /dev/null +++ b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v4/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package datatype + +import ( + "time" + + "github.com/google/uuid" +) + +type Foo struct { + Bar *time.Time + Baz *uuid.UUID +} diff --git a/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..9565609 --- /dev/null +++ b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,48 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package datatype + +import ( + "context" + "time" + + "github.com/google/uuid" +) + +const find = `-- name: Find :one +SELECT bar FROM foo WHERE baz = $1 +` + +func (q *Queries) Find(ctx context.Context, baz *uuid.UUID) (*time.Time, error) { + row := q.db.QueryRow(ctx, find, baz) + var bar *time.Time + err := row.Scan(&bar) + return bar, err +} + +const list = `-- name: List :many +SELECT bar, baz FROM foo +` + +func (q *Queries) List(ctx context.Context) ([]Foo, error) { + rows, err := q.db.Query(ctx, list) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.Bar, &i.Baz); 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/pointer_type_import/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..b94846f --- /dev/null +++ b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v4/query.sql @@ -0,0 +1,5 @@ +-- name: List :many +SELECT * FROM foo; + +-- name: Find :one +SELECT bar FROM foo WHERE baz = $1; diff --git a/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..532ae99 --- /dev/null +++ b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar date, baz uuid); + diff --git a/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..56341ec --- /dev/null +++ b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "datatype", + "schema": "schema.sql", + "queries": "query.sql", + "emit_pointers_for_null_types": true + } + ] +} diff --git a/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/exec.json b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..b57247c --- /dev/null +++ b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package datatype + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/pointer_type_import/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..bb0f5de --- /dev/null +++ b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package datatype + +import ( + "net/netip" +) + +type Foo struct { + Bar *netip.Addr + Baz *netip.Prefix +} diff --git a/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..76c1c5f --- /dev/null +++ b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,46 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package datatype + +import ( + "context" + "net/netip" +) + +const find = `-- name: Find :one +SELECT bar FROM foo WHERE baz = $1 +` + +func (q *Queries) Find(ctx context.Context, baz *netip.Prefix) (*netip.Addr, error) { + row := q.db.QueryRow(ctx, find, baz) + var bar *netip.Addr + err := row.Scan(&bar) + return bar, err +} + +const list = `-- name: List :many +SELECT bar, baz FROM foo +` + +func (q *Queries) List(ctx context.Context) ([]Foo, error) { + rows, err := q.db.Query(ctx, list) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.Bar, &i.Baz); 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/pointer_type_import/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..b94846f --- /dev/null +++ b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/query.sql @@ -0,0 +1,5 @@ +-- name: List :many +SELECT * FROM foo; + +-- name: Find :one +SELECT bar FROM foo WHERE baz = $1; diff --git a/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..4b28530 --- /dev/null +++ b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar inet, baz cidr); + diff --git a/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..7465088 --- /dev/null +++ b/internal/endtoend/testdata/pointer_type_import/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "datatype", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/prepared_queries/mysql/go/db.go b/internal/endtoend/testdata/prepared_queries/mysql/go/db.go new file mode 100644 index 0000000..9c72c93 --- /dev/null +++ b/internal/endtoend/testdata/prepared_queries/mysql/go/db.go @@ -0,0 +1,128 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" + "fmt" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +func Prepare(ctx context.Context, db DBTX) (*Queries, error) { + q := Queries{db: db} + var err error + if q.deleteUsersByNameStmt, err = db.PrepareContext(ctx, deleteUsersByName); err != nil { + return nil, fmt.Errorf("error preparing query DeleteUsersByName: %w", err) + } + if q.getUserByIDStmt, err = db.PrepareContext(ctx, getUserByID); err != nil { + return nil, fmt.Errorf("error preparing query GetUserByID: %w", err) + } + if q.insertNewUserStmt, err = db.PrepareContext(ctx, insertNewUser); err != nil { + return nil, fmt.Errorf("error preparing query InsertNewUser: %w", err) + } + if q.insertNewUserWithResultStmt, err = db.PrepareContext(ctx, insertNewUserWithResult); err != nil { + return nil, fmt.Errorf("error preparing query InsertNewUserWithResult: %w", err) + } + if q.listUsersStmt, err = db.PrepareContext(ctx, listUsers); err != nil { + return nil, fmt.Errorf("error preparing query ListUsers: %w", err) + } + return &q, nil +} + +func (q *Queries) Close() error { + var err error + if q.deleteUsersByNameStmt != nil { + if cerr := q.deleteUsersByNameStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing deleteUsersByNameStmt: %w", cerr) + } + } + if q.getUserByIDStmt != nil { + if cerr := q.getUserByIDStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getUserByIDStmt: %w", cerr) + } + } + if q.insertNewUserStmt != nil { + if cerr := q.insertNewUserStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing insertNewUserStmt: %w", cerr) + } + } + if q.insertNewUserWithResultStmt != nil { + if cerr := q.insertNewUserWithResultStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing insertNewUserWithResultStmt: %w", cerr) + } + } + if q.listUsersStmt != nil { + if cerr := q.listUsersStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing listUsersStmt: %w", cerr) + } + } + return err +} + +func (q *Queries) exec(ctx context.Context, stmt *sql.Stmt, query string, args ...any) (sql.Result, error) { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).ExecContext(ctx, args...) + case stmt != nil: + return stmt.ExecContext(ctx, args...) + default: + return q.db.ExecContext(ctx, query, args...) + } +} + +func (q *Queries) query(ctx context.Context, stmt *sql.Stmt, query string, args ...any) (*sql.Rows, error) { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).QueryContext(ctx, args...) + case stmt != nil: + return stmt.QueryContext(ctx, args...) + default: + return q.db.QueryContext(ctx, query, args...) + } +} + +func (q *Queries) queryRow(ctx context.Context, stmt *sql.Stmt, query string, args ...any) *sql.Row { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).QueryRowContext(ctx, args...) + case stmt != nil: + return stmt.QueryRowContext(ctx, args...) + default: + return q.db.QueryRowContext(ctx, query, args...) + } +} + +type Queries struct { + db DBTX + tx *sql.Tx + deleteUsersByNameStmt *sql.Stmt + getUserByIDStmt *sql.Stmt + insertNewUserStmt *sql.Stmt + insertNewUserWithResultStmt *sql.Stmt + listUsersStmt *sql.Stmt +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + tx: tx, + deleteUsersByNameStmt: q.deleteUsersByNameStmt, + getUserByIDStmt: q.getUserByIDStmt, + insertNewUserStmt: q.insertNewUserStmt, + insertNewUserWithResultStmt: q.insertNewUserWithResultStmt, + listUsersStmt: q.listUsersStmt, + } +} diff --git a/internal/endtoend/testdata/prepared_queries/mysql/go/models.go b/internal/endtoend/testdata/prepared_queries/mysql/go/models.go new file mode 100644 index 0000000..9dbd0bf --- /dev/null +++ b/internal/endtoend/testdata/prepared_queries/mysql/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID uint64 + FirstName string + LastName sql.NullString +} diff --git a/internal/endtoend/testdata/prepared_queries/mysql/go/query.sql.go b/internal/endtoend/testdata/prepared_queries/mysql/go/query.sql.go new file mode 100644 index 0000000..f2021cb --- /dev/null +++ b/internal/endtoend/testdata/prepared_queries/mysql/go/query.sql.go @@ -0,0 +1,104 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const deleteUsersByName = `-- name: DeleteUsersByName :execrows +DELETE FROM users WHERE first_name = ? AND last_name = ? +` + +type DeleteUsersByNameParams struct { + FirstName string + LastName sql.NullString +} + +func (q *Queries) DeleteUsersByName(ctx context.Context, arg DeleteUsersByNameParams) (int64, error) { + result, err := q.exec(ctx, q.deleteUsersByNameStmt, deleteUsersByName, arg.FirstName, arg.LastName) + if err != nil { + return 0, err + } + return result.RowsAffected() +} + +const getUserByID = `-- name: GetUserByID :one +SELECT first_name, id, last_name FROM users WHERE id = ? +` + +type GetUserByIDRow struct { + FirstName string + ID uint64 + LastName sql.NullString +} + +func (q *Queries) GetUserByID(ctx context.Context, targetID uint64) (GetUserByIDRow, error) { + row := q.queryRow(ctx, q.getUserByIDStmt, getUserByID, targetID) + var i GetUserByIDRow + err := row.Scan(&i.FirstName, &i.ID, &i.LastName) + return i, err +} + +const insertNewUser = `-- name: InsertNewUser :exec +INSERT INTO users (first_name, last_name) VALUES (?, ?) +` + +type InsertNewUserParams struct { + FirstName string + LastName sql.NullString +} + +func (q *Queries) InsertNewUser(ctx context.Context, arg InsertNewUserParams) error { + _, err := q.exec(ctx, q.insertNewUserStmt, insertNewUser, arg.FirstName, arg.LastName) + return err +} + +const insertNewUserWithResult = `-- name: InsertNewUserWithResult :execresult +INSERT INTO users (first_name, last_name) VALUES (?, ?) +` + +type InsertNewUserWithResultParams struct { + FirstName string + LastName sql.NullString +} + +func (q *Queries) InsertNewUserWithResult(ctx context.Context, arg InsertNewUserWithResultParams) (sql.Result, error) { + return q.exec(ctx, q.insertNewUserWithResultStmt, insertNewUserWithResult, arg.FirstName, arg.LastName) +} + +const listUsers = `-- name: ListUsers :many +SELECT first_name, last_name FROM users +` + +type ListUsersRow struct { + FirstName string + LastName sql.NullString +} + +func (q *Queries) ListUsers(ctx context.Context) ([]ListUsersRow, error) { + rows, err := q.query(ctx, q.listUsersStmt, listUsers) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUsersRow + for rows.Next() { + var i ListUsersRow + if err := rows.Scan(&i.FirstName, &i.LastName); 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/prepared_queries/mysql/query.sql b/internal/endtoend/testdata/prepared_queries/mysql/query.sql new file mode 100644 index 0000000..b743aee --- /dev/null +++ b/internal/endtoend/testdata/prepared_queries/mysql/query.sql @@ -0,0 +1,14 @@ +/* name: GetUserByID :one */ +SELECT first_name, id, last_name FROM users WHERE id = sqlc.arg('target_id'); + +/* name: ListUsers :many */ +SELECT first_name, last_name FROM users; + +/* name: InsertNewUser :exec */ +INSERT INTO users (first_name, last_name) VALUES (?, ?); + +/* name: InsertNewUserWithResult :execresult */ +INSERT INTO users (first_name, last_name) VALUES (?, ?); + +/* name: DeleteUsersByName :execrows */ +DELETE FROM users WHERE first_name = ? AND last_name = ?; diff --git a/internal/endtoend/testdata/prepared_queries/mysql/schema.sql b/internal/endtoend/testdata/prepared_queries/mysql/schema.sql new file mode 100644 index 0000000..c928f3b --- /dev/null +++ b/internal/endtoend/testdata/prepared_queries/mysql/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + id SERIAL NOT NULL, + first_name varchar(255) NOT NULL, + last_name varchar(255) +); + diff --git a/internal/endtoend/testdata/prepared_queries/mysql/sqlc.json b/internal/endtoend/testdata/prepared_queries/mysql/sqlc.json new file mode 100644 index 0000000..9d96bdc --- /dev/null +++ b/internal/endtoend/testdata/prepared_queries/mysql/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "schema.sql", + "queries": "query.sql", + "engine": "mysql", + "emit_prepared_queries": true + } + ] +} diff --git a/internal/endtoend/testdata/prepared_queries/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/prepared_queries/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..9c72c93 --- /dev/null +++ b/internal/endtoend/testdata/prepared_queries/postgresql/stdlib/go/db.go @@ -0,0 +1,128 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" + "fmt" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +func Prepare(ctx context.Context, db DBTX) (*Queries, error) { + q := Queries{db: db} + var err error + if q.deleteUsersByNameStmt, err = db.PrepareContext(ctx, deleteUsersByName); err != nil { + return nil, fmt.Errorf("error preparing query DeleteUsersByName: %w", err) + } + if q.getUserByIDStmt, err = db.PrepareContext(ctx, getUserByID); err != nil { + return nil, fmt.Errorf("error preparing query GetUserByID: %w", err) + } + if q.insertNewUserStmt, err = db.PrepareContext(ctx, insertNewUser); err != nil { + return nil, fmt.Errorf("error preparing query InsertNewUser: %w", err) + } + if q.insertNewUserWithResultStmt, err = db.PrepareContext(ctx, insertNewUserWithResult); err != nil { + return nil, fmt.Errorf("error preparing query InsertNewUserWithResult: %w", err) + } + if q.listUsersStmt, err = db.PrepareContext(ctx, listUsers); err != nil { + return nil, fmt.Errorf("error preparing query ListUsers: %w", err) + } + return &q, nil +} + +func (q *Queries) Close() error { + var err error + if q.deleteUsersByNameStmt != nil { + if cerr := q.deleteUsersByNameStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing deleteUsersByNameStmt: %w", cerr) + } + } + if q.getUserByIDStmt != nil { + if cerr := q.getUserByIDStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getUserByIDStmt: %w", cerr) + } + } + if q.insertNewUserStmt != nil { + if cerr := q.insertNewUserStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing insertNewUserStmt: %w", cerr) + } + } + if q.insertNewUserWithResultStmt != nil { + if cerr := q.insertNewUserWithResultStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing insertNewUserWithResultStmt: %w", cerr) + } + } + if q.listUsersStmt != nil { + if cerr := q.listUsersStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing listUsersStmt: %w", cerr) + } + } + return err +} + +func (q *Queries) exec(ctx context.Context, stmt *sql.Stmt, query string, args ...any) (sql.Result, error) { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).ExecContext(ctx, args...) + case stmt != nil: + return stmt.ExecContext(ctx, args...) + default: + return q.db.ExecContext(ctx, query, args...) + } +} + +func (q *Queries) query(ctx context.Context, stmt *sql.Stmt, query string, args ...any) (*sql.Rows, error) { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).QueryContext(ctx, args...) + case stmt != nil: + return stmt.QueryContext(ctx, args...) + default: + return q.db.QueryContext(ctx, query, args...) + } +} + +func (q *Queries) queryRow(ctx context.Context, stmt *sql.Stmt, query string, args ...any) *sql.Row { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).QueryRowContext(ctx, args...) + case stmt != nil: + return stmt.QueryRowContext(ctx, args...) + default: + return q.db.QueryRowContext(ctx, query, args...) + } +} + +type Queries struct { + db DBTX + tx *sql.Tx + deleteUsersByNameStmt *sql.Stmt + getUserByIDStmt *sql.Stmt + insertNewUserStmt *sql.Stmt + insertNewUserWithResultStmt *sql.Stmt + listUsersStmt *sql.Stmt +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + tx: tx, + deleteUsersByNameStmt: q.deleteUsersByNameStmt, + getUserByIDStmt: q.getUserByIDStmt, + insertNewUserStmt: q.insertNewUserStmt, + insertNewUserWithResultStmt: q.insertNewUserWithResultStmt, + listUsersStmt: q.listUsersStmt, + } +} diff --git a/internal/endtoend/testdata/prepared_queries/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/prepared_queries/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..d54fc5a --- /dev/null +++ b/internal/endtoend/testdata/prepared_queries/postgresql/stdlib/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID int32 + FirstName string + LastName sql.NullString +} diff --git a/internal/endtoend/testdata/prepared_queries/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/prepared_queries/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..f4c96a4 --- /dev/null +++ b/internal/endtoend/testdata/prepared_queries/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,104 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const deleteUsersByName = `-- name: DeleteUsersByName :execrows +DELETE FROM users WHERE first_name = $1 AND last_name = $2 +` + +type DeleteUsersByNameParams struct { + FirstName string + LastName sql.NullString +} + +func (q *Queries) DeleteUsersByName(ctx context.Context, arg DeleteUsersByNameParams) (int64, error) { + result, err := q.exec(ctx, q.deleteUsersByNameStmt, deleteUsersByName, arg.FirstName, arg.LastName) + if err != nil { + return 0, err + } + return result.RowsAffected() +} + +const getUserByID = `-- name: GetUserByID :one +SELECT first_name, id, last_name FROM users WHERE id = $1 +` + +type GetUserByIDRow struct { + FirstName string + ID int32 + LastName sql.NullString +} + +func (q *Queries) GetUserByID(ctx context.Context, targetID int32) (GetUserByIDRow, error) { + row := q.queryRow(ctx, q.getUserByIDStmt, getUserByID, targetID) + var i GetUserByIDRow + err := row.Scan(&i.FirstName, &i.ID, &i.LastName) + return i, err +} + +const insertNewUser = `-- name: InsertNewUser :exec +INSERT INTO users (first_name, last_name) VALUES ($1, $2) +` + +type InsertNewUserParams struct { + FirstName string + LastName sql.NullString +} + +func (q *Queries) InsertNewUser(ctx context.Context, arg InsertNewUserParams) error { + _, err := q.exec(ctx, q.insertNewUserStmt, insertNewUser, arg.FirstName, arg.LastName) + return err +} + +const insertNewUserWithResult = `-- name: InsertNewUserWithResult :execresult +INSERT INTO users (first_name, last_name) VALUES ($1, $2) +` + +type InsertNewUserWithResultParams struct { + FirstName string + LastName sql.NullString +} + +func (q *Queries) InsertNewUserWithResult(ctx context.Context, arg InsertNewUserWithResultParams) (sql.Result, error) { + return q.exec(ctx, q.insertNewUserWithResultStmt, insertNewUserWithResult, arg.FirstName, arg.LastName) +} + +const listUsers = `-- name: ListUsers :many +SELECT first_name, last_name FROM users +` + +type ListUsersRow struct { + FirstName string + LastName sql.NullString +} + +func (q *Queries) ListUsers(ctx context.Context) ([]ListUsersRow, error) { + rows, err := q.query(ctx, q.listUsersStmt, listUsers) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUsersRow + for rows.Next() { + var i ListUsersRow + if err := rows.Scan(&i.FirstName, &i.LastName); 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/prepared_queries/postgresql/stdlib/query.sql b/internal/endtoend/testdata/prepared_queries/postgresql/stdlib/query.sql new file mode 100644 index 0000000..d2f54f2 --- /dev/null +++ b/internal/endtoend/testdata/prepared_queries/postgresql/stdlib/query.sql @@ -0,0 +1,14 @@ +/* name: GetUserByID :one */ +SELECT first_name, id, last_name FROM users WHERE id = sqlc.arg('target_id'); + +/* name: ListUsers :many */ +SELECT first_name, last_name FROM users; + +/* name: InsertNewUser :exec */ +INSERT INTO users (first_name, last_name) VALUES ($1, $2); + +/* name: InsertNewUserWithResult :execresult */ +INSERT INTO users (first_name, last_name) VALUES ($1, $2); + +/* name: DeleteUsersByName :execrows */ +DELETE FROM users WHERE first_name = $1 AND last_name = $2; diff --git a/internal/endtoend/testdata/prepared_queries/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/prepared_queries/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..c928f3b --- /dev/null +++ b/internal/endtoend/testdata/prepared_queries/postgresql/stdlib/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + id SERIAL NOT NULL, + first_name varchar(255) NOT NULL, + last_name varchar(255) +); + diff --git a/internal/endtoend/testdata/prepared_queries/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/prepared_queries/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..ff1ae98 --- /dev/null +++ b/internal/endtoend/testdata/prepared_queries/postgresql/stdlib/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql", + "emit_prepared_queries": true + } + ] +} diff --git a/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..c1d9086 --- /dev/null +++ b/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package primary_key_later + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/primary_key_later/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..0a9eae1 --- /dev/null +++ b/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v4/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package primary_key_later + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v4/go/queries.sql.go b/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v4/go/queries.sql.go new file mode 100644 index 0000000..469dcfa --- /dev/null +++ b/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v4/go/queries.sql.go @@ -0,0 +1,27 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: queries.sql + +package primary_key_later + +import ( + "context" +) + +const getAuthor = `-- name: GetAuthor :one +SELECT + id, name, bio +FROM + authors +WHERE + id = $1 +LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRow(ctx, getAuthor, id) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} diff --git a/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v4/queries.sql b/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v4/queries.sql new file mode 100644 index 0000000..158a7c6 --- /dev/null +++ b/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v4/queries.sql @@ -0,0 +1,9 @@ +-- name: GetAuthor :one +SELECT + * +FROM + authors +WHERE + id = $1 +LIMIT 1; + diff --git a/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..652d4f1 --- /dev/null +++ b/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v4/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE authors ( + id bigserial, + name text NOT NULL, + bio text, + PRIMARY KEY (id) +); + diff --git a/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..662dbe4 --- /dev/null +++ b/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "primary_key_later", + "schema": "schema.sql", + "queries": "queries.sql" + } + ] +} diff --git a/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..6223302 --- /dev/null +++ b/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package primary_key_later + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/primary_key_later/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a612b37 --- /dev/null +++ b/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v5/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package primary_key_later + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Author struct { + ID int64 + Name string + Bio pgtype.Text +} diff --git a/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v5/go/queries.sql.go b/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v5/go/queries.sql.go new file mode 100644 index 0000000..469dcfa --- /dev/null +++ b/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v5/go/queries.sql.go @@ -0,0 +1,27 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: queries.sql + +package primary_key_later + +import ( + "context" +) + +const getAuthor = `-- name: GetAuthor :one +SELECT + id, name, bio +FROM + authors +WHERE + id = $1 +LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRow(ctx, getAuthor, id) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} diff --git a/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v5/queries.sql b/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v5/queries.sql new file mode 100644 index 0000000..158a7c6 --- /dev/null +++ b/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v5/queries.sql @@ -0,0 +1,9 @@ +-- name: GetAuthor :one +SELECT + * +FROM + authors +WHERE + id = $1 +LIMIT 1; + diff --git a/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..652d4f1 --- /dev/null +++ b/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v5/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE authors ( + id bigserial, + name text NOT NULL, + bio text, + PRIMARY KEY (id) +); + diff --git a/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..798d222 --- /dev/null +++ b/internal/endtoend/testdata/primary_key_later/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "primary_key_later", + "schema": "schema.sql", + "queries": "queries.sql" + } + ] +} diff --git a/internal/endtoend/testdata/primary_key_later/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/primary_key_later/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..dd92c6e --- /dev/null +++ b/internal/endtoend/testdata/primary_key_later/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package primary_key_later + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/primary_key_later/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/primary_key_later/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..0a9eae1 --- /dev/null +++ b/internal/endtoend/testdata/primary_key_later/postgresql/stdlib/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package primary_key_later + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/primary_key_later/postgresql/stdlib/go/queries.sql.go b/internal/endtoend/testdata/primary_key_later/postgresql/stdlib/go/queries.sql.go new file mode 100644 index 0000000..2a6b8ee --- /dev/null +++ b/internal/endtoend/testdata/primary_key_later/postgresql/stdlib/go/queries.sql.go @@ -0,0 +1,27 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: queries.sql + +package primary_key_later + +import ( + "context" +) + +const getAuthor = `-- name: GetAuthor :one +SELECT + id, name, bio +FROM + authors +WHERE + id = $1 +LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} diff --git a/internal/endtoend/testdata/primary_key_later/postgresql/stdlib/queries.sql b/internal/endtoend/testdata/primary_key_later/postgresql/stdlib/queries.sql new file mode 100644 index 0000000..158a7c6 --- /dev/null +++ b/internal/endtoend/testdata/primary_key_later/postgresql/stdlib/queries.sql @@ -0,0 +1,9 @@ +-- name: GetAuthor :one +SELECT + * +FROM + authors +WHERE + id = $1 +LIMIT 1; + diff --git a/internal/endtoend/testdata/primary_key_later/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/primary_key_later/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..652d4f1 --- /dev/null +++ b/internal/endtoend/testdata/primary_key_later/postgresql/stdlib/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE authors ( + id bigserial, + name text NOT NULL, + bio text, + PRIMARY KEY (id) +); + diff --git a/internal/endtoend/testdata/primary_key_later/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/primary_key_later/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..c1defb3 --- /dev/null +++ b/internal/endtoend/testdata/primary_key_later/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "primary_key_later", + "schema": "schema.sql", + "queries": "queries.sql" + } + ] +} diff --git a/internal/endtoend/testdata/process_plugin_disabled/exec.json b/internal/endtoend/testdata/process_plugin_disabled/exec.json new file mode 100644 index 0000000..d88b817 --- /dev/null +++ b/internal/endtoend/testdata/process_plugin_disabled/exec.json @@ -0,0 +1,6 @@ +{ + "process": "sqlc-gen-json", + "env": { + "SQLCDEBUG": "processplugins=0" + } +} diff --git a/internal/endtoend/testdata/process_plugin_disabled/query.sql b/internal/endtoend/testdata/process_plugin_disabled/query.sql new file mode 100644 index 0000000..75e38b2 --- /dev/null +++ b/internal/endtoend/testdata/process_plugin_disabled/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_disabled/schema.sql b/internal/endtoend/testdata/process_plugin_disabled/schema.sql new file mode 100644 index 0000000..b4fad78 --- /dev/null +++ b/internal/endtoend/testdata/process_plugin_disabled/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_disabled/sqlc.json b/internal/endtoend/testdata/process_plugin_disabled/sqlc.json new file mode 100644 index 0000000..f471891 --- /dev/null +++ b/internal/endtoend/testdata/process_plugin_disabled/sqlc.json @@ -0,0 +1,28 @@ +{ + "version": "2", + "sql": [ + { + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql", + "codegen": [ + { + "out": "gen", + "plugin": "jsonb", + "options": { + "indent": " ", + "filename": "codegen.json" + } + } + ] + } + ], + "plugins": [ + { + "name": "jsonb", + "process": { + "cmd": "sqlc-gen-json" + } + } + ] +} diff --git a/internal/endtoend/testdata/process_plugin_disabled/stderr.txt b/internal/endtoend/testdata/process_plugin_disabled/stderr.txt new file mode 100644 index 0000000..85ee900 --- /dev/null +++ b/internal/endtoend/testdata/process_plugin_disabled/stderr.txt @@ -0,0 +1 @@ +error validating sqlc.json: plugin: process-based plugins disabled via SQLCDEBUG=processplugins=0 diff --git a/internal/endtoend/testdata/process_plugin_format_json/exec.json b/internal/endtoend/testdata/process_plugin_format_json/exec.json new file mode 100644 index 0000000..2cfb9f2 --- /dev/null +++ b/internal/endtoend/testdata/process_plugin_format_json/exec.json @@ -0,0 +1,4 @@ +{ + "process": "test-json-process-plugin", + "os": [ "darwin", "linux" ] +} diff --git a/internal/endtoend/testdata/process_plugin_format_json/gen/hello.txt b/internal/endtoend/testdata/process_plugin_format_json/gen/hello.txt new file mode 100644 index 0000000..05d6799 --- /dev/null +++ b/internal/endtoend/testdata/process_plugin_format_json/gen/hello.txt @@ -0,0 +1,12 @@ +SELECT id, name, bio FROM authors +WHERE id = $1 LIMIT 1 +SELECT id, name, bio FROM authors +ORDER BY name +INSERT INTO authors ( + name, bio +) VALUES ( + $1, $2 +) +RETURNING id, name, bio +DELETE FROM authors +WHERE id = $1 diff --git a/internal/endtoend/testdata/process_plugin_format_json/query.sql b/internal/endtoend/testdata/process_plugin_format_json/query.sql new file mode 100644 index 0000000..75e38b2 --- /dev/null +++ b/internal/endtoend/testdata/process_plugin_format_json/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_format_json/schema.sql b/internal/endtoend/testdata/process_plugin_format_json/schema.sql new file mode 100644 index 0000000..b4fad78 --- /dev/null +++ b/internal/endtoend/testdata/process_plugin_format_json/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_format_json/sqlc.json b/internal/endtoend/testdata/process_plugin_format_json/sqlc.json new file mode 100644 index 0000000..28055fa --- /dev/null +++ b/internal/endtoend/testdata/process_plugin_format_json/sqlc.json @@ -0,0 +1,25 @@ +{ + "version": "2", + "sql": [ + { + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql", + "codegen": [ + { + "out": "gen", + "plugin": "jsonb" + } + ] + } + ], + "plugins": [ + { + "name": "jsonb", + "process": { + "cmd": "test-json-process-plugin", + "format": "json" + } + } + ] +} diff --git a/internal/endtoend/testdata/process_plugin_sqlc_gen_json/exec.json b/internal/endtoend/testdata/process_plugin_sqlc_gen_json/exec.json new file mode 100644 index 0000000..e38046c --- /dev/null +++ b/internal/endtoend/testdata/process_plugin_sqlc_gen_json/exec.json @@ -0,0 +1,4 @@ +{ + "contexts": ["base"], + "process": "sqlc-gen-json" +} diff --git a/internal/endtoend/testdata/process_plugin_sqlc_gen_json/query.sql b/internal/endtoend/testdata/process_plugin_sqlc_gen_json/query.sql new file mode 100644 index 0000000..75e38b2 --- /dev/null +++ b/internal/endtoend/testdata/process_plugin_sqlc_gen_json/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_json/schema.sql b/internal/endtoend/testdata/process_plugin_sqlc_gen_json/schema.sql new file mode 100644 index 0000000..b4fad78 --- /dev/null +++ b/internal/endtoend/testdata/process_plugin_sqlc_gen_json/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_json/sqlc.json b/internal/endtoend/testdata/process_plugin_sqlc_gen_json/sqlc.json new file mode 100644 index 0000000..f471891 --- /dev/null +++ b/internal/endtoend/testdata/process_plugin_sqlc_gen_json/sqlc.json @@ -0,0 +1,28 @@ +{ + "version": "2", + "sql": [ + { + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql", + "codegen": [ + { + "out": "gen", + "plugin": "jsonb", + "options": { + "indent": " ", + "filename": "codegen.json" + } + } + ] + } + ], + "plugins": [ + { + "name": "jsonb", + "process": { + "cmd": "sqlc-gen-json" + } + } + ] +} 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 0000000..1aa4920 --- /dev/null +++ b/internal/endtoend/testdata/process_plugin_sqlc_gen_test/exec.json @@ -0,0 +1,4 @@ +{ + "process": "sqlc-gen-test", + "os": ["linux", "darwin"] +} 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 0000000..48e316b --- /dev/null +++ b/internal/endtoend/testdata/process_plugin_sqlc_gen_test/gen/env.json @@ -0,0 +1,6 @@ +{ + "env": [ + "SQLC_VERSION=v1.31.1", + "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 0000000..75e38b2 --- /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 0000000..b4fad78 --- /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 0000000..a2b0e8b --- /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_invalid/postgresql/query.sql b/internal/endtoend/testdata/query_parameter_limit_invalid/postgresql/query.sql new file mode 100644 index 0000000..a71d662 --- /dev/null +++ b/internal/endtoend/testdata/query_parameter_limit_invalid/postgresql/query.sql @@ -0,0 +1,19 @@ +-- name: GetAuthor :one +SELECT * FROM authors +WHERE name = $1 AND country_code = $2 LIMIT 1; + +-- name: ListAuthors :many +SELECT * FROM authors +ORDER BY name; + +-- name: CreateAuthor :one +INSERT INTO authors ( + name, bio, country_code +) VALUES ( + $1, $2, $3 +) +RETURNING *; + +-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = $1; diff --git a/internal/endtoend/testdata/query_parameter_limit_invalid/postgresql/schema.sql b/internal/endtoend/testdata/query_parameter_limit_invalid/postgresql/schema.sql new file mode 100644 index 0000000..6027f56 --- /dev/null +++ b/internal/endtoend/testdata/query_parameter_limit_invalid/postgresql/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text, + country_code CHAR(2) NOT NULL +); diff --git a/internal/endtoend/testdata/query_parameter_limit_invalid/postgresql/sqlc.json b/internal/endtoend/testdata/query_parameter_limit_invalid/postgresql/sqlc.json new file mode 100644 index 0000000..c473270 --- /dev/null +++ b/internal/endtoend/testdata/query_parameter_limit_invalid/postgresql/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "query_parameter_limit": -1 + } + ] + } + \ No newline at end of file diff --git a/internal/endtoend/testdata/query_parameter_limit_invalid/postgresql/stderr.txt b/internal/endtoend/testdata/query_parameter_limit_invalid/postgresql/stderr.txt new file mode 100644 index 0000000..9e1760f --- /dev/null +++ b/internal/endtoend/testdata/query_parameter_limit_invalid/postgresql/stderr.txt @@ -0,0 +1,2 @@ +# package querytest +error generating code: invalid options: query parameter limit must not be negative 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 0000000..32faa9f --- /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.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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 0000000..093c6ff --- /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.31.1 + +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 0000000..fff756a --- /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.31.1 + +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 0000000..44287c0 --- /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.31.1 +// 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 0000000..7622baf --- /dev/null +++ b/internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/query.sql @@ -0,0 +1,8 @@ +-- 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/schema.sql b/internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/schema.sql new file mode 100644 index 0000000..f07b5f4 --- /dev/null +++ b/internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/schema.sql @@ -0,0 +1,8 @@ +CREATE TABLE notice ( + id INTEGER NOT NULL, + cnt INTEGER NOT NULL, + status TEXT NOT NULL, + notice_at TIMESTAMP, + created_at TIMESTAMP NOT NULL +); + 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 0000000..78d96c3 --- /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": "schema.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/db.go b/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_to_two/postgresql/go/models.go b/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/go/models.go new file mode 100644 index 0000000..e70c52a --- /dev/null +++ b/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/go/models.go @@ -0,0 +1,22 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString + 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 new file mode 100644 index 0000000..971b1ef --- /dev/null +++ b/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/go/query.sql.go @@ -0,0 +1,164 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" + "strings" + + "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 +) VALUES ( + $1, $2, $3, $4 +) +RETURNING id, name, bio, country_code, titles +` + +type CreateAuthorParams struct { + Name string + Bio sql.NullString + CountryCode string + Titles []string +} + +func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (Author, error) { + row := q.db.QueryRowContext(ctx, createAuthor, + arg.Name, + arg.Bio, + arg.CountryCode, + pq.Array(arg.Titles), + ) + var i Author + err := row.Scan( + &i.ID, + &i.Name, + &i.Bio, + &i.CountryCode, + pq.Array(&i.Titles), + ) + return i, err +} + +const createAuthorOnlyTitles = `-- name: CreateAuthorOnlyTitles :one +INSERT INTO authors (name, titles) VALUES ($1, $2) RETURNING id, name, bio, country_code, titles +` + +func (q *Queries) CreateAuthorOnlyTitles(ctx context.Context, name string, titles []string) (Author, error) { + row := q.db.QueryRowContext(ctx, createAuthorOnlyTitles, name, pq.Array(titles)) + var i Author + err := row.Scan( + &i.ID, + &i.Name, + &i.Bio, + &i.CountryCode, + pq.Array(&i.Titles), + ) + return i, err +} + +const deleteAuthor = `-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = $1 +` + +func (q *Queries) DeleteAuthor(ctx context.Context, id int64) error { + _, err := q.db.ExecContext(ctx, deleteAuthor, id) + return err +} + +const deleteAuthors = `-- name: DeleteAuthors :exec +DELETE FROM authors +WHERE id IN ($2) AND name = $1 +` + +func (q *Queries) DeleteAuthors(ctx context.Context, name string, ids []int64) error { + query := deleteAuthors + var queryParams []any + queryParams = append(queryParams, name) + if len(ids) > 0 { + for _, v := range ids { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:ids*/?", strings.Repeat(",?", len(ids))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:ids*/?", "NULL", 1) + } + _, err := q.db.ExecContext(ctx, query, queryParams...) + return err +} + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, bio, country_code, titles FROM authors +WHERE name = $1 AND country_code = $2 LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, name string, countryCode string) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, name, countryCode) + var i Author + err := row.Scan( + &i.ID, + &i.Name, + &i.Bio, + &i.CountryCode, + pq.Array(&i.Titles), + ) + return i, err +} + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name, bio, country_code, titles FROM authors +ORDER BY name +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan( + &i.ID, + &i.Name, + &i.Bio, + &i.CountryCode, + pq.Array(&i.Titles), + ); 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/query_parameter_limit_to_two/postgresql/query.sql b/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/query.sql new file mode 100644 index 0000000..b255f75 --- /dev/null +++ b/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/query.sql @@ -0,0 +1,34 @@ +-- name: GetAuthor :one +SELECT * FROM authors +WHERE name = $1 AND country_code = $2 LIMIT 1; + +-- name: ListAuthors :many +SELECT * FROM authors +ORDER BY name; + +-- name: CreateAuthor :one +INSERT INTO authors ( + name, bio, country_code, titles +) VALUES ( + $1, $2, $3, $4 +) +RETURNING *; + +-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = $1; + +-- name: DeleteAuthors :exec +DELETE FROM authors +WHERE id IN (sqlc.slice(ids)) AND name = $1; + +-- name: CreateAuthorOnlyTitles :one +INSERT INTO authors (name, titles) VALUES ($1, $2) RETURNING *; + +-- name: AddNewClient :one +INSERT INTO clients ( + id, name +) VALUES ( + $1, $2 +) +RETURNING *; diff --git a/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/schema.sql b/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/schema.sql new file mode 100644 index 0000000..eef7025 --- /dev/null +++ b/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/schema.sql @@ -0,0 +1,13 @@ +-- Example queries for sqlc +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text, + country_code CHAR(2) NOT NULL, + titles TEXT[] +); + +CREATE TABLE clients ( + id INT PRIMARY KEY, + name TEXT NOT NULL +); diff --git a/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/sqlc.json b/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/sqlc.json new file mode 100644 index 0000000..5aea38d --- /dev/null +++ b/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "query_parameter_limit": 2 + } + ] + } + \ No newline at end of file diff --git a/internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/go/db.go b/internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_to_zero/postgresql/go/models.go b/internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/go/models.go new file mode 100644 index 0000000..7b281eb --- /dev/null +++ b/internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString + CountryCode string +} diff --git a/internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/go/querier.go b/internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/go/querier.go new file mode 100644 index 0000000..568101f --- /dev/null +++ b/internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/go/querier.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" +) + +type Querier interface { + CreateAuthor(ctx context.Context, arg CreateAuthorParams) (Author, error) + DeleteAuthor(ctx context.Context, arg DeleteAuthorParams) error + GetAuthor(ctx context.Context, arg GetAuthorParams) (Author, error) + ListAuthors(ctx context.Context) ([]Author, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/go/query.sql.go b/internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/go/query.sql.go new file mode 100644 index 0000000..471b116 --- /dev/null +++ b/internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/go/query.sql.go @@ -0,0 +1,107 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const createAuthor = `-- name: CreateAuthor :one +INSERT INTO authors ( + name, bio, country_code +) VALUES ( + $1, $2, $3 +) +RETURNING id, name, bio, country_code +` + +type CreateAuthorParams struct { + Name string + Bio sql.NullString + CountryCode string +} + +func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (Author, error) { + row := q.db.QueryRowContext(ctx, createAuthor, arg.Name, arg.Bio, arg.CountryCode) + var i Author + err := row.Scan( + &i.ID, + &i.Name, + &i.Bio, + &i.CountryCode, + ) + return i, err +} + +const deleteAuthor = `-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = $1 +` + +type DeleteAuthorParams struct { + ID int64 +} + +func (q *Queries) DeleteAuthor(ctx context.Context, arg DeleteAuthorParams) error { + _, err := q.db.ExecContext(ctx, deleteAuthor, arg.ID) + return err +} + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, bio, country_code FROM authors +WHERE name = $1 AND country_code = $2 LIMIT 1 +` + +type GetAuthorParams struct { + Name string + CountryCode string +} + +func (q *Queries) GetAuthor(ctx context.Context, arg GetAuthorParams) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, arg.Name, arg.CountryCode) + var i Author + err := row.Scan( + &i.ID, + &i.Name, + &i.Bio, + &i.CountryCode, + ) + return i, err +} + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name, bio, country_code FROM authors +ORDER BY name +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan( + &i.ID, + &i.Name, + &i.Bio, + &i.CountryCode, + ); 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/query_parameter_limit_to_zero/postgresql/query.sql b/internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/query.sql new file mode 100644 index 0000000..a71d662 --- /dev/null +++ b/internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/query.sql @@ -0,0 +1,19 @@ +-- name: GetAuthor :one +SELECT * FROM authors +WHERE name = $1 AND country_code = $2 LIMIT 1; + +-- name: ListAuthors :many +SELECT * FROM authors +ORDER BY name; + +-- name: CreateAuthor :one +INSERT INTO authors ( + name, bio, country_code +) VALUES ( + $1, $2, $3 +) +RETURNING *; + +-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = $1; diff --git a/internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/schema.sql b/internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/schema.sql new file mode 100644 index 0000000..d06fd86 --- /dev/null +++ b/internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/schema.sql @@ -0,0 +1,8 @@ +-- Example queries for sqlc +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text, + country_code CHAR(2) NOT NULL +); + diff --git a/internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/sqlc.json b/internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/sqlc.json new file mode 100644 index 0000000..af2da73 --- /dev/null +++ b/internal/endtoend/testdata/query_parameter_limit_to_zero/postgresql/sqlc.json @@ -0,0 +1,15 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "query_parameter_limit": 0, + "emit_interface": true + } + ] + } + diff --git a/internal/endtoend/testdata/quoted_colname/sqlite/go/db.go b/internal/endtoend/testdata/quoted_colname/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/quoted_colname/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/quoted_colname/sqlite/go/models.go b/internal/endtoend/testdata/quoted_colname/sqlite/go/models.go new file mode 100644 index 0000000..9182ff9 --- /dev/null +++ b/internal/endtoend/testdata/quoted_colname/sqlite/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Test struct { + ID string +} diff --git a/internal/endtoend/testdata/quoted_colname/sqlite/go/query.sql.go b/internal/endtoend/testdata/quoted_colname/sqlite/go/query.sql.go new file mode 100644 index 0000000..1e5ad1e --- /dev/null +++ b/internal/endtoend/testdata/quoted_colname/sqlite/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const testList = `-- name: TestList :many +SELECT id FROM test +` + +func (q *Queries) TestList(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, testList) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 +} diff --git a/internal/endtoend/testdata/quoted_colname/sqlite/query.sql b/internal/endtoend/testdata/quoted_colname/sqlite/query.sql new file mode 100644 index 0000000..10a35f0 --- /dev/null +++ b/internal/endtoend/testdata/quoted_colname/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: TestList :many +SELECT * FROM test; diff --git a/internal/endtoend/testdata/quoted_colname/sqlite/schema.sql b/internal/endtoend/testdata/quoted_colname/sqlite/schema.sql new file mode 100644 index 0000000..8e6b5b3 --- /dev/null +++ b/internal/endtoend/testdata/quoted_colname/sqlite/schema.sql @@ -0,0 +1,6 @@ +-- Example queries for sqlc +CREATE TABLE "test" +( + "id" TEXT NOT NULL +); + diff --git a/internal/endtoend/testdata/quoted_colname/sqlite/sqlc.json b/internal/endtoend/testdata/quoted_colname/sqlite/sqlc.json new file mode 100644 index 0000000..ea4a234 --- /dev/null +++ b/internal/endtoend/testdata/quoted_colname/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "schema": "schema.sql", + "queries": "query.sql", + "name": "querytest" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/quoted_names_complex/sqlite/go/db.go b/internal/endtoend/testdata/quoted_names_complex/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/quoted_names_complex/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/quoted_names_complex/sqlite/go/models.go b/internal/endtoend/testdata/quoted_names_complex/sqlite/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/quoted_names_complex/sqlite/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/quoted_names_complex/sqlite/go/query.sql.go b/internal/endtoend/testdata/quoted_names_complex/sqlite/go/query.sql.go new file mode 100644 index 0000000..80e5d9b --- /dev/null +++ b/internal/endtoend/testdata/quoted_names_complex/sqlite/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/quoted_names_complex/sqlite/query.sql b/internal/endtoend/testdata/quoted_names_complex/sqlite/query.sql new file mode 100644 index 0000000..6520aef --- /dev/null +++ b/internal/endtoend/testdata/quoted_names_complex/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/quoted_names_complex/sqlite/schema.sql b/internal/endtoend/testdata/quoted_names_complex/sqlite/schema.sql new file mode 100644 index 0000000..5486831 --- /dev/null +++ b/internal/endtoend/testdata/quoted_names_complex/sqlite/schema.sql @@ -0,0 +1,22 @@ +-- Test complex quoted table and column names with special characters +-- Covers spaces, hyphens, uppercase, and mixed operations +CREATE TABLE "user profiles" (id integer primary key, data text); +CREATE TABLE "ORDERS" (id integer primary key, data text); +CREATE TABLE products (id integer primary key, data text); +CREATE TABLE "item-categories" (id integer primary key, data text); + +-- Test ALTER statements with complex identifiers +ALTER TABLE "user profiles" RENAME COLUMN data TO "profile data"; +ALTER TABLE "ORDERS" RENAME TO "customer_orders"; +ALTER TABLE products ADD COLUMN "Price Info" text; + +-- Test mixed case operations across different statement types +INSERT INTO "user profiles" ("profile data") VALUES ('test data'); +UPDATE "customer_orders" SET data = 'updated' WHERE id = 1; +DELETE FROM products WHERE id = 1; + +-- Test DROP with various identifier formats +DROP TABLE "user profiles"; +DROP TABLE "customer_orders"; +DROP TABLE "item-categories"; +DROP TABLE products; diff --git a/internal/endtoend/testdata/quoted_names_complex/sqlite/sqlc.json b/internal/endtoend/testdata/quoted_names_complex/sqlite/sqlc.json new file mode 100644 index 0000000..cd66df0 --- /dev/null +++ b/internal/endtoend/testdata/quoted_names_complex/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/quoted_tablename/sqlite/go/db.go b/internal/endtoend/testdata/quoted_tablename/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/quoted_tablename/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/quoted_tablename/sqlite/go/models.go b/internal/endtoend/testdata/quoted_tablename/sqlite/go/models.go new file mode 100644 index 0000000..2e3921b --- /dev/null +++ b/internal/endtoend/testdata/quoted_tablename/sqlite/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type User struct { + ID string +} diff --git a/internal/endtoend/testdata/quoted_tablename/sqlite/go/query.sql.go b/internal/endtoend/testdata/quoted_tablename/sqlite/go/query.sql.go new file mode 100644 index 0000000..6743358 --- /dev/null +++ b/internal/endtoend/testdata/quoted_tablename/sqlite/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const testList = `-- name: TestList :many +SELECT id FROM users +` + +func (q *Queries) TestList(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, testList) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + 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 +} diff --git a/internal/endtoend/testdata/quoted_tablename/sqlite/query.sql b/internal/endtoend/testdata/quoted_tablename/sqlite/query.sql new file mode 100644 index 0000000..0d3b8e2 --- /dev/null +++ b/internal/endtoend/testdata/quoted_tablename/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: TestList :many +SELECT * FROM users; diff --git a/internal/endtoend/testdata/quoted_tablename/sqlite/schema.sql b/internal/endtoend/testdata/quoted_tablename/sqlite/schema.sql new file mode 100644 index 0000000..078fa24 --- /dev/null +++ b/internal/endtoend/testdata/quoted_tablename/sqlite/schema.sql @@ -0,0 +1,6 @@ +-- Example queries for sqlc +CREATE TABLE "users" +( + id TEXT NOT NULL +); + diff --git a/internal/endtoend/testdata/quoted_tablename/sqlite/sqlc.json b/internal/endtoend/testdata/quoted_tablename/sqlite/sqlc.json new file mode 100644 index 0000000..ea4a234 --- /dev/null +++ b/internal/endtoend/testdata/quoted_tablename/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "schema": "schema.sql", + "queries": "query.sql", + "name": "querytest" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/ranges/pgx/v5/go/db.go b/internal/endtoend/testdata/ranges/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/ranges/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/ranges/pgx/v5/go/models.go b/internal/endtoend/testdata/ranges/pgx/v5/go/models.go new file mode 100644 index 0000000..008296c --- /dev/null +++ b/internal/endtoend/testdata/ranges/pgx/v5/go/models.go @@ -0,0 +1,36 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type TestTable struct { + VDaterangeNull pgtype.Range[pgtype.Date] + VDatemultirangeNull pgtype.Multirange[pgtype.Range[pgtype.Date]] + VTsrangeNull pgtype.Range[pgtype.Timestamp] + VTsmultirangeNull pgtype.Multirange[pgtype.Range[pgtype.Timestamp]] + VTstzrangeNull pgtype.Range[pgtype.Timestamptz] + VTstzmultirangeNull pgtype.Multirange[pgtype.Range[pgtype.Timestamptz]] + VNumrangeNull pgtype.Range[pgtype.Numeric] + VNummultirangeNull pgtype.Multirange[pgtype.Range[pgtype.Numeric]] + VInt4rangeNull pgtype.Range[pgtype.Int4] + VInt4multirangeNull pgtype.Multirange[pgtype.Range[pgtype.Int4]] + VInt8rangeNull pgtype.Range[pgtype.Int8] + VInt8multirangeNull pgtype.Multirange[pgtype.Range[pgtype.Int8]] + VDaterange pgtype.Range[pgtype.Date] + VDatemultirange pgtype.Multirange[pgtype.Range[pgtype.Date]] + VTsrange pgtype.Range[pgtype.Timestamp] + VTsmultirange pgtype.Multirange[pgtype.Range[pgtype.Timestamp]] + VTstzrange pgtype.Range[pgtype.Timestamptz] + VTstzmultirange pgtype.Multirange[pgtype.Range[pgtype.Timestamptz]] + VNumrange pgtype.Range[pgtype.Numeric] + VNummultirange pgtype.Multirange[pgtype.Range[pgtype.Numeric]] + VInt4range pgtype.Range[pgtype.Int4] + VInt4multirange pgtype.Multirange[pgtype.Range[pgtype.Int4]] + VInt8range pgtype.Range[pgtype.Int8] + VInt8multirange pgtype.Multirange[pgtype.Range[pgtype.Int8]] +} diff --git a/internal/endtoend/testdata/ranges/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ranges/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..e04465f --- /dev/null +++ b/internal/endtoend/testdata/ranges/pgx/v5/go/query.sql.go @@ -0,0 +1,59 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const selectTest = `-- name: SelectTest :many +SELECT v_daterange_null, v_datemultirange_null, v_tsrange_null, v_tsmultirange_null, v_tstzrange_null, v_tstzmultirange_null, v_numrange_null, v_nummultirange_null, v_int4range_null, v_int4multirange_null, v_int8range_null, v_int8multirange_null, v_daterange, v_datemultirange, v_tsrange, v_tsmultirange, v_tstzrange, v_tstzmultirange, v_numrange, v_nummultirange, v_int4range, v_int4multirange, v_int8range, v_int8multirange 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.VDaterangeNull, + &i.VDatemultirangeNull, + &i.VTsrangeNull, + &i.VTsmultirangeNull, + &i.VTstzrangeNull, + &i.VTstzmultirangeNull, + &i.VNumrangeNull, + &i.VNummultirangeNull, + &i.VInt4rangeNull, + &i.VInt4multirangeNull, + &i.VInt8rangeNull, + &i.VInt8multirangeNull, + &i.VDaterange, + &i.VDatemultirange, + &i.VTsrange, + &i.VTsmultirange, + &i.VTstzrange, + &i.VTstzmultirange, + &i.VNumrange, + &i.VNummultirange, + &i.VInt4range, + &i.VInt4multirange, + &i.VInt8range, + &i.VInt8multirange, + ); 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/ranges/pgx/v5/query.sql b/internal/endtoend/testdata/ranges/pgx/v5/query.sql new file mode 100644 index 0000000..0119001 --- /dev/null +++ b/internal/endtoend/testdata/ranges/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: SelectTest :many +SELECT * from test_table; diff --git a/internal/endtoend/testdata/ranges/pgx/v5/schema.sql b/internal/endtoend/testdata/ranges/pgx/v5/schema.sql new file mode 100644 index 0000000..d217bb6 --- /dev/null +++ b/internal/endtoend/testdata/ranges/pgx/v5/schema.sql @@ -0,0 +1,28 @@ +CREATE TABLE test_table +( + v_daterange_null daterange, + v_datemultirange_null datemultirange, + v_tsrange_null tsrange, + v_tsmultirange_null tsmultirange, + v_tstzrange_null tstzrange, + v_tstzmultirange_null tstzmultirange, + v_numrange_null numrange, + v_nummultirange_null nummultirange, + v_int4range_null int4range, + v_int4multirange_null int4multirange, + v_int8range_null int8range, + v_int8multirange_null int8multirange, + v_daterange daterange not null, + v_datemultirange datemultirange not null, + v_tsrange tsrange not null, + v_tsmultirange tsmultirange not null, + v_tstzrange tstzrange not null, + v_tstzmultirange tstzmultirange not null, + v_numrange numrange not null, + v_nummultirange nummultirange not null, + v_int4range int4range not null, + v_int4multirange int4multirange not null, + v_int8range int8range not null, + v_int8multirange int8multirange not null +); + diff --git a/internal/endtoend/testdata/ranges/pgx/v5/sqlc.json b/internal/endtoend/testdata/ranges/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/ranges/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/refreshmatview/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..f39382e --- /dev/null +++ b/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Myview struct { + int32 +} diff --git a/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..d899ee8 --- /dev/null +++ b/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const refresh = `-- name: Refresh :exec +REFRESH MATERIALIZED VIEW myview +` + +func (q *Queries) Refresh(ctx context.Context) error { + _, err := q.db.Exec(ctx, refresh) + return err +} diff --git a/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..3b3af63 --- /dev/null +++ b/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Refresh :exec +REFRESH MATERIALIZED VIEW myview; diff --git a/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..5b5f556 --- /dev/null +++ b/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE MATERIALIZED VIEW myview AS (SELECT 1); + diff --git a/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/refreshmatview/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..f39382e --- /dev/null +++ b/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Myview struct { + int32 +} diff --git a/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..d899ee8 --- /dev/null +++ b/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const refresh = `-- name: Refresh :exec +REFRESH MATERIALIZED VIEW myview +` + +func (q *Queries) Refresh(ctx context.Context) error { + _, err := q.db.Exec(ctx, refresh) + return err +} diff --git a/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..3b3af63 --- /dev/null +++ b/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Refresh :exec +REFRESH MATERIALIZED VIEW myview; diff --git a/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..5b5f556 --- /dev/null +++ b/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE MATERIALIZED VIEW myview AS (SELECT 1); + diff --git a/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/refreshmatview/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/relation_does_not_exist/postgresql/query.sql b/internal/endtoend/testdata/relation_does_not_exist/postgresql/query.sql new file mode 100644 index 0000000..cb7e6e1 --- /dev/null +++ b/internal/endtoend/testdata/relation_does_not_exist/postgresql/query.sql @@ -0,0 +1,11 @@ +-- name: MissingSelect :many +SELECT * FROM nonexisting_relation WHERE name = 'foo'; + +-- name: MissingParam :many +SELECT * FROM nonexisting_relation WHERE name = $1; + +-- name: MissingUpdate :exec +UPDATE nonexisting_relation SET name = $1; + +-- name: MisingInsert :exec +INSERT INTO nonexisting_relation (id) VALUES ($1); diff --git a/internal/endtoend/testdata/relation_does_not_exist/postgresql/schema.sql b/internal/endtoend/testdata/relation_does_not_exist/postgresql/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/relation_does_not_exist/postgresql/sqlc.json b/internal/endtoend/testdata/relation_does_not_exist/postgresql/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/relation_does_not_exist/postgresql/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/relation_does_not_exist/postgresql/stderr/base.txt b/internal/endtoend/testdata/relation_does_not_exist/postgresql/stderr/base.txt new file mode 100644 index 0000000..0d8930e --- /dev/null +++ b/internal/endtoend/testdata/relation_does_not_exist/postgresql/stderr/base.txt @@ -0,0 +1,5 @@ +# package querytest +query.sql:1:1: relation "nonexisting_relation" does not exist +query.sql:5:1: relation "nonexisting_relation" does not exist +query.sql:8:1: relation "nonexisting_relation" does not exist +query.sql:11:1: relation "nonexisting_relation" does not exist diff --git a/internal/endtoend/testdata/relation_does_not_exist/postgresql/stderr/managed-db.txt b/internal/endtoend/testdata/relation_does_not_exist/postgresql/stderr/managed-db.txt new file mode 100644 index 0000000..5621f97 --- /dev/null +++ b/internal/endtoend/testdata/relation_does_not_exist/postgresql/stderr/managed-db.txt @@ -0,0 +1,5 @@ +# package querytest +query.sql:2:15: relation "nonexisting_relation" does not exist +query.sql:5:15: relation "nonexisting_relation" does not exist +query.sql:8:8: relation "nonexisting_relation" does not exist +query.sql:11:13: relation "nonexisting_relation" does not exist diff --git a/internal/endtoend/testdata/rename/v1/pgx/v4/go/db.go b/internal/endtoend/testdata/rename/v1/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/rename/v1/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/rename/v1/pgx/v4/go/models.go b/internal/endtoend/testdata/rename/v1/pgx/v4/go/models.go new file mode 100644 index 0000000..1d4f75a --- /dev/null +++ b/internal/endtoend/testdata/rename/v1/pgx/v4/go/models.go @@ -0,0 +1,58 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type IPProtocol string + +const ( + IPProtocolTCP IPProtocol = "tcp" + IpProtocolIp IPProtocol = "ip" + IpProtocolIcmp IPProtocol = "icmp" +) + +func (e *IPProtocol) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = IPProtocol(s) + case string: + *e = IPProtocol(s) + default: + return fmt.Errorf("unsupported scan type for IPProtocol: %T", src) + } + return nil +} + +type NullIPProtocol struct { + IPProtocol IPProtocol + Valid bool // Valid is true if IPProtocol is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullIPProtocol) Scan(value any) error { + if value == nil { + ns.IPProtocol, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.IPProtocol.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullIPProtocol) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.IPProtocol), nil +} + +type BarNew struct { + IDNew int32 + IpOld IPProtocol +} diff --git a/internal/endtoend/testdata/rename/v1/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/rename/v1/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..98787cd --- /dev/null +++ b/internal/endtoend/testdata/rename/v1/pgx/v4/go/query.sql.go @@ -0,0 +1,70 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listBar = `-- name: ListBar :many +SELECT id_old, ip_old FROM bar_old +` + +func (q *Queries) ListBar(ctx context.Context) ([]BarNew, error) { + rows, err := q.db.Query(ctx, listBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []BarNew + for rows.Next() { + var i BarNew + if err := rows.Scan(&i.IDNew, &i.IpOld); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listFoo = `-- name: ListFoo :many +SELECT id_old as foo_old, id_old as baz_old +FROM bar_old +WHERE ip_old = $1 AND id_old = $2 +` + +type ListFooParams struct { + IpOld IPProtocol + IDNew int32 +} + +type ListFooRow struct { + FooNew int32 + BazOld int32 +} + +func (q *Queries) ListFoo(ctx context.Context, arg ListFooParams) ([]ListFooRow, error) { + rows, err := q.db.Query(ctx, listFoo, arg.IpOld, arg.IDNew) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListFooRow + for rows.Next() { + var i ListFooRow + if err := rows.Scan(&i.FooNew, &i.BazOld); 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/rename/v1/pgx/v4/query.sql b/internal/endtoend/testdata/rename/v1/pgx/v4/query.sql new file mode 100644 index 0000000..a8211d0 --- /dev/null +++ b/internal/endtoend/testdata/rename/v1/pgx/v4/query.sql @@ -0,0 +1,8 @@ +-- name: ListFoo :many +SELECT id_old as foo_old, id_old as baz_old +FROM bar_old +WHERE ip_old = $1 AND id_old = $2; + +-- name: ListBar :many +SELECT * FROM bar_old; + diff --git a/internal/endtoend/testdata/rename/v1/pgx/v4/schema.sql b/internal/endtoend/testdata/rename/v1/pgx/v4/schema.sql new file mode 100644 index 0000000..764436c --- /dev/null +++ b/internal/endtoend/testdata/rename/v1/pgx/v4/schema.sql @@ -0,0 +1,4 @@ +CREATE TYPE ip_protocol AS enum('tcp', 'ip', 'icmp'); + +CREATE TABLE bar_old (id_old serial not null, ip_old ip_protocol NOT NULL); + diff --git a/internal/endtoend/testdata/rename/v1/pgx/v4/sqlc.json b/internal/endtoend/testdata/rename/v1/pgx/v4/sqlc.json new file mode 100644 index 0000000..50288fc --- /dev/null +++ b/internal/endtoend/testdata/rename/v1/pgx/v4/sqlc.json @@ -0,0 +1,20 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ], + "rename": { + "id_old": "IDNew", + "bar_old": "BarNew", + "foo_old": "FooNew", + "ip_protocol": "IPProtocol", + "ip_protocol_tcp": "IPProtocolTCP" + } +} diff --git a/internal/endtoend/testdata/rename/v1/pgx/v5/go/db.go b/internal/endtoend/testdata/rename/v1/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/rename/v1/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/rename/v1/pgx/v5/go/models.go b/internal/endtoend/testdata/rename/v1/pgx/v5/go/models.go new file mode 100644 index 0000000..1d4f75a --- /dev/null +++ b/internal/endtoend/testdata/rename/v1/pgx/v5/go/models.go @@ -0,0 +1,58 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type IPProtocol string + +const ( + IPProtocolTCP IPProtocol = "tcp" + IpProtocolIp IPProtocol = "ip" + IpProtocolIcmp IPProtocol = "icmp" +) + +func (e *IPProtocol) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = IPProtocol(s) + case string: + *e = IPProtocol(s) + default: + return fmt.Errorf("unsupported scan type for IPProtocol: %T", src) + } + return nil +} + +type NullIPProtocol struct { + IPProtocol IPProtocol + Valid bool // Valid is true if IPProtocol is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullIPProtocol) Scan(value any) error { + if value == nil { + ns.IPProtocol, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.IPProtocol.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullIPProtocol) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.IPProtocol), nil +} + +type BarNew struct { + IDNew int32 + IpOld IPProtocol +} diff --git a/internal/endtoend/testdata/rename/v1/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/rename/v1/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..98787cd --- /dev/null +++ b/internal/endtoend/testdata/rename/v1/pgx/v5/go/query.sql.go @@ -0,0 +1,70 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listBar = `-- name: ListBar :many +SELECT id_old, ip_old FROM bar_old +` + +func (q *Queries) ListBar(ctx context.Context) ([]BarNew, error) { + rows, err := q.db.Query(ctx, listBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []BarNew + for rows.Next() { + var i BarNew + if err := rows.Scan(&i.IDNew, &i.IpOld); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listFoo = `-- name: ListFoo :many +SELECT id_old as foo_old, id_old as baz_old +FROM bar_old +WHERE ip_old = $1 AND id_old = $2 +` + +type ListFooParams struct { + IpOld IPProtocol + IDNew int32 +} + +type ListFooRow struct { + FooNew int32 + BazOld int32 +} + +func (q *Queries) ListFoo(ctx context.Context, arg ListFooParams) ([]ListFooRow, error) { + rows, err := q.db.Query(ctx, listFoo, arg.IpOld, arg.IDNew) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListFooRow + for rows.Next() { + var i ListFooRow + if err := rows.Scan(&i.FooNew, &i.BazOld); 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/rename/v1/pgx/v5/query.sql b/internal/endtoend/testdata/rename/v1/pgx/v5/query.sql new file mode 100644 index 0000000..a8211d0 --- /dev/null +++ b/internal/endtoend/testdata/rename/v1/pgx/v5/query.sql @@ -0,0 +1,8 @@ +-- name: ListFoo :many +SELECT id_old as foo_old, id_old as baz_old +FROM bar_old +WHERE ip_old = $1 AND id_old = $2; + +-- name: ListBar :many +SELECT * FROM bar_old; + diff --git a/internal/endtoend/testdata/rename/v1/pgx/v5/schema.sql b/internal/endtoend/testdata/rename/v1/pgx/v5/schema.sql new file mode 100644 index 0000000..764436c --- /dev/null +++ b/internal/endtoend/testdata/rename/v1/pgx/v5/schema.sql @@ -0,0 +1,4 @@ +CREATE TYPE ip_protocol AS enum('tcp', 'ip', 'icmp'); + +CREATE TABLE bar_old (id_old serial not null, ip_old ip_protocol NOT NULL); + diff --git a/internal/endtoend/testdata/rename/v1/pgx/v5/sqlc.json b/internal/endtoend/testdata/rename/v1/pgx/v5/sqlc.json new file mode 100644 index 0000000..8922571 --- /dev/null +++ b/internal/endtoend/testdata/rename/v1/pgx/v5/sqlc.json @@ -0,0 +1,20 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ], + "rename": { + "id_old": "IDNew", + "bar_old": "BarNew", + "foo_old": "FooNew", + "ip_protocol": "IPProtocol", + "ip_protocol_tcp": "IPProtocolTCP" + } +} diff --git a/internal/endtoend/testdata/rename/v1/stdlib/go/db.go b/internal/endtoend/testdata/rename/v1/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/rename/v1/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/rename/v1/stdlib/go/models.go b/internal/endtoend/testdata/rename/v1/stdlib/go/models.go new file mode 100644 index 0000000..1d4f75a --- /dev/null +++ b/internal/endtoend/testdata/rename/v1/stdlib/go/models.go @@ -0,0 +1,58 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type IPProtocol string + +const ( + IPProtocolTCP IPProtocol = "tcp" + IpProtocolIp IPProtocol = "ip" + IpProtocolIcmp IPProtocol = "icmp" +) + +func (e *IPProtocol) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = IPProtocol(s) + case string: + *e = IPProtocol(s) + default: + return fmt.Errorf("unsupported scan type for IPProtocol: %T", src) + } + return nil +} + +type NullIPProtocol struct { + IPProtocol IPProtocol + Valid bool // Valid is true if IPProtocol is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullIPProtocol) Scan(value any) error { + if value == nil { + ns.IPProtocol, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.IPProtocol.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullIPProtocol) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.IPProtocol), nil +} + +type BarNew struct { + IDNew int32 + IpOld IPProtocol +} diff --git a/internal/endtoend/testdata/rename/v1/stdlib/go/query.sql.go b/internal/endtoend/testdata/rename/v1/stdlib/go/query.sql.go new file mode 100644 index 0000000..cdc7467 --- /dev/null +++ b/internal/endtoend/testdata/rename/v1/stdlib/go/query.sql.go @@ -0,0 +1,76 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listBar = `-- name: ListBar :many +SELECT id_old, ip_old FROM bar_old +` + +func (q *Queries) ListBar(ctx context.Context) ([]BarNew, error) { + rows, err := q.db.QueryContext(ctx, listBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []BarNew + for rows.Next() { + var i BarNew + if err := rows.Scan(&i.IDNew, &i.IpOld); 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 listFoo = `-- name: ListFoo :many +SELECT id_old as foo_old, id_old as baz_old +FROM bar_old +WHERE ip_old = $1 AND id_old = $2 +` + +type ListFooParams struct { + IpOld IPProtocol + IDNew int32 +} + +type ListFooRow struct { + FooNew int32 + BazOld int32 +} + +func (q *Queries) ListFoo(ctx context.Context, arg ListFooParams) ([]ListFooRow, error) { + rows, err := q.db.QueryContext(ctx, listFoo, arg.IpOld, arg.IDNew) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListFooRow + for rows.Next() { + var i ListFooRow + if err := rows.Scan(&i.FooNew, &i.BazOld); 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/rename/v1/stdlib/query.sql b/internal/endtoend/testdata/rename/v1/stdlib/query.sql new file mode 100644 index 0000000..a8211d0 --- /dev/null +++ b/internal/endtoend/testdata/rename/v1/stdlib/query.sql @@ -0,0 +1,8 @@ +-- name: ListFoo :many +SELECT id_old as foo_old, id_old as baz_old +FROM bar_old +WHERE ip_old = $1 AND id_old = $2; + +-- name: ListBar :many +SELECT * FROM bar_old; + diff --git a/internal/endtoend/testdata/rename/v1/stdlib/schema.sql b/internal/endtoend/testdata/rename/v1/stdlib/schema.sql new file mode 100644 index 0000000..764436c --- /dev/null +++ b/internal/endtoend/testdata/rename/v1/stdlib/schema.sql @@ -0,0 +1,4 @@ +CREATE TYPE ip_protocol AS enum('tcp', 'ip', 'icmp'); + +CREATE TABLE bar_old (id_old serial not null, ip_old ip_protocol NOT NULL); + diff --git a/internal/endtoend/testdata/rename/v1/stdlib/sqlc.json b/internal/endtoend/testdata/rename/v1/stdlib/sqlc.json new file mode 100644 index 0000000..630709d --- /dev/null +++ b/internal/endtoend/testdata/rename/v1/stdlib/sqlc.json @@ -0,0 +1,18 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ], + "rename": { + "id_old": "IDNew", + "bar_old": "BarNew", + "foo_old": "FooNew", + "ip_protocol": "IPProtocol", + "ip_protocol_tcp": "IPProtocolTCP" + } +} diff --git a/internal/endtoend/testdata/rename/v2/pgx/v4/go/db.go b/internal/endtoend/testdata/rename/v2/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/rename/v2/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/rename/v2/pgx/v4/go/models.go b/internal/endtoend/testdata/rename/v2/pgx/v4/go/models.go new file mode 100644 index 0000000..1d4f75a --- /dev/null +++ b/internal/endtoend/testdata/rename/v2/pgx/v4/go/models.go @@ -0,0 +1,58 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type IPProtocol string + +const ( + IPProtocolTCP IPProtocol = "tcp" + IpProtocolIp IPProtocol = "ip" + IpProtocolIcmp IPProtocol = "icmp" +) + +func (e *IPProtocol) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = IPProtocol(s) + case string: + *e = IPProtocol(s) + default: + return fmt.Errorf("unsupported scan type for IPProtocol: %T", src) + } + return nil +} + +type NullIPProtocol struct { + IPProtocol IPProtocol + Valid bool // Valid is true if IPProtocol is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullIPProtocol) Scan(value any) error { + if value == nil { + ns.IPProtocol, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.IPProtocol.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullIPProtocol) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.IPProtocol), nil +} + +type BarNew struct { + IDNew int32 + IpOld IPProtocol +} diff --git a/internal/endtoend/testdata/rename/v2/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/rename/v2/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..98787cd --- /dev/null +++ b/internal/endtoend/testdata/rename/v2/pgx/v4/go/query.sql.go @@ -0,0 +1,70 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listBar = `-- name: ListBar :many +SELECT id_old, ip_old FROM bar_old +` + +func (q *Queries) ListBar(ctx context.Context) ([]BarNew, error) { + rows, err := q.db.Query(ctx, listBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []BarNew + for rows.Next() { + var i BarNew + if err := rows.Scan(&i.IDNew, &i.IpOld); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listFoo = `-- name: ListFoo :many +SELECT id_old as foo_old, id_old as baz_old +FROM bar_old +WHERE ip_old = $1 AND id_old = $2 +` + +type ListFooParams struct { + IpOld IPProtocol + IDNew int32 +} + +type ListFooRow struct { + FooNew int32 + BazOld int32 +} + +func (q *Queries) ListFoo(ctx context.Context, arg ListFooParams) ([]ListFooRow, error) { + rows, err := q.db.Query(ctx, listFoo, arg.IpOld, arg.IDNew) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListFooRow + for rows.Next() { + var i ListFooRow + if err := rows.Scan(&i.FooNew, &i.BazOld); 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/rename/v2/pgx/v4/query.sql b/internal/endtoend/testdata/rename/v2/pgx/v4/query.sql new file mode 100644 index 0000000..a8211d0 --- /dev/null +++ b/internal/endtoend/testdata/rename/v2/pgx/v4/query.sql @@ -0,0 +1,8 @@ +-- name: ListFoo :many +SELECT id_old as foo_old, id_old as baz_old +FROM bar_old +WHERE ip_old = $1 AND id_old = $2; + +-- name: ListBar :many +SELECT * FROM bar_old; + diff --git a/internal/endtoend/testdata/rename/v2/pgx/v4/schema.sql b/internal/endtoend/testdata/rename/v2/pgx/v4/schema.sql new file mode 100644 index 0000000..764436c --- /dev/null +++ b/internal/endtoend/testdata/rename/v2/pgx/v4/schema.sql @@ -0,0 +1,4 @@ +CREATE TYPE ip_protocol AS enum('tcp', 'ip', 'icmp'); + +CREATE TABLE bar_old (id_old serial not null, ip_old ip_protocol NOT NULL); + diff --git a/internal/endtoend/testdata/rename/v2/pgx/v4/sqlc.json b/internal/endtoend/testdata/rename/v2/pgx/v4/sqlc.json new file mode 100644 index 0000000..ae08b82 --- /dev/null +++ b/internal/endtoend/testdata/rename/v2/pgx/v4/sqlc.json @@ -0,0 +1,24 @@ +{ + "version": "2", + "sql": [ + { + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql", + "gen": { + "go": { + "sql_package": "pgx/v4", + "package": "querytest", + "out": "go", + "rename": { + "id_old": "IDNew", + "bar_old": "BarNew", + "foo_old": "FooNew", + "ip_protocol": "IPProtocol", + "ip_protocol_tcp": "IPProtocolTCP" + } + } + } + } + ] +} diff --git a/internal/endtoend/testdata/rename/v2/pgx/v5/go/db.go b/internal/endtoend/testdata/rename/v2/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/rename/v2/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/rename/v2/pgx/v5/go/models.go b/internal/endtoend/testdata/rename/v2/pgx/v5/go/models.go new file mode 100644 index 0000000..1d4f75a --- /dev/null +++ b/internal/endtoend/testdata/rename/v2/pgx/v5/go/models.go @@ -0,0 +1,58 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type IPProtocol string + +const ( + IPProtocolTCP IPProtocol = "tcp" + IpProtocolIp IPProtocol = "ip" + IpProtocolIcmp IPProtocol = "icmp" +) + +func (e *IPProtocol) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = IPProtocol(s) + case string: + *e = IPProtocol(s) + default: + return fmt.Errorf("unsupported scan type for IPProtocol: %T", src) + } + return nil +} + +type NullIPProtocol struct { + IPProtocol IPProtocol + Valid bool // Valid is true if IPProtocol is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullIPProtocol) Scan(value any) error { + if value == nil { + ns.IPProtocol, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.IPProtocol.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullIPProtocol) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.IPProtocol), nil +} + +type BarNew struct { + IDNew int32 + IpOld IPProtocol +} diff --git a/internal/endtoend/testdata/rename/v2/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/rename/v2/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..98787cd --- /dev/null +++ b/internal/endtoend/testdata/rename/v2/pgx/v5/go/query.sql.go @@ -0,0 +1,70 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listBar = `-- name: ListBar :many +SELECT id_old, ip_old FROM bar_old +` + +func (q *Queries) ListBar(ctx context.Context) ([]BarNew, error) { + rows, err := q.db.Query(ctx, listBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []BarNew + for rows.Next() { + var i BarNew + if err := rows.Scan(&i.IDNew, &i.IpOld); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listFoo = `-- name: ListFoo :many +SELECT id_old as foo_old, id_old as baz_old +FROM bar_old +WHERE ip_old = $1 AND id_old = $2 +` + +type ListFooParams struct { + IpOld IPProtocol + IDNew int32 +} + +type ListFooRow struct { + FooNew int32 + BazOld int32 +} + +func (q *Queries) ListFoo(ctx context.Context, arg ListFooParams) ([]ListFooRow, error) { + rows, err := q.db.Query(ctx, listFoo, arg.IpOld, arg.IDNew) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListFooRow + for rows.Next() { + var i ListFooRow + if err := rows.Scan(&i.FooNew, &i.BazOld); 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/rename/v2/pgx/v5/query.sql b/internal/endtoend/testdata/rename/v2/pgx/v5/query.sql new file mode 100644 index 0000000..a8211d0 --- /dev/null +++ b/internal/endtoend/testdata/rename/v2/pgx/v5/query.sql @@ -0,0 +1,8 @@ +-- name: ListFoo :many +SELECT id_old as foo_old, id_old as baz_old +FROM bar_old +WHERE ip_old = $1 AND id_old = $2; + +-- name: ListBar :many +SELECT * FROM bar_old; + diff --git a/internal/endtoend/testdata/rename/v2/pgx/v5/schema.sql b/internal/endtoend/testdata/rename/v2/pgx/v5/schema.sql new file mode 100644 index 0000000..764436c --- /dev/null +++ b/internal/endtoend/testdata/rename/v2/pgx/v5/schema.sql @@ -0,0 +1,4 @@ +CREATE TYPE ip_protocol AS enum('tcp', 'ip', 'icmp'); + +CREATE TABLE bar_old (id_old serial not null, ip_old ip_protocol NOT NULL); + diff --git a/internal/endtoend/testdata/rename/v2/pgx/v5/sqlc.json b/internal/endtoend/testdata/rename/v2/pgx/v5/sqlc.json new file mode 100644 index 0000000..8f0a34d --- /dev/null +++ b/internal/endtoend/testdata/rename/v2/pgx/v5/sqlc.json @@ -0,0 +1,24 @@ +{ + "version": "2", + "sql": [ + { + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "gen": { + "go": { + "package": "querytest", + "out": "go", + "sql_package": "pgx/v5", + "rename": { + "id_old": "IDNew", + "bar_old": "BarNew", + "foo_old": "FooNew", + "ip_protocol": "IPProtocol", + "ip_protocol_tcp": "IPProtocolTCP" + } + } + } + } + ] +} diff --git a/internal/endtoend/testdata/rename/v2/stdlib/go/db.go b/internal/endtoend/testdata/rename/v2/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/rename/v2/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/rename/v2/stdlib/go/models.go b/internal/endtoend/testdata/rename/v2/stdlib/go/models.go new file mode 100644 index 0000000..1d4f75a --- /dev/null +++ b/internal/endtoend/testdata/rename/v2/stdlib/go/models.go @@ -0,0 +1,58 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type IPProtocol string + +const ( + IPProtocolTCP IPProtocol = "tcp" + IpProtocolIp IPProtocol = "ip" + IpProtocolIcmp IPProtocol = "icmp" +) + +func (e *IPProtocol) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = IPProtocol(s) + case string: + *e = IPProtocol(s) + default: + return fmt.Errorf("unsupported scan type for IPProtocol: %T", src) + } + return nil +} + +type NullIPProtocol struct { + IPProtocol IPProtocol + Valid bool // Valid is true if IPProtocol is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullIPProtocol) Scan(value any) error { + if value == nil { + ns.IPProtocol, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.IPProtocol.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullIPProtocol) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.IPProtocol), nil +} + +type BarNew struct { + IDNew int32 + IpOld IPProtocol +} diff --git a/internal/endtoend/testdata/rename/v2/stdlib/go/query.sql.go b/internal/endtoend/testdata/rename/v2/stdlib/go/query.sql.go new file mode 100644 index 0000000..cdc7467 --- /dev/null +++ b/internal/endtoend/testdata/rename/v2/stdlib/go/query.sql.go @@ -0,0 +1,76 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listBar = `-- name: ListBar :many +SELECT id_old, ip_old FROM bar_old +` + +func (q *Queries) ListBar(ctx context.Context) ([]BarNew, error) { + rows, err := q.db.QueryContext(ctx, listBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []BarNew + for rows.Next() { + var i BarNew + if err := rows.Scan(&i.IDNew, &i.IpOld); 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 listFoo = `-- name: ListFoo :many +SELECT id_old as foo_old, id_old as baz_old +FROM bar_old +WHERE ip_old = $1 AND id_old = $2 +` + +type ListFooParams struct { + IpOld IPProtocol + IDNew int32 +} + +type ListFooRow struct { + FooNew int32 + BazOld int32 +} + +func (q *Queries) ListFoo(ctx context.Context, arg ListFooParams) ([]ListFooRow, error) { + rows, err := q.db.QueryContext(ctx, listFoo, arg.IpOld, arg.IDNew) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListFooRow + for rows.Next() { + var i ListFooRow + if err := rows.Scan(&i.FooNew, &i.BazOld); 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/rename/v2/stdlib/query.sql b/internal/endtoend/testdata/rename/v2/stdlib/query.sql new file mode 100644 index 0000000..a8211d0 --- /dev/null +++ b/internal/endtoend/testdata/rename/v2/stdlib/query.sql @@ -0,0 +1,8 @@ +-- name: ListFoo :many +SELECT id_old as foo_old, id_old as baz_old +FROM bar_old +WHERE ip_old = $1 AND id_old = $2; + +-- name: ListBar :many +SELECT * FROM bar_old; + diff --git a/internal/endtoend/testdata/rename/v2/stdlib/schema.sql b/internal/endtoend/testdata/rename/v2/stdlib/schema.sql new file mode 100644 index 0000000..764436c --- /dev/null +++ b/internal/endtoend/testdata/rename/v2/stdlib/schema.sql @@ -0,0 +1,4 @@ +CREATE TYPE ip_protocol AS enum('tcp', 'ip', 'icmp'); + +CREATE TABLE bar_old (id_old serial not null, ip_old ip_protocol NOT NULL); + diff --git a/internal/endtoend/testdata/rename/v2/stdlib/sqlc.json b/internal/endtoend/testdata/rename/v2/stdlib/sqlc.json new file mode 100644 index 0000000..22372ff --- /dev/null +++ b/internal/endtoend/testdata/rename/v2/stdlib/sqlc.json @@ -0,0 +1,23 @@ +{ + "version": "2", + "sql": [ + { + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql", + "gen": { + "go": { + "package": "querytest", + "out": "go", + "rename": { + "id_old": "IDNew", + "bar_old": "BarNew", + "foo_old": "FooNew", + "ip_protocol": "IPProtocol", + "ip_protocol_tcp": "IPProtocolTCP" + } + } + } + } + ] +} diff --git a/internal/endtoend/testdata/returning/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/returning/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/returning/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/returning/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/returning/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..4df212e --- /dev/null +++ b/internal/endtoend/testdata/returning/postgresql/pgx/v4/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + Name sql.NullString + ID int32 +} diff --git a/internal/endtoend/testdata/returning/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/returning/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..780396d --- /dev/null +++ b/internal/endtoend/testdata/returning/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,97 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const deleteUserAndReturnID = `-- name: DeleteUserAndReturnID :one +DELETE FROM users + WHERE name = $1 + RETURNING id +` + +func (q *Queries) DeleteUserAndReturnID(ctx context.Context, name sql.NullString) (int32, error) { + row := q.db.QueryRow(ctx, deleteUserAndReturnID, name) + var id int32 + err := row.Scan(&id) + return id, err +} + +const deleteUserAndReturnUser = `-- name: DeleteUserAndReturnUser :one +DELETE FROM users + WHERE name = $1 + RETURNING name, id +` + +func (q *Queries) DeleteUserAndReturnUser(ctx context.Context, name sql.NullString) (User, error) { + row := q.db.QueryRow(ctx, deleteUserAndReturnUser, name) + var i User + err := row.Scan(&i.Name, &i.ID) + return i, err +} + +const insertUserAndReturnID = `-- name: InsertUserAndReturnID :one +INSERT INTO users (name) VALUES ($1) + RETURNING id +` + +func (q *Queries) InsertUserAndReturnID(ctx context.Context, name sql.NullString) (int32, error) { + row := q.db.QueryRow(ctx, insertUserAndReturnID, name) + var id int32 + err := row.Scan(&id) + return id, err +} + +const insertUserAndReturnUser = `-- name: InsertUserAndReturnUser :one +INSERT INTO users (name) VALUES ($1) + RETURNING name, id +` + +func (q *Queries) InsertUserAndReturnUser(ctx context.Context, name sql.NullString) (User, error) { + row := q.db.QueryRow(ctx, insertUserAndReturnUser, name) + var i User + err := row.Scan(&i.Name, &i.ID) + return i, err +} + +const updateUserAndReturnID = `-- name: UpdateUserAndReturnID :one +UPDATE users SET name = $1 + WHERE name = $2 + RETURNING id +` + +type UpdateUserAndReturnIDParams struct { + Name sql.NullString + Name_2 sql.NullString +} + +func (q *Queries) UpdateUserAndReturnID(ctx context.Context, arg UpdateUserAndReturnIDParams) (int32, error) { + row := q.db.QueryRow(ctx, updateUserAndReturnID, arg.Name, arg.Name_2) + var id int32 + err := row.Scan(&id) + return id, err +} + +const updateUserAndReturnUser = `-- name: UpdateUserAndReturnUser :one +UPDATE users SET name = $1 + WHERE name = $2 + RETURNING name, id +` + +type UpdateUserAndReturnUserParams struct { + Name sql.NullString + Name_2 sql.NullString +} + +func (q *Queries) UpdateUserAndReturnUser(ctx context.Context, arg UpdateUserAndReturnUserParams) (User, error) { + row := q.db.QueryRow(ctx, updateUserAndReturnUser, arg.Name, arg.Name_2) + var i User + err := row.Scan(&i.Name, &i.ID) + return i, err +} diff --git a/internal/endtoend/testdata/returning/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/returning/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..1da5061 --- /dev/null +++ b/internal/endtoend/testdata/returning/postgresql/pgx/v4/query.sql @@ -0,0 +1,27 @@ +-- name: InsertUserAndReturnID :one +INSERT INTO users (name) VALUES ($1) + RETURNING id; + +-- name: InsertUserAndReturnUser :one +INSERT INTO users (name) VALUES ($1) + RETURNING *; + +-- name: UpdateUserAndReturnID :one +UPDATE users SET name = $1 + WHERE name = $2 + RETURNING id; + +-- name: UpdateUserAndReturnUser :one +UPDATE users SET name = $1 + WHERE name = $2 + RETURNING *; + +-- name: DeleteUserAndReturnID :one +DELETE FROM users + WHERE name = $1 + RETURNING id; + +-- name: DeleteUserAndReturnUser :one +DELETE FROM users + WHERE name = $1 + RETURNING *; diff --git a/internal/endtoend/testdata/returning/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/returning/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..5502e8e --- /dev/null +++ b/internal/endtoend/testdata/returning/postgresql/pgx/v4/schema.sql @@ -0,0 +1 @@ +CREATE TABLE users (name text, id serial primary key); diff --git a/internal/endtoend/testdata/returning/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/returning/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/returning/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/returning/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/returning/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/returning/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/returning/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/returning/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..b73d378 --- /dev/null +++ b/internal/endtoend/testdata/returning/postgresql/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type User struct { + Name pgtype.Text + ID int32 +} diff --git a/internal/endtoend/testdata/returning/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/returning/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..b11556f --- /dev/null +++ b/internal/endtoend/testdata/returning/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,98 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const deleteUserAndReturnID = `-- name: DeleteUserAndReturnID :one +DELETE FROM users + WHERE name = $1 + RETURNING id +` + +func (q *Queries) DeleteUserAndReturnID(ctx context.Context, name pgtype.Text) (int32, error) { + row := q.db.QueryRow(ctx, deleteUserAndReturnID, name) + var id int32 + err := row.Scan(&id) + return id, err +} + +const deleteUserAndReturnUser = `-- name: DeleteUserAndReturnUser :one +DELETE FROM users + WHERE name = $1 + RETURNING name, id +` + +func (q *Queries) DeleteUserAndReturnUser(ctx context.Context, name pgtype.Text) (User, error) { + row := q.db.QueryRow(ctx, deleteUserAndReturnUser, name) + var i User + err := row.Scan(&i.Name, &i.ID) + return i, err +} + +const insertUserAndReturnID = `-- name: InsertUserAndReturnID :one +INSERT INTO users (name) VALUES ($1) + RETURNING id +` + +func (q *Queries) InsertUserAndReturnID(ctx context.Context, name pgtype.Text) (int32, error) { + row := q.db.QueryRow(ctx, insertUserAndReturnID, name) + var id int32 + err := row.Scan(&id) + return id, err +} + +const insertUserAndReturnUser = `-- name: InsertUserAndReturnUser :one +INSERT INTO users (name) VALUES ($1) + RETURNING name, id +` + +func (q *Queries) InsertUserAndReturnUser(ctx context.Context, name pgtype.Text) (User, error) { + row := q.db.QueryRow(ctx, insertUserAndReturnUser, name) + var i User + err := row.Scan(&i.Name, &i.ID) + return i, err +} + +const updateUserAndReturnID = `-- name: UpdateUserAndReturnID :one +UPDATE users SET name = $1 + WHERE name = $2 + RETURNING id +` + +type UpdateUserAndReturnIDParams struct { + Name pgtype.Text + Name_2 pgtype.Text +} + +func (q *Queries) UpdateUserAndReturnID(ctx context.Context, arg UpdateUserAndReturnIDParams) (int32, error) { + row := q.db.QueryRow(ctx, updateUserAndReturnID, arg.Name, arg.Name_2) + var id int32 + err := row.Scan(&id) + return id, err +} + +const updateUserAndReturnUser = `-- name: UpdateUserAndReturnUser :one +UPDATE users SET name = $1 + WHERE name = $2 + RETURNING name, id +` + +type UpdateUserAndReturnUserParams struct { + Name pgtype.Text + Name_2 pgtype.Text +} + +func (q *Queries) UpdateUserAndReturnUser(ctx context.Context, arg UpdateUserAndReturnUserParams) (User, error) { + row := q.db.QueryRow(ctx, updateUserAndReturnUser, arg.Name, arg.Name_2) + var i User + err := row.Scan(&i.Name, &i.ID) + return i, err +} diff --git a/internal/endtoend/testdata/returning/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/returning/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..1da5061 --- /dev/null +++ b/internal/endtoend/testdata/returning/postgresql/pgx/v5/query.sql @@ -0,0 +1,27 @@ +-- name: InsertUserAndReturnID :one +INSERT INTO users (name) VALUES ($1) + RETURNING id; + +-- name: InsertUserAndReturnUser :one +INSERT INTO users (name) VALUES ($1) + RETURNING *; + +-- name: UpdateUserAndReturnID :one +UPDATE users SET name = $1 + WHERE name = $2 + RETURNING id; + +-- name: UpdateUserAndReturnUser :one +UPDATE users SET name = $1 + WHERE name = $2 + RETURNING *; + +-- name: DeleteUserAndReturnID :one +DELETE FROM users + WHERE name = $1 + RETURNING id; + +-- name: DeleteUserAndReturnUser :one +DELETE FROM users + WHERE name = $1 + RETURNING *; diff --git a/internal/endtoend/testdata/returning/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/returning/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..5502e8e --- /dev/null +++ b/internal/endtoend/testdata/returning/postgresql/pgx/v5/schema.sql @@ -0,0 +1 @@ +CREATE TABLE users (name text, id serial primary key); diff --git a/internal/endtoend/testdata/returning/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/returning/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/returning/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/returning/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/returning/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/returning/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/returning/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/returning/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..4df212e --- /dev/null +++ b/internal/endtoend/testdata/returning/postgresql/stdlib/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + Name sql.NullString + ID int32 +} diff --git a/internal/endtoend/testdata/returning/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/returning/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..a955d47 --- /dev/null +++ b/internal/endtoend/testdata/returning/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,97 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const deleteUserAndReturnID = `-- name: DeleteUserAndReturnID :one +DELETE FROM users + WHERE name = $1 + RETURNING id +` + +func (q *Queries) DeleteUserAndReturnID(ctx context.Context, name sql.NullString) (int32, error) { + row := q.db.QueryRowContext(ctx, deleteUserAndReturnID, name) + var id int32 + err := row.Scan(&id) + return id, err +} + +const deleteUserAndReturnUser = `-- name: DeleteUserAndReturnUser :one +DELETE FROM users + WHERE name = $1 + RETURNING name, id +` + +func (q *Queries) DeleteUserAndReturnUser(ctx context.Context, name sql.NullString) (User, error) { + row := q.db.QueryRowContext(ctx, deleteUserAndReturnUser, name) + var i User + err := row.Scan(&i.Name, &i.ID) + return i, err +} + +const insertUserAndReturnID = `-- name: InsertUserAndReturnID :one +INSERT INTO users (name) VALUES ($1) + RETURNING id +` + +func (q *Queries) InsertUserAndReturnID(ctx context.Context, name sql.NullString) (int32, error) { + row := q.db.QueryRowContext(ctx, insertUserAndReturnID, name) + var id int32 + err := row.Scan(&id) + return id, err +} + +const insertUserAndReturnUser = `-- name: InsertUserAndReturnUser :one +INSERT INTO users (name) VALUES ($1) + RETURNING name, id +` + +func (q *Queries) InsertUserAndReturnUser(ctx context.Context, name sql.NullString) (User, error) { + row := q.db.QueryRowContext(ctx, insertUserAndReturnUser, name) + var i User + err := row.Scan(&i.Name, &i.ID) + return i, err +} + +const updateUserAndReturnID = `-- name: UpdateUserAndReturnID :one +UPDATE users SET name = $1 + WHERE name = $2 + RETURNING id +` + +type UpdateUserAndReturnIDParams struct { + Name sql.NullString + Name_2 sql.NullString +} + +func (q *Queries) UpdateUserAndReturnID(ctx context.Context, arg UpdateUserAndReturnIDParams) (int32, error) { + row := q.db.QueryRowContext(ctx, updateUserAndReturnID, arg.Name, arg.Name_2) + var id int32 + err := row.Scan(&id) + return id, err +} + +const updateUserAndReturnUser = `-- name: UpdateUserAndReturnUser :one +UPDATE users SET name = $1 + WHERE name = $2 + RETURNING name, id +` + +type UpdateUserAndReturnUserParams struct { + Name sql.NullString + Name_2 sql.NullString +} + +func (q *Queries) UpdateUserAndReturnUser(ctx context.Context, arg UpdateUserAndReturnUserParams) (User, error) { + row := q.db.QueryRowContext(ctx, updateUserAndReturnUser, arg.Name, arg.Name_2) + var i User + err := row.Scan(&i.Name, &i.ID) + return i, err +} diff --git a/internal/endtoend/testdata/returning/postgresql/stdlib/query.sql b/internal/endtoend/testdata/returning/postgresql/stdlib/query.sql new file mode 100644 index 0000000..1da5061 --- /dev/null +++ b/internal/endtoend/testdata/returning/postgresql/stdlib/query.sql @@ -0,0 +1,27 @@ +-- name: InsertUserAndReturnID :one +INSERT INTO users (name) VALUES ($1) + RETURNING id; + +-- name: InsertUserAndReturnUser :one +INSERT INTO users (name) VALUES ($1) + RETURNING *; + +-- name: UpdateUserAndReturnID :one +UPDATE users SET name = $1 + WHERE name = $2 + RETURNING id; + +-- name: UpdateUserAndReturnUser :one +UPDATE users SET name = $1 + WHERE name = $2 + RETURNING *; + +-- name: DeleteUserAndReturnID :one +DELETE FROM users + WHERE name = $1 + RETURNING id; + +-- name: DeleteUserAndReturnUser :one +DELETE FROM users + WHERE name = $1 + RETURNING *; diff --git a/internal/endtoend/testdata/returning/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/returning/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..5502e8e --- /dev/null +++ b/internal/endtoend/testdata/returning/postgresql/stdlib/schema.sql @@ -0,0 +1 @@ +CREATE TABLE users (name text, id serial primary key); diff --git a/internal/endtoend/testdata/returning/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/returning/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/returning/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/returning/sqlite/go/db.go b/internal/endtoend/testdata/returning/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/returning/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/returning/sqlite/go/models.go b/internal/endtoend/testdata/returning/sqlite/go/models.go new file mode 100644 index 0000000..65b7a31 --- /dev/null +++ b/internal/endtoend/testdata/returning/sqlite/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + Name sql.NullString + ID int64 +} diff --git a/internal/endtoend/testdata/returning/sqlite/go/query.sql.go b/internal/endtoend/testdata/returning/sqlite/go/query.sql.go new file mode 100644 index 0000000..c081f1c --- /dev/null +++ b/internal/endtoend/testdata/returning/sqlite/go/query.sql.go @@ -0,0 +1,101 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const deleteUserAndReturnID = `-- name: DeleteUserAndReturnID :one +DELETE FROM users +WHERE name = ?1 +RETURNING id +` + +func (q *Queries) DeleteUserAndReturnID(ctx context.Context, name sql.NullString) (int64, error) { + row := q.db.QueryRowContext(ctx, deleteUserAndReturnID, name) + var id int64 + err := row.Scan(&id) + return id, err +} + +const deleteUserAndReturnUser = `-- name: DeleteUserAndReturnUser :one +DELETE FROM users +WHERE name = ?1 +RETURNING name, id +` + +func (q *Queries) DeleteUserAndReturnUser(ctx context.Context, name sql.NullString) (User, error) { + row := q.db.QueryRowContext(ctx, deleteUserAndReturnUser, name) + var i User + err := row.Scan(&i.Name, &i.ID) + return i, err +} + +const insertUserAndReturnID = `-- name: InsertUserAndReturnID :one +INSERT INTO users (name) +VALUES (?1) +RETURNING id +` + +func (q *Queries) InsertUserAndReturnID(ctx context.Context, name sql.NullString) (int64, error) { + row := q.db.QueryRowContext(ctx, insertUserAndReturnID, name) + var id int64 + err := row.Scan(&id) + return id, err +} + +const insertUserAndReturnUser = `-- name: InsertUserAndReturnUser :one +INSERT INTO users (name) +VALUES (?1) +RETURNING name, id +` + +func (q *Queries) InsertUserAndReturnUser(ctx context.Context, name sql.NullString) (User, error) { + row := q.db.QueryRowContext(ctx, insertUserAndReturnUser, name) + var i User + err := row.Scan(&i.Name, &i.ID) + return i, err +} + +const updateUserAndReturnID = `-- name: UpdateUserAndReturnID :one +UPDATE users +SET name = ?1 +WHERE name = ?2 +RETURNING id +` + +type UpdateUserAndReturnIDParams struct { + Name sql.NullString + Name_2 sql.NullString +} + +func (q *Queries) UpdateUserAndReturnID(ctx context.Context, arg UpdateUserAndReturnIDParams) (int64, error) { + row := q.db.QueryRowContext(ctx, updateUserAndReturnID, arg.Name, arg.Name_2) + var id int64 + err := row.Scan(&id) + return id, err +} + +const updateUserAndReturnUser = `-- name: UpdateUserAndReturnUser :one +UPDATE users +SET name = ?1 +WHERE name = ?2 +RETURNING name, id +` + +type UpdateUserAndReturnUserParams struct { + Name sql.NullString + Name_2 sql.NullString +} + +func (q *Queries) UpdateUserAndReturnUser(ctx context.Context, arg UpdateUserAndReturnUserParams) (User, error) { + row := q.db.QueryRowContext(ctx, updateUserAndReturnUser, arg.Name, arg.Name_2) + var i User + err := row.Scan(&i.Name, &i.ID) + return i, err +} diff --git a/internal/endtoend/testdata/returning/sqlite/query.sql b/internal/endtoend/testdata/returning/sqlite/query.sql new file mode 100644 index 0000000..974f37e --- /dev/null +++ b/internal/endtoend/testdata/returning/sqlite/query.sql @@ -0,0 +1,31 @@ +-- name: InsertUserAndReturnID :one +INSERT INTO users (name) +VALUES (?1) +RETURNING id; + +-- name: InsertUserAndReturnUser :one +INSERT INTO users (name) +VALUES (?1) +RETURNING *; + +-- name: UpdateUserAndReturnID :one +UPDATE users +SET name = ?1 +WHERE name = ?2 +RETURNING id; + +-- name: UpdateUserAndReturnUser :one +UPDATE users +SET name = ?1 +WHERE name = ?2 +RETURNING *; + +-- name: DeleteUserAndReturnID :one +DELETE FROM users +WHERE name = ?1 +RETURNING id; + +-- name: DeleteUserAndReturnUser :one +DELETE FROM users +WHERE name = ?1 +RETURNING *; diff --git a/internal/endtoend/testdata/returning/sqlite/schema.sql b/internal/endtoend/testdata/returning/sqlite/schema.sql new file mode 100644 index 0000000..6a2a156 --- /dev/null +++ b/internal/endtoend/testdata/returning/sqlite/schema.sql @@ -0,0 +1 @@ +CREATE TABLE users (name text, id integer PRIMARY KEY AUTOINCREMENT); diff --git a/internal/endtoend/testdata/returning/sqlite/sqlc.json b/internal/endtoend/testdata/returning/sqlite/sqlc.json new file mode 100644 index 0000000..d4963e7 --- /dev/null +++ b/internal/endtoend/testdata/returning/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/exec.json b/internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/returning_old_new/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..b2a355d --- /dev/null +++ b/internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type User struct { + ID int64 + Name string + Bio pgtype.Text +} diff --git a/internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..1ef5f23 --- /dev/null +++ b/internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,124 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const deleteReturningOldNew = `-- name: DeleteReturningOldNew :one +DELETE FROM users WHERE id = $1 +RETURNING old.name, new.name +` + +type DeleteReturningOldNewRow struct { + Name string + Name_2 pgtype.Text +} + +func (q *Queries) DeleteReturningOldNew(ctx context.Context, id int64) (DeleteReturningOldNewRow, error) { + row := q.db.QueryRow(ctx, deleteReturningOldNew, id) + var i DeleteReturningOldNewRow + err := row.Scan(&i.Name, &i.Name_2) + return i, err +} + +const insertReturningOldNew = `-- name: InsertReturningOldNew :one +INSERT INTO users (name) VALUES ($1) +RETURNING old.id, new.id +` + +type InsertReturningOldNewRow struct { + ID pgtype.Int8 + ID_2 int64 +} + +func (q *Queries) InsertReturningOldNew(ctx context.Context, name string) (InsertReturningOldNewRow, error) { + row := q.db.QueryRow(ctx, insertReturningOldNew, name) + var i InsertReturningOldNewRow + err := row.Scan(&i.ID, &i.ID_2) + return i, err +} + +const updateReturningOld = `-- name: UpdateReturningOld :one +UPDATE users SET name = $1 WHERE id = $2 +RETURNING old.name +` + +type UpdateReturningOldParams struct { + Name string + ID int64 +} + +func (q *Queries) UpdateReturningOld(ctx context.Context, arg UpdateReturningOldParams) (string, error) { + row := q.db.QueryRow(ctx, updateReturningOld, arg.Name, arg.ID) + var name string + err := row.Scan(&name) + return name, err +} + +const updateReturningOldNew = `-- name: UpdateReturningOldNew :one +UPDATE users SET name = $1 WHERE id = $2 +RETURNING old.name, new.name +` + +type UpdateReturningOldNewParams struct { + Name string + ID int64 +} + +type UpdateReturningOldNewRow struct { + Name string + Name_2 string +} + +func (q *Queries) UpdateReturningOldNew(ctx context.Context, arg UpdateReturningOldNewParams) (UpdateReturningOldNewRow, error) { + row := q.db.QueryRow(ctx, updateReturningOldNew, arg.Name, arg.ID) + var i UpdateReturningOldNewRow + err := row.Scan(&i.Name, &i.Name_2) + return i, err +} + +const updateReturningOldStar = `-- name: UpdateReturningOldStar :one +UPDATE users SET name = $1 WHERE id = $2 +RETURNING old.id, old.name, old.bio +` + +type UpdateReturningOldStarParams struct { + Name string + ID int64 +} + +func (q *Queries) UpdateReturningOldStar(ctx context.Context, arg UpdateReturningOldStarParams) (User, error) { + row := q.db.QueryRow(ctx, updateReturningOldStar, arg.Name, arg.ID) + var i User + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const updateReturningWithAliases = `-- name: UpdateReturningWithAliases :one +UPDATE users SET name = $1 WHERE id = $2 +RETURNING WITH (OLD AS o, NEW AS n) o.name, n.name +` + +type UpdateReturningWithAliasesParams struct { + Name string + ID int64 +} + +type UpdateReturningWithAliasesRow struct { + Name string + Name_2 string +} + +func (q *Queries) UpdateReturningWithAliases(ctx context.Context, arg UpdateReturningWithAliasesParams) (UpdateReturningWithAliasesRow, error) { + row := q.db.QueryRow(ctx, updateReturningWithAliases, arg.Name, arg.ID) + var i UpdateReturningWithAliasesRow + err := row.Scan(&i.Name, &i.Name_2) + return i, err +} diff --git a/internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..ca465ee --- /dev/null +++ b/internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/query.sql @@ -0,0 +1,23 @@ +-- name: UpdateReturningOld :one +UPDATE users SET name = $1 WHERE id = $2 +RETURNING old.name; + +-- name: UpdateReturningOldNew :one +UPDATE users SET name = $1 WHERE id = $2 +RETURNING old.name, new.name; + +-- name: UpdateReturningOldStar :one +UPDATE users SET name = $1 WHERE id = $2 +RETURNING old.*; + +-- name: InsertReturningOldNew :one +INSERT INTO users (name) VALUES ($1) +RETURNING old.id, new.id; + +-- name: DeleteReturningOldNew :one +DELETE FROM users WHERE id = $1 +RETURNING old.name, new.name; + +-- name: UpdateReturningWithAliases :one +UPDATE users SET name = $1 WHERE id = $2 +RETURNING WITH (OLD AS o, NEW AS n) o.name, n.name; diff --git a/internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..ad2d63a --- /dev/null +++ b/internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE users ( + id bigserial PRIMARY KEY, + name text NOT NULL, + bio text +); diff --git a/internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/returning_old_new/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/returning_old_new/postgresql/stdlib/exec.json b/internal/endtoend/testdata/returning_old_new/postgresql/stdlib/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/returning_old_new/postgresql/stdlib/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/returning_old_new/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/returning_old_new/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/returning_old_new/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/returning_old_new/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/returning_old_new/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..b5f44f2 --- /dev/null +++ b/internal/endtoend/testdata/returning_old_new/postgresql/stdlib/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/returning_old_new/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/returning_old_new/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..ba3139e --- /dev/null +++ b/internal/endtoend/testdata/returning_old_new/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,123 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const deleteReturningOldNew = `-- name: DeleteReturningOldNew :one +DELETE FROM users WHERE id = $1 +RETURNING old.name, new.name +` + +type DeleteReturningOldNewRow struct { + Name string + Name_2 sql.NullString +} + +func (q *Queries) DeleteReturningOldNew(ctx context.Context, id int64) (DeleteReturningOldNewRow, error) { + row := q.db.QueryRowContext(ctx, deleteReturningOldNew, id) + var i DeleteReturningOldNewRow + err := row.Scan(&i.Name, &i.Name_2) + return i, err +} + +const insertReturningOldNew = `-- name: InsertReturningOldNew :one +INSERT INTO users (name) VALUES ($1) +RETURNING old.id, new.id +` + +type InsertReturningOldNewRow struct { + ID sql.NullInt64 + ID_2 int64 +} + +func (q *Queries) InsertReturningOldNew(ctx context.Context, name string) (InsertReturningOldNewRow, error) { + row := q.db.QueryRowContext(ctx, insertReturningOldNew, name) + var i InsertReturningOldNewRow + err := row.Scan(&i.ID, &i.ID_2) + return i, err +} + +const updateReturningOld = `-- name: UpdateReturningOld :one +UPDATE users SET name = $1 WHERE id = $2 +RETURNING old.name +` + +type UpdateReturningOldParams struct { + Name string + ID int64 +} + +func (q *Queries) UpdateReturningOld(ctx context.Context, arg UpdateReturningOldParams) (string, error) { + row := q.db.QueryRowContext(ctx, updateReturningOld, arg.Name, arg.ID) + var name string + err := row.Scan(&name) + return name, err +} + +const updateReturningOldNew = `-- name: UpdateReturningOldNew :one +UPDATE users SET name = $1 WHERE id = $2 +RETURNING old.name, new.name +` + +type UpdateReturningOldNewParams struct { + Name string + ID int64 +} + +type UpdateReturningOldNewRow struct { + Name string + Name_2 string +} + +func (q *Queries) UpdateReturningOldNew(ctx context.Context, arg UpdateReturningOldNewParams) (UpdateReturningOldNewRow, error) { + row := q.db.QueryRowContext(ctx, updateReturningOldNew, arg.Name, arg.ID) + var i UpdateReturningOldNewRow + err := row.Scan(&i.Name, &i.Name_2) + return i, err +} + +const updateReturningOldStar = `-- name: UpdateReturningOldStar :one +UPDATE users SET name = $1 WHERE id = $2 +RETURNING old.id, old.name, old.bio +` + +type UpdateReturningOldStarParams struct { + Name string + ID int64 +} + +func (q *Queries) UpdateReturningOldStar(ctx context.Context, arg UpdateReturningOldStarParams) (User, error) { + row := q.db.QueryRowContext(ctx, updateReturningOldStar, arg.Name, arg.ID) + var i User + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const updateReturningWithAliases = `-- name: UpdateReturningWithAliases :one +UPDATE users SET name = $1 WHERE id = $2 +RETURNING WITH (OLD AS o, NEW AS n) o.name, n.name +` + +type UpdateReturningWithAliasesParams struct { + Name string + ID int64 +} + +type UpdateReturningWithAliasesRow struct { + Name string + Name_2 string +} + +func (q *Queries) UpdateReturningWithAliases(ctx context.Context, arg UpdateReturningWithAliasesParams) (UpdateReturningWithAliasesRow, error) { + row := q.db.QueryRowContext(ctx, updateReturningWithAliases, arg.Name, arg.ID) + var i UpdateReturningWithAliasesRow + err := row.Scan(&i.Name, &i.Name_2) + return i, err +} diff --git a/internal/endtoend/testdata/returning_old_new/postgresql/stdlib/query.sql b/internal/endtoend/testdata/returning_old_new/postgresql/stdlib/query.sql new file mode 100644 index 0000000..ca465ee --- /dev/null +++ b/internal/endtoend/testdata/returning_old_new/postgresql/stdlib/query.sql @@ -0,0 +1,23 @@ +-- name: UpdateReturningOld :one +UPDATE users SET name = $1 WHERE id = $2 +RETURNING old.name; + +-- name: UpdateReturningOldNew :one +UPDATE users SET name = $1 WHERE id = $2 +RETURNING old.name, new.name; + +-- name: UpdateReturningOldStar :one +UPDATE users SET name = $1 WHERE id = $2 +RETURNING old.*; + +-- name: InsertReturningOldNew :one +INSERT INTO users (name) VALUES ($1) +RETURNING old.id, new.id; + +-- name: DeleteReturningOldNew :one +DELETE FROM users WHERE id = $1 +RETURNING old.name, new.name; + +-- name: UpdateReturningWithAliases :one +UPDATE users SET name = $1 WHERE id = $2 +RETURNING WITH (OLD AS o, NEW AS n) o.name, n.name; diff --git a/internal/endtoend/testdata/returning_old_new/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/returning_old_new/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..ad2d63a --- /dev/null +++ b/internal/endtoend/testdata/returning_old_new/postgresql/stdlib/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE users ( + id bigserial PRIMARY KEY, + name text NOT NULL, + bio text +); diff --git a/internal/endtoend/testdata/returning_old_new/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/returning_old_new/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/returning_old_new/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/schema_scoped_create/mysql/exec.json b/internal/endtoend/testdata/schema_scoped_create/mysql/exec.json new file mode 100644 index 0000000..c85ca2d --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/mysql/exec.json @@ -0,0 +1,6 @@ +{ + "contexts": ["base"], + "meta": { + "invalid_schema": true + } +} diff --git a/internal/endtoend/testdata/schema_scoped_create/mysql/go/db.go b/internal/endtoend/testdata/schema_scoped_create/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/schema_scoped_create/mysql/go/models.go b/internal/endtoend/testdata/schema_scoped_create/mysql/go/models.go new file mode 100644 index 0000000..2b9689e --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/mysql/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type FooBar struct { + ID uint64 + Name string +} diff --git a/internal/endtoend/testdata/schema_scoped_create/mysql/go/query.sql.go b/internal/endtoend/testdata/schema_scoped_create/mysql/go/query.sql.go new file mode 100644 index 0000000..ff8227e --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/mysql/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const schemaScopedCreate = `-- name: SchemaScopedCreate :execresult +INSERT INTO foo.bar (id, name) VALUES (?, ?) +` + +type SchemaScopedCreateParams struct { + ID uint64 + Name string +} + +func (q *Queries) SchemaScopedCreate(ctx context.Context, arg SchemaScopedCreateParams) (sql.Result, error) { + return q.db.ExecContext(ctx, schemaScopedCreate, arg.ID, arg.Name) +} diff --git a/internal/endtoend/testdata/schema_scoped_create/mysql/query.sql b/internal/endtoend/testdata/schema_scoped_create/mysql/query.sql new file mode 100644 index 0000000..ac7e203 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: SchemaScopedCreate :execresult +INSERT INTO foo.bar (id, name) VALUES (?, ?); diff --git a/internal/endtoend/testdata/schema_scoped_create/mysql/schema.sql b/internal/endtoend/testdata/schema_scoped_create/mysql/schema.sql new file mode 100644 index 0000000..71e23e5 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/mysql/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (id serial not null, name text not null); + diff --git a/internal/endtoend/testdata/schema_scoped_create/mysql/sqlc.json b/internal/endtoend/testdata/schema_scoped_create/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/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/schema_scoped_create/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/schema_scoped_create/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..44bab59 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v4/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type FooBar struct { + ID int32 + Name string +} diff --git a/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..a6a3bbe --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,26 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const schemaScopedCreate = `-- name: SchemaScopedCreate :one +INSERT INTO foo.bar (id, name) VALUES ($1, $2) RETURNING id +` + +type SchemaScopedCreateParams struct { + ID int32 + Name string +} + +func (q *Queries) SchemaScopedCreate(ctx context.Context, arg SchemaScopedCreateParams) (int32, error) { + row := q.db.QueryRow(ctx, schemaScopedCreate, arg.ID, arg.Name) + var id int32 + err := row.Scan(&id) + return id, err +} diff --git a/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..ecc6fb1 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: SchemaScopedCreate :one +INSERT INTO foo.bar (id, name) VALUES ($1, $2) RETURNING id; diff --git a/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..71e23e5 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (id serial not null, name text not null); + diff --git a/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/schema_scoped_create/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..44bab59 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v5/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type FooBar struct { + ID int32 + Name string +} diff --git a/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..a6a3bbe --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,26 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const schemaScopedCreate = `-- name: SchemaScopedCreate :one +INSERT INTO foo.bar (id, name) VALUES ($1, $2) RETURNING id +` + +type SchemaScopedCreateParams struct { + ID int32 + Name string +} + +func (q *Queries) SchemaScopedCreate(ctx context.Context, arg SchemaScopedCreateParams) (int32, error) { + row := q.db.QueryRow(ctx, schemaScopedCreate, arg.ID, arg.Name) + var id int32 + err := row.Scan(&id) + return id, err +} diff --git a/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..ecc6fb1 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: SchemaScopedCreate :one +INSERT INTO foo.bar (id, name) VALUES ($1, $2) RETURNING id; diff --git a/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..71e23e5 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (id serial not null, name text not null); + diff --git a/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/schema_scoped_create/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/schema_scoped_create/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/schema_scoped_create/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/schema_scoped_create/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..44bab59 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/postgresql/stdlib/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type FooBar struct { + ID int32 + Name string +} diff --git a/internal/endtoend/testdata/schema_scoped_create/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/schema_scoped_create/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..3fb8671 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,26 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const schemaScopedCreate = `-- name: SchemaScopedCreate :one +INSERT INTO foo.bar (id, name) VALUES ($1, $2) RETURNING id +` + +type SchemaScopedCreateParams struct { + ID int32 + Name string +} + +func (q *Queries) SchemaScopedCreate(ctx context.Context, arg SchemaScopedCreateParams) (int32, error) { + row := q.db.QueryRowContext(ctx, schemaScopedCreate, arg.ID, arg.Name) + var id int32 + err := row.Scan(&id) + return id, err +} diff --git a/internal/endtoend/testdata/schema_scoped_create/postgresql/stdlib/query.sql b/internal/endtoend/testdata/schema_scoped_create/postgresql/stdlib/query.sql new file mode 100644 index 0000000..ecc6fb1 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: SchemaScopedCreate :one +INSERT INTO foo.bar (id, name) VALUES ($1, $2) RETURNING id; diff --git a/internal/endtoend/testdata/schema_scoped_create/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/schema_scoped_create/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..71e23e5 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/postgresql/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (id serial not null, name text not null); + diff --git a/internal/endtoend/testdata/schema_scoped_create/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/schema_scoped_create/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_create/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/schema_scoped_delete/mysql/exec.json b/internal/endtoend/testdata/schema_scoped_delete/mysql/exec.json new file mode 100644 index 0000000..a0e224b --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/mysql/exec.json @@ -0,0 +1,7 @@ +{ + "contexts": ["base"], + "meta": { + "invalid_schema": true + } +} + \ No newline at end of file diff --git a/internal/endtoend/testdata/schema_scoped_delete/mysql/go/db.go b/internal/endtoend/testdata/schema_scoped_delete/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/schema_scoped_delete/mysql/go/models.go b/internal/endtoend/testdata/schema_scoped_delete/mysql/go/models.go new file mode 100644 index 0000000..850ce65 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/mysql/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type FooBar struct { + ID uint64 +} diff --git a/internal/endtoend/testdata/schema_scoped_delete/mysql/go/query.sql.go b/internal/endtoend/testdata/schema_scoped_delete/mysql/go/query.sql.go new file mode 100644 index 0000000..95c5c20 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/mysql/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const schemaScopedDelete = `-- name: SchemaScopedDelete :exec +DELETE FROM foo.bar WHERE id = ? +` + +func (q *Queries) SchemaScopedDelete(ctx context.Context, id uint64) error { + _, err := q.db.ExecContext(ctx, schemaScopedDelete, id) + return err +} diff --git a/internal/endtoend/testdata/schema_scoped_delete/mysql/query.sql b/internal/endtoend/testdata/schema_scoped_delete/mysql/query.sql new file mode 100644 index 0000000..3ba7420 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: SchemaScopedDelete :exec +DELETE FROM foo.bar WHERE id = ?; diff --git a/internal/endtoend/testdata/schema_scoped_delete/mysql/schema.sql b/internal/endtoend/testdata/schema_scoped_delete/mysql/schema.sql new file mode 100644 index 0000000..a22ab09 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/mysql/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (id serial not null); + diff --git a/internal/endtoend/testdata/schema_scoped_delete/mysql/sqlc.json b/internal/endtoend/testdata/schema_scoped_delete/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/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/schema_scoped_delete/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/schema_scoped_delete/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..5e4ee90 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type FooBar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8d0cb34 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const schemaScopedDelete = `-- name: SchemaScopedDelete :exec +DELETE FROM foo.bar WHERE id = $1 +` + +func (q *Queries) SchemaScopedDelete(ctx context.Context, id int32) error { + _, err := q.db.Exec(ctx, schemaScopedDelete, id) + return err +} diff --git a/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..e83763c --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: SchemaScopedDelete :exec +DELETE FROM foo.bar WHERE id = $1; diff --git a/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..a22ab09 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (id serial not null); + diff --git a/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/schema_scoped_delete/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..5e4ee90 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type FooBar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..8d0cb34 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const schemaScopedDelete = `-- name: SchemaScopedDelete :exec +DELETE FROM foo.bar WHERE id = $1 +` + +func (q *Queries) SchemaScopedDelete(ctx context.Context, id int32) error { + _, err := q.db.Exec(ctx, schemaScopedDelete, id) + return err +} diff --git a/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..e83763c --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: SchemaScopedDelete :exec +DELETE FROM foo.bar WHERE id = $1; diff --git a/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..a22ab09 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (id serial not null); + diff --git a/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/schema_scoped_delete/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/schema_scoped_delete/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/schema_scoped_delete/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/schema_scoped_delete/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..5e4ee90 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/postgresql/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type FooBar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/schema_scoped_delete/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/schema_scoped_delete/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..021d2a3 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const schemaScopedDelete = `-- name: SchemaScopedDelete :exec +DELETE FROM foo.bar WHERE id = $1 +` + +func (q *Queries) SchemaScopedDelete(ctx context.Context, id int32) error { + _, err := q.db.ExecContext(ctx, schemaScopedDelete, id) + return err +} diff --git a/internal/endtoend/testdata/schema_scoped_delete/postgresql/stdlib/query.sql b/internal/endtoend/testdata/schema_scoped_delete/postgresql/stdlib/query.sql new file mode 100644 index 0000000..e83763c --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: SchemaScopedDelete :exec +DELETE FROM foo.bar WHERE id = $1; diff --git a/internal/endtoend/testdata/schema_scoped_delete/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/schema_scoped_delete/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..a22ab09 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/postgresql/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (id serial not null); + diff --git a/internal/endtoend/testdata/schema_scoped_delete/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/schema_scoped_delete/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_delete/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/schema_scoped_enum/pgx/v4/go/db.go b/internal/endtoend/testdata/schema_scoped_enum/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_enum/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/schema_scoped_enum/pgx/v4/go/models.go b/internal/endtoend/testdata/schema_scoped_enum/pgx/v4/go/models.go new file mode 100644 index 0000000..9f3f953 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_enum/pgx/v4/go/models.go @@ -0,0 +1,56 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type FooTypeUserRole string + +const ( + FooTypeUserRoleAdmin FooTypeUserRole = "admin" + FooTypeUserRoleUser FooTypeUserRole = "user" +) + +func (e *FooTypeUserRole) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = FooTypeUserRole(s) + case string: + *e = FooTypeUserRole(s) + default: + return fmt.Errorf("unsupported scan type for FooTypeUserRole: %T", src) + } + return nil +} + +type NullFooTypeUserRole struct { + FooTypeUserRole FooTypeUserRole + Valid bool // Valid is true if FooTypeUserRole is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullFooTypeUserRole) Scan(value any) error { + if value == nil { + ns.FooTypeUserRole, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.FooTypeUserRole.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullFooTypeUserRole) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.FooTypeUserRole), nil +} + +type FooUser struct { + Role NullFooTypeUserRole +} diff --git a/internal/endtoend/testdata/schema_scoped_enum/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/schema_scoped_enum/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..46a7d0e --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_enum/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listUsersByRole = `-- name: ListUsersByRole :many +SELECT role FROM foo.users WHERE role = $1 +` + +func (q *Queries) ListUsersByRole(ctx context.Context, role NullFooTypeUserRole) ([]NullFooTypeUserRole, error) { + rows, err := q.db.Query(ctx, listUsersByRole, role) + if err != nil { + return nil, err + } + defer rows.Close() + var items []NullFooTypeUserRole + for rows.Next() { + var role NullFooTypeUserRole + if err := rows.Scan(&role); err != nil { + return nil, err + } + items = append(items, role) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/schema_scoped_enum/pgx/v4/query.sql b/internal/endtoend/testdata/schema_scoped_enum/pgx/v4/query.sql new file mode 100644 index 0000000..df3634b --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_enum/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: ListUsersByRole :many +SELECT * FROM foo.users WHERE role = $1; diff --git a/internal/endtoend/testdata/schema_scoped_enum/pgx/v4/schema.sql b/internal/endtoend/testdata/schema_scoped_enum/pgx/v4/schema.sql new file mode 100644 index 0000000..b04cda6 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_enum/pgx/v4/schema.sql @@ -0,0 +1,8 @@ +CREATE SCHEMA foo; + +CREATE TYPE foo.type_user_role AS ENUM ('admin', 'user'); + +CREATE TABLE foo.users ( + role foo.type_user_role +); + diff --git a/internal/endtoend/testdata/schema_scoped_enum/pgx/v4/sqlc.json b/internal/endtoend/testdata/schema_scoped_enum/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_enum/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/schema_scoped_enum/pgx/v5/go/db.go b/internal/endtoend/testdata/schema_scoped_enum/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_enum/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/schema_scoped_enum/pgx/v5/go/models.go b/internal/endtoend/testdata/schema_scoped_enum/pgx/v5/go/models.go new file mode 100644 index 0000000..9f3f953 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_enum/pgx/v5/go/models.go @@ -0,0 +1,56 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type FooTypeUserRole string + +const ( + FooTypeUserRoleAdmin FooTypeUserRole = "admin" + FooTypeUserRoleUser FooTypeUserRole = "user" +) + +func (e *FooTypeUserRole) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = FooTypeUserRole(s) + case string: + *e = FooTypeUserRole(s) + default: + return fmt.Errorf("unsupported scan type for FooTypeUserRole: %T", src) + } + return nil +} + +type NullFooTypeUserRole struct { + FooTypeUserRole FooTypeUserRole + Valid bool // Valid is true if FooTypeUserRole is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullFooTypeUserRole) Scan(value any) error { + if value == nil { + ns.FooTypeUserRole, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.FooTypeUserRole.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullFooTypeUserRole) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.FooTypeUserRole), nil +} + +type FooUser struct { + Role NullFooTypeUserRole +} diff --git a/internal/endtoend/testdata/schema_scoped_enum/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/schema_scoped_enum/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..46a7d0e --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_enum/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listUsersByRole = `-- name: ListUsersByRole :many +SELECT role FROM foo.users WHERE role = $1 +` + +func (q *Queries) ListUsersByRole(ctx context.Context, role NullFooTypeUserRole) ([]NullFooTypeUserRole, error) { + rows, err := q.db.Query(ctx, listUsersByRole, role) + if err != nil { + return nil, err + } + defer rows.Close() + var items []NullFooTypeUserRole + for rows.Next() { + var role NullFooTypeUserRole + if err := rows.Scan(&role); err != nil { + return nil, err + } + items = append(items, role) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/schema_scoped_enum/pgx/v5/query.sql b/internal/endtoend/testdata/schema_scoped_enum/pgx/v5/query.sql new file mode 100644 index 0000000..df3634b --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_enum/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: ListUsersByRole :many +SELECT * FROM foo.users WHERE role = $1; diff --git a/internal/endtoend/testdata/schema_scoped_enum/pgx/v5/schema.sql b/internal/endtoend/testdata/schema_scoped_enum/pgx/v5/schema.sql new file mode 100644 index 0000000..b04cda6 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_enum/pgx/v5/schema.sql @@ -0,0 +1,8 @@ +CREATE SCHEMA foo; + +CREATE TYPE foo.type_user_role AS ENUM ('admin', 'user'); + +CREATE TABLE foo.users ( + role foo.type_user_role +); + diff --git a/internal/endtoend/testdata/schema_scoped_enum/pgx/v5/sqlc.json b/internal/endtoend/testdata/schema_scoped_enum/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_enum/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/schema_scoped_enum/stdlib/go/db.go b/internal/endtoend/testdata/schema_scoped_enum/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_enum/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/schema_scoped_enum/stdlib/go/models.go b/internal/endtoend/testdata/schema_scoped_enum/stdlib/go/models.go new file mode 100644 index 0000000..9f3f953 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_enum/stdlib/go/models.go @@ -0,0 +1,56 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql/driver" + "fmt" +) + +type FooTypeUserRole string + +const ( + FooTypeUserRoleAdmin FooTypeUserRole = "admin" + FooTypeUserRoleUser FooTypeUserRole = "user" +) + +func (e *FooTypeUserRole) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = FooTypeUserRole(s) + case string: + *e = FooTypeUserRole(s) + default: + return fmt.Errorf("unsupported scan type for FooTypeUserRole: %T", src) + } + return nil +} + +type NullFooTypeUserRole struct { + FooTypeUserRole FooTypeUserRole + Valid bool // Valid is true if FooTypeUserRole is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullFooTypeUserRole) Scan(value any) error { + if value == nil { + ns.FooTypeUserRole, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.FooTypeUserRole.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullFooTypeUserRole) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.FooTypeUserRole), nil +} + +type FooUser struct { + Role NullFooTypeUserRole +} diff --git a/internal/endtoend/testdata/schema_scoped_enum/stdlib/go/query.sql.go b/internal/endtoend/testdata/schema_scoped_enum/stdlib/go/query.sql.go new file mode 100644 index 0000000..c28c1ca --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_enum/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listUsersByRole = `-- name: ListUsersByRole :many +SELECT role FROM foo.users WHERE role = $1 +` + +func (q *Queries) ListUsersByRole(ctx context.Context, role NullFooTypeUserRole) ([]NullFooTypeUserRole, error) { + rows, err := q.db.QueryContext(ctx, listUsersByRole, role) + if err != nil { + return nil, err + } + defer rows.Close() + var items []NullFooTypeUserRole + for rows.Next() { + var role NullFooTypeUserRole + if err := rows.Scan(&role); err != nil { + return nil, err + } + items = append(items, role) + } + 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/schema_scoped_enum/stdlib/query.sql b/internal/endtoend/testdata/schema_scoped_enum/stdlib/query.sql new file mode 100644 index 0000000..df3634b --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_enum/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: ListUsersByRole :many +SELECT * FROM foo.users WHERE role = $1; diff --git a/internal/endtoend/testdata/schema_scoped_enum/stdlib/schema.sql b/internal/endtoend/testdata/schema_scoped_enum/stdlib/schema.sql new file mode 100644 index 0000000..b04cda6 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_enum/stdlib/schema.sql @@ -0,0 +1,8 @@ +CREATE SCHEMA foo; + +CREATE TYPE foo.type_user_role AS ENUM ('admin', 'user'); + +CREATE TABLE foo.users ( + role foo.type_user_role +); + diff --git a/internal/endtoend/testdata/schema_scoped_enum/stdlib/sqlc.json b/internal/endtoend/testdata/schema_scoped_enum/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_enum/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/schema_scoped_filter/mysql/exec.json b/internal/endtoend/testdata/schema_scoped_filter/mysql/exec.json new file mode 100644 index 0000000..c85ca2d --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/mysql/exec.json @@ -0,0 +1,6 @@ +{ + "contexts": ["base"], + "meta": { + "invalid_schema": true + } +} diff --git a/internal/endtoend/testdata/schema_scoped_filter/mysql/go/db.go b/internal/endtoend/testdata/schema_scoped_filter/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/schema_scoped_filter/mysql/go/models.go b/internal/endtoend/testdata/schema_scoped_filter/mysql/go/models.go new file mode 100644 index 0000000..850ce65 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/mysql/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type FooBar struct { + ID uint64 +} diff --git a/internal/endtoend/testdata/schema_scoped_filter/mysql/go/query.sql.go b/internal/endtoend/testdata/schema_scoped_filter/mysql/go/query.sql.go new file mode 100644 index 0000000..72a1a55 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/mysql/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const schemaScopedFilter = `-- name: SchemaScopedFilter :many +SELECT id FROM foo.bar WHERE id = ? +` + +func (q *Queries) SchemaScopedFilter(ctx context.Context, id uint64) ([]uint64, error) { + rows, err := q.db.QueryContext(ctx, schemaScopedFilter, id) + 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 +} diff --git a/internal/endtoend/testdata/schema_scoped_filter/mysql/query.sql b/internal/endtoend/testdata/schema_scoped_filter/mysql/query.sql new file mode 100644 index 0000000..1149089 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: SchemaScopedFilter :many +SELECT * FROM foo.bar WHERE id = ?; diff --git a/internal/endtoend/testdata/schema_scoped_filter/mysql/schema.sql b/internal/endtoend/testdata/schema_scoped_filter/mysql/schema.sql new file mode 100644 index 0000000..e5cb43f --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (id serial not null); diff --git a/internal/endtoend/testdata/schema_scoped_filter/mysql/sqlc.json b/internal/endtoend/testdata/schema_scoped_filter/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/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/schema_scoped_filter/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/schema_scoped_filter/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..5e4ee90 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type FooBar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..cc723ed --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const schemaScopedFilter = `-- name: SchemaScopedFilter :many +SELECT id FROM foo.bar WHERE id = $1 +` + +func (q *Queries) SchemaScopedFilter(ctx context.Context, id int32) ([]int32, error) { + rows, err := q.db.Query(ctx, schemaScopedFilter, id) + 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 +} diff --git a/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..11cba02 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: SchemaScopedFilter :many +SELECT * FROM foo.bar WHERE id = $1; diff --git a/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..a22ab09 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (id serial not null); + diff --git a/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/schema_scoped_filter/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..5e4ee90 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type FooBar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..cc723ed --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const schemaScopedFilter = `-- name: SchemaScopedFilter :many +SELECT id FROM foo.bar WHERE id = $1 +` + +func (q *Queries) SchemaScopedFilter(ctx context.Context, id int32) ([]int32, error) { + rows, err := q.db.Query(ctx, schemaScopedFilter, id) + 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 +} diff --git a/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..11cba02 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: SchemaScopedFilter :many +SELECT * FROM foo.bar WHERE id = $1; diff --git a/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..a22ab09 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (id serial not null); + diff --git a/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/schema_scoped_filter/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/schema_scoped_filter/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/schema_scoped_filter/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/schema_scoped_filter/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..5e4ee90 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/postgresql/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type FooBar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/schema_scoped_filter/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/schema_scoped_filter/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..3fe07f3 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const schemaScopedFilter = `-- name: SchemaScopedFilter :many +SELECT id FROM foo.bar WHERE id = $1 +` + +func (q *Queries) SchemaScopedFilter(ctx context.Context, id int32) ([]int32, error) { + rows, err := q.db.QueryContext(ctx, schemaScopedFilter, id) + 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 +} diff --git a/internal/endtoend/testdata/schema_scoped_filter/postgresql/stdlib/query.sql b/internal/endtoend/testdata/schema_scoped_filter/postgresql/stdlib/query.sql new file mode 100644 index 0000000..11cba02 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: SchemaScopedFilter :many +SELECT * FROM foo.bar WHERE id = $1; diff --git a/internal/endtoend/testdata/schema_scoped_filter/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/schema_scoped_filter/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..a22ab09 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/postgresql/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (id serial not null); + diff --git a/internal/endtoend/testdata/schema_scoped_filter/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/schema_scoped_filter/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_filter/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/schema_scoped_list/mysql/exec.json b/internal/endtoend/testdata/schema_scoped_list/mysql/exec.json new file mode 100644 index 0000000..c85ca2d --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/mysql/exec.json @@ -0,0 +1,6 @@ +{ + "contexts": ["base"], + "meta": { + "invalid_schema": true + } +} diff --git a/internal/endtoend/testdata/schema_scoped_list/mysql/go/db.go b/internal/endtoend/testdata/schema_scoped_list/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/schema_scoped_list/mysql/go/models.go b/internal/endtoend/testdata/schema_scoped_list/mysql/go/models.go new file mode 100644 index 0000000..850ce65 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/mysql/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type FooBar struct { + ID uint64 +} 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 new file mode 100644 index 0000000..b724f88 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/mysql/go/query.sql.go @@ -0,0 +1,64 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +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 +` + +func (q *Queries) SchemaScopedList(ctx context.Context) ([]uint64, error) { + rows, err := q.db.QueryContext(ctx, schemaScopedList) + 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 +} diff --git a/internal/endtoend/testdata/schema_scoped_list/mysql/query.sql b/internal/endtoend/testdata/schema_scoped_list/mysql/query.sql new file mode 100644 index 0000000..66dab6b --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/mysql/query.sql @@ -0,0 +1,5 @@ +-- 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/mysql/schema.sql b/internal/endtoend/testdata/schema_scoped_list/mysql/schema.sql new file mode 100644 index 0000000..a22ab09 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/mysql/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (id serial not null); + diff --git a/internal/endtoend/testdata/schema_scoped_list/mysql/sqlc.json b/internal/endtoend/testdata/schema_scoped_list/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/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/schema_scoped_list/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/schema_scoped_list/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..5e4ee90 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type FooBar struct { + ID int32 +} 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 new file mode 100644 index 0000000..4449bbe --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,58 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +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 +` + +func (q *Queries) SchemaScopedList(ctx context.Context) ([]int32, error) { + rows, err := q.db.Query(ctx, schemaScopedList) + 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 +} 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 new file mode 100644 index 0000000..c508143 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/query.sql @@ -0,0 +1,5 @@ +-- 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/v4/schema.sql b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..a22ab09 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (id serial not null); + diff --git a/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/schema_scoped_list/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..5e4ee90 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type FooBar struct { + ID int32 +} 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 new file mode 100644 index 0000000..4449bbe --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,58 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +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 +` + +func (q *Queries) SchemaScopedList(ctx context.Context) ([]int32, error) { + rows, err := q.db.Query(ctx, schemaScopedList) + 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 +} 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 new file mode 100644 index 0000000..c508143 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/query.sql @@ -0,0 +1,5 @@ +-- 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/schema.sql b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..a22ab09 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (id serial not null); + diff --git a/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/schema_scoped_list/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..5e4ee90 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type FooBar struct { + ID int32 +} 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 new file mode 100644 index 0000000..a7b3a49 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,64 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +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 +` + +func (q *Queries) SchemaScopedList(ctx context.Context) ([]int32, error) { + rows, err := q.db.QueryContext(ctx, schemaScopedList) + 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 +} diff --git a/internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/query.sql b/internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/query.sql new file mode 100644 index 0000000..c508143 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/query.sql @@ -0,0 +1,5 @@ +-- 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/schema.sql b/internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..a22ab09 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (id serial not null); + diff --git a/internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/schema_scoped_update/mysql/exec.json b/internal/endtoend/testdata/schema_scoped_update/mysql/exec.json new file mode 100644 index 0000000..c85ca2d --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/mysql/exec.json @@ -0,0 +1,6 @@ +{ + "contexts": ["base"], + "meta": { + "invalid_schema": true + } +} diff --git a/internal/endtoend/testdata/schema_scoped_update/mysql/go/db.go b/internal/endtoend/testdata/schema_scoped_update/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/schema_scoped_update/mysql/go/models.go b/internal/endtoend/testdata/schema_scoped_update/mysql/go/models.go new file mode 100644 index 0000000..2b9689e --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/mysql/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type FooBar struct { + ID uint64 + Name string +} diff --git a/internal/endtoend/testdata/schema_scoped_update/mysql/go/query.sql.go b/internal/endtoend/testdata/schema_scoped_update/mysql/go/query.sql.go new file mode 100644 index 0000000..19858da --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/mysql/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const schemaScopedUpdate = `-- name: SchemaScopedUpdate :exec +UPDATE foo.bar SET name = ? WHERE id = ? +` + +type SchemaScopedUpdateParams struct { + Name string + ID uint64 +} + +func (q *Queries) SchemaScopedUpdate(ctx context.Context, arg SchemaScopedUpdateParams) error { + _, err := q.db.ExecContext(ctx, schemaScopedUpdate, arg.Name, arg.ID) + return err +} diff --git a/internal/endtoend/testdata/schema_scoped_update/mysql/query.sql b/internal/endtoend/testdata/schema_scoped_update/mysql/query.sql new file mode 100644 index 0000000..1c3c644 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: SchemaScopedUpdate :exec +UPDATE foo.bar SET name = ? WHERE id = ?; diff --git a/internal/endtoend/testdata/schema_scoped_update/mysql/schema.sql b/internal/endtoend/testdata/schema_scoped_update/mysql/schema.sql new file mode 100644 index 0000000..71e23e5 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/mysql/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (id serial not null, name text not null); + diff --git a/internal/endtoend/testdata/schema_scoped_update/mysql/sqlc.json b/internal/endtoend/testdata/schema_scoped_update/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/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/schema_scoped_update/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/schema_scoped_update/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..44bab59 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v4/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type FooBar struct { + ID int32 + Name string +} diff --git a/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..75f6672 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const schemaScopedUpdate = `-- name: SchemaScopedUpdate :exec +UPDATE foo.bar SET name = $2 WHERE id = $1 +` + +type SchemaScopedUpdateParams struct { + ID int32 + Name string +} + +func (q *Queries) SchemaScopedUpdate(ctx context.Context, arg SchemaScopedUpdateParams) error { + _, err := q.db.Exec(ctx, schemaScopedUpdate, arg.ID, arg.Name) + return err +} diff --git a/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..3649c25 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: SchemaScopedUpdate :exec +UPDATE foo.bar SET name = $2 WHERE id = $1; diff --git a/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..71e23e5 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (id serial not null, name text not null); + diff --git a/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/schema_scoped_update/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..44bab59 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v5/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type FooBar struct { + ID int32 + Name string +} diff --git a/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..75f6672 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const schemaScopedUpdate = `-- name: SchemaScopedUpdate :exec +UPDATE foo.bar SET name = $2 WHERE id = $1 +` + +type SchemaScopedUpdateParams struct { + ID int32 + Name string +} + +func (q *Queries) SchemaScopedUpdate(ctx context.Context, arg SchemaScopedUpdateParams) error { + _, err := q.db.Exec(ctx, schemaScopedUpdate, arg.ID, arg.Name) + return err +} diff --git a/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..3649c25 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: SchemaScopedUpdate :exec +UPDATE foo.bar SET name = $2 WHERE id = $1; diff --git a/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..71e23e5 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (id serial not null, name text not null); + diff --git a/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/schema_scoped_update/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/schema_scoped_update/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/schema_scoped_update/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/schema_scoped_update/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..44bab59 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/postgresql/stdlib/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type FooBar struct { + ID int32 + Name string +} diff --git a/internal/endtoend/testdata/schema_scoped_update/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/schema_scoped_update/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..e56c19f --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const schemaScopedUpdate = `-- name: SchemaScopedUpdate :exec +UPDATE foo.bar SET name = $2 WHERE id = $1 +` + +type SchemaScopedUpdateParams struct { + ID int32 + Name string +} + +func (q *Queries) SchemaScopedUpdate(ctx context.Context, arg SchemaScopedUpdateParams) error { + _, err := q.db.ExecContext(ctx, schemaScopedUpdate, arg.ID, arg.Name) + return err +} diff --git a/internal/endtoend/testdata/schema_scoped_update/postgresql/stdlib/query.sql b/internal/endtoend/testdata/schema_scoped_update/postgresql/stdlib/query.sql new file mode 100644 index 0000000..3649c25 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: SchemaScopedUpdate :exec +UPDATE foo.bar SET name = $2 WHERE id = $1; diff --git a/internal/endtoend/testdata/schema_scoped_update/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/schema_scoped_update/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..71e23e5 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/postgresql/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA foo; +CREATE TABLE foo.bar (id serial not null, name text not null); + diff --git a/internal/endtoend/testdata/schema_scoped_update/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/schema_scoped_update/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/schema_scoped_update/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/schema_table_column_ref/issue.md b/internal/endtoend/testdata/schema_table_column_ref/issue.md new file mode 100644 index 0000000..f58a7d0 --- /dev/null +++ b/internal/endtoend/testdata/schema_table_column_ref/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/2948 diff --git a/internal/endtoend/testdata/schema_table_column_ref/postgresql/pgx/go/db.go b/internal/endtoend/testdata/schema_table_column_ref/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/schema_table_column_ref/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/schema_table_column_ref/postgresql/pgx/go/models.go b/internal/endtoend/testdata/schema_table_column_ref/postgresql/pgx/go/models.go new file mode 100644 index 0000000..f1cc6b6 --- /dev/null +++ b/internal/endtoend/testdata/schema_table_column_ref/postgresql/pgx/go/models.go @@ -0,0 +1,23 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type AstoriaSlackFeedback struct { + ID int64 + WorkspaceID int64 + CreatedAt pgtype.Timestamp + IssueRaised pgtype.Bool +} + +type AstoriaTicket struct { + ID int64 + WorkspaceID int64 + CreatedAt pgtype.Timestamp + Source string +} diff --git a/internal/endtoend/testdata/schema_table_column_ref/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/schema_table_column_ref/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..ce83f76 --- /dev/null +++ b/internal/endtoend/testdata/schema_table_column_ref/postgresql/pgx/go/query.sql.go @@ -0,0 +1,77 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const getTotalSlackQueries = `-- name: GetTotalSlackQueries :one +SELECT + COUNT(*) AS count +FROM astoria.slack_feedback +WHERE astoria.slack_feedback.workspace_id = $1 +AND created_at BETWEEN $2::date AND $3::date +` + +type GetTotalSlackQueriesParams struct { + WorkspaceID int64 + Column2 pgtype.Date + Column3 pgtype.Date +} + +func (q *Queries) GetTotalSlackQueries(ctx context.Context, arg GetTotalSlackQueriesParams) (int64, error) { + row := q.db.QueryRow(ctx, getTotalSlackQueries, arg.WorkspaceID, arg.Column2, arg.Column3) + var count int64 + err := row.Scan(&count) + return count, err +} + +const getTotalSlackQueriesRequestsCreated = `-- name: GetTotalSlackQueriesRequestsCreated :one +SELECT + COUNT(*) AS count +FROM astoria.tickets +WHERE astoria.tickets.workspace_id = $1 + AND source = 'RAISED_FROM_BOT' + AND created_at BETWEEN $2::date AND $3::date +` + +type GetTotalSlackQueriesRequestsCreatedParams struct { + WorkspaceID int64 + Column2 pgtype.Date + Column3 pgtype.Date +} + +func (q *Queries) GetTotalSlackQueriesRequestsCreated(ctx context.Context, arg GetTotalSlackQueriesRequestsCreatedParams) (int64, error) { + row := q.db.QueryRow(ctx, getTotalSlackQueriesRequestsCreated, arg.WorkspaceID, arg.Column2, arg.Column3) + var count int64 + err := row.Scan(&count) + return count, err +} + +const getTotalSlackQueriesResolved = `-- name: GetTotalSlackQueriesResolved :one +SELECT + COUNT(*) AS count +FROM astoria.slack_feedback +WHERE astoria.slack_feedback.workspace_id = $1 + AND (issue_raised = false OR issue_raised IS NULL) + AND created_at BETWEEN $2::date AND $3::date +` + +type GetTotalSlackQueriesResolvedParams struct { + WorkspaceID int64 + Column2 pgtype.Date + Column3 pgtype.Date +} + +func (q *Queries) GetTotalSlackQueriesResolved(ctx context.Context, arg GetTotalSlackQueriesResolvedParams) (int64, error) { + row := q.db.QueryRow(ctx, getTotalSlackQueriesResolved, arg.WorkspaceID, arg.Column2, arg.Column3) + var count int64 + err := row.Scan(&count) + return count, err +} diff --git a/internal/endtoend/testdata/schema_table_column_ref/postgresql/pgx/query.sql b/internal/endtoend/testdata/schema_table_column_ref/postgresql/pgx/query.sql new file mode 100644 index 0000000..3aa8ae1 --- /dev/null +++ b/internal/endtoend/testdata/schema_table_column_ref/postgresql/pgx/query.sql @@ -0,0 +1,22 @@ +-- name: GetTotalSlackQueries :one +SELECT + COUNT(*) AS count +FROM astoria.slack_feedback +WHERE astoria.slack_feedback.workspace_id = $1 +AND created_at BETWEEN $2::date AND $3::date; + +-- name: GetTotalSlackQueriesResolved :one +SELECT + COUNT(*) AS count +FROM astoria.slack_feedback +WHERE astoria.slack_feedback.workspace_id = $1 + AND (issue_raised = false OR issue_raised IS NULL) + AND created_at BETWEEN $2::date AND $3::date; + +-- name: GetTotalSlackQueriesRequestsCreated :one +SELECT + COUNT(*) AS count +FROM astoria.tickets +WHERE astoria.tickets.workspace_id = $1 + AND source = 'RAISED_FROM_BOT' + AND created_at BETWEEN $2::date AND $3::date; diff --git a/internal/endtoend/testdata/schema_table_column_ref/postgresql/pgx/schema.sql b/internal/endtoend/testdata/schema_table_column_ref/postgresql/pgx/schema.sql new file mode 100644 index 0000000..48ccc12 --- /dev/null +++ b/internal/endtoend/testdata/schema_table_column_ref/postgresql/pgx/schema.sql @@ -0,0 +1,15 @@ +CREATE SCHEMA astoria; + +CREATE TABLE astoria.slack_feedback ( + id BIGSERIAL PRIMARY KEY, + workspace_id BIGINT NOT NULL, + created_at TIMESTAMP NOT NULL, + issue_raised BOOLEAN +); + +CREATE TABLE astoria.tickets ( + id BIGSERIAL PRIMARY KEY, + workspace_id BIGINT NOT NULL, + created_at TIMESTAMP NOT NULL, + source text NOT NULL +); diff --git a/internal/endtoend/testdata/schema_table_column_ref/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/schema_table_column_ref/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/schema_table_column_ref/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/select_column_cast/mysql/go/db.go b/internal/endtoend/testdata/select_column_cast/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_column_cast/mysql/go/models.go b/internal/endtoend/testdata/select_column_cast/mysql/go/models.go new file mode 100644 index 0000000..e2a9591 --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/mysql/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar bool +} diff --git a/internal/endtoend/testdata/select_column_cast/mysql/go/query.sql.go b/internal/endtoend/testdata/select_column_cast/mysql/go/query.sql.go new file mode 100644 index 0000000..a66217e --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/mysql/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const selectColumnCast = `-- name: SelectColumnCast :many +SELECT CAST(bar AS UNSIGNED) FROM foo +` + +func (q *Queries) SelectColumnCast(ctx context.Context) ([]int64, error) { + rows, err := q.db.QueryContext(ctx, selectColumnCast) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var bar int64 + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + 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_column_cast/mysql/query.sql b/internal/endtoend/testdata/select_column_cast/mysql/query.sql new file mode 100644 index 0000000..dc083f3 --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: SelectColumnCast :many +SELECT CAST(bar AS UNSIGNED) FROM foo; diff --git a/internal/endtoend/testdata/select_column_cast/mysql/schema.sql b/internal/endtoend/testdata/select_column_cast/mysql/schema.sql new file mode 100644 index 0000000..51f66c6 --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar BOOLEAN NOT NULL); + diff --git a/internal/endtoend/testdata/select_column_cast/mysql/sqlc.json b/internal/endtoend/testdata/select_column_cast/mysql/sqlc.json new file mode 100644 index 0000000..0390f67 --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/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/select_column_cast/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/select_column_cast/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..e2a9591 --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar bool +} diff --git a/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..54f358e --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const selectColumnCast = `-- name: SelectColumnCast :many +SELECT bar::int FROM foo +` + +func (q *Queries) SelectColumnCast(ctx context.Context) ([]int32, error) { + rows, err := q.db.Query(ctx, selectColumnCast) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int32 + for rows.Next() { + var bar int32 + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..bbb1b9a --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: SelectColumnCast :many +SELECT bar::int FROM foo; diff --git a/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..1d3eb6d --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar bool not null); + diff --git a/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/select_column_cast/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..e2a9591 --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar bool +} diff --git a/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..54f358e --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const selectColumnCast = `-- name: SelectColumnCast :many +SELECT bar::int FROM foo +` + +func (q *Queries) SelectColumnCast(ctx context.Context) ([]int32, error) { + rows, err := q.db.Query(ctx, selectColumnCast) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int32 + for rows.Next() { + var bar int32 + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..bbb1b9a --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: SelectColumnCast :many +SELECT bar::int FROM foo; diff --git a/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..1d3eb6d --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar bool not null); + diff --git a/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_column_cast/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/select_column_cast/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_column_cast/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/select_column_cast/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..e2a9591 --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/postgresql/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar bool +} diff --git a/internal/endtoend/testdata/select_column_cast/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/select_column_cast/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..1c5bf04 --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const selectColumnCast = `-- name: SelectColumnCast :many +SELECT bar::int FROM foo +` + +func (q *Queries) SelectColumnCast(ctx context.Context) ([]int32, error) { + rows, err := q.db.QueryContext(ctx, selectColumnCast) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int32 + for rows.Next() { + var bar int32 + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + 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_column_cast/postgresql/stdlib/query.sql b/internal/endtoend/testdata/select_column_cast/postgresql/stdlib/query.sql new file mode 100644 index 0000000..bbb1b9a --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: SelectColumnCast :many +SELECT bar::int FROM foo; diff --git a/internal/endtoend/testdata/select_column_cast/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/select_column_cast/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..1d3eb6d --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar bool not null); + diff --git a/internal/endtoend/testdata/select_column_cast/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/select_column_cast/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/postgresql/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_column_cast/sqlite/go/db.go b/internal/endtoend/testdata/select_column_cast/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_column_cast/sqlite/go/models.go b/internal/endtoend/testdata/select_column_cast/sqlite/go/models.go new file mode 100644 index 0000000..d324fe9 --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/sqlite/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Bar string +} diff --git a/internal/endtoend/testdata/select_column_cast/sqlite/go/query.sql.go b/internal/endtoend/testdata/select_column_cast/sqlite/go/query.sql.go new file mode 100644 index 0000000..a8c2742 --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/sqlite/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const selectColumnCast = `-- name: SelectColumnCast :many +SELECT CAST(bar AS BLOB) FROM foo +` + +func (q *Queries) SelectColumnCast(ctx context.Context) ([][]byte, error) { + rows, err := q.db.QueryContext(ctx, selectColumnCast) + if err != nil { + return nil, err + } + defer rows.Close() + var items [][]byte + for rows.Next() { + var bar []byte + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + 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_column_cast/sqlite/query.sql b/internal/endtoend/testdata/select_column_cast/sqlite/query.sql new file mode 100644 index 0000000..4775543 --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: SelectColumnCast :many +SELECT CAST(bar AS BLOB) FROM foo; diff --git a/internal/endtoend/testdata/select_column_cast/sqlite/schema.sql b/internal/endtoend/testdata/select_column_cast/sqlite/schema.sql new file mode 100644 index 0000000..883b458 --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/sqlite/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar TEXT NOT NULL); + diff --git a/internal/endtoend/testdata/select_column_cast/sqlite/sqlc.json b/internal/endtoend/testdata/select_column_cast/sqlite/sqlc.json new file mode 100644 index 0000000..95b9cd0 --- /dev/null +++ b/internal/endtoend/testdata/select_column_cast/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_cte/sqlite/go/db.go b/internal/endtoend/testdata/select_cte/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_cte/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_cte/sqlite/go/models.go b/internal/endtoend/testdata/select_cte/sqlite/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/select_cte/sqlite/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/select_cte/sqlite/go/query.sql.go b/internal/endtoend/testdata/select_cte/sqlite/go/query.sql.go new file mode 100644 index 0000000..8d2b8ae --- /dev/null +++ b/internal/endtoend/testdata/select_cte/sqlite/go/query.sql.go @@ -0,0 +1,40 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listAuthors = `-- name: ListAuthors :many +WITH abc AS ( + SELECT 1 AS n +) +SELECT n FROM abc +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]int64, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var n int64 + if err := rows.Scan(&n); err != nil { + return nil, err + } + items = append(items, n) + } + 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_cte/sqlite/query.sql b/internal/endtoend/testdata/select_cte/sqlite/query.sql new file mode 100644 index 0000000..2f538b8 --- /dev/null +++ b/internal/endtoend/testdata/select_cte/sqlite/query.sql @@ -0,0 +1,5 @@ +-- name: ListAuthors :many +WITH abc AS ( + SELECT 1 AS n +) +SELECT * FROM abc; diff --git a/internal/endtoend/testdata/select_cte/sqlite/schema.sql b/internal/endtoend/testdata/select_cte/sqlite/schema.sql new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/internal/endtoend/testdata/select_cte/sqlite/schema.sql @@ -0,0 +1 @@ + diff --git a/internal/endtoend/testdata/select_cte/sqlite/sqlc.json b/internal/endtoend/testdata/select_cte/sqlite/sqlc.json new file mode 100644 index 0000000..ea4a234 --- /dev/null +++ b/internal/endtoend/testdata/select_cte/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "schema": "schema.sql", + "queries": "query.sql", + "name": "querytest" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/select_distinct/pgx/v4/go/db.go b/internal/endtoend/testdata/select_distinct/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/select_distinct/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/select_distinct/pgx/v4/go/models.go b/internal/endtoend/testdata/select_distinct/pgx/v4/go/models.go new file mode 100644 index 0000000..9792445 --- /dev/null +++ b/internal/endtoend/testdata/select_distinct/pgx/v4/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ID int32 + Name sql.NullString +} diff --git a/internal/endtoend/testdata/select_distinct/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/select_distinct/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..84a7ab5 --- /dev/null +++ b/internal/endtoend/testdata/select_distinct/pgx/v4/go/query.sql.go @@ -0,0 +1,35 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getBars = `-- name: GetBars :many +SELECT DISTINCT ON (a.id) a.id, a.name +FROM bar a +` + +func (q *Queries) GetBars(ctx context.Context) ([]Bar, error) { + rows, err := q.db.Query(ctx, getBars) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Bar + for rows.Next() { + var i Bar + if err := rows.Scan(&i.ID, &i.Name); 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_distinct/pgx/v4/query.sql b/internal/endtoend/testdata/select_distinct/pgx/v4/query.sql new file mode 100644 index 0000000..8f8cafc --- /dev/null +++ b/internal/endtoend/testdata/select_distinct/pgx/v4/query.sql @@ -0,0 +1,3 @@ +-- name: GetBars :many +SELECT DISTINCT ON (a.id) a.* +FROM bar a; diff --git a/internal/endtoend/testdata/select_distinct/pgx/v4/schema.sql b/internal/endtoend/testdata/select_distinct/pgx/v4/schema.sql new file mode 100644 index 0000000..a4d38d3 --- /dev/null +++ b/internal/endtoend/testdata/select_distinct/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null, name text); + diff --git a/internal/endtoend/testdata/select_distinct/pgx/v4/sqlc.json b/internal/endtoend/testdata/select_distinct/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/select_distinct/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_distinct/pgx/v5/go/db.go b/internal/endtoend/testdata/select_distinct/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/select_distinct/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/select_distinct/pgx/v5/go/models.go b/internal/endtoend/testdata/select_distinct/pgx/v5/go/models.go new file mode 100644 index 0000000..ca7c68f --- /dev/null +++ b/internal/endtoend/testdata/select_distinct/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Bar struct { + ID int32 + Name pgtype.Text +} diff --git a/internal/endtoend/testdata/select_distinct/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/select_distinct/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..84a7ab5 --- /dev/null +++ b/internal/endtoend/testdata/select_distinct/pgx/v5/go/query.sql.go @@ -0,0 +1,35 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getBars = `-- name: GetBars :many +SELECT DISTINCT ON (a.id) a.id, a.name +FROM bar a +` + +func (q *Queries) GetBars(ctx context.Context) ([]Bar, error) { + rows, err := q.db.Query(ctx, getBars) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Bar + for rows.Next() { + var i Bar + if err := rows.Scan(&i.ID, &i.Name); 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_distinct/pgx/v5/query.sql b/internal/endtoend/testdata/select_distinct/pgx/v5/query.sql new file mode 100644 index 0000000..8f8cafc --- /dev/null +++ b/internal/endtoend/testdata/select_distinct/pgx/v5/query.sql @@ -0,0 +1,3 @@ +-- name: GetBars :many +SELECT DISTINCT ON (a.id) a.* +FROM bar a; diff --git a/internal/endtoend/testdata/select_distinct/pgx/v5/schema.sql b/internal/endtoend/testdata/select_distinct/pgx/v5/schema.sql new file mode 100644 index 0000000..a4d38d3 --- /dev/null +++ b/internal/endtoend/testdata/select_distinct/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null, name text); + diff --git a/internal/endtoend/testdata/select_distinct/pgx/v5/sqlc.json b/internal/endtoend/testdata/select_distinct/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/select_distinct/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_distinct/stdlib/go/db.go b/internal/endtoend/testdata/select_distinct/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_distinct/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_distinct/stdlib/go/models.go b/internal/endtoend/testdata/select_distinct/stdlib/go/models.go new file mode 100644 index 0000000..9792445 --- /dev/null +++ b/internal/endtoend/testdata/select_distinct/stdlib/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ID int32 + Name sql.NullString +} diff --git a/internal/endtoend/testdata/select_distinct/stdlib/go/query.sql.go b/internal/endtoend/testdata/select_distinct/stdlib/go/query.sql.go new file mode 100644 index 0000000..8f3b369 --- /dev/null +++ b/internal/endtoend/testdata/select_distinct/stdlib/go/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getBars = `-- name: GetBars :many +SELECT DISTINCT ON (a.id) a.id, a.name +FROM bar a +` + +func (q *Queries) GetBars(ctx context.Context) ([]Bar, error) { + rows, err := q.db.QueryContext(ctx, getBars) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Bar + for rows.Next() { + var i Bar + if err := rows.Scan(&i.ID, &i.Name); 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_distinct/stdlib/query.sql b/internal/endtoend/testdata/select_distinct/stdlib/query.sql new file mode 100644 index 0000000..8f8cafc --- /dev/null +++ b/internal/endtoend/testdata/select_distinct/stdlib/query.sql @@ -0,0 +1,3 @@ +-- name: GetBars :many +SELECT DISTINCT ON (a.id) a.* +FROM bar a; diff --git a/internal/endtoend/testdata/select_distinct/stdlib/schema.sql b/internal/endtoend/testdata/select_distinct/stdlib/schema.sql new file mode 100644 index 0000000..a4d38d3 --- /dev/null +++ b/internal/endtoend/testdata/select_distinct/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null, name text); + diff --git a/internal/endtoend/testdata/select_distinct/stdlib/sqlc.json b/internal/endtoend/testdata/select_distinct/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/select_distinct/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_empty_column_list/mysql/query.sql b/internal/endtoend/testdata/select_empty_column_list/mysql/query.sql new file mode 100644 index 0000000..ae6cd0c --- /dev/null +++ b/internal/endtoend/testdata/select_empty_column_list/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: GetBars :many +SELECT FROM bar; diff --git a/internal/endtoend/testdata/select_empty_column_list/mysql/schema.sql b/internal/endtoend/testdata/select_empty_column_list/mysql/schema.sql new file mode 100644 index 0000000..fb18b4b --- /dev/null +++ b/internal/endtoend/testdata/select_empty_column_list/mysql/schema.sql @@ -0,0 +1 @@ +CREATE TABLE bar (name text); diff --git a/internal/endtoend/testdata/select_empty_column_list/mysql/sqlc.json b/internal/endtoend/testdata/select_empty_column_list/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/select_empty_column_list/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/select_empty_column_list/mysql/stderr.txt b/internal/endtoend/testdata/select_empty_column_list/mysql/stderr.txt new file mode 100644 index 0000000..2744126 --- /dev/null +++ b/internal/endtoend/testdata/select_empty_column_list/mysql/stderr.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:2:12: syntax error near "FROM bar;" diff --git a/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/select_empty_column_list/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..9792445 --- /dev/null +++ b/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v4/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ID int32 + Name sql.NullString +} diff --git a/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..a477f23 --- /dev/null +++ b/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getBars = `-- name: GetBars :many +SELECT FROM bar LIMIT 5 +` + +type GetBarsRow struct { +} + +func (q *Queries) GetBars(ctx context.Context) ([]GetBarsRow, error) { + rows, err := q.db.Query(ctx, getBars) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetBarsRow + for rows.Next() { + var i GetBarsRow + if err := rows.Scan(); 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_empty_column_list/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..d673329 --- /dev/null +++ b/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: GetBars :many +SELECT FROM bar LIMIT 5; \ No newline at end of file diff --git a/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..a4d38d3 --- /dev/null +++ b/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null, name text); + diff --git a/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/select_empty_column_list/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..ca7c68f --- /dev/null +++ b/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Bar struct { + ID int32 + Name pgtype.Text +} diff --git a/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..a477f23 --- /dev/null +++ b/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getBars = `-- name: GetBars :many +SELECT FROM bar LIMIT 5 +` + +type GetBarsRow struct { +} + +func (q *Queries) GetBars(ctx context.Context) ([]GetBarsRow, error) { + rows, err := q.db.Query(ctx, getBars) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetBarsRow + for rows.Next() { + var i GetBarsRow + if err := rows.Scan(); 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_empty_column_list/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..d673329 --- /dev/null +++ b/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: GetBars :many +SELECT FROM bar LIMIT 5; \ No newline at end of file diff --git a/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..a4d38d3 --- /dev/null +++ b/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null, name text); + diff --git a/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/select_empty_column_list/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_empty_column_list/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/select_empty_column_list/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_empty_column_list/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_empty_column_list/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/select_empty_column_list/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..9792445 --- /dev/null +++ b/internal/endtoend/testdata/select_empty_column_list/postgresql/stdlib/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ID int32 + Name sql.NullString +} diff --git a/internal/endtoend/testdata/select_empty_column_list/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/select_empty_column_list/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..af2067d --- /dev/null +++ b/internal/endtoend/testdata/select_empty_column_list/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,40 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getBars = `-- name: GetBars :many +SELECT FROM bar LIMIT 5 +` + +type GetBarsRow struct { +} + +func (q *Queries) GetBars(ctx context.Context) ([]GetBarsRow, error) { + rows, err := q.db.QueryContext(ctx, getBars) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetBarsRow + for rows.Next() { + var i GetBarsRow + if err := rows.Scan(); 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_empty_column_list/postgresql/stdlib/query.sql b/internal/endtoend/testdata/select_empty_column_list/postgresql/stdlib/query.sql new file mode 100644 index 0000000..d673329 --- /dev/null +++ b/internal/endtoend/testdata/select_empty_column_list/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: GetBars :many +SELECT FROM bar LIMIT 5; \ No newline at end of file diff --git a/internal/endtoend/testdata/select_empty_column_list/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/select_empty_column_list/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..a4d38d3 --- /dev/null +++ b/internal/endtoend/testdata/select_empty_column_list/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null, name text); + diff --git a/internal/endtoend/testdata/select_empty_column_list/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/select_empty_column_list/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/select_empty_column_list/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_exists/pgx/v4/go/db.go b/internal/endtoend/testdata/select_exists/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/select_exists/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/select_exists/pgx/v4/go/models.go b/internal/endtoend/testdata/select_exists/pgx/v4/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/select_exists/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/select_exists/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/select_exists/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..359df59 --- /dev/null +++ b/internal/endtoend/testdata/select_exists/pgx/v4/go/query.sql.go @@ -0,0 +1,29 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const barExists = `-- name: BarExists :one +SELECT + EXISTS ( + SELECT + 1 + FROM + bar + where + id = $1 + ) +` + +func (q *Queries) BarExists(ctx context.Context, id int32) (bool, error) { + row := q.db.QueryRow(ctx, barExists, id) + var exists bool + err := row.Scan(&exists) + return exists, err +} diff --git a/internal/endtoend/testdata/select_exists/pgx/v4/query.sql b/internal/endtoend/testdata/select_exists/pgx/v4/query.sql new file mode 100644 index 0000000..635b468 --- /dev/null +++ b/internal/endtoend/testdata/select_exists/pgx/v4/query.sql @@ -0,0 +1,10 @@ +-- name: BarExists :one +SELECT + EXISTS ( + SELECT + 1 + FROM + bar + where + id = $1 + ); diff --git a/internal/endtoend/testdata/select_exists/pgx/v4/schema.sql b/internal/endtoend/testdata/select_exists/pgx/v4/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/select_exists/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/select_exists/pgx/v4/sqlc.json b/internal/endtoend/testdata/select_exists/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/select_exists/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_exists/pgx/v5/go/db.go b/internal/endtoend/testdata/select_exists/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/select_exists/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/select_exists/pgx/v5/go/models.go b/internal/endtoend/testdata/select_exists/pgx/v5/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/select_exists/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/select_exists/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/select_exists/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..359df59 --- /dev/null +++ b/internal/endtoend/testdata/select_exists/pgx/v5/go/query.sql.go @@ -0,0 +1,29 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const barExists = `-- name: BarExists :one +SELECT + EXISTS ( + SELECT + 1 + FROM + bar + where + id = $1 + ) +` + +func (q *Queries) BarExists(ctx context.Context, id int32) (bool, error) { + row := q.db.QueryRow(ctx, barExists, id) + var exists bool + err := row.Scan(&exists) + return exists, err +} diff --git a/internal/endtoend/testdata/select_exists/pgx/v5/query.sql b/internal/endtoend/testdata/select_exists/pgx/v5/query.sql new file mode 100644 index 0000000..635b468 --- /dev/null +++ b/internal/endtoend/testdata/select_exists/pgx/v5/query.sql @@ -0,0 +1,10 @@ +-- name: BarExists :one +SELECT + EXISTS ( + SELECT + 1 + FROM + bar + where + id = $1 + ); diff --git a/internal/endtoend/testdata/select_exists/pgx/v5/schema.sql b/internal/endtoend/testdata/select_exists/pgx/v5/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/select_exists/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/select_exists/pgx/v5/sqlc.json b/internal/endtoend/testdata/select_exists/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/select_exists/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_exists/sqlite/go/db.go b/internal/endtoend/testdata/select_exists/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_exists/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_exists/sqlite/go/models.go b/internal/endtoend/testdata/select_exists/sqlite/go/models.go new file mode 100644 index 0000000..bc354e0 --- /dev/null +++ b/internal/endtoend/testdata/select_exists/sqlite/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int64 +} diff --git a/internal/endtoend/testdata/select_exists/sqlite/go/query.sql.go b/internal/endtoend/testdata/select_exists/sqlite/go/query.sql.go new file mode 100644 index 0000000..d0d6804 --- /dev/null +++ b/internal/endtoend/testdata/select_exists/sqlite/go/query.sql.go @@ -0,0 +1,26 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const barExists = `-- name: BarExists :one +SELECT + EXISTS ( + SELECT 1 + FROM bar + WHERE id = ? + ) +` + +func (q *Queries) BarExists(ctx context.Context, id int64) (bool, error) { + row := q.db.QueryRowContext(ctx, barExists, id) + var exists bool + err := row.Scan(&exists) + return exists, err +} diff --git a/internal/endtoend/testdata/select_exists/sqlite/query.sql b/internal/endtoend/testdata/select_exists/sqlite/query.sql new file mode 100644 index 0000000..15ef7be --- /dev/null +++ b/internal/endtoend/testdata/select_exists/sqlite/query.sql @@ -0,0 +1,7 @@ +-- name: BarExists :one +SELECT + EXISTS ( + SELECT 1 + FROM bar + WHERE id = ? + ); diff --git a/internal/endtoend/testdata/select_exists/sqlite/schema.sql b/internal/endtoend/testdata/select_exists/sqlite/schema.sql new file mode 100644 index 0000000..cf6a8b9 --- /dev/null +++ b/internal/endtoend/testdata/select_exists/sqlite/schema.sql @@ -0,0 +1 @@ +CREATE TABLE bar (id integer not null primary key autoincrement); diff --git a/internal/endtoend/testdata/select_exists/sqlite/sqlc.json b/internal/endtoend/testdata/select_exists/sqlite/sqlc.json new file mode 100644 index 0000000..9655954 --- /dev/null +++ b/internal/endtoend/testdata/select_exists/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "engine": "sqlite", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_exists/stdlib/go/db.go b/internal/endtoend/testdata/select_exists/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_exists/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_exists/stdlib/go/models.go b/internal/endtoend/testdata/select_exists/stdlib/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/select_exists/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/select_exists/stdlib/go/query.sql.go b/internal/endtoend/testdata/select_exists/stdlib/go/query.sql.go new file mode 100644 index 0000000..cfbcd91 --- /dev/null +++ b/internal/endtoend/testdata/select_exists/stdlib/go/query.sql.go @@ -0,0 +1,29 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const barExists = `-- name: BarExists :one +SELECT + EXISTS ( + SELECT + 1 + FROM + bar + where + id = $1 + ) +` + +func (q *Queries) BarExists(ctx context.Context, id int32) (bool, error) { + row := q.db.QueryRowContext(ctx, barExists, id) + var exists bool + err := row.Scan(&exists) + return exists, err +} diff --git a/internal/endtoend/testdata/select_exists/stdlib/query.sql b/internal/endtoend/testdata/select_exists/stdlib/query.sql new file mode 100644 index 0000000..635b468 --- /dev/null +++ b/internal/endtoend/testdata/select_exists/stdlib/query.sql @@ -0,0 +1,10 @@ +-- name: BarExists :one +SELECT + EXISTS ( + SELECT + 1 + FROM + bar + where + id = $1 + ); diff --git a/internal/endtoend/testdata/select_exists/stdlib/schema.sql b/internal/endtoend/testdata/select_exists/stdlib/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/select_exists/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/select_exists/stdlib/sqlc.json b/internal/endtoend/testdata/select_exists/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/select_exists/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_in_and/sqlite/go/db.go b/internal/endtoend/testdata/select_in_and/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_in_and/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_in_and/sqlite/go/models.go b/internal/endtoend/testdata/select_in_and/sqlite/go/models.go new file mode 100644 index 0000000..838d082 --- /dev/null +++ b/internal/endtoend/testdata/select_in_and/sqlite/go/models.go @@ -0,0 +1,28 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Age sql.NullInt64 +} + +type Book struct { + ID int64 + Author string + Translator string + Year sql.NullInt64 +} + +type Translator struct { + ID int64 + Name string + Age sql.NullInt64 +} diff --git a/internal/endtoend/testdata/select_in_and/sqlite/go/query.sql.go b/internal/endtoend/testdata/select_in_and/sqlite/go/query.sql.go new file mode 100644 index 0000000..3a97dad --- /dev/null +++ b/internal/endtoend/testdata/select_in_and/sqlite/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const deleteAuthor = `-- name: DeleteAuthor :exec +DELETE FROM books AS b +WHERE NOT b.author IN ( + SELECT a.name + FROM authors AS a + WHERE a.age >= ? + ) + AND NOT b.translator IN ( + SELECT t.name + FROM translators AS t + WHERE t.age >= ? + ) + AND b.year <= ? +` + +type DeleteAuthorParams struct { + Age sql.NullInt64 + Age_2 sql.NullInt64 + Year sql.NullInt64 +} + +func (q *Queries) DeleteAuthor(ctx context.Context, arg DeleteAuthorParams) error { + _, err := q.db.ExecContext(ctx, deleteAuthor, arg.Age, arg.Age_2, arg.Year) + return err +} diff --git a/internal/endtoend/testdata/select_in_and/sqlite/query.sql b/internal/endtoend/testdata/select_in_and/sqlite/query.sql new file mode 100644 index 0000000..a4e760f --- /dev/null +++ b/internal/endtoend/testdata/select_in_and/sqlite/query.sql @@ -0,0 +1,13 @@ +-- name: DeleteAuthor :exec +DELETE FROM books AS b +WHERE NOT b.author IN ( + SELECT a.name + FROM authors AS a + WHERE a.age >= ? + ) + AND NOT b.translator IN ( + SELECT t.name + FROM translators AS t + WHERE t.age >= ? + ) + AND b.year <= ?; diff --git a/internal/endtoend/testdata/select_in_and/sqlite/schema.sql b/internal/endtoend/testdata/select_in_and/sqlite/schema.sql new file mode 100644 index 0000000..76505b1 --- /dev/null +++ b/internal/endtoend/testdata/select_in_and/sqlite/schema.sql @@ -0,0 +1,20 @@ +-- Example queries for sqlc +CREATE TABLE authors ( + id integer PRIMARY KEY, + name text NOT NULL, + age integer +); + +CREATE TABLE translators ( + id integer PRIMARY KEY, + name text NOT NULL, + age integer +); + +CREATE TABLE books ( + id integer PRIMARY KEY, + author text NOT NULL, + translator text NOT NULL, + year integer +); + diff --git a/internal/endtoend/testdata/select_in_and/sqlite/sqlc.json b/internal/endtoend/testdata/select_in_and/sqlite/sqlc.json new file mode 100644 index 0000000..99b3b5f --- /dev/null +++ b/internal/endtoend/testdata/select_in_and/sqlite/sqlc.json @@ -0,0 +1 @@ +{"version": "1", "packages": [{"path": "go", "engine": "sqlite", "schema": "schema.sql", "queries": "query.sql", "name": "querytest"}]} \ No newline at end of file diff --git a/internal/endtoend/testdata/select_limit/mysql/go/db.go b/internal/endtoend/testdata/select_limit/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_limit/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_limit/mysql/go/models.go b/internal/endtoend/testdata/select_limit/mysql/go/models.go new file mode 100644 index 0000000..f05c6b5 --- /dev/null +++ b/internal/endtoend/testdata/select_limit/mysql/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString +} diff --git a/internal/endtoend/testdata/select_limit/mysql/go/query.sql.go b/internal/endtoend/testdata/select_limit/mysql/go/query.sql.go new file mode 100644 index 0000000..163da54 --- /dev/null +++ b/internal/endtoend/testdata/select_limit/mysql/go/query.sql.go @@ -0,0 +1,72 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const fooLimit = `-- name: FooLimit :many +SELECT a FROM foo +LIMIT ? +` + +func (q *Queries) FooLimit(ctx context.Context, limit int32) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, fooLimit, limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var a sql.NullString + if err := rows.Scan(&a); err != nil { + return nil, err + } + items = append(items, a) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const fooLimitOffset = `-- name: FooLimitOffset :many +SELECT a FROM foo +LIMIT ? OFFSET ? +` + +type FooLimitOffsetParams struct { + Limit int32 + Offset int32 +} + +func (q *Queries) FooLimitOffset(ctx context.Context, arg FooLimitOffsetParams) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, fooLimitOffset, arg.Limit, arg.Offset) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var a sql.NullString + if err := rows.Scan(&a); err != nil { + return nil, err + } + items = append(items, a) + } + 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_limit/mysql/query.sql b/internal/endtoend/testdata/select_limit/mysql/query.sql new file mode 100644 index 0000000..1fea17c --- /dev/null +++ b/internal/endtoend/testdata/select_limit/mysql/query.sql @@ -0,0 +1,7 @@ +/* name: FooLimit :many */ +SELECT a FROM foo +LIMIT ?; + +/* name: FooLimitOffset :many */ +SELECT a FROM foo +LIMIT ? OFFSET ?; diff --git a/internal/endtoend/testdata/select_limit/mysql/schema.sql b/internal/endtoend/testdata/select_limit/mysql/schema.sql new file mode 100644 index 0000000..f30f6c2 --- /dev/null +++ b/internal/endtoend/testdata/select_limit/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text); + diff --git a/internal/endtoend/testdata/select_limit/mysql/sqlc.json b/internal/endtoend/testdata/select_limit/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/select_limit/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_limit/postgresql/pgx/v4/exec.json b/internal/endtoend/testdata/select_limit/postgresql/pgx/v4/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/select_limit/postgresql/pgx/v4/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/select_limit/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/select_limit/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/select_limit/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/select_limit/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/select_limit/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..f05c6b5 --- /dev/null +++ b/internal/endtoend/testdata/select_limit/postgresql/pgx/v4/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString +} diff --git a/internal/endtoend/testdata/select_limit/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/select_limit/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..e13ab38 --- /dev/null +++ b/internal/endtoend/testdata/select_limit/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,66 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const fooLimit = `-- name: FooLimit :many +SELECT a FROM foo +LIMIT $1 +` + +func (q *Queries) FooLimit(ctx context.Context, limit int32) ([]sql.NullString, error) { + rows, err := q.db.Query(ctx, fooLimit, limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var a sql.NullString + if err := rows.Scan(&a); err != nil { + return nil, err + } + items = append(items, a) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const fooLimitOffset = `-- name: FooLimitOffset :many +SELECT a FROM foo +LIMIT $1 OFFSET $2 +` + +type FooLimitOffsetParams struct { + Limit int32 + Offset int32 +} + +func (q *Queries) FooLimitOffset(ctx context.Context, arg FooLimitOffsetParams) ([]sql.NullString, error) { + rows, err := q.db.Query(ctx, fooLimitOffset, arg.Limit, arg.Offset) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var a sql.NullString + if err := rows.Scan(&a); err != nil { + return nil, err + } + items = append(items, a) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/select_limit/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/select_limit/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..11907d0 --- /dev/null +++ b/internal/endtoend/testdata/select_limit/postgresql/pgx/v4/query.sql @@ -0,0 +1,7 @@ +-- name: FooLimit :many +SELECT a FROM foo +LIMIT $1; + +-- name: FooLimitOffset :many +SELECT a FROM foo +LIMIT $1 OFFSET $2; diff --git a/internal/endtoend/testdata/select_limit/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/select_limit/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..f30f6c2 --- /dev/null +++ b/internal/endtoend/testdata/select_limit/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text); + diff --git a/internal/endtoend/testdata/select_limit/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/select_limit/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/select_limit/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_limit/postgresql/pgx/v5/exec.json b/internal/endtoend/testdata/select_limit/postgresql/pgx/v5/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/select_limit/postgresql/pgx/v5/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/select_limit/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/select_limit/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/select_limit/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/select_limit/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/select_limit/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..94fa185 --- /dev/null +++ b/internal/endtoend/testdata/select_limit/postgresql/pgx/v5/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + A pgtype.Text +} diff --git a/internal/endtoend/testdata/select_limit/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/select_limit/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..95e18d4 --- /dev/null +++ b/internal/endtoend/testdata/select_limit/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,67 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const fooLimit = `-- name: FooLimit :many +SELECT a FROM foo +LIMIT $1 +` + +func (q *Queries) FooLimit(ctx context.Context, limit int32) ([]pgtype.Text, error) { + rows, err := q.db.Query(ctx, fooLimit, limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []pgtype.Text + for rows.Next() { + var a pgtype.Text + if err := rows.Scan(&a); err != nil { + return nil, err + } + items = append(items, a) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const fooLimitOffset = `-- name: FooLimitOffset :many +SELECT a FROM foo +LIMIT $1 OFFSET $2 +` + +type FooLimitOffsetParams struct { + Limit int32 + Offset int32 +} + +func (q *Queries) FooLimitOffset(ctx context.Context, arg FooLimitOffsetParams) ([]pgtype.Text, error) { + rows, err := q.db.Query(ctx, fooLimitOffset, arg.Limit, arg.Offset) + if err != nil { + return nil, err + } + defer rows.Close() + var items []pgtype.Text + for rows.Next() { + var a pgtype.Text + if err := rows.Scan(&a); err != nil { + return nil, err + } + items = append(items, a) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/select_limit/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/select_limit/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..11907d0 --- /dev/null +++ b/internal/endtoend/testdata/select_limit/postgresql/pgx/v5/query.sql @@ -0,0 +1,7 @@ +-- name: FooLimit :many +SELECT a FROM foo +LIMIT $1; + +-- name: FooLimitOffset :many +SELECT a FROM foo +LIMIT $1 OFFSET $2; diff --git a/internal/endtoend/testdata/select_limit/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/select_limit/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..f30f6c2 --- /dev/null +++ b/internal/endtoend/testdata/select_limit/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text); + diff --git a/internal/endtoend/testdata/select_limit/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/select_limit/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/select_limit/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_limit/postgresql/stdlib/exec.json b/internal/endtoend/testdata/select_limit/postgresql/stdlib/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/select_limit/postgresql/stdlib/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/select_limit/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/select_limit/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_limit/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_limit/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/select_limit/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..f05c6b5 --- /dev/null +++ b/internal/endtoend/testdata/select_limit/postgresql/stdlib/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString +} diff --git a/internal/endtoend/testdata/select_limit/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/select_limit/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..a977098 --- /dev/null +++ b/internal/endtoend/testdata/select_limit/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,72 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const fooLimit = `-- name: FooLimit :many +SELECT a FROM foo +LIMIT $1 +` + +func (q *Queries) FooLimit(ctx context.Context, limit int32) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, fooLimit, limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var a sql.NullString + if err := rows.Scan(&a); err != nil { + return nil, err + } + items = append(items, a) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const fooLimitOffset = `-- name: FooLimitOffset :many +SELECT a FROM foo +LIMIT $1 OFFSET $2 +` + +type FooLimitOffsetParams struct { + Limit int32 + Offset int32 +} + +func (q *Queries) FooLimitOffset(ctx context.Context, arg FooLimitOffsetParams) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, fooLimitOffset, arg.Limit, arg.Offset) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var a sql.NullString + if err := rows.Scan(&a); err != nil { + return nil, err + } + items = append(items, a) + } + 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_limit/postgresql/stdlib/query.sql b/internal/endtoend/testdata/select_limit/postgresql/stdlib/query.sql new file mode 100644 index 0000000..11907d0 --- /dev/null +++ b/internal/endtoend/testdata/select_limit/postgresql/stdlib/query.sql @@ -0,0 +1,7 @@ +-- name: FooLimit :many +SELECT a FROM foo +LIMIT $1; + +-- name: FooLimitOffset :many +SELECT a FROM foo +LIMIT $1 OFFSET $2; diff --git a/internal/endtoend/testdata/select_limit/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/select_limit/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..f30f6c2 --- /dev/null +++ b/internal/endtoend/testdata/select_limit/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text); + diff --git a/internal/endtoend/testdata/select_limit/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/select_limit/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..cd51867 --- /dev/null +++ b/internal/endtoend/testdata/select_limit/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_limit/sqlite/go/db.go b/internal/endtoend/testdata/select_limit/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_limit/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_limit/sqlite/go/models.go b/internal/endtoend/testdata/select_limit/sqlite/go/models.go new file mode 100644 index 0000000..f05c6b5 --- /dev/null +++ b/internal/endtoend/testdata/select_limit/sqlite/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString +} diff --git a/internal/endtoend/testdata/select_limit/sqlite/go/query.sql.go b/internal/endtoend/testdata/select_limit/sqlite/go/query.sql.go new file mode 100644 index 0000000..8eba03c --- /dev/null +++ b/internal/endtoend/testdata/select_limit/sqlite/go/query.sql.go @@ -0,0 +1,75 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const fooLimit = `-- name: FooLimit :many +SELECT a +FROM foo +LIMIT ? +` + +func (q *Queries) FooLimit(ctx context.Context, limit int64) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, fooLimit, limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var a sql.NullString + if err := rows.Scan(&a); err != nil { + return nil, err + } + items = append(items, a) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const fooLimitOffset = `-- name: FooLimitOffset :many +SELECT a +FROM foo +LIMIT ? +OFFSET ? +` + +type FooLimitOffsetParams struct { + Limit int64 + Offset int64 +} + +func (q *Queries) FooLimitOffset(ctx context.Context, arg FooLimitOffsetParams) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, fooLimitOffset, arg.Limit, arg.Offset) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var a sql.NullString + if err := rows.Scan(&a); err != nil { + return nil, err + } + items = append(items, a) + } + 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_limit/sqlite/query.sql b/internal/endtoend/testdata/select_limit/sqlite/query.sql new file mode 100644 index 0000000..c2e9c39 --- /dev/null +++ b/internal/endtoend/testdata/select_limit/sqlite/query.sql @@ -0,0 +1,10 @@ +/* name: FooLimit :many */ +SELECT a +FROM foo +LIMIT ?; + +/* name: FooLimitOffset :many */ +SELECT a +FROM foo +LIMIT ? +OFFSET ?; diff --git a/internal/endtoend/testdata/select_limit/sqlite/schema.sql b/internal/endtoend/testdata/select_limit/sqlite/schema.sql new file mode 100644 index 0000000..f30f6c2 --- /dev/null +++ b/internal/endtoend/testdata/select_limit/sqlite/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text); + diff --git a/internal/endtoend/testdata/select_limit/sqlite/sqlc.json b/internal/endtoend/testdata/select_limit/sqlite/sqlc.json new file mode 100644 index 0000000..f8e8051 --- /dev/null +++ b/internal/endtoend/testdata/select_limit/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "sqlite", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/select_nested_count/mysql/go/db.go b/internal/endtoend/testdata/select_nested_count/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_nested_count/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_nested_count/mysql/go/models.go b/internal/endtoend/testdata/select_nested_count/mysql/go/models.go new file mode 100644 index 0000000..4073af0 --- /dev/null +++ b/internal/endtoend/testdata/select_nested_count/mysql/go/models.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} + +type Book struct { + ID int64 + AuthorID int64 + Title string +} diff --git a/internal/endtoend/testdata/select_nested_count/mysql/go/query.sql.go b/internal/endtoend/testdata/select_nested_count/mysql/go/query.sql.go new file mode 100644 index 0000000..ca97855 --- /dev/null +++ b/internal/endtoend/testdata/select_nested_count/mysql/go/query.sql.go @@ -0,0 +1,54 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const getAuthorsWithBooksCount = `-- name: GetAuthorsWithBooksCount :many +SELECT id, name, bio, ( + SELECT COUNT(id) FROM books + WHERE books.author_id = id +) AS books_count +FROM authors +` + +type GetAuthorsWithBooksCountRow struct { + ID int64 + Name string + Bio sql.NullString + BooksCount int64 +} + +func (q *Queries) GetAuthorsWithBooksCount(ctx context.Context) ([]GetAuthorsWithBooksCountRow, error) { + rows, err := q.db.QueryContext(ctx, getAuthorsWithBooksCount) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetAuthorsWithBooksCountRow + for rows.Next() { + var i GetAuthorsWithBooksCountRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.Bio, + &i.BooksCount, + ); 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_nested_count/mysql/query.sql b/internal/endtoend/testdata/select_nested_count/mysql/query.sql new file mode 100644 index 0000000..3fe5195 --- /dev/null +++ b/internal/endtoend/testdata/select_nested_count/mysql/query.sql @@ -0,0 +1,6 @@ +-- name: GetAuthorsWithBooksCount :many +SELECT *, ( + SELECT COUNT(id) FROM books + WHERE books.author_id = id +) AS books_count +FROM authors; diff --git a/internal/endtoend/testdata/select_nested_count/mysql/schema.sql b/internal/endtoend/testdata/select_nested_count/mysql/schema.sql new file mode 100644 index 0000000..dffe2e9 --- /dev/null +++ b/internal/endtoend/testdata/select_nested_count/mysql/schema.sql @@ -0,0 +1,13 @@ +CREATE TABLE authors ( + id bigint PRIMARY KEY, + name text NOT NULL, + bio text +); + +CREATE TABLE books ( + id bigint PRIMARY KEY, + author_id bigint NOT NULL + REFERENCES authors(id), + title text NOT NULL +); + diff --git a/internal/endtoend/testdata/select_nested_count/mysql/sqlc.json b/internal/endtoend/testdata/select_nested_count/mysql/sqlc.json new file mode 100644 index 0000000..d3ae3f4 --- /dev/null +++ b/internal/endtoend/testdata/select_nested_count/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "engine": "mysql" + } + ] +} diff --git a/internal/endtoend/testdata/select_nested_count/postgresql/go/db.go b/internal/endtoend/testdata/select_nested_count/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_nested_count/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_nested_count/postgresql/go/models.go b/internal/endtoend/testdata/select_nested_count/postgresql/go/models.go new file mode 100644 index 0000000..4073af0 --- /dev/null +++ b/internal/endtoend/testdata/select_nested_count/postgresql/go/models.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} + +type Book struct { + ID int64 + AuthorID int64 + Title string +} diff --git a/internal/endtoend/testdata/select_nested_count/postgresql/go/query.sql.go b/internal/endtoend/testdata/select_nested_count/postgresql/go/query.sql.go new file mode 100644 index 0000000..ca97855 --- /dev/null +++ b/internal/endtoend/testdata/select_nested_count/postgresql/go/query.sql.go @@ -0,0 +1,54 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const getAuthorsWithBooksCount = `-- name: GetAuthorsWithBooksCount :many +SELECT id, name, bio, ( + SELECT COUNT(id) FROM books + WHERE books.author_id = id +) AS books_count +FROM authors +` + +type GetAuthorsWithBooksCountRow struct { + ID int64 + Name string + Bio sql.NullString + BooksCount int64 +} + +func (q *Queries) GetAuthorsWithBooksCount(ctx context.Context) ([]GetAuthorsWithBooksCountRow, error) { + rows, err := q.db.QueryContext(ctx, getAuthorsWithBooksCount) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetAuthorsWithBooksCountRow + for rows.Next() { + var i GetAuthorsWithBooksCountRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.Bio, + &i.BooksCount, + ); 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_nested_count/postgresql/query.sql b/internal/endtoend/testdata/select_nested_count/postgresql/query.sql new file mode 100644 index 0000000..3fe5195 --- /dev/null +++ b/internal/endtoend/testdata/select_nested_count/postgresql/query.sql @@ -0,0 +1,6 @@ +-- name: GetAuthorsWithBooksCount :many +SELECT *, ( + SELECT COUNT(id) FROM books + WHERE books.author_id = id +) AS books_count +FROM authors; diff --git a/internal/endtoend/testdata/select_nested_count/postgresql/schema.sql b/internal/endtoend/testdata/select_nested_count/postgresql/schema.sql new file mode 100644 index 0000000..85e8fd5 --- /dev/null +++ b/internal/endtoend/testdata/select_nested_count/postgresql/schema.sql @@ -0,0 +1,13 @@ +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); + +CREATE TABLE books ( + id BIGSERIAL PRIMARY KEY, + author_id BIGSERIAL NOT NULL + REFERENCES authors(id), + title text NOT NULL +); + diff --git a/internal/endtoend/testdata/select_nested_count/postgresql/sqlc.json b/internal/endtoend/testdata/select_nested_count/postgresql/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/select_nested_count/postgresql/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_nested_count/sqlite/go/db.go b/internal/endtoend/testdata/select_nested_count/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_nested_count/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_nested_count/sqlite/go/models.go b/internal/endtoend/testdata/select_nested_count/sqlite/go/models.go new file mode 100644 index 0000000..4073af0 --- /dev/null +++ b/internal/endtoend/testdata/select_nested_count/sqlite/go/models.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} + +type Book struct { + ID int64 + AuthorID int64 + Title string +} diff --git a/internal/endtoend/testdata/select_nested_count/sqlite/go/query.sql.go b/internal/endtoend/testdata/select_nested_count/sqlite/go/query.sql.go new file mode 100644 index 0000000..0b610a9 --- /dev/null +++ b/internal/endtoend/testdata/select_nested_count/sqlite/go/query.sql.go @@ -0,0 +1,57 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const getAuthorsWithBooksCount = `-- name: GetAuthorsWithBooksCount :many +SELECT + id, name, bio, + ( + SELECT count(id) + FROM books + WHERE books.author_id = id + ) AS books_count +FROM authors +` + +type GetAuthorsWithBooksCountRow struct { + ID int64 + Name string + Bio sql.NullString + BooksCount int64 +} + +func (q *Queries) GetAuthorsWithBooksCount(ctx context.Context) ([]GetAuthorsWithBooksCountRow, error) { + rows, err := q.db.QueryContext(ctx, getAuthorsWithBooksCount) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetAuthorsWithBooksCountRow + for rows.Next() { + var i GetAuthorsWithBooksCountRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.Bio, + &i.BooksCount, + ); 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_nested_count/sqlite/query.sql b/internal/endtoend/testdata/select_nested_count/sqlite/query.sql new file mode 100644 index 0000000..9006996 --- /dev/null +++ b/internal/endtoend/testdata/select_nested_count/sqlite/query.sql @@ -0,0 +1,9 @@ +-- name: GetAuthorsWithBooksCount :many +SELECT + *, + ( + SELECT count(id) + FROM books + WHERE books.author_id = id + ) AS books_count +FROM authors; diff --git a/internal/endtoend/testdata/select_nested_count/sqlite/schema.sql b/internal/endtoend/testdata/select_nested_count/sqlite/schema.sql new file mode 100644 index 0000000..dffe2e9 --- /dev/null +++ b/internal/endtoend/testdata/select_nested_count/sqlite/schema.sql @@ -0,0 +1,13 @@ +CREATE TABLE authors ( + id bigint PRIMARY KEY, + name text NOT NULL, + bio text +); + +CREATE TABLE books ( + id bigint PRIMARY KEY, + author_id bigint NOT NULL + REFERENCES authors(id), + title text NOT NULL +); + diff --git a/internal/endtoend/testdata/select_nested_count/sqlite/sqlc.json b/internal/endtoend/testdata/select_nested_count/sqlite/sqlc.json new file mode 100644 index 0000000..53eda65 --- /dev/null +++ b/internal/endtoend/testdata/select_nested_count/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "engine": "sqlite" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/select_not_exists/pgx/v4/go/db.go b/internal/endtoend/testdata/select_not_exists/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/select_not_exists/pgx/v4/go/models.go b/internal/endtoend/testdata/select_not_exists/pgx/v4/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/select_not_exists/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/select_not_exists/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..2f9ec4b --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/pgx/v4/go/query.sql.go @@ -0,0 +1,29 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const barNotExists = `-- name: BarNotExists :one +SELECT + NOT EXISTS ( + SELECT + 1 + FROM + bar + where + id = $1 + ) +` + +func (q *Queries) BarNotExists(ctx context.Context, id int32) (bool, error) { + row := q.db.QueryRow(ctx, barNotExists, id) + var not_exists bool + err := row.Scan(¬_exists) + return not_exists, err +} diff --git a/internal/endtoend/testdata/select_not_exists/pgx/v4/query.sql b/internal/endtoend/testdata/select_not_exists/pgx/v4/query.sql new file mode 100644 index 0000000..f32ee62 --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/pgx/v4/query.sql @@ -0,0 +1,10 @@ +-- name: BarNotExists :one +SELECT + NOT EXISTS ( + SELECT + 1 + FROM + bar + where + id = $1 + ); diff --git a/internal/endtoend/testdata/select_not_exists/pgx/v4/schema.sql b/internal/endtoend/testdata/select_not_exists/pgx/v4/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/select_not_exists/pgx/v4/sqlc.json b/internal/endtoend/testdata/select_not_exists/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_not_exists/pgx/v5/go/db.go b/internal/endtoend/testdata/select_not_exists/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/select_not_exists/pgx/v5/go/models.go b/internal/endtoend/testdata/select_not_exists/pgx/v5/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/select_not_exists/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/select_not_exists/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..2f9ec4b --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/pgx/v5/go/query.sql.go @@ -0,0 +1,29 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const barNotExists = `-- name: BarNotExists :one +SELECT + NOT EXISTS ( + SELECT + 1 + FROM + bar + where + id = $1 + ) +` + +func (q *Queries) BarNotExists(ctx context.Context, id int32) (bool, error) { + row := q.db.QueryRow(ctx, barNotExists, id) + var not_exists bool + err := row.Scan(¬_exists) + return not_exists, err +} diff --git a/internal/endtoend/testdata/select_not_exists/pgx/v5/query.sql b/internal/endtoend/testdata/select_not_exists/pgx/v5/query.sql new file mode 100644 index 0000000..f32ee62 --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/pgx/v5/query.sql @@ -0,0 +1,10 @@ +-- name: BarNotExists :one +SELECT + NOT EXISTS ( + SELECT + 1 + FROM + bar + where + id = $1 + ); diff --git a/internal/endtoend/testdata/select_not_exists/pgx/v5/schema.sql b/internal/endtoend/testdata/select_not_exists/pgx/v5/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/select_not_exists/pgx/v5/sqlc.json b/internal/endtoend/testdata/select_not_exists/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_not_exists/sqlite/exec.json b/internal/endtoend/testdata/select_not_exists/sqlite/exec.json new file mode 100644 index 0000000..e5dfda7 --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/sqlite/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/select_not_exists/sqlite/go/db.go b/internal/endtoend/testdata/select_not_exists/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_not_exists/sqlite/go/models.go b/internal/endtoend/testdata/select_not_exists/sqlite/go/models.go new file mode 100644 index 0000000..bc354e0 --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/sqlite/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int64 +} diff --git a/internal/endtoend/testdata/select_not_exists/sqlite/go/query.sql.go b/internal/endtoend/testdata/select_not_exists/sqlite/go/query.sql.go new file mode 100644 index 0000000..dfa8dce --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/sqlite/go/query.sql.go @@ -0,0 +1,26 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const barNotExists = `-- name: BarNotExists :one +SELECT + NOT EXISTS ( + SELECT 1 + FROM bar + WHERE id = ? + ) +` + +func (q *Queries) BarNotExists(ctx context.Context, id int64) (bool, error) { + row := q.db.QueryRowContext(ctx, barNotExists, id) + var not_exists bool + err := row.Scan(¬_exists) + return not_exists, err +} diff --git a/internal/endtoend/testdata/select_not_exists/sqlite/query.sql b/internal/endtoend/testdata/select_not_exists/sqlite/query.sql new file mode 100644 index 0000000..f5dab6a --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/sqlite/query.sql @@ -0,0 +1,7 @@ +-- name: BarNotExists :one +SELECT + NOT EXISTS ( + SELECT 1 + FROM bar + WHERE id = ? + ); diff --git a/internal/endtoend/testdata/select_not_exists/sqlite/schema.sql b/internal/endtoend/testdata/select_not_exists/sqlite/schema.sql new file mode 100644 index 0000000..6cc3882 --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/sqlite/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id integer not null primary key autoincrement); + diff --git a/internal/endtoend/testdata/select_not_exists/sqlite/sqlc.json b/internal/endtoend/testdata/select_not_exists/sqlite/sqlc.json new file mode 100644 index 0000000..9655954 --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "engine": "sqlite", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_not_exists/stdlib/go/db.go b/internal/endtoend/testdata/select_not_exists/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_not_exists/stdlib/go/models.go b/internal/endtoend/testdata/select_not_exists/stdlib/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/select_not_exists/stdlib/go/query.sql.go b/internal/endtoend/testdata/select_not_exists/stdlib/go/query.sql.go new file mode 100644 index 0000000..abb293a --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/stdlib/go/query.sql.go @@ -0,0 +1,29 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const barNotExists = `-- name: BarNotExists :one +SELECT + NOT EXISTS ( + SELECT + 1 + FROM + bar + where + id = $1 + ) +` + +func (q *Queries) BarNotExists(ctx context.Context, id int32) (bool, error) { + row := q.db.QueryRowContext(ctx, barNotExists, id) + var not_exists bool + err := row.Scan(¬_exists) + return not_exists, err +} diff --git a/internal/endtoend/testdata/select_not_exists/stdlib/query.sql b/internal/endtoend/testdata/select_not_exists/stdlib/query.sql new file mode 100644 index 0000000..f32ee62 --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/stdlib/query.sql @@ -0,0 +1,10 @@ +-- name: BarNotExists :one +SELECT + NOT EXISTS ( + SELECT + 1 + FROM + bar + where + id = $1 + ); diff --git a/internal/endtoend/testdata/select_not_exists/stdlib/schema.sql b/internal/endtoend/testdata/select_not_exists/stdlib/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/select_not_exists/stdlib/sqlc.json b/internal/endtoend/testdata/select_not_exists/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/select_not_exists/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_sequence/issue.md b/internal/endtoend/testdata/select_sequence/issue.md new file mode 100644 index 0000000..38c550f --- /dev/null +++ b/internal/endtoend/testdata/select_sequence/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1634 diff --git a/internal/endtoend/testdata/select_sequence/postgresql/pgx/exec.json b/internal/endtoend/testdata/select_sequence/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/select_sequence/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/select_sequence/postgresql/pgx/go/db.go b/internal/endtoend/testdata/select_sequence/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/select_sequence/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/select_sequence/postgresql/pgx/go/models.go b/internal/endtoend/testdata/select_sequence/postgresql/pgx/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/select_sequence/postgresql/pgx/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/select_sequence/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/select_sequence/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..54c86df --- /dev/null +++ b/internal/endtoend/testdata/select_sequence/postgresql/pgx/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getLastValue = `-- name: GetLastValue :one +SELECT last_value FROM my_sequence +` + +func (q *Queries) GetLastValue(ctx context.Context) (int64, error) { + row := q.db.QueryRow(ctx, getLastValue) + var last_value int64 + err := row.Scan(&last_value) + return last_value, err +} diff --git a/internal/endtoend/testdata/select_sequence/postgresql/pgx/query.sql b/internal/endtoend/testdata/select_sequence/postgresql/pgx/query.sql new file mode 100644 index 0000000..82cc9b0 --- /dev/null +++ b/internal/endtoend/testdata/select_sequence/postgresql/pgx/query.sql @@ -0,0 +1,2 @@ +-- name: GetLastValue :one +SELECT last_value FROM my_sequence; diff --git a/internal/endtoend/testdata/select_sequence/postgresql/pgx/schema.sql b/internal/endtoend/testdata/select_sequence/postgresql/pgx/schema.sql new file mode 100644 index 0000000..94a6932 --- /dev/null +++ b/internal/endtoend/testdata/select_sequence/postgresql/pgx/schema.sql @@ -0,0 +1,6 @@ +CREATE SEQUENCE public.my_sequence + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; diff --git a/internal/endtoend/testdata/select_sequence/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/select_sequence/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/select_sequence/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/select_star/mysql/go/db.go b/internal/endtoend/testdata/select_star/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_star/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_star/mysql/go/models.go b/internal/endtoend/testdata/select_star/mysql/go/models.go new file mode 100644 index 0000000..643ee29 --- /dev/null +++ b/internal/endtoend/testdata/select_star/mysql/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID int32 + FirstName string + LastName sql.NullString + Age int32 +} diff --git a/internal/endtoend/testdata/select_star/mysql/go/query.sql.go b/internal/endtoend/testdata/select_star/mysql/go/query.sql.go new file mode 100644 index 0000000..bf9df75 --- /dev/null +++ b/internal/endtoend/testdata/select_star/mysql/go/query.sql.go @@ -0,0 +1,69 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]User, error) { + rows, err := q.db.QueryContext(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + ); 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 getIDAll = `-- name: GetIDAll :many +SELECT id FROM (SELECT id FROM users) t +` + +func (q *Queries) GetIDAll(ctx context.Context) ([]int32, error) { + rows, err := q.db.QueryContext(ctx, getIDAll) + 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 +} diff --git a/internal/endtoend/testdata/select_star/mysql/query.sql b/internal/endtoend/testdata/select_star/mysql/query.sql new file mode 100644 index 0000000..4c23062 --- /dev/null +++ b/internal/endtoend/testdata/select_star/mysql/query.sql @@ -0,0 +1,5 @@ +/* name: GetAll :many */ +SELECT * FROM users; + +/* name: GetIDAll :many */ +SELECT * FROM (SELECT id FROM users) t; diff --git a/internal/endtoend/testdata/select_star/mysql/schema.sql b/internal/endtoend/testdata/select_star/mysql/schema.sql new file mode 100644 index 0000000..00fb1b5 --- /dev/null +++ b/internal/endtoend/testdata/select_star/mysql/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + id integer NOT NULL AUTO_INCREMENT PRIMARY KEY, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL +) ENGINE=InnoDB; diff --git a/internal/endtoend/testdata/select_star/mysql/sqlc.json b/internal/endtoend/testdata/select_star/mysql/sqlc.json new file mode 100644 index 0000000..a9e7b05 --- /dev/null +++ b/internal/endtoend/testdata/select_star/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "schema.sql", + "queries": "query.sql", + "engine": "mysql" + } + ] +} diff --git a/internal/endtoend/testdata/select_star/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/select_star/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/select_star/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/select_star/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/select_star/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..643ee29 --- /dev/null +++ b/internal/endtoend/testdata/select_star/postgresql/pgx/v4/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID int32 + FirstName string + LastName sql.NullString + Age int32 +} diff --git a/internal/endtoend/testdata/select_star/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/select_star/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..5709c64 --- /dev/null +++ b/internal/endtoend/testdata/select_star/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,63 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]User, error) { + rows, err := q.db.Query(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getIDAll = `-- name: GetIDAll :many +SELECT id FROM (SELECT id FROM users) t +` + +func (q *Queries) GetIDAll(ctx context.Context) ([]int32, error) { + rows, err := q.db.Query(ctx, getIDAll) + 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 +} diff --git a/internal/endtoend/testdata/select_star/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/select_star/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..0952880 --- /dev/null +++ b/internal/endtoend/testdata/select_star/postgresql/pgx/v4/query.sql @@ -0,0 +1,5 @@ +-- name: GetAll :many +SELECT * FROM users; + +/* name: GetIDAll :many */ +SELECT * FROM (SELECT id FROM users) t; \ No newline at end of file diff --git a/internal/endtoend/testdata/select_star/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/select_star/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..0fe1b79 --- /dev/null +++ b/internal/endtoend/testdata/select_star/postgresql/pgx/v4/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + id integer NOT NULL PRIMARY KEY, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL +); diff --git a/internal/endtoend/testdata/select_star/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/select_star/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/select_star/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_star/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/select_star/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/select_star/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/select_star/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/select_star/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..116ee8f --- /dev/null +++ b/internal/endtoend/testdata/select_star/postgresql/pgx/v5/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type User struct { + ID int32 + FirstName string + LastName pgtype.Text + Age int32 +} diff --git a/internal/endtoend/testdata/select_star/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/select_star/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..5709c64 --- /dev/null +++ b/internal/endtoend/testdata/select_star/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,63 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]User, error) { + rows, err := q.db.Query(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getIDAll = `-- name: GetIDAll :many +SELECT id FROM (SELECT id FROM users) t +` + +func (q *Queries) GetIDAll(ctx context.Context) ([]int32, error) { + rows, err := q.db.Query(ctx, getIDAll) + 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 +} diff --git a/internal/endtoend/testdata/select_star/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/select_star/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..0952880 --- /dev/null +++ b/internal/endtoend/testdata/select_star/postgresql/pgx/v5/query.sql @@ -0,0 +1,5 @@ +-- name: GetAll :many +SELECT * FROM users; + +/* name: GetIDAll :many */ +SELECT * FROM (SELECT id FROM users) t; \ No newline at end of file diff --git a/internal/endtoend/testdata/select_star/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/select_star/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..0fe1b79 --- /dev/null +++ b/internal/endtoend/testdata/select_star/postgresql/pgx/v5/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + id integer NOT NULL PRIMARY KEY, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL +); diff --git a/internal/endtoend/testdata/select_star/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/select_star/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/select_star/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_star/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/select_star/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_star/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_star/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/select_star/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..643ee29 --- /dev/null +++ b/internal/endtoend/testdata/select_star/postgresql/stdlib/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID int32 + FirstName string + LastName sql.NullString + Age int32 +} diff --git a/internal/endtoend/testdata/select_star/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/select_star/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..bf9df75 --- /dev/null +++ b/internal/endtoend/testdata/select_star/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,69 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]User, error) { + rows, err := q.db.QueryContext(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + ); 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 getIDAll = `-- name: GetIDAll :many +SELECT id FROM (SELECT id FROM users) t +` + +func (q *Queries) GetIDAll(ctx context.Context) ([]int32, error) { + rows, err := q.db.QueryContext(ctx, getIDAll) + 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 +} diff --git a/internal/endtoend/testdata/select_star/postgresql/stdlib/query.sql b/internal/endtoend/testdata/select_star/postgresql/stdlib/query.sql new file mode 100644 index 0000000..0952880 --- /dev/null +++ b/internal/endtoend/testdata/select_star/postgresql/stdlib/query.sql @@ -0,0 +1,5 @@ +-- name: GetAll :many +SELECT * FROM users; + +/* name: GetIDAll :many */ +SELECT * FROM (SELECT id FROM users) t; \ No newline at end of file diff --git a/internal/endtoend/testdata/select_star/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/select_star/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..0fe1b79 --- /dev/null +++ b/internal/endtoend/testdata/select_star/postgresql/stdlib/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + id integer NOT NULL PRIMARY KEY, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL +); diff --git a/internal/endtoend/testdata/select_star/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/select_star/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/select_star/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_star/sqlite/go/db.go b/internal/endtoend/testdata/select_star/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_star/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_star/sqlite/go/models.go b/internal/endtoend/testdata/select_star/sqlite/go/models.go new file mode 100644 index 0000000..deb1559 --- /dev/null +++ b/internal/endtoend/testdata/select_star/sqlite/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + ID int64 + FirstName string + LastName sql.NullString + Age int64 +} diff --git a/internal/endtoend/testdata/select_star/sqlite/go/query.sql.go b/internal/endtoend/testdata/select_star/sqlite/go/query.sql.go new file mode 100644 index 0000000..e9e6c25 --- /dev/null +++ b/internal/endtoend/testdata/select_star/sqlite/go/query.sql.go @@ -0,0 +1,69 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAll = `-- name: GetAll :many +SELECT id, first_name, last_name, age FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]User, error) { + rows, err := q.db.QueryContext(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []User + for rows.Next() { + var i User + if err := rows.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.Age, + ); 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 getIDAll = `-- name: GetIDAll :many +SELECT id FROM (SELECT id FROM users) AS t +` + +func (q *Queries) GetIDAll(ctx context.Context) ([]int64, error) { + rows, err := q.db.QueryContext(ctx, getIDAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var id int64 + 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 +} diff --git a/internal/endtoend/testdata/select_star/sqlite/query.sql b/internal/endtoend/testdata/select_star/sqlite/query.sql new file mode 100644 index 0000000..ba7ed34 --- /dev/null +++ b/internal/endtoend/testdata/select_star/sqlite/query.sql @@ -0,0 +1,5 @@ +-- name: GetAll :many +SELECT * FROM users; + +/* name: GetIDAll :many */ +SELECT * FROM (SELECT id FROM users) AS t; diff --git a/internal/endtoend/testdata/select_star/sqlite/schema.sql b/internal/endtoend/testdata/select_star/sqlite/schema.sql new file mode 100644 index 0000000..0fe1b79 --- /dev/null +++ b/internal/endtoend/testdata/select_star/sqlite/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE users ( + id integer NOT NULL PRIMARY KEY, + first_name varchar(255) NOT NULL, + last_name varchar(255), + age integer NOT NULL +); diff --git a/internal/endtoend/testdata/select_star/sqlite/sqlc.json b/internal/endtoend/testdata/select_star/sqlite/sqlc.json new file mode 100644 index 0000000..55a79aa --- /dev/null +++ b/internal/endtoend/testdata/select_star/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "schema.sql", + "queries": "query.sql", + "engine": "sqlite" + } + ] +} diff --git a/internal/endtoend/testdata/select_star_quoted/mysql/go/db.go b/internal/endtoend/testdata/select_star_quoted/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_star_quoted/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_star_quoted/mysql/go/models.go b/internal/endtoend/testdata/select_star_quoted/mysql/go/models.go new file mode 100644 index 0000000..6e82f4a --- /dev/null +++ b/internal/endtoend/testdata/select_star_quoted/mysql/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + Camelcase sql.NullString +} diff --git a/internal/endtoend/testdata/select_star_quoted/mysql/go/query.sql.go b/internal/endtoend/testdata/select_star_quoted/mysql/go/query.sql.go new file mode 100644 index 0000000..e59023c --- /dev/null +++ b/internal/endtoend/testdata/select_star_quoted/mysql/go/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const getAll = `-- name: GetAll :many +SELECT camelcase FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var camelcase sql.NullString + if err := rows.Scan(&camelcase); err != nil { + return nil, err + } + items = append(items, camelcase) + } + 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_star_quoted/mysql/query.sql b/internal/endtoend/testdata/select_star_quoted/mysql/query.sql new file mode 100644 index 0000000..e2f85e2 --- /dev/null +++ b/internal/endtoend/testdata/select_star_quoted/mysql/query.sql @@ -0,0 +1,2 @@ +/* name: GetAll :many */ +SELECT * FROM users; diff --git a/internal/endtoend/testdata/select_star_quoted/mysql/schema.sql b/internal/endtoend/testdata/select_star_quoted/mysql/schema.sql new file mode 100644 index 0000000..8adc3dd --- /dev/null +++ b/internal/endtoend/testdata/select_star_quoted/mysql/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE users ( + `CamelCase` varchar(255) +) ENGINE=InnoDB; diff --git a/internal/endtoend/testdata/select_star_quoted/mysql/sqlc.json b/internal/endtoend/testdata/select_star_quoted/mysql/sqlc.json new file mode 100644 index 0000000..a9e7b05 --- /dev/null +++ b/internal/endtoend/testdata/select_star_quoted/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "schema.sql", + "queries": "query.sql", + "engine": "mysql" + } + ] +} diff --git a/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/select_star_quoted/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..dd9a57d --- /dev/null +++ b/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v4/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + CamelCase sql.NullString +} diff --git a/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..9bf2782 --- /dev/null +++ b/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,35 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const getAll = `-- name: GetAll :many +SELECT "CamelCase" FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]sql.NullString, error) { + rows, err := q.db.Query(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var CamelCase sql.NullString + if err := rows.Scan(&CamelCase); err != nil { + return nil, err + } + items = append(items, CamelCase) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..237b201 --- /dev/null +++ b/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: GetAll :many +SELECT * FROM users; diff --git a/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..d701c41 --- /dev/null +++ b/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE users ( + "CamelCase" varchar(255) +); diff --git a/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/select_star_quoted/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..72efcd6 --- /dev/null +++ b/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v5/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type User struct { + CamelCase pgtype.Text +} diff --git a/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..ad7e060 --- /dev/null +++ b/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,36 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const getAll = `-- name: GetAll :many +SELECT "CamelCase" FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]pgtype.Text, error) { + rows, err := q.db.Query(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []pgtype.Text + for rows.Next() { + var CamelCase pgtype.Text + if err := rows.Scan(&CamelCase); err != nil { + return nil, err + } + items = append(items, CamelCase) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..237b201 --- /dev/null +++ b/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: GetAll :many +SELECT * FROM users; diff --git a/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..d701c41 --- /dev/null +++ b/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE users ( + "CamelCase" varchar(255) +); diff --git a/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/select_star_quoted/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_star_quoted/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/select_star_quoted/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_star_quoted/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_star_quoted/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/select_star_quoted/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..dd9a57d --- /dev/null +++ b/internal/endtoend/testdata/select_star_quoted/postgresql/stdlib/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type User struct { + CamelCase sql.NullString +} diff --git a/internal/endtoend/testdata/select_star_quoted/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/select_star_quoted/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..d78319b --- /dev/null +++ b/internal/endtoend/testdata/select_star_quoted/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const getAll = `-- name: GetAll :many +SELECT "CamelCase" FROM users +` + +func (q *Queries) GetAll(ctx context.Context) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, getAll) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var CamelCase sql.NullString + if err := rows.Scan(&CamelCase); err != nil { + return nil, err + } + items = append(items, CamelCase) + } + 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_star_quoted/postgresql/stdlib/query.sql b/internal/endtoend/testdata/select_star_quoted/postgresql/stdlib/query.sql new file mode 100644 index 0000000..237b201 --- /dev/null +++ b/internal/endtoend/testdata/select_star_quoted/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: GetAll :many +SELECT * FROM users; diff --git a/internal/endtoend/testdata/select_star_quoted/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/select_star_quoted/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..d701c41 --- /dev/null +++ b/internal/endtoend/testdata/select_star_quoted/postgresql/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE users ( + "CamelCase" varchar(255) +); diff --git a/internal/endtoend/testdata/select_star_quoted/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/select_star_quoted/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/select_star_quoted/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_subquery/postgresql/issue.md b/internal/endtoend/testdata/select_subquery/postgresql/issue.md new file mode 100644 index 0000000..fa59b3a --- /dev/null +++ b/internal/endtoend/testdata/select_subquery/postgresql/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/pull/2639 diff --git a/internal/endtoend/testdata/select_subquery/postgresql/stdlib/exec.json b/internal/endtoend/testdata/select_subquery/postgresql/stdlib/exec.json new file mode 100644 index 0000000..e5dfda7 --- /dev/null +++ b/internal/endtoend/testdata/select_subquery/postgresql/stdlib/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/select_subquery/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/select_subquery/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_subquery/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_subquery/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/select_subquery/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..96bb6df --- /dev/null +++ b/internal/endtoend/testdata/select_subquery/postgresql/stdlib/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + A int32 + Alias sql.NullString +} + +type Foo struct { + A int32 + Name sql.NullString +} diff --git a/internal/endtoend/testdata/select_subquery/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/select_subquery/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..9dda476 --- /dev/null +++ b/internal/endtoend/testdata/select_subquery/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,53 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const subquery = `-- name: Subquery :many +SELECT + a, + name, + (SELECT alias FROM bar WHERE bar.a=foo.a AND alias = $1 ORDER BY bar.a DESC limit 1) as alias +FROM FOO WHERE a = $2 +` + +type SubqueryParams struct { + Column1 sql.NullString + Column2 sql.NullInt32 +} + +type SubqueryRow struct { + A int32 + Name sql.NullString + Alias sql.NullString +} + +func (q *Queries) Subquery(ctx context.Context, arg SubqueryParams) ([]SubqueryRow, error) { + rows, err := q.db.QueryContext(ctx, subquery, arg.Column1, arg.Column2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []SubqueryRow + for rows.Next() { + var i SubqueryRow + if err := rows.Scan(&i.A, &i.Name, &i.Alias); 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_subquery/postgresql/stdlib/query.sql b/internal/endtoend/testdata/select_subquery/postgresql/stdlib/query.sql new file mode 100644 index 0000000..3d9b058 --- /dev/null +++ b/internal/endtoend/testdata/select_subquery/postgresql/stdlib/query.sql @@ -0,0 +1,6 @@ +-- name: Subquery :many +SELECT + a, + name, + (SELECT alias FROM bar WHERE bar.a=foo.a AND alias = $1 ORDER BY bar.a DESC limit 1) as alias +FROM FOO WHERE a = $2; diff --git a/internal/endtoend/testdata/select_subquery/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/select_subquery/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..b256bf6 --- /dev/null +++ b/internal/endtoend/testdata/select_subquery/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a int not null, name text); +CREATE TABLE bar (a int not null, alias text); diff --git a/internal/endtoend/testdata/select_subquery/postgresql/stdlib/sqlc.yaml b/internal/endtoend/testdata/select_subquery/postgresql/stdlib/sqlc.yaml new file mode 100644 index 0000000..8c68222 --- /dev/null +++ b/internal/endtoend/testdata/select_subquery/postgresql/stdlib/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "database/sql" diff --git a/internal/endtoend/testdata/select_subquery_alias/issue.md b/internal/endtoend/testdata/select_subquery_alias/issue.md new file mode 100644 index 0000000..1f15e67 --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_alias/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1990 diff --git a/internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/exec.json b/internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/go/db.go b/internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/select_subquery_alias/postgresql/pgx/go/models.go b/internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/go/models.go new file mode 100644 index 0000000..2cbaed2 --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Wallet struct { + ID int64 + Address string + Type string + Balance pgtype.Numeric +} diff --git a/internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..e35db53 --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/go/query.sql.go @@ -0,0 +1,61 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const findWallets = `-- name: FindWallets :many +select id, address, balance, total_balance from +( + select id, address, balance, + sum(balance) over (order by balance desc rows between unbounded preceding and current row) as total_balance, + sum(balance) over (order by balance desc rows between unbounded preceding and current row) - balance as last_balance + from wallets + where type=$1 +) amounts +where amounts.last_balance < $2 +` + +type FindWalletsParams struct { + Column1 pgtype.Text + Column2 pgtype.Numeric +} + +type FindWalletsRow struct { + ID int64 + Address string + Balance pgtype.Numeric + TotalBalance pgtype.Numeric +} + +func (q *Queries) FindWallets(ctx context.Context, arg FindWalletsParams) ([]FindWalletsRow, error) { + rows, err := q.db.Query(ctx, findWallets, arg.Column1, arg.Column2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []FindWalletsRow + for rows.Next() { + var i FindWalletsRow + if err := rows.Scan( + &i.ID, + &i.Address, + &i.Balance, + &i.TotalBalance, + ); 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_subquery_alias/postgresql/pgx/query.sql b/internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/query.sql new file mode 100644 index 0000000..b341223 --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/query.sql @@ -0,0 +1,10 @@ +-- name: FindWallets :many +select id, address, balance, total_balance from +( + select id, address, balance, + sum(balance) over (order by balance desc rows between unbounded preceding and current row) as total_balance, + sum(balance) over (order by balance desc rows between unbounded preceding and current row) - balance as last_balance + from wallets + where type=$1 +) amounts +where amounts.last_balance < $2; diff --git a/internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/schema.sql b/internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/schema.sql new file mode 100644 index 0000000..275a65e --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE IF NOT EXISTS wallets +( + id BIGSERIAL PRIMARY KEY, + address VARCHAR(44) NOT NULL, + type VARCHAR(44) NOT NULL, + balance DECIMAL(32, 18) NULL +); diff --git a/internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_alias/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/select_subquery_no_alias/mysql/go/db.go b/internal/endtoend/testdata/select_subquery_no_alias/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_no_alias/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_subquery_no_alias/mysql/go/models.go b/internal/endtoend/testdata/select_subquery_no_alias/mysql/go/models.go new file mode 100644 index 0000000..f9c03a5 --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_no_alias/mysql/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A int32 + Name sql.NullString +} diff --git a/internal/endtoend/testdata/select_subquery_no_alias/mysql/go/query.sql.go b/internal/endtoend/testdata/select_subquery_no_alias/mysql/go/query.sql.go new file mode 100644 index 0000000..34bfb57 --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_no_alias/mysql/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const subquery = `-- name: Subquery :many +SELECT a, name FROM (SELECT a, name FROM foo) +` + +func (q *Queries) Subquery(ctx context.Context) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, subquery) + 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.Name); 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_subquery_no_alias/mysql/query.sql b/internal/endtoend/testdata/select_subquery_no_alias/mysql/query.sql new file mode 100644 index 0000000..87477e3 --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_no_alias/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: Subquery :many +SELECT * FROM (SELECT * FROM foo); diff --git a/internal/endtoend/testdata/select_subquery_no_alias/mysql/schema.sql b/internal/endtoend/testdata/select_subquery_no_alias/mysql/schema.sql new file mode 100644 index 0000000..3d06ae0 --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_no_alias/mysql/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (a int not null, name text); diff --git a/internal/endtoend/testdata/select_subquery_no_alias/mysql/sqlc.yaml b/internal/endtoend/testdata/select_subquery_no_alias/mysql/sqlc.yaml new file mode 100644 index 0000000..b843ef5 --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_no_alias/mysql/sqlc.yaml @@ -0,0 +1,9 @@ +version: "2" +sql: + - engine: "mysql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" diff --git a/internal/endtoend/testdata/select_subquery_no_alias/postgres/stdlib/go/db.go b/internal/endtoend/testdata/select_subquery_no_alias/postgres/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_no_alias/postgres/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_subquery_no_alias/postgres/stdlib/go/models.go b/internal/endtoend/testdata/select_subquery_no_alias/postgres/stdlib/go/models.go new file mode 100644 index 0000000..f9c03a5 --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_no_alias/postgres/stdlib/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A int32 + Name sql.NullString +} diff --git a/internal/endtoend/testdata/select_subquery_no_alias/postgres/stdlib/go/query.sql.go b/internal/endtoend/testdata/select_subquery_no_alias/postgres/stdlib/go/query.sql.go new file mode 100644 index 0000000..34bfb57 --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_no_alias/postgres/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const subquery = `-- name: Subquery :many +SELECT a, name FROM (SELECT a, name FROM foo) +` + +func (q *Queries) Subquery(ctx context.Context) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, subquery) + 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.Name); 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_subquery_no_alias/postgres/stdlib/query.sql b/internal/endtoend/testdata/select_subquery_no_alias/postgres/stdlib/query.sql new file mode 100644 index 0000000..87477e3 --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_no_alias/postgres/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Subquery :many +SELECT * FROM (SELECT * FROM foo); diff --git a/internal/endtoend/testdata/select_subquery_no_alias/postgres/stdlib/schema.sql b/internal/endtoend/testdata/select_subquery_no_alias/postgres/stdlib/schema.sql new file mode 100644 index 0000000..3d06ae0 --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_no_alias/postgres/stdlib/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (a int not null, name text); diff --git a/internal/endtoend/testdata/select_subquery_no_alias/postgres/stdlib/sqlc.yaml b/internal/endtoend/testdata/select_subquery_no_alias/postgres/stdlib/sqlc.yaml new file mode 100644 index 0000000..8c68222 --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_no_alias/postgres/stdlib/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "database/sql" diff --git a/internal/endtoend/testdata/select_subquery_no_alias/sqlite/go/db.go b/internal/endtoend/testdata/select_subquery_no_alias/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_no_alias/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_subquery_no_alias/sqlite/go/models.go b/internal/endtoend/testdata/select_subquery_no_alias/sqlite/go/models.go new file mode 100644 index 0000000..9aba85a --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_no_alias/sqlite/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A int64 + Name sql.NullString +} diff --git a/internal/endtoend/testdata/select_subquery_no_alias/sqlite/go/query.sql.go b/internal/endtoend/testdata/select_subquery_no_alias/sqlite/go/query.sql.go new file mode 100644 index 0000000..34bfb57 --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_no_alias/sqlite/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const subquery = `-- name: Subquery :many +SELECT a, name FROM (SELECT a, name FROM foo) +` + +func (q *Queries) Subquery(ctx context.Context) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, subquery) + 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.Name); 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_subquery_no_alias/sqlite/query.sql b/internal/endtoend/testdata/select_subquery_no_alias/sqlite/query.sql new file mode 100644 index 0000000..87477e3 --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_no_alias/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: Subquery :many +SELECT * FROM (SELECT * FROM foo); diff --git a/internal/endtoend/testdata/select_subquery_no_alias/sqlite/schema.sql b/internal/endtoend/testdata/select_subquery_no_alias/sqlite/schema.sql new file mode 100644 index 0000000..3d06ae0 --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_no_alias/sqlite/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (a int not null, name text); diff --git a/internal/endtoend/testdata/select_subquery_no_alias/sqlite/sqlc.yaml b/internal/endtoend/testdata/select_subquery_no_alias/sqlite/sqlc.yaml new file mode 100644 index 0000000..bd74199 --- /dev/null +++ b/internal/endtoend/testdata/select_subquery_no_alias/sqlite/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "sqlite" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "database/sql" diff --git a/internal/endtoend/testdata/select_system/issue.md b/internal/endtoend/testdata/select_system/issue.md new file mode 100644 index 0000000..7e53607 --- /dev/null +++ b/internal/endtoend/testdata/select_system/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1745 diff --git a/internal/endtoend/testdata/select_system/pgx/exec.json b/internal/endtoend/testdata/select_system/pgx/exec.json new file mode 100644 index 0000000..e5dfda7 --- /dev/null +++ b/internal/endtoend/testdata/select_system/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/select_system/pgx/go/db.go b/internal/endtoend/testdata/select_system/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/select_system/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/select_system/pgx/go/models.go b/internal/endtoend/testdata/select_system/pgx/go/models.go new file mode 100644 index 0000000..c6fcc44 --- /dev/null +++ b/internal/endtoend/testdata/select_system/pgx/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Test struct { + ID pgtype.Int4 +} diff --git a/internal/endtoend/testdata/select_system/pgx/go/query.sql.go b/internal/endtoend/testdata/select_system/pgx/go/query.sql.go new file mode 100644 index 0000000..f35c7f5 --- /dev/null +++ b/internal/endtoend/testdata/select_system/pgx/go/query.sql.go @@ -0,0 +1,41 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const getSystemColumns = `-- name: GetSystemColumns :one +SELECT + tableoid, xmin, cmin, xmax, cmax, ctid +FROM test +` + +type GetSystemColumnsRow struct { + Tableoid pgtype.Uint32 + Xmin pgtype.Uint32 + Cmin pgtype.Uint32 + Xmax pgtype.Uint32 + Cmax pgtype.Uint32 + Ctid pgtype.TID +} + +func (q *Queries) GetSystemColumns(ctx context.Context) (GetSystemColumnsRow, error) { + row := q.db.QueryRow(ctx, getSystemColumns) + var i GetSystemColumnsRow + err := row.Scan( + &i.Tableoid, + &i.Xmin, + &i.Cmin, + &i.Xmax, + &i.Cmax, + &i.Ctid, + ) + return i, err +} diff --git a/internal/endtoend/testdata/select_system/pgx/query.sql b/internal/endtoend/testdata/select_system/pgx/query.sql new file mode 100644 index 0000000..11ddeb7 --- /dev/null +++ b/internal/endtoend/testdata/select_system/pgx/query.sql @@ -0,0 +1,4 @@ +-- name: GetSystemColumns :one +SELECT + tableoid, xmin, cmin, xmax, cmax, ctid +FROM test; diff --git a/internal/endtoend/testdata/select_system/pgx/schema.sql b/internal/endtoend/testdata/select_system/pgx/schema.sql new file mode 100644 index 0000000..7518997 --- /dev/null +++ b/internal/endtoend/testdata/select_system/pgx/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE test ( + id INT +); diff --git a/internal/endtoend/testdata/select_system/pgx/sqlc.yaml b/internal/endtoend/testdata/select_system/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/select_system/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/select_text_array/pgx/v4/go/db.go b/internal/endtoend/testdata/select_text_array/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/select_text_array/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/select_text_array/pgx/v4/go/models.go b/internal/endtoend/testdata/select_text_array/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/select_text_array/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/select_text_array/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/select_text_array/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..6cde5ae --- /dev/null +++ b/internal/endtoend/testdata/select_text_array/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const selectTextArray = `-- name: SelectTextArray :many +SELECT $1::TEXT[] +` + +func (q *Queries) SelectTextArray(ctx context.Context, dollar_1 []string) ([][]string, error) { + rows, err := q.db.Query(ctx, selectTextArray, dollar_1) + if err != nil { + return nil, err + } + defer rows.Close() + var items [][]string + for rows.Next() { + var column_1 []string + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/select_text_array/pgx/v4/query.sql b/internal/endtoend/testdata/select_text_array/pgx/v4/query.sql new file mode 100644 index 0000000..2bf44b9 --- /dev/null +++ b/internal/endtoend/testdata/select_text_array/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: SelectTextArray :many +SELECT $1::TEXT[]; diff --git a/internal/endtoend/testdata/select_text_array/pgx/v4/schema.sql b/internal/endtoend/testdata/select_text_array/pgx/v4/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/select_text_array/pgx/v4/sqlc.json b/internal/endtoend/testdata/select_text_array/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/select_text_array/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_text_array/pgx/v5/go/db.go b/internal/endtoend/testdata/select_text_array/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/select_text_array/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/select_text_array/pgx/v5/go/models.go b/internal/endtoend/testdata/select_text_array/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/select_text_array/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/select_text_array/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/select_text_array/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..6cde5ae --- /dev/null +++ b/internal/endtoend/testdata/select_text_array/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const selectTextArray = `-- name: SelectTextArray :many +SELECT $1::TEXT[] +` + +func (q *Queries) SelectTextArray(ctx context.Context, dollar_1 []string) ([][]string, error) { + rows, err := q.db.Query(ctx, selectTextArray, dollar_1) + if err != nil { + return nil, err + } + defer rows.Close() + var items [][]string + for rows.Next() { + var column_1 []string + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/select_text_array/pgx/v5/query.sql b/internal/endtoend/testdata/select_text_array/pgx/v5/query.sql new file mode 100644 index 0000000..2bf44b9 --- /dev/null +++ b/internal/endtoend/testdata/select_text_array/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: SelectTextArray :many +SELECT $1::TEXT[]; diff --git a/internal/endtoend/testdata/select_text_array/pgx/v5/schema.sql b/internal/endtoend/testdata/select_text_array/pgx/v5/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/select_text_array/pgx/v5/sqlc.json b/internal/endtoend/testdata/select_text_array/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/select_text_array/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_text_array/stdlib/go/db.go b/internal/endtoend/testdata/select_text_array/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_text_array/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_text_array/stdlib/go/models.go b/internal/endtoend/testdata/select_text_array/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/select_text_array/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/select_text_array/stdlib/go/query.sql.go b/internal/endtoend/testdata/select_text_array/stdlib/go/query.sql.go new file mode 100644 index 0000000..5ce044c --- /dev/null +++ b/internal/endtoend/testdata/select_text_array/stdlib/go/query.sql.go @@ -0,0 +1,39 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/lib/pq" +) + +const selectTextArray = `-- name: SelectTextArray :many +SELECT $1::TEXT[] +` + +func (q *Queries) SelectTextArray(ctx context.Context, dollar_1 []string) ([][]string, error) { + rows, err := q.db.QueryContext(ctx, selectTextArray, pq.Array(dollar_1)) + if err != nil { + return nil, err + } + defer rows.Close() + var items [][]string + for rows.Next() { + var column_1 []string + if err := rows.Scan(pq.Array(&column_1)); err != nil { + return nil, err + } + items = append(items, column_1) + } + 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_text_array/stdlib/query.sql b/internal/endtoend/testdata/select_text_array/stdlib/query.sql new file mode 100644 index 0000000..2bf44b9 --- /dev/null +++ b/internal/endtoend/testdata/select_text_array/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: SelectTextArray :many +SELECT $1::TEXT[]; diff --git a/internal/endtoend/testdata/select_text_array/stdlib/schema.sql b/internal/endtoend/testdata/select_text_array/stdlib/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/select_text_array/stdlib/sqlc.json b/internal/endtoend/testdata/select_text_array/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/select_text_array/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_union/mysql/go/db.go b/internal/endtoend/testdata/select_union/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_union/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/mysql/go/models.go b/internal/endtoend/testdata/select_union/mysql/go/models.go new file mode 100644 index 0000000..a3b9f9c --- /dev/null +++ b/internal/endtoend/testdata/select_union/mysql/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +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/mysql/go/query.sql.go b/internal/endtoend/testdata/select_union/mysql/go/query.sql.go new file mode 100644 index 0000000..5d5560a --- /dev/null +++ b/internal/endtoend/testdata/select_union/mysql/go/query.sql.go @@ -0,0 +1,190 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// 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 selectUnionAliased = `-- name: SelectUnionAliased :many +(SELECT a, b FROM foo) +UNION +SELECT a, b FROM bar +` + +func (q *Queries) SelectUnionAliased(ctx context.Context) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, selectUnionAliased) + 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 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 new file mode 100644 index 0000000..c706921 --- /dev/null +++ b/internal/endtoend/testdata/select_union/mysql/query.sql @@ -0,0 +1,30 @@ +-- 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; + +-- name: SelectUnionAliased :many +(SELECT * FROM foo) +UNION +SELECT * FROM bar; diff --git a/internal/endtoend/testdata/select_union/mysql/schema.sql b/internal/endtoend/testdata/select_union/mysql/schema.sql new file mode 100644 index 0000000..47a0314 --- /dev/null +++ b/internal/endtoend/testdata/select_union/mysql/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (a text, b text); +CREATE TABLE bar (a text, b text); + diff --git a/internal/endtoend/testdata/select_union/mysql/sqlc.json b/internal/endtoend/testdata/select_union/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/select_union/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_union/postgres/pgx/v4/exec.json b/internal/endtoend/testdata/select_union/postgres/pgx/v4/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/select_union/postgres/pgx/v4/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/select_union/postgres/pgx/v4/go/db.go b/internal/endtoend/testdata/select_union/postgres/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/select_union/postgres/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/select_union/postgres/pgx/v4/go/models.go b/internal/endtoend/testdata/select_union/postgres/pgx/v4/go/models.go new file mode 100644 index 0000000..a3b9f9c --- /dev/null +++ b/internal/endtoend/testdata/select_union/postgres/pgx/v4/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +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/postgres/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/select_union/postgres/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..d7e818b --- /dev/null +++ b/internal/endtoend/testdata/select_union/postgres/pgx/v4/go/query.sql.go @@ -0,0 +1,172 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// 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.Query(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.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.Query(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.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.Query(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.Err(); err != nil { + return nil, err + } + return items, nil +} + +const selectUnionAliased = `-- name: SelectUnionAliased :many +(SELECT a, b FROM foo) +UNION +SELECT a, b FROM foo +` + +func (q *Queries) SelectUnionAliased(ctx context.Context) ([]Foo, error) { + rows, err := q.db.Query(ctx, selectUnionAliased) + 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 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 new file mode 100644 index 0000000..f44f1fd --- /dev/null +++ b/internal/endtoend/testdata/select_union/postgres/pgx/v4/query.sql @@ -0,0 +1,30 @@ +-- 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 +SELECT * FROM foo; + +-- name: SelectIntersect :many +SELECT * FROM foo +INTERSECT +SELECT * FROM foo; + +-- name: SelectUnionOther :many +SELECT * FROM foo +UNION +SELECT * FROM bar; + +-- name: SelectUnionAliased :many +(SELECT * FROM foo) +UNION +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/select_union/postgres/pgx/v4/schema.sql b/internal/endtoend/testdata/select_union/postgres/pgx/v4/schema.sql new file mode 100644 index 0000000..47a0314 --- /dev/null +++ b/internal/endtoend/testdata/select_union/postgres/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (a text, b text); +CREATE TABLE bar (a text, b text); + diff --git a/internal/endtoend/testdata/select_union/postgres/pgx/v4/sqlc.json b/internal/endtoend/testdata/select_union/postgres/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/select_union/postgres/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_union/postgres/pgx/v5/exec.json b/internal/endtoend/testdata/select_union/postgres/pgx/v5/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/select_union/postgres/pgx/v5/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/select_union/postgres/pgx/v5/go/db.go b/internal/endtoend/testdata/select_union/postgres/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/select_union/postgres/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/select_union/postgres/pgx/v5/go/models.go b/internal/endtoend/testdata/select_union/postgres/pgx/v5/go/models.go new file mode 100644 index 0000000..9ab4919 --- /dev/null +++ b/internal/endtoend/testdata/select_union/postgres/pgx/v5/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +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 new file mode 100644 index 0000000..d7e818b --- /dev/null +++ b/internal/endtoend/testdata/select_union/postgres/pgx/v5/go/query.sql.go @@ -0,0 +1,172 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// 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.Query(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.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.Query(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.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.Query(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.Err(); err != nil { + return nil, err + } + return items, nil +} + +const selectUnionAliased = `-- name: SelectUnionAliased :many +(SELECT a, b FROM foo) +UNION +SELECT a, b FROM foo +` + +func (q *Queries) SelectUnionAliased(ctx context.Context) ([]Foo, error) { + rows, err := q.db.Query(ctx, selectUnionAliased) + 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 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 new file mode 100644 index 0000000..f44f1fd --- /dev/null +++ b/internal/endtoend/testdata/select_union/postgres/pgx/v5/query.sql @@ -0,0 +1,30 @@ +-- 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 +SELECT * FROM foo; + +-- name: SelectIntersect :many +SELECT * FROM foo +INTERSECT +SELECT * FROM foo; + +-- name: SelectUnionOther :many +SELECT * FROM foo +UNION +SELECT * FROM bar; + +-- name: SelectUnionAliased :many +(SELECT * FROM foo) +UNION +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/select_union/postgres/pgx/v5/schema.sql b/internal/endtoend/testdata/select_union/postgres/pgx/v5/schema.sql new file mode 100644 index 0000000..47a0314 --- /dev/null +++ b/internal/endtoend/testdata/select_union/postgres/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (a text, b text); +CREATE TABLE bar (a text, b text); + diff --git a/internal/endtoend/testdata/select_union/postgres/pgx/v5/sqlc.json b/internal/endtoend/testdata/select_union/postgres/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/select_union/postgres/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_union/postgres/stdlib/exec.json b/internal/endtoend/testdata/select_union/postgres/stdlib/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/select_union/postgres/stdlib/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/select_union/postgres/stdlib/go/db.go b/internal/endtoend/testdata/select_union/postgres/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_union/postgres/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/postgres/stdlib/go/models.go b/internal/endtoend/testdata/select_union/postgres/stdlib/go/models.go new file mode 100644 index 0000000..a3b9f9c --- /dev/null +++ b/internal/endtoend/testdata/select_union/postgres/stdlib/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +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/postgres/stdlib/go/query.sql.go b/internal/endtoend/testdata/select_union/postgres/stdlib/go/query.sql.go new file mode 100644 index 0000000..0d0ff61 --- /dev/null +++ b/internal/endtoend/testdata/select_union/postgres/stdlib/go/query.sql.go @@ -0,0 +1,190 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// 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 selectUnionAliased = `-- name: SelectUnionAliased :many +(SELECT a, b FROM foo) +UNION +SELECT a, b FROM foo +` + +func (q *Queries) SelectUnionAliased(ctx context.Context) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, selectUnionAliased) + 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 $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 new file mode 100644 index 0000000..f44f1fd --- /dev/null +++ b/internal/endtoend/testdata/select_union/postgres/stdlib/query.sql @@ -0,0 +1,30 @@ +-- 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 +SELECT * FROM foo; + +-- name: SelectIntersect :many +SELECT * FROM foo +INTERSECT +SELECT * FROM foo; + +-- name: SelectUnionOther :many +SELECT * FROM foo +UNION +SELECT * FROM bar; + +-- name: SelectUnionAliased :many +(SELECT * FROM foo) +UNION +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/select_union/postgres/stdlib/schema.sql b/internal/endtoend/testdata/select_union/postgres/stdlib/schema.sql new file mode 100644 index 0000000..47a0314 --- /dev/null +++ b/internal/endtoend/testdata/select_union/postgres/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (a text, b text); +CREATE TABLE bar (a text, b text); + diff --git a/internal/endtoend/testdata/select_union/postgres/stdlib/sqlc.json b/internal/endtoend/testdata/select_union/postgres/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/select_union/postgres/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} 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 0000000..32faa9f --- /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.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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 0000000..a3b9f9c --- /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.31.1 + +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 0000000..42d9cde --- /dev/null +++ b/internal/endtoend/testdata/select_union/sqlite/go/query.sql.go @@ -0,0 +1,162 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// 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 0000000..1880a56 --- /dev/null +++ b/internal/endtoend/testdata/select_union/sqlite/query.sql @@ -0,0 +1,26 @@ +-- 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; diff --git a/internal/endtoend/testdata/select_union/sqlite/schema.sql b/internal/endtoend/testdata/select_union/sqlite/schema.sql new file mode 100644 index 0000000..47a0314 --- /dev/null +++ b/internal/endtoend/testdata/select_union/sqlite/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (a text, b text); +CREATE TABLE bar (a text, b text); + 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 0000000..1f9d43d --- /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": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/select_union_subquery/issue.md b/internal/endtoend/testdata/select_union_subquery/issue.md new file mode 100644 index 0000000..138725a --- /dev/null +++ b/internal/endtoend/testdata/select_union_subquery/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/2260 diff --git a/internal/endtoend/testdata/select_union_subquery/mysql/go/db.go b/internal/endtoend/testdata/select_union_subquery/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/select_union_subquery/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_subquery/mysql/go/models.go b/internal/endtoend/testdata/select_union_subquery/mysql/go/models.go new file mode 100644 index 0000000..4dbc5a5 --- /dev/null +++ b/internal/endtoend/testdata/select_union_subquery/mysql/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int32 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/select_union_subquery/mysql/go/query.sql.go b/internal/endtoend/testdata/select_union_subquery/mysql/go/query.sql.go new file mode 100644 index 0000000..8fa6947 --- /dev/null +++ b/internal/endtoend/testdata/select_union_subquery/mysql/go/query.sql.go @@ -0,0 +1,41 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const testSubqueryUnion = `-- name: TestSubqueryUnion :many +SELECT tmp.id, tmp.name, tmp.bio FROM ( + SELECT id, name, bio FROM authors + UNION + SELECT id, name, bio FROM authors +) tmp LIMIT 5 +` + +func (q *Queries) TestSubqueryUnion(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, testSubqueryUnion) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); 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_subquery/mysql/query.sql b/internal/endtoend/testdata/select_union_subquery/mysql/query.sql new file mode 100644 index 0000000..6eaabdc --- /dev/null +++ b/internal/endtoend/testdata/select_union_subquery/mysql/query.sql @@ -0,0 +1,6 @@ +-- name: TestSubqueryUnion :many +SELECT tmp.* FROM ( + SELECT * FROM authors + UNION + SELECT * FROM authors +) tmp LIMIT 5; diff --git a/internal/endtoend/testdata/select_union_subquery/mysql/schema.sql b/internal/endtoend/testdata/select_union_subquery/mysql/schema.sql new file mode 100644 index 0000000..7793468 --- /dev/null +++ b/internal/endtoend/testdata/select_union_subquery/mysql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE authors ( + id int PRIMARY KEY, + name text NOT NULL, + bio text +); diff --git a/internal/endtoend/testdata/select_union_subquery/mysql/sqlc.yaml b/internal/endtoend/testdata/select_union_subquery/mysql/sqlc.yaml new file mode 100644 index 0000000..b843ef5 --- /dev/null +++ b/internal/endtoend/testdata/select_union_subquery/mysql/sqlc.yaml @@ -0,0 +1,9 @@ +version: "2" +sql: + - engine: "mysql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" diff --git a/internal/endtoend/testdata/select_union_subquery/postgresql/go/db.go b/internal/endtoend/testdata/select_union_subquery/postgresql/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/select_union_subquery/postgresql/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/select_union_subquery/postgresql/go/models.go b/internal/endtoend/testdata/select_union_subquery/postgresql/go/models.go new file mode 100644 index 0000000..cdb82d0 --- /dev/null +++ b/internal/endtoend/testdata/select_union_subquery/postgresql/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Author struct { + ID int32 + Name string + Bio pgtype.Text +} diff --git a/internal/endtoend/testdata/select_union_subquery/postgresql/go/query.sql.go b/internal/endtoend/testdata/select_union_subquery/postgresql/go/query.sql.go new file mode 100644 index 0000000..56780c4 --- /dev/null +++ b/internal/endtoend/testdata/select_union_subquery/postgresql/go/query.sql.go @@ -0,0 +1,38 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const testSubqueryUnion = `-- name: TestSubqueryUnion :many +SELECT tmp.id, tmp.name, tmp.bio FROM ( + SELECT id, name, bio FROM authors + UNION + SELECT id, name, bio FROM authors +) tmp LIMIT 5 +` + +func (q *Queries) TestSubqueryUnion(ctx context.Context) ([]Author, error) { + rows, err := q.db.Query(ctx, testSubqueryUnion) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); 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_subquery/postgresql/query.sql b/internal/endtoend/testdata/select_union_subquery/postgresql/query.sql new file mode 100644 index 0000000..6eaabdc --- /dev/null +++ b/internal/endtoend/testdata/select_union_subquery/postgresql/query.sql @@ -0,0 +1,6 @@ +-- name: TestSubqueryUnion :many +SELECT tmp.* FROM ( + SELECT * FROM authors + UNION + SELECT * FROM authors +) tmp LIMIT 5; diff --git a/internal/endtoend/testdata/select_union_subquery/postgresql/schema.sql b/internal/endtoend/testdata/select_union_subquery/postgresql/schema.sql new file mode 100644 index 0000000..7793468 --- /dev/null +++ b/internal/endtoend/testdata/select_union_subquery/postgresql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE authors ( + id int PRIMARY KEY, + name text NOT NULL, + bio text +); diff --git a/internal/endtoend/testdata/select_union_subquery/postgresql/sqlc.yaml b/internal/endtoend/testdata/select_union_subquery/postgresql/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/select_union_subquery/postgresql/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/selectstatic/mysql/go/db.go b/internal/endtoend/testdata/selectstatic/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/selectstatic/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/selectstatic/mysql/go/models.go b/internal/endtoend/testdata/selectstatic/mysql/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/selectstatic/mysql/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/selectstatic/mysql/go/query.sql.go b/internal/endtoend/testdata/selectstatic/mysql/go/query.sql.go new file mode 100644 index 0000000..c48efce --- /dev/null +++ b/internal/endtoend/testdata/selectstatic/mysql/go/query.sql.go @@ -0,0 +1,35 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const selectStatic = `-- name: SelectStatic :one +SELECT 'a', 'b' AS b, 1 AS num, true AS truefield, 1.0 AS floater +` + +type SelectStaticRow struct { + Column1 string + B string + Num int32 + Truefield bool + Floater float64 +} + +func (q *Queries) SelectStatic(ctx context.Context) (SelectStaticRow, error) { + row := q.db.QueryRowContext(ctx, selectStatic) + var i SelectStaticRow + err := row.Scan( + &i.Column1, + &i.B, + &i.Num, + &i.Truefield, + &i.Floater, + ) + return i, err +} diff --git a/internal/endtoend/testdata/selectstatic/mysql/query.sql b/internal/endtoend/testdata/selectstatic/mysql/query.sql new file mode 100644 index 0000000..3a184df --- /dev/null +++ b/internal/endtoend/testdata/selectstatic/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: SelectStatic :one +SELECT 'a', 'b' AS b, 1 AS num, true AS truefield, 1.0 AS floater diff --git a/internal/endtoend/testdata/selectstatic/mysql/schema.sql b/internal/endtoend/testdata/selectstatic/mysql/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/selectstatic/mysql/sqlc.json b/internal/endtoend/testdata/selectstatic/mysql/sqlc.json new file mode 100644 index 0000000..b474940 --- /dev/null +++ b/internal/endtoend/testdata/selectstatic/mysql/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "sql_package": "database/sql", + "engine": "mysql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/show_warnings/mysql/go/db.go b/internal/endtoend/testdata/show_warnings/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/show_warnings/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/show_warnings/mysql/go/models.go b/internal/endtoend/testdata/show_warnings/mysql/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/show_warnings/mysql/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/show_warnings/mysql/go/query.sql.go b/internal/endtoend/testdata/show_warnings/mysql/go/query.sql.go new file mode 100644 index 0000000..d8c5962 --- /dev/null +++ b/internal/endtoend/testdata/show_warnings/mysql/go/query.sql.go @@ -0,0 +1,43 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const showWarnings = `-- name: ShowWarnings :many +SHOW WARNINGS +` + +type ShowWarningsRow struct { + Level string + Code int32 + Message string +} + +func (q *Queries) ShowWarnings(ctx context.Context) ([]ShowWarningsRow, error) { + rows, err := q.db.QueryContext(ctx, showWarnings) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ShowWarningsRow + for rows.Next() { + var i ShowWarningsRow + if err := rows.Scan(&i.Level, &i.Code, &i.Message); 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/show_warnings/mysql/query.sql b/internal/endtoend/testdata/show_warnings/mysql/query.sql new file mode 100644 index 0000000..fa67110 --- /dev/null +++ b/internal/endtoend/testdata/show_warnings/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: ShowWarnings :many +SHOW WARNINGS; diff --git a/internal/endtoend/testdata/show_warnings/mysql/schema.sql b/internal/endtoend/testdata/show_warnings/mysql/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/show_warnings/mysql/sqlc.json b/internal/endtoend/testdata/show_warnings/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/show_warnings/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/single_param_conflict/mysql/go/db.go b/internal/endtoend/testdata/single_param_conflict/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/single_param_conflict/mysql/go/models.go b/internal/endtoend/testdata/single_param_conflict/mysql/go/models.go new file mode 100644 index 0000000..1a1f2ca --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/mysql/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} + +type User struct { + Sub string +} diff --git a/internal/endtoend/testdata/single_param_conflict/mysql/go/query.sql.go b/internal/endtoend/testdata/single_param_conflict/mysql/go/query.sql.go new file mode 100644 index 0000000..71681b3 --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/mysql/go/query.sql.go @@ -0,0 +1,52 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAuthorByID = `-- name: GetAuthorByID :one +SELECT id, name, bio +FROM authors +WHERE id = ? +LIMIT 1 +` + +func (q *Queries) GetAuthorByID(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthorByID, id) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const getAuthorIDByID = `-- name: GetAuthorIDByID :one +SELECT id +FROM authors +WHERE id = ? +LIMIT 1 +` + +func (q *Queries) GetAuthorIDByID(ctx context.Context, id int64) (int64, error) { + row := q.db.QueryRowContext(ctx, getAuthorIDByID, id) + var id_2 int64 + err := row.Scan(&id_2) + return id_2, err +} + +const getUser = `-- name: GetUser :one +SELECT sub +FROM users +WHERE sub = ? +LIMIT 1 +` + +func (q *Queries) GetUser(ctx context.Context, sub string) (string, error) { + row := q.db.QueryRowContext(ctx, getUser, sub) + var sub_2 string + err := row.Scan(&sub_2) + return sub_2, err +} diff --git a/internal/endtoend/testdata/single_param_conflict/mysql/query.sql b/internal/endtoend/testdata/single_param_conflict/mysql/query.sql new file mode 100644 index 0000000..23b454d --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/mysql/query.sql @@ -0,0 +1,17 @@ +-- name: GetAuthorIDByID :one +SELECT id +FROM authors +WHERE id = ? +LIMIT 1; + +-- name: GetAuthorByID :one +SELECT id, name, bio +FROM authors +WHERE id = ? +LIMIT 1; + +-- name: GetUser :one +SELECT sub +FROM users +WHERE sub = ? +LIMIT 1; diff --git a/internal/endtoend/testdata/single_param_conflict/mysql/schema.sql b/internal/endtoend/testdata/single_param_conflict/mysql/schema.sql new file mode 100644 index 0000000..2f49d21 --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/mysql/schema.sql @@ -0,0 +1,11 @@ +-- Example queries for sqlc +CREATE TABLE authors ( + id BIGINT PRIMARY KEY, + name TEXT NOT NULL, + bio text +); + +-- https://github.com/sqlc-dev/sqlc/issues/1290 +CREATE TABLE users ( + sub VARCHAR(10) PRIMARY KEY +); diff --git a/internal/endtoend/testdata/single_param_conflict/mysql/sqlc.json b/internal/endtoend/testdata/single_param_conflict/mysql/sqlc.json new file mode 100644 index 0000000..c7c930d --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/single_param_conflict/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..907d986 --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v4/go/models.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + + "github.com/google/uuid" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} + +type User struct { + Sub uuid.UUID +} diff --git a/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..8f5f9f0 --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,70 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/google/uuid" +) + +const getAuthorByID = `-- name: GetAuthorByID :one +SELECT id, name, bio +FROM authors +WHERE id = $1 +LIMIT 1 +` + +func (q *Queries) GetAuthorByID(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRow(ctx, getAuthorByID, id) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const getAuthorIDByID = `-- name: GetAuthorIDByID :one +SELECT id +FROM authors +WHERE id = $1 +LIMIT 1 +` + +func (q *Queries) GetAuthorIDByID(ctx context.Context, id int64) (int64, error) { + row := q.db.QueryRow(ctx, getAuthorIDByID, id) + var id_2 int64 + err := row.Scan(&id_2) + return id_2, err +} + +const getUser = `-- name: GetUser :one +SELECT sub +FROM users +WHERE sub = $1 +LIMIT 1 +` + +func (q *Queries) GetUser(ctx context.Context, sub uuid.UUID) (uuid.UUID, error) { + row := q.db.QueryRow(ctx, getUser, sub) + var sub_2 uuid.UUID + err := row.Scan(&sub_2) + return sub_2, err +} + +const setDefaultName = `-- name: SetDefaultName :one + +UPDATE authors +SET name = 'Default Name' +WHERE id = $1 +RETURNING id +` + +// https://github.com/sqlc-dev/sqlc/issues/1235 +func (q *Queries) SetDefaultName(ctx context.Context, id int64) (int64, error) { + row := q.db.QueryRow(ctx, setDefaultName, id) + var id_2 int64 + err := row.Scan(&id_2) + return id_2, err +} diff --git a/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..ca3fc5c --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v4/query.sql @@ -0,0 +1,25 @@ +-- name: GetAuthorIDByID :one +SELECT id +FROM authors +WHERE id = $1 +LIMIT 1; + +-- name: GetAuthorByID :one +SELECT id, name, bio +FROM authors +WHERE id = $1 +LIMIT 1; + +-- name: GetUser :one +SELECT sub +FROM users +WHERE sub = $1 +LIMIT 1; + +-- https://github.com/sqlc-dev/sqlc/issues/1235 + +-- name: SetDefaultName :one +UPDATE authors +SET name = 'Default Name' +WHERE id = $1 +RETURNING id; diff --git a/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..0c4555a --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v4/schema.sql @@ -0,0 +1,11 @@ +-- Example queries for sqlc +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name TEXT NOT NULL, + bio text +); + +-- https://github.com/sqlc-dev/sqlc/issues/1290 +CREATE TABLE users ( + sub UUID PRIMARY KEY +); diff --git a/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..827c74c --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "sql_package": "pgx/v4", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/single_param_conflict/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..35aa9ca --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v5/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Author struct { + ID int64 + Name string + Bio pgtype.Text +} + +type User struct { + Sub pgtype.UUID +} diff --git a/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..e6b88ee --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,70 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const getAuthorByID = `-- name: GetAuthorByID :one +SELECT id, name, bio +FROM authors +WHERE id = $1 +LIMIT 1 +` + +func (q *Queries) GetAuthorByID(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRow(ctx, getAuthorByID, id) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const getAuthorIDByID = `-- name: GetAuthorIDByID :one +SELECT id +FROM authors +WHERE id = $1 +LIMIT 1 +` + +func (q *Queries) GetAuthorIDByID(ctx context.Context, id int64) (int64, error) { + row := q.db.QueryRow(ctx, getAuthorIDByID, id) + var id_2 int64 + err := row.Scan(&id_2) + return id_2, err +} + +const getUser = `-- name: GetUser :one +SELECT sub +FROM users +WHERE sub = $1 +LIMIT 1 +` + +func (q *Queries) GetUser(ctx context.Context, sub pgtype.UUID) (pgtype.UUID, error) { + row := q.db.QueryRow(ctx, getUser, sub) + var sub_2 pgtype.UUID + err := row.Scan(&sub_2) + return sub_2, err +} + +const setDefaultName = `-- name: SetDefaultName :one + +UPDATE authors +SET name = 'Default Name' +WHERE id = $1 +RETURNING id +` + +// https://github.com/sqlc-dev/sqlc/issues/1235 +func (q *Queries) SetDefaultName(ctx context.Context, id int64) (int64, error) { + row := q.db.QueryRow(ctx, setDefaultName, id) + var id_2 int64 + err := row.Scan(&id_2) + return id_2, err +} diff --git a/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..ca3fc5c --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v5/query.sql @@ -0,0 +1,25 @@ +-- name: GetAuthorIDByID :one +SELECT id +FROM authors +WHERE id = $1 +LIMIT 1; + +-- name: GetAuthorByID :one +SELECT id, name, bio +FROM authors +WHERE id = $1 +LIMIT 1; + +-- name: GetUser :one +SELECT sub +FROM users +WHERE sub = $1 +LIMIT 1; + +-- https://github.com/sqlc-dev/sqlc/issues/1235 + +-- name: SetDefaultName :one +UPDATE authors +SET name = 'Default Name' +WHERE id = $1 +RETURNING id; diff --git a/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..0c4555a --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v5/schema.sql @@ -0,0 +1,11 @@ +-- Example queries for sqlc +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name TEXT NOT NULL, + bio text +); + +-- https://github.com/sqlc-dev/sqlc/issues/1290 +CREATE TABLE users ( + sub UUID PRIMARY KEY +); diff --git a/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..fbae807 --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "sql_package": "pgx/v5", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/single_param_conflict/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/single_param_conflict/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/single_param_conflict/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/single_param_conflict/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..907d986 --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/postgresql/stdlib/go/models.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + + "github.com/google/uuid" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} + +type User struct { + Sub uuid.UUID +} diff --git a/internal/endtoend/testdata/single_param_conflict/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/single_param_conflict/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..4df9667 --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,70 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/google/uuid" +) + +const getAuthorByID = `-- name: GetAuthorByID :one +SELECT id, name, bio +FROM authors +WHERE id = $1 +LIMIT 1 +` + +func (q *Queries) GetAuthorByID(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthorByID, id) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const getAuthorIDByID = `-- name: GetAuthorIDByID :one +SELECT id +FROM authors +WHERE id = $1 +LIMIT 1 +` + +func (q *Queries) GetAuthorIDByID(ctx context.Context, id int64) (int64, error) { + row := q.db.QueryRowContext(ctx, getAuthorIDByID, id) + var id_2 int64 + err := row.Scan(&id_2) + return id_2, err +} + +const getUser = `-- name: GetUser :one +SELECT sub +FROM users +WHERE sub = $1 +LIMIT 1 +` + +func (q *Queries) GetUser(ctx context.Context, sub uuid.UUID) (uuid.UUID, error) { + row := q.db.QueryRowContext(ctx, getUser, sub) + var sub_2 uuid.UUID + err := row.Scan(&sub_2) + return sub_2, err +} + +const setDefaultName = `-- name: SetDefaultName :one + +UPDATE authors +SET name = 'Default Name' +WHERE id = $1 +RETURNING id +` + +// https://github.com/sqlc-dev/sqlc/issues/1235 +func (q *Queries) SetDefaultName(ctx context.Context, id int64) (int64, error) { + row := q.db.QueryRowContext(ctx, setDefaultName, id) + var id_2 int64 + err := row.Scan(&id_2) + return id_2, err +} diff --git a/internal/endtoend/testdata/single_param_conflict/postgresql/stdlib/query.sql b/internal/endtoend/testdata/single_param_conflict/postgresql/stdlib/query.sql new file mode 100644 index 0000000..ca3fc5c --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/postgresql/stdlib/query.sql @@ -0,0 +1,25 @@ +-- name: GetAuthorIDByID :one +SELECT id +FROM authors +WHERE id = $1 +LIMIT 1; + +-- name: GetAuthorByID :one +SELECT id, name, bio +FROM authors +WHERE id = $1 +LIMIT 1; + +-- name: GetUser :one +SELECT sub +FROM users +WHERE sub = $1 +LIMIT 1; + +-- https://github.com/sqlc-dev/sqlc/issues/1235 + +-- name: SetDefaultName :one +UPDATE authors +SET name = 'Default Name' +WHERE id = $1 +RETURNING id; diff --git a/internal/endtoend/testdata/single_param_conflict/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/single_param_conflict/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..0c4555a --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/postgresql/stdlib/schema.sql @@ -0,0 +1,11 @@ +-- Example queries for sqlc +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name TEXT NOT NULL, + bio text +); + +-- https://github.com/sqlc-dev/sqlc/issues/1290 +CREATE TABLE users ( + sub UUID PRIMARY KEY +); diff --git a/internal/endtoend/testdata/single_param_conflict/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/single_param_conflict/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..1a9272b --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/single_param_conflict/sqlite/go/db.go b/internal/endtoend/testdata/single_param_conflict/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/single_param_conflict/sqlite/go/models.go b/internal/endtoend/testdata/single_param_conflict/sqlite/go/models.go new file mode 100644 index 0000000..1a1f2ca --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/sqlite/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} + +type User struct { + Sub string +} diff --git a/internal/endtoend/testdata/single_param_conflict/sqlite/go/query.sql.go b/internal/endtoend/testdata/single_param_conflict/sqlite/go/query.sql.go new file mode 100644 index 0000000..0499ffb --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/sqlite/go/query.sql.go @@ -0,0 +1,52 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAuthorByID = `-- name: GetAuthorByID :one +SELECT id, name, bio +FROM authors +WHERE id = ? +LIMIT 1 +` + +func (q *Queries) GetAuthorByID(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthorByID, id) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const getAuthorIDByID = `-- name: GetAuthorIDByID :one +SELECT id +FROM authors +WHERE id = ? +LIMIT 1 +` + +func (q *Queries) GetAuthorIDByID(ctx context.Context, id int64) (int64, error) { + row := q.db.QueryRowContext(ctx, getAuthorIDByID, id) + var id_2 int64 + err := row.Scan(&id_2) + return id_2, err +} + +const getUser = `-- name: GetUser :one +SELECT sub +FROM users +WHERE sub = ? +LIMIT 1 +` + +func (q *Queries) GetUser(ctx context.Context, sub string) (string, error) { + row := q.db.QueryRowContext(ctx, getUser, sub) + var sub_2 string + err := row.Scan(&sub_2) + return sub_2, err +} diff --git a/internal/endtoend/testdata/single_param_conflict/sqlite/query.sql b/internal/endtoend/testdata/single_param_conflict/sqlite/query.sql new file mode 100644 index 0000000..504f779 --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/sqlite/query.sql @@ -0,0 +1,17 @@ +-- name: GetAuthorIDByID :one +SELECT id +FROM authors +WHERE id = ? +LIMIT 1; + +-- name: GetAuthorByID :one +SELECT id, name, bio +FROM authors +WHERE id = ? +LIMIT 1; + +-- name: GetUser :one +SELECT sub +FROM users +WHERE sub = ? +LIMIT 1; diff --git a/internal/endtoend/testdata/single_param_conflict/sqlite/schema.sql b/internal/endtoend/testdata/single_param_conflict/sqlite/schema.sql new file mode 100644 index 0000000..376329e --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/sqlite/schema.sql @@ -0,0 +1,11 @@ +-- Example queries for sqlc +CREATE TABLE authors ( + id BIGINT PRIMARY KEY, + name TEXT NOT NULL, + bio text +); + +-- https://github.com/sqlc-dev/sqlc/issues/1290 +CREATE TABLE users ( + sub TEXT PRIMARY KEY +); diff --git a/internal/endtoend/testdata/single_param_conflict/sqlite/sqlc.json b/internal/endtoend/testdata/single_param_conflict/sqlite/sqlc.json new file mode 100644 index 0000000..1f9d43d --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "sqlite", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/sql_syntax_calling_funcs/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v4/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..9e8369a --- /dev/null +++ b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,76 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const mixedNotation = `-- name: MixedNotation :one +SELECT concat_lower_or_upper('Hello', 'World', uppercase => true) +` + +func (q *Queries) MixedNotation(ctx context.Context) (string, error) { + row := q.db.QueryRow(ctx, mixedNotation) + var concat_lower_or_upper string + err := row.Scan(&concat_lower_or_upper) + return concat_lower_or_upper, err +} + +const namedAnyOrder = `-- name: NamedAnyOrder :one +SELECT concat_lower_or_upper(a => 'Hello', b => 'World', uppercase => true) +` + +func (q *Queries) NamedAnyOrder(ctx context.Context) (string, error) { + row := q.db.QueryRow(ctx, namedAnyOrder) + var concat_lower_or_upper string + err := row.Scan(&concat_lower_or_upper) + return concat_lower_or_upper, err +} + +const namedNotation = `-- name: NamedNotation :one +SELECT concat_lower_or_upper(a => 'Hello', b => 'World') +` + +func (q *Queries) NamedNotation(ctx context.Context) (string, error) { + row := q.db.QueryRow(ctx, namedNotation) + var concat_lower_or_upper string + err := row.Scan(&concat_lower_or_upper) + return concat_lower_or_upper, err +} + +const namedOtherOrder = `-- name: NamedOtherOrder :one +SELECT concat_lower_or_upper(a => 'Hello', uppercase => true, b => 'World') +` + +func (q *Queries) NamedOtherOrder(ctx context.Context) (string, error) { + row := q.db.QueryRow(ctx, namedOtherOrder) + var concat_lower_or_upper string + err := row.Scan(&concat_lower_or_upper) + return concat_lower_or_upper, err +} + +const positionalNoDefaault = `-- name: PositionalNoDefaault :one +SELECT concat_lower_or_upper('Hello', 'World') +` + +func (q *Queries) PositionalNoDefaault(ctx context.Context) (string, error) { + row := q.db.QueryRow(ctx, positionalNoDefaault) + var concat_lower_or_upper string + err := row.Scan(&concat_lower_or_upper) + return concat_lower_or_upper, err +} + +const positionalNotation = `-- name: PositionalNotation :one +SELECT concat_lower_or_upper('Hello', 'World', true) +` + +func (q *Queries) PositionalNotation(ctx context.Context) (string, error) { + row := q.db.QueryRow(ctx, positionalNotation) + var concat_lower_or_upper string + err := row.Scan(&concat_lower_or_upper) + return concat_lower_or_upper, err +} diff --git a/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..c1fc6ea --- /dev/null +++ b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v4/query.sql @@ -0,0 +1,17 @@ +-- name: PositionalNotation :one +SELECT concat_lower_or_upper('Hello', 'World', true); + +-- name: PositionalNoDefaault :one +SELECT concat_lower_or_upper('Hello', 'World'); + +-- name: NamedNotation :one +SELECT concat_lower_or_upper(a => 'Hello', b => 'World'); + +-- name: NamedAnyOrder :one +SELECT concat_lower_or_upper(a => 'Hello', b => 'World', uppercase => true); + +-- name: NamedOtherOrder :one +SELECT concat_lower_or_upper(a => 'Hello', uppercase => true, b => 'World'); + +-- name: MixedNotation :one +SELECT concat_lower_or_upper('Hello', 'World', uppercase => true); diff --git a/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..8f20642 --- /dev/null +++ b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v4/schema.sql @@ -0,0 +1,12 @@ +-- https://www.postgresql.org/docs/current/sql-syntax-calling-funcs.html +CREATE FUNCTION concat_lower_or_upper(a text, b text, uppercase boolean DEFAULT false) +RETURNS text +AS +$$ + SELECT CASE + WHEN $3 THEN UPPER($1 || ' ' || $2) + ELSE LOWER($1 || ' ' || $2) + END; +$$ +LANGUAGE SQL IMMUTABLE STRICT; + diff --git a/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/sql_syntax_calling_funcs/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v5/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..9e8369a --- /dev/null +++ b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,76 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const mixedNotation = `-- name: MixedNotation :one +SELECT concat_lower_or_upper('Hello', 'World', uppercase => true) +` + +func (q *Queries) MixedNotation(ctx context.Context) (string, error) { + row := q.db.QueryRow(ctx, mixedNotation) + var concat_lower_or_upper string + err := row.Scan(&concat_lower_or_upper) + return concat_lower_or_upper, err +} + +const namedAnyOrder = `-- name: NamedAnyOrder :one +SELECT concat_lower_or_upper(a => 'Hello', b => 'World', uppercase => true) +` + +func (q *Queries) NamedAnyOrder(ctx context.Context) (string, error) { + row := q.db.QueryRow(ctx, namedAnyOrder) + var concat_lower_or_upper string + err := row.Scan(&concat_lower_or_upper) + return concat_lower_or_upper, err +} + +const namedNotation = `-- name: NamedNotation :one +SELECT concat_lower_or_upper(a => 'Hello', b => 'World') +` + +func (q *Queries) NamedNotation(ctx context.Context) (string, error) { + row := q.db.QueryRow(ctx, namedNotation) + var concat_lower_or_upper string + err := row.Scan(&concat_lower_or_upper) + return concat_lower_or_upper, err +} + +const namedOtherOrder = `-- name: NamedOtherOrder :one +SELECT concat_lower_or_upper(a => 'Hello', uppercase => true, b => 'World') +` + +func (q *Queries) NamedOtherOrder(ctx context.Context) (string, error) { + row := q.db.QueryRow(ctx, namedOtherOrder) + var concat_lower_or_upper string + err := row.Scan(&concat_lower_or_upper) + return concat_lower_or_upper, err +} + +const positionalNoDefaault = `-- name: PositionalNoDefaault :one +SELECT concat_lower_or_upper('Hello', 'World') +` + +func (q *Queries) PositionalNoDefaault(ctx context.Context) (string, error) { + row := q.db.QueryRow(ctx, positionalNoDefaault) + var concat_lower_or_upper string + err := row.Scan(&concat_lower_or_upper) + return concat_lower_or_upper, err +} + +const positionalNotation = `-- name: PositionalNotation :one +SELECT concat_lower_or_upper('Hello', 'World', true) +` + +func (q *Queries) PositionalNotation(ctx context.Context) (string, error) { + row := q.db.QueryRow(ctx, positionalNotation) + var concat_lower_or_upper string + err := row.Scan(&concat_lower_or_upper) + return concat_lower_or_upper, err +} diff --git a/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..c1fc6ea --- /dev/null +++ b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v5/query.sql @@ -0,0 +1,17 @@ +-- name: PositionalNotation :one +SELECT concat_lower_or_upper('Hello', 'World', true); + +-- name: PositionalNoDefaault :one +SELECT concat_lower_or_upper('Hello', 'World'); + +-- name: NamedNotation :one +SELECT concat_lower_or_upper(a => 'Hello', b => 'World'); + +-- name: NamedAnyOrder :one +SELECT concat_lower_or_upper(a => 'Hello', b => 'World', uppercase => true); + +-- name: NamedOtherOrder :one +SELECT concat_lower_or_upper(a => 'Hello', uppercase => true, b => 'World'); + +-- name: MixedNotation :one +SELECT concat_lower_or_upper('Hello', 'World', uppercase => true); diff --git a/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..8f20642 --- /dev/null +++ b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v5/schema.sql @@ -0,0 +1,12 @@ +-- https://www.postgresql.org/docs/current/sql-syntax-calling-funcs.html +CREATE FUNCTION concat_lower_or_upper(a text, b text, uppercase boolean DEFAULT false) +RETURNS text +AS +$$ + SELECT CASE + WHEN $3 THEN UPPER($1 || ' ' || $2) + ELSE LOWER($1 || ' ' || $2) + END; +$$ +LANGUAGE SQL IMMUTABLE STRICT; + diff --git a/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/sql_syntax_calling_funcs/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a1a6c48 --- /dev/null +++ b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/stdlib/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest diff --git a/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..b5af495 --- /dev/null +++ b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,76 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const mixedNotation = `-- name: MixedNotation :one +SELECT concat_lower_or_upper('Hello', 'World', uppercase => true) +` + +func (q *Queries) MixedNotation(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, mixedNotation) + var concat_lower_or_upper string + err := row.Scan(&concat_lower_or_upper) + return concat_lower_or_upper, err +} + +const namedAnyOrder = `-- name: NamedAnyOrder :one +SELECT concat_lower_or_upper(a => 'Hello', b => 'World', uppercase => true) +` + +func (q *Queries) NamedAnyOrder(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, namedAnyOrder) + var concat_lower_or_upper string + err := row.Scan(&concat_lower_or_upper) + return concat_lower_or_upper, err +} + +const namedNotation = `-- name: NamedNotation :one +SELECT concat_lower_or_upper(a => 'Hello', b => 'World') +` + +func (q *Queries) NamedNotation(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, namedNotation) + var concat_lower_or_upper string + err := row.Scan(&concat_lower_or_upper) + return concat_lower_or_upper, err +} + +const namedOtherOrder = `-- name: NamedOtherOrder :one +SELECT concat_lower_or_upper(a => 'Hello', uppercase => true, b => 'World') +` + +func (q *Queries) NamedOtherOrder(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, namedOtherOrder) + var concat_lower_or_upper string + err := row.Scan(&concat_lower_or_upper) + return concat_lower_or_upper, err +} + +const positionalNoDefaault = `-- name: PositionalNoDefaault :one +SELECT concat_lower_or_upper('Hello', 'World') +` + +func (q *Queries) PositionalNoDefaault(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, positionalNoDefaault) + var concat_lower_or_upper string + err := row.Scan(&concat_lower_or_upper) + return concat_lower_or_upper, err +} + +const positionalNotation = `-- name: PositionalNotation :one +SELECT concat_lower_or_upper('Hello', 'World', true) +` + +func (q *Queries) PositionalNotation(ctx context.Context) (string, error) { + row := q.db.QueryRowContext(ctx, positionalNotation) + var concat_lower_or_upper string + err := row.Scan(&concat_lower_or_upper) + return concat_lower_or_upper, err +} diff --git a/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/stdlib/query.sql b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/stdlib/query.sql new file mode 100644 index 0000000..c1fc6ea --- /dev/null +++ b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/stdlib/query.sql @@ -0,0 +1,17 @@ +-- name: PositionalNotation :one +SELECT concat_lower_or_upper('Hello', 'World', true); + +-- name: PositionalNoDefaault :one +SELECT concat_lower_or_upper('Hello', 'World'); + +-- name: NamedNotation :one +SELECT concat_lower_or_upper(a => 'Hello', b => 'World'); + +-- name: NamedAnyOrder :one +SELECT concat_lower_or_upper(a => 'Hello', b => 'World', uppercase => true); + +-- name: NamedOtherOrder :one +SELECT concat_lower_or_upper(a => 'Hello', uppercase => true, b => 'World'); + +-- name: MixedNotation :one +SELECT concat_lower_or_upper('Hello', 'World', uppercase => true); diff --git a/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..8f20642 --- /dev/null +++ b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/stdlib/schema.sql @@ -0,0 +1,12 @@ +-- https://www.postgresql.org/docs/current/sql-syntax-calling-funcs.html +CREATE FUNCTION concat_lower_or_upper(a text, b text, uppercase boolean DEFAULT false) +RETURNS text +AS +$$ + SELECT CASE + WHEN $3 THEN UPPER($1 || ' ' || $2) + ELSE LOWER($1 || ' ' || $2) + END; +$$ +LANGUAGE SQL IMMUTABLE STRICT; + diff --git a/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..cd51867 --- /dev/null +++ b/internal/endtoend/testdata/sql_syntax_calling_funcs/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/sqlc_arg/mysql/go/db.go b/internal/endtoend/testdata/sqlc_arg/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/sqlc_arg/mysql/go/models.go b/internal/endtoend/testdata/sqlc_arg/mysql/go/models.go new file mode 100644 index 0000000..78dff94 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/mysql/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Name string +} diff --git a/internal/endtoend/testdata/sqlc_arg/mysql/go/query.sql.go b/internal/endtoend/testdata/sqlc_arg/mysql/go/query.sql.go new file mode 100644 index 0000000..cacea70 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/mysql/go/query.sql.go @@ -0,0 +1,96 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const complicated = `-- name: Complicated :many +WITH names AS (SELECT name from foo WHERE foo.name = ?) +SELECT name FROM names WHERE name IN (SELECT name FROM foo WHERE foo.name = ?) +` + +type ComplicatedParams struct { + Slug string +} + +func (q *Queries) Complicated(ctx context.Context, arg ComplicatedParams) ([]string, error) { + rows, err := q.db.QueryContext(ctx, complicated, arg.Slug, arg.Slug) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const funcParamIdent = `-- name: FuncParamIdent :many +SELECT name FROM foo WHERE name = ? +` + +func (q *Queries) FuncParamIdent(ctx context.Context, slug string) ([]string, error) { + rows, err := q.db.QueryContext(ctx, funcParamIdent, slug) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const funcParamString = `-- name: FuncParamString :many +SELECT name FROM foo WHERE name = ? +` + +func (q *Queries) FuncParamString(ctx context.Context, slug string) ([]string, error) { + rows, err := q.db.QueryContext(ctx, funcParamString, slug) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + 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/sqlc_arg/mysql/query.sql b/internal/endtoend/testdata/sqlc_arg/mysql/query.sql new file mode 100644 index 0000000..15cb700 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/mysql/query.sql @@ -0,0 +1,9 @@ +/* name: FuncParamIdent :many */ +SELECT name FROM foo WHERE name = sqlc.arg(slug); + +/* name: FuncParamString :many */ +SELECT name FROM foo WHERE name = sqlc.arg('slug'); + +/* name: Complicated :many */ +WITH names AS (SELECT name from foo WHERE foo.name = sqlc.arg('slug')) +SELECT name FROM names WHERE name IN (SELECT name FROM foo WHERE foo.name = sqlc.arg('slug')); diff --git a/internal/endtoend/testdata/sqlc_arg/mysql/schema.sql b/internal/endtoend/testdata/sqlc_arg/mysql/schema.sql new file mode 100644 index 0000000..ec46e55 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (name text not null); + diff --git a/internal/endtoend/testdata/sqlc_arg/mysql/sqlc.json b/internal/endtoend/testdata/sqlc_arg/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/sqlc_arg/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..78dff94 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Name string +} diff --git a/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..eed0d84 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,58 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const funcParamIdent = `-- name: FuncParamIdent :many +SELECT name FROM foo WHERE name = $1 +` + +func (q *Queries) FuncParamIdent(ctx context.Context, slug string) ([]string, error) { + rows, err := q.db.Query(ctx, funcParamIdent, slug) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const funcParamString = `-- name: FuncParamString :many +SELECT name FROM foo WHERE name = $1 +` + +func (q *Queries) FuncParamString(ctx context.Context, slug string) ([]string, error) { + rows, err := q.db.Query(ctx, funcParamString, slug) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..2dfaa9c --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v4/query.sql @@ -0,0 +1,5 @@ +-- name: FuncParamIdent :many +SELECT name FROM foo WHERE name = sqlc.arg(slug); + +-- name: FuncParamString :many +SELECT name FROM foo WHERE name = sqlc.arg('slug'); diff --git a/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..ec46e55 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (name text not null); + diff --git a/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/sqlc_arg/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..78dff94 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Name string +} diff --git a/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..eed0d84 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,58 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const funcParamIdent = `-- name: FuncParamIdent :many +SELECT name FROM foo WHERE name = $1 +` + +func (q *Queries) FuncParamIdent(ctx context.Context, slug string) ([]string, error) { + rows, err := q.db.Query(ctx, funcParamIdent, slug) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const funcParamString = `-- name: FuncParamString :many +SELECT name FROM foo WHERE name = $1 +` + +func (q *Queries) FuncParamString(ctx context.Context, slug string) ([]string, error) { + rows, err := q.db.Query(ctx, funcParamString, slug) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..2dfaa9c --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v5/query.sql @@ -0,0 +1,5 @@ +-- name: FuncParamIdent :many +SELECT name FROM foo WHERE name = sqlc.arg(slug); + +-- name: FuncParamString :many +SELECT name FROM foo WHERE name = sqlc.arg('slug'); diff --git a/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..ec46e55 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (name text not null); + diff --git a/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/sqlc_arg/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/sqlc_arg/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/sqlc_arg/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/sqlc_arg/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..78dff94 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/postgresql/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Name string +} diff --git a/internal/endtoend/testdata/sqlc_arg/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/sqlc_arg/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..aede74f --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,64 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const funcParamIdent = `-- name: FuncParamIdent :many +SELECT name FROM foo WHERE name = $1 +` + +func (q *Queries) FuncParamIdent(ctx context.Context, slug string) ([]string, error) { + rows, err := q.db.QueryContext(ctx, funcParamIdent, slug) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const funcParamString = `-- name: FuncParamString :many +SELECT name FROM foo WHERE name = $1 +` + +func (q *Queries) FuncParamString(ctx context.Context, slug string) ([]string, error) { + rows, err := q.db.QueryContext(ctx, funcParamString, slug) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + 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/sqlc_arg/postgresql/stdlib/query.sql b/internal/endtoend/testdata/sqlc_arg/postgresql/stdlib/query.sql new file mode 100644 index 0000000..2dfaa9c --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/postgresql/stdlib/query.sql @@ -0,0 +1,5 @@ +-- name: FuncParamIdent :many +SELECT name FROM foo WHERE name = sqlc.arg(slug); + +-- name: FuncParamString :many +SELECT name FROM foo WHERE name = sqlc.arg('slug'); diff --git a/internal/endtoend/testdata/sqlc_arg/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/sqlc_arg/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..ec46e55 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (name text not null); + diff --git a/internal/endtoend/testdata/sqlc_arg/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/sqlc_arg/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..cd51867 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/sqlc_arg/sqlite/go/db.go b/internal/endtoend/testdata/sqlc_arg/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/sqlc_arg/sqlite/go/models.go b/internal/endtoend/testdata/sqlc_arg/sqlite/go/models.go new file mode 100644 index 0000000..78dff94 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/sqlite/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Name string +} diff --git a/internal/endtoend/testdata/sqlc_arg/sqlite/go/query.sql.go b/internal/endtoend/testdata/sqlc_arg/sqlite/go/query.sql.go new file mode 100644 index 0000000..c24bd6c --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/sqlite/go/query.sql.go @@ -0,0 +1,64 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const funcParamIdent = `-- name: FuncParamIdent :many +SELECT name FROM foo WHERE name = ?1 +` + +func (q *Queries) FuncParamIdent(ctx context.Context, slug string) ([]string, error) { + rows, err := q.db.QueryContext(ctx, funcParamIdent, slug) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const funcParamString = `-- name: FuncParamString :many +SELECT name FROM foo WHERE name = ?1 +` + +func (q *Queries) FuncParamString(ctx context.Context, slug string) ([]string, error) { + rows, err := q.db.QueryContext(ctx, funcParamString, slug) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + 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/sqlc_arg/sqlite/query.sql b/internal/endtoend/testdata/sqlc_arg/sqlite/query.sql new file mode 100644 index 0000000..b9a01ed --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/sqlite/query.sql @@ -0,0 +1,5 @@ +/* name: FuncParamIdent :many */ +SELECT name FROM foo WHERE name = sqlc.arg(slug); + +/* name: FuncParamString :many */ +SELECT name FROM foo WHERE name = sqlc.arg('slug'); diff --git a/internal/endtoend/testdata/sqlc_arg/sqlite/schema.sql b/internal/endtoend/testdata/sqlc_arg/sqlite/schema.sql new file mode 100644 index 0000000..ec46e55 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/sqlite/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (name text not null); + diff --git a/internal/endtoend/testdata/sqlc_arg/sqlite/sqlc.json b/internal/endtoend/testdata/sqlc_arg/sqlite/sqlc.json new file mode 100644 index 0000000..1f9d43d --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "sqlite", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/sqlc_arg_invalid/mysql/query.sql b/internal/endtoend/testdata/sqlc_arg_invalid/mysql/query.sql new file mode 100644 index 0000000..80d171b --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg_invalid/mysql/query.sql @@ -0,0 +1,14 @@ +-- name: WrongFunc :one +select id, first_name from users where id = sqlc.argh(target_id); + +-- name: TooManyArgs :one +select id, first_name from users where id = sqlc.arg('foo', 'bar'); + +-- name: TooFewArgs :one +select id, first_name from users where id = sqlc.arg(); + +-- name: InvalidArgFunc :one +select id, first_name from users where id = sqlc.arg(sqlc.arg(target_id)); + +-- name: InvalidArgPlaceholder :one +select id, first_name from users where id = sqlc.arg(?); diff --git a/internal/endtoend/testdata/sqlc_arg_invalid/mysql/schema.sql b/internal/endtoend/testdata/sqlc_arg_invalid/mysql/schema.sql new file mode 100644 index 0000000..b11bfef --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg_invalid/mysql/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE users ( + id serial, + first_name text not null +); diff --git a/internal/endtoend/testdata/sqlc_arg_invalid/mysql/sqlc.json b/internal/endtoend/testdata/sqlc_arg_invalid/mysql/sqlc.json new file mode 100644 index 0000000..a9e7b05 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg_invalid/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "schema.sql", + "queries": "query.sql", + "engine": "mysql" + } + ] +} diff --git a/internal/endtoend/testdata/sqlc_arg_invalid/mysql/stderr.txt b/internal/endtoend/testdata/sqlc_arg_invalid/mysql/stderr.txt new file mode 100644 index 0000000..6e2cf13 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg_invalid/mysql/stderr.txt @@ -0,0 +1,6 @@ +# package querytest +query.sql:2:45: function "sqlc.argh" does not exist +query.sql:5:45: expected 1 parameter to sqlc.arg; got 2 +query.sql:8:45: expected 1 parameter to sqlc.arg; got 0 +query.sql:11:45: expected parameter to sqlc.arg to be string or reference; got "sqlc.arg(target_id)" +query.sql:14:45: expected parameter to sqlc.arg to be string or reference; got "?" diff --git a/internal/endtoend/testdata/sqlc_arg_invalid/postgresql/query.sql b/internal/endtoend/testdata/sqlc_arg_invalid/postgresql/query.sql new file mode 100644 index 0000000..3978501 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg_invalid/postgresql/query.sql @@ -0,0 +1,14 @@ +-- name: WrongFunc :one +select id, first_name from users where id = sqlc.argh(target_id); + +-- name: TooManyArgs :one +select id, first_name from users where id = sqlc.arg('foo', 'bar'); + +-- name: TooFewArgs :one +select id, first_name from users where id = sqlc.arg(); + +-- name: InvalidArgFunc :one +select id, first_name from users where id = sqlc.arg(sqlc.arg(target_id)); + +-- name: InvalidArgPlaceholder :one +select id, first_name from users where id = sqlc.arg($1); diff --git a/internal/endtoend/testdata/sqlc_arg_invalid/postgresql/schema.sql b/internal/endtoend/testdata/sqlc_arg_invalid/postgresql/schema.sql new file mode 100644 index 0000000..0a380b5 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg_invalid/postgresql/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE users ( + id serial, + first_name text not null +); \ No newline at end of file diff --git a/internal/endtoend/testdata/sqlc_arg_invalid/postgresql/sqlc.json b/internal/endtoend/testdata/sqlc_arg_invalid/postgresql/sqlc.json new file mode 100644 index 0000000..f5a835c --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg_invalid/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql" + } + ] +} diff --git a/internal/endtoend/testdata/sqlc_arg_invalid/postgresql/stderr.txt b/internal/endtoend/testdata/sqlc_arg_invalid/postgresql/stderr.txt new file mode 100644 index 0000000..2bc3407 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg_invalid/postgresql/stderr.txt @@ -0,0 +1,6 @@ +# package querytest +query.sql:2:45: function "sqlc.argh" does not exist +query.sql:5:45: expected 1 parameter to sqlc.arg; got 2 +query.sql:8:45: expected 1 parameter to sqlc.arg; got 0 +query.sql:11:45: expected parameter to sqlc.arg to be string or reference; got "sqlc.arg(target_id)" +query.sql:14:45: expected parameter to sqlc.arg to be string or reference; got "$1" diff --git a/internal/endtoend/testdata/sqlc_arg_invalid/sqlite/query.sql b/internal/endtoend/testdata/sqlc_arg_invalid/sqlite/query.sql new file mode 100644 index 0000000..3e46d72 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg_invalid/sqlite/query.sql @@ -0,0 +1,19 @@ +CREATE TABLE users ( + id serial, + first_name text not null +); + +-- name: WrongFunc :one +select id, first_name from users where id = sqlc.argh(target_id); + +-- name: TooManyArgs :one +select id, first_name from users where id = sqlc.arg('foo', 'bar'); + +-- name: TooFewArgs :one +select id, first_name from users where id = sqlc.arg(); + +-- name: InvalidArgFunc :one +select id, first_name from users where id = sqlc.arg(sqlc.arg(target_id)); + +-- name: InvalidArgPlaceholder :one +select id, first_name from users where id = sqlc.arg(?); diff --git a/internal/endtoend/testdata/sqlc_arg_invalid/sqlite/sqlc.json b/internal/endtoend/testdata/sqlc_arg_invalid/sqlite/sqlc.json new file mode 100644 index 0000000..8c3dbae --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg_invalid/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "query.sql", + "queries": "query.sql", + "engine": "sqlite" + } + ] +} diff --git a/internal/endtoend/testdata/sqlc_arg_invalid/sqlite/stderr.txt b/internal/endtoend/testdata/sqlc_arg_invalid/sqlite/stderr.txt new file mode 100644 index 0000000..4cf898b --- /dev/null +++ b/internal/endtoend/testdata/sqlc_arg_invalid/sqlite/stderr.txt @@ -0,0 +1,6 @@ +# package querytest +query.sql:7:45: function "sqlc.argh" does not exist +query.sql:10:45: expected 1 parameter to sqlc.arg; got 2 +query.sql:13:45: expected 1 parameter to sqlc.arg; got 0 +query.sql:16:45: expected parameter to sqlc.arg to be string or reference; got "sqlc.arg(target_id)" +query.sql:19:45: expected parameter to sqlc.arg to be string or reference; got "?" diff --git a/internal/endtoend/testdata/sqlc_embed/mysql/exec.json b/internal/endtoend/testdata/sqlc_embed/mysql/exec.json new file mode 100644 index 0000000..c85ca2d --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/mysql/exec.json @@ -0,0 +1,6 @@ +{ + "contexts": ["base"], + "meta": { + "invalid_schema": true + } +} diff --git a/internal/endtoend/testdata/sqlc_embed/mysql/go/db.go b/internal/endtoend/testdata/sqlc_embed/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/sqlc_embed/mysql/go/models.go b/internal/endtoend/testdata/sqlc_embed/mysql/go/models.go new file mode 100644 index 0000000..ee1256c --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/mysql/go/models.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type BazUser struct { + ID int32 + Name string +} + +type Post struct { + ID int32 + UserID int32 +} + +type User struct { + ID int32 + Name string + Age sql.NullInt32 +} diff --git a/internal/endtoend/testdata/sqlc_embed/mysql/go/query.sql.go b/internal/endtoend/testdata/sqlc_embed/mysql/go/query.sql.go new file mode 100644 index 0000000..f2f4dec --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/mysql/go/query.sql.go @@ -0,0 +1,203 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const duplicate = `-- name: Duplicate :one +SELECT users.id, users.name, users.age, users.id, users.name, users.age FROM users +` + +type DuplicateRow struct { + User User + User_2 User +} + +func (q *Queries) Duplicate(ctx context.Context) (DuplicateRow, error) { + row := q.db.QueryRowContext(ctx, duplicate) + var i DuplicateRow + err := row.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.User_2.ID, + &i.User_2.Name, + &i.User_2.Age, + ) + return i, err +} + +const join = `-- name: Join :one +SELECT users.id, users.name, users.age, posts.id, posts.user_id FROM posts +INNER JOIN users ON posts.user_id = users.id +` + +type JoinRow struct { + User User + Post Post +} + +func (q *Queries) Join(ctx context.Context) (JoinRow, error) { + row := q.db.QueryRowContext(ctx, join) + var i JoinRow + err := row.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.Post.ID, + &i.Post.UserID, + ) + return i, err +} + +const only = `-- name: Only :one +SELECT users.id, users.name, users.age FROM users +` + +type OnlyRow struct { + User User +} + +func (q *Queries) Only(ctx context.Context) (OnlyRow, error) { + row := q.db.QueryRowContext(ctx, only) + var i OnlyRow + err := row.Scan(&i.User.ID, &i.User.Name, &i.User.Age) + return i, err +} + +const withAlias = `-- name: WithAlias :one +SELECT u.id, u.name, u.age FROM users u +` + +type WithAliasRow struct { + User User +} + +func (q *Queries) WithAlias(ctx context.Context) (WithAliasRow, error) { + row := q.db.QueryRowContext(ctx, withAlias) + var i WithAliasRow + err := row.Scan(&i.User.ID, &i.User.Name, &i.User.Age) + return i, err +} + +const withAsterisk = `-- name: WithAsterisk :one +SELECT users.id, users.name, users.age, id, name, age FROM users +` + +type WithAsteriskRow struct { + User User + ID int32 + Name string + Age sql.NullInt32 +} + +func (q *Queries) WithAsterisk(ctx context.Context) (WithAsteriskRow, error) { + row := q.db.QueryRowContext(ctx, withAsterisk) + var i WithAsteriskRow + err := row.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.ID, + &i.Name, + &i.Age, + ) + return i, err +} + +const withCrossSchema = `-- name: WithCrossSchema :many +SELECT users.id, users.name, users.age, bu.id, bu.name FROM users +INNER JOIN baz.users bu ON users.id = bu.id +` + +type WithCrossSchemaRow struct { + User User + BazUser BazUser +} + +func (q *Queries) WithCrossSchema(ctx context.Context) ([]WithCrossSchemaRow, error) { + rows, err := q.db.QueryContext(ctx, withCrossSchema) + if err != nil { + return nil, err + } + defer rows.Close() + var items []WithCrossSchemaRow + for rows.Next() { + var i WithCrossSchemaRow + if err := rows.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.BazUser.ID, + &i.BazUser.Name, + ); 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 withSchema = `-- name: WithSchema :one +SELECT bu.id, bu.name FROM baz.users bu +` + +type WithSchemaRow struct { + BazUser BazUser +} + +func (q *Queries) WithSchema(ctx context.Context) (WithSchemaRow, error) { + row := q.db.QueryRowContext(ctx, withSchema) + var i WithSchemaRow + err := row.Scan(&i.BazUser.ID, &i.BazUser.Name) + return i, err +} + +const withSubquery = `-- name: WithSubquery :many +SELECT users.id, users.name, users.age, (SELECT count(*) FROM users) AS total_count FROM users +` + +type WithSubqueryRow struct { + User User + TotalCount int64 +} + +func (q *Queries) WithSubquery(ctx context.Context) ([]WithSubqueryRow, error) { + rows, err := q.db.QueryContext(ctx, withSubquery) + if err != nil { + return nil, err + } + defer rows.Close() + var items []WithSubqueryRow + for rows.Next() { + var i WithSubqueryRow + if err := rows.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.TotalCount, + ); 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/sqlc_embed/mysql/query.sql b/internal/endtoend/testdata/sqlc_embed/mysql/query.sql new file mode 100644 index 0000000..7822145 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/mysql/query.sql @@ -0,0 +1,25 @@ +-- name: Only :one +SELECT sqlc.embed(users) FROM users; + +-- name: WithAlias :one +SELECT sqlc.embed(u) FROM users u; + +-- name: WithSubquery :many +SELECT sqlc.embed(users), (SELECT count(*) FROM users) AS total_count FROM users; + +-- name: WithAsterisk :one +SELECT sqlc.embed(users), * FROM users; + +-- name: Duplicate :one +SELECT sqlc.embed(users), sqlc.embed(users) FROM users; + +-- name: Join :one +SELECT sqlc.embed(users), sqlc.embed(posts) FROM posts +INNER JOIN users ON posts.user_id = users.id; + +-- name: WithSchema :one +SELECT sqlc.embed(bu) FROM baz.users bu; + +-- name: WithCrossSchema :many +SELECT sqlc.embed(users), sqlc.embed(bu) FROM users +INNER JOIN baz.users bu ON users.id = bu.id; \ No newline at end of file diff --git a/internal/endtoend/testdata/sqlc_embed/mysql/schema.sql b/internal/endtoend/testdata/sqlc_embed/mysql/schema.sql new file mode 100644 index 0000000..28751aa --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/mysql/schema.sql @@ -0,0 +1,19 @@ +CREATE SCHEMA IF NOT EXISTS baz; + +CREATE TABLE users ( + id integer NOT NULL PRIMARY KEY, + name varchar(255) NOT NULL, + age integer NULL +); + +CREATE TABLE posts ( + id integer NOT NULL PRIMARY KEY, + user_id integer NOT NULL +); + +CREATE TABLE baz.users ( + id integer NOT NULL PRIMARY KEY, + name varchar(255) NOT NULL +); + + diff --git a/internal/endtoend/testdata/sqlc_embed/mysql/sqlc.json b/internal/endtoend/testdata/sqlc_embed/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/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/sqlc_embed/postgresql/pgx/go/db.go b/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/sqlc_embed/postgresql/pgx/go/models.go b/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/go/models.go new file mode 100644 index 0000000..2ff4607 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/go/models.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type BazUser struct { + ID int32 `db:"id" json:"id"` + Name string `db:"name" json:"name"` +} + +type Post struct { + ID int32 `db:"id" json:"id"` + UserID int32 `db:"user_id" json:"user_id"` +} + +type User struct { + ID int32 `db:"id" json:"id"` + Name string `db:"name" json:"name"` + Age sql.NullInt32 `db:"age" json:"age"` +} diff --git a/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..e627e8d --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/go/query.sql.go @@ -0,0 +1,197 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const duplicate = `-- name: Duplicate :one +SELECT users.id, users.name, users.age, users.id, users.name, users.age FROM users +` + +type DuplicateRow struct { + User User `db:"user" json:"user"` + User_2 User `db:"user_2" json:"user_2"` +} + +func (q *Queries) Duplicate(ctx context.Context) (DuplicateRow, error) { + row := q.db.QueryRow(ctx, duplicate) + var i DuplicateRow + err := row.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.User_2.ID, + &i.User_2.Name, + &i.User_2.Age, + ) + return i, err +} + +const join = `-- name: Join :one +SELECT users.id, users.name, users.age, posts.id, posts.user_id FROM posts +INNER JOIN users ON posts.user_id = users.id +` + +type JoinRow struct { + User User `db:"user" json:"user"` + Post Post `db:"post" json:"post"` +} + +func (q *Queries) Join(ctx context.Context) (JoinRow, error) { + row := q.db.QueryRow(ctx, join) + var i JoinRow + err := row.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.Post.ID, + &i.Post.UserID, + ) + return i, err +} + +const only = `-- name: Only :one +SELECT users.id, users.name, users.age FROM users +` + +type OnlyRow struct { + User User `db:"user" json:"user"` +} + +func (q *Queries) Only(ctx context.Context) (OnlyRow, error) { + row := q.db.QueryRow(ctx, only) + var i OnlyRow + err := row.Scan(&i.User.ID, &i.User.Name, &i.User.Age) + return i, err +} + +const withAlias = `-- name: WithAlias :one +SELECT u.id, u.name, u.age FROM users u +` + +type WithAliasRow struct { + User User `db:"user" json:"user"` +} + +func (q *Queries) WithAlias(ctx context.Context) (WithAliasRow, error) { + row := q.db.QueryRow(ctx, withAlias) + var i WithAliasRow + err := row.Scan(&i.User.ID, &i.User.Name, &i.User.Age) + return i, err +} + +const withAsterisk = `-- name: WithAsterisk :one +SELECT users.id, users.name, users.age, id, name, age FROM users +` + +type WithAsteriskRow struct { + User User `db:"user" json:"user"` + ID int32 `db:"id" json:"id"` + Name string `db:"name" json:"name"` + Age sql.NullInt32 `db:"age" json:"age"` +} + +func (q *Queries) WithAsterisk(ctx context.Context) (WithAsteriskRow, error) { + row := q.db.QueryRow(ctx, withAsterisk) + var i WithAsteriskRow + err := row.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.ID, + &i.Name, + &i.Age, + ) + return i, err +} + +const withCrossSchema = `-- name: WithCrossSchema :many +SELECT users.id, users.name, users.age, bu.id, bu.name FROM users +INNER JOIN baz.users bu ON users.id = bu.id +` + +type WithCrossSchemaRow struct { + User User `db:"user" json:"user"` + BazUser BazUser `db:"baz_user" json:"baz_user"` +} + +func (q *Queries) WithCrossSchema(ctx context.Context) ([]WithCrossSchemaRow, error) { + rows, err := q.db.Query(ctx, withCrossSchema) + if err != nil { + return nil, err + } + defer rows.Close() + var items []WithCrossSchemaRow + for rows.Next() { + var i WithCrossSchemaRow + if err := rows.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.BazUser.ID, + &i.BazUser.Name, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const withSchema = `-- name: WithSchema :one +SELECT bu.id, bu.name FROM baz.users bu +` + +type WithSchemaRow struct { + BazUser BazUser `db:"baz_user" json:"baz_user"` +} + +func (q *Queries) WithSchema(ctx context.Context) (WithSchemaRow, error) { + row := q.db.QueryRow(ctx, withSchema) + var i WithSchemaRow + err := row.Scan(&i.BazUser.ID, &i.BazUser.Name) + return i, err +} + +const withSubquery = `-- name: WithSubquery :many +SELECT users.id, users.name, users.age, (SELECT count(*) FROM users) AS total_count FROM users +` + +type WithSubqueryRow struct { + User User `db:"user" json:"user"` + TotalCount int64 `db:"total_count" json:"total_count"` +} + +func (q *Queries) WithSubquery(ctx context.Context) ([]WithSubqueryRow, error) { + rows, err := q.db.Query(ctx, withSubquery) + if err != nil { + return nil, err + } + defer rows.Close() + var items []WithSubqueryRow + for rows.Next() { + var i WithSubqueryRow + if err := rows.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.TotalCount, + ); 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/sqlc_embed/postgresql/pgx/query.sql b/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/query.sql new file mode 100644 index 0000000..7822145 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/query.sql @@ -0,0 +1,25 @@ +-- name: Only :one +SELECT sqlc.embed(users) FROM users; + +-- name: WithAlias :one +SELECT sqlc.embed(u) FROM users u; + +-- name: WithSubquery :many +SELECT sqlc.embed(users), (SELECT count(*) FROM users) AS total_count FROM users; + +-- name: WithAsterisk :one +SELECT sqlc.embed(users), * FROM users; + +-- name: Duplicate :one +SELECT sqlc.embed(users), sqlc.embed(users) FROM users; + +-- name: Join :one +SELECT sqlc.embed(users), sqlc.embed(posts) FROM posts +INNER JOIN users ON posts.user_id = users.id; + +-- name: WithSchema :one +SELECT sqlc.embed(bu) FROM baz.users bu; + +-- name: WithCrossSchema :many +SELECT sqlc.embed(users), sqlc.embed(bu) FROM users +INNER JOIN baz.users bu ON users.id = bu.id; \ No newline at end of file diff --git a/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/schema.sql b/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/schema.sql new file mode 100644 index 0000000..28751aa --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/schema.sql @@ -0,0 +1,19 @@ +CREATE SCHEMA IF NOT EXISTS baz; + +CREATE TABLE users ( + id integer NOT NULL PRIMARY KEY, + name varchar(255) NOT NULL, + age integer NULL +); + +CREATE TABLE posts ( + id integer NOT NULL PRIMARY KEY, + user_id integer NOT NULL +); + +CREATE TABLE baz.users ( + id integer NOT NULL PRIMARY KEY, + name varchar(255) NOT NULL +); + + diff --git a/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/sqlc.json b/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/sqlc.json new file mode 100644 index 0000000..c74e245 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/sqlc.json @@ -0,0 +1,15 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_json_tags": true, + "emit_db_tags": true + } + ] +} diff --git a/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/sqlc_embed/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..99a2072 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/go/models.go @@ -0,0 +1,26 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type BazUser struct { + ID int32 + Name string +} + +type Post struct { + ID int32 + UserID int32 + Likes []int32 +} + +type User struct { + ID int32 + Name string + Age sql.NullInt32 +} diff --git a/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..09eebce --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,206 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" + + "github.com/lib/pq" +) + +const duplicate = `-- name: Duplicate :one +SELECT users.id, users.name, users.age, users.id, users.name, users.age FROM users +` + +type DuplicateRow struct { + User User + User_2 User +} + +func (q *Queries) Duplicate(ctx context.Context) (DuplicateRow, error) { + row := q.db.QueryRowContext(ctx, duplicate) + var i DuplicateRow + err := row.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.User_2.ID, + &i.User_2.Name, + &i.User_2.Age, + ) + return i, err +} + +const join = `-- name: Join :one +SELECT users.id, users.name, users.age, posts.id, posts.user_id, posts.likes FROM posts +INNER JOIN users ON posts.user_id = users.id +` + +type JoinRow struct { + User User + Post Post +} + +func (q *Queries) Join(ctx context.Context) (JoinRow, error) { + row := q.db.QueryRowContext(ctx, join) + var i JoinRow + err := row.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.Post.ID, + &i.Post.UserID, + pq.Array(&i.Post.Likes), + ) + return i, err +} + +const only = `-- name: Only :one +SELECT users.id, users.name, users.age FROM users +` + +type OnlyRow struct { + User User +} + +func (q *Queries) Only(ctx context.Context) (OnlyRow, error) { + row := q.db.QueryRowContext(ctx, only) + var i OnlyRow + err := row.Scan(&i.User.ID, &i.User.Name, &i.User.Age) + return i, err +} + +const withAlias = `-- name: WithAlias :one +SELECT u.id, u.name, u.age FROM users u +` + +type WithAliasRow struct { + User User +} + +func (q *Queries) WithAlias(ctx context.Context) (WithAliasRow, error) { + row := q.db.QueryRowContext(ctx, withAlias) + var i WithAliasRow + err := row.Scan(&i.User.ID, &i.User.Name, &i.User.Age) + return i, err +} + +const withAsterisk = `-- name: WithAsterisk :one +SELECT users.id, users.name, users.age, id, name, age FROM users +` + +type WithAsteriskRow struct { + User User + ID int32 + Name string + Age sql.NullInt32 +} + +func (q *Queries) WithAsterisk(ctx context.Context) (WithAsteriskRow, error) { + row := q.db.QueryRowContext(ctx, withAsterisk) + var i WithAsteriskRow + err := row.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.ID, + &i.Name, + &i.Age, + ) + return i, err +} + +const withCrossSchema = `-- name: WithCrossSchema :many +SELECT users.id, users.name, users.age, bu.id, bu.name FROM users +INNER JOIN baz.users bu ON users.id = bu.id +` + +type WithCrossSchemaRow struct { + User User + BazUser BazUser +} + +func (q *Queries) WithCrossSchema(ctx context.Context) ([]WithCrossSchemaRow, error) { + rows, err := q.db.QueryContext(ctx, withCrossSchema) + if err != nil { + return nil, err + } + defer rows.Close() + var items []WithCrossSchemaRow + for rows.Next() { + var i WithCrossSchemaRow + if err := rows.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.BazUser.ID, + &i.BazUser.Name, + ); 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 withSchema = `-- name: WithSchema :one +SELECT bu.id, bu.name FROM baz.users bu +` + +type WithSchemaRow struct { + BazUser BazUser +} + +func (q *Queries) WithSchema(ctx context.Context) (WithSchemaRow, error) { + row := q.db.QueryRowContext(ctx, withSchema) + var i WithSchemaRow + err := row.Scan(&i.BazUser.ID, &i.BazUser.Name) + return i, err +} + +const withSubquery = `-- name: WithSubquery :many +SELECT users.id, users.name, users.age, (SELECT count(*) FROM users) AS total_count FROM users +` + +type WithSubqueryRow struct { + User User + TotalCount int64 +} + +func (q *Queries) WithSubquery(ctx context.Context) ([]WithSubqueryRow, error) { + rows, err := q.db.QueryContext(ctx, withSubquery) + if err != nil { + return nil, err + } + defer rows.Close() + var items []WithSubqueryRow + for rows.Next() { + var i WithSubqueryRow + if err := rows.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.TotalCount, + ); 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/sqlc_embed/postgresql/stdlib/query.sql b/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/query.sql new file mode 100644 index 0000000..7822145 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/query.sql @@ -0,0 +1,25 @@ +-- name: Only :one +SELECT sqlc.embed(users) FROM users; + +-- name: WithAlias :one +SELECT sqlc.embed(u) FROM users u; + +-- name: WithSubquery :many +SELECT sqlc.embed(users), (SELECT count(*) FROM users) AS total_count FROM users; + +-- name: WithAsterisk :one +SELECT sqlc.embed(users), * FROM users; + +-- name: Duplicate :one +SELECT sqlc.embed(users), sqlc.embed(users) FROM users; + +-- name: Join :one +SELECT sqlc.embed(users), sqlc.embed(posts) FROM posts +INNER JOIN users ON posts.user_id = users.id; + +-- name: WithSchema :one +SELECT sqlc.embed(bu) FROM baz.users bu; + +-- name: WithCrossSchema :many +SELECT sqlc.embed(users), sqlc.embed(bu) FROM users +INNER JOIN baz.users bu ON users.id = bu.id; \ No newline at end of file diff --git a/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..7a60bb1 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/schema.sql @@ -0,0 +1,20 @@ +CREATE SCHEMA IF NOT EXISTS baz; + +CREATE TABLE users ( + id integer NOT NULL PRIMARY KEY, + name varchar(255) NOT NULL, + age integer NULL +); + +CREATE TABLE posts ( + id integer NOT NULL PRIMARY KEY, + user_id integer NOT NULL, + likes integer[] NOT NULL +); + +CREATE TABLE baz.users ( + id integer NOT NULL PRIMARY KEY, + name varchar(255) NOT NULL +); + + diff --git a/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/sqlc_embed/sqlite/go/db.go b/internal/endtoend/testdata/sqlc_embed/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/sqlc_embed/sqlite/go/models.go b/internal/endtoend/testdata/sqlc_embed/sqlite/go/models.go new file mode 100644 index 0000000..e093aaa --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/sqlite/go/models.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type BazUser struct { + ID int64 + Name string +} + +type Post struct { + ID int64 + UserID int64 +} + +type User struct { + ID int64 + Name string + Age sql.NullInt64 +} diff --git a/internal/endtoend/testdata/sqlc_embed/sqlite/go/query.sql.go b/internal/endtoend/testdata/sqlc_embed/sqlite/go/query.sql.go new file mode 100644 index 0000000..ff1dd53 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/sqlite/go/query.sql.go @@ -0,0 +1,203 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const duplicate = `-- name: Duplicate :one +SELECT users.id, users.name, users.age, users.id, users.name, users.age FROM users +` + +type DuplicateRow struct { + User User + User_2 User +} + +func (q *Queries) Duplicate(ctx context.Context) (DuplicateRow, error) { + row := q.db.QueryRowContext(ctx, duplicate) + var i DuplicateRow + err := row.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.User_2.ID, + &i.User_2.Name, + &i.User_2.Age, + ) + return i, err +} + +const join = `-- name: Join :one +SELECT u.id, u.name, u.age, p.id, p.user_id FROM posts AS p +INNER JOIN users AS u ON p.user_id = u.id +` + +type JoinRow struct { + User User + Post Post +} + +func (q *Queries) Join(ctx context.Context) (JoinRow, error) { + row := q.db.QueryRowContext(ctx, join) + var i JoinRow + err := row.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.Post.ID, + &i.Post.UserID, + ) + return i, err +} + +const only = `-- name: Only :one +SELECT users.id, users.name, users.age FROM users +` + +type OnlyRow struct { + User User +} + +func (q *Queries) Only(ctx context.Context) (OnlyRow, error) { + row := q.db.QueryRowContext(ctx, only) + var i OnlyRow + err := row.Scan(&i.User.ID, &i.User.Name, &i.User.Age) + return i, err +} + +const withAlias = `-- name: WithAlias :one +SELECT u.id, u.name, u.age FROM users AS u +` + +type WithAliasRow struct { + User User +} + +func (q *Queries) WithAlias(ctx context.Context) (WithAliasRow, error) { + row := q.db.QueryRowContext(ctx, withAlias) + var i WithAliasRow + err := row.Scan(&i.User.ID, &i.User.Name, &i.User.Age) + return i, err +} + +const withAsterisk = `-- name: WithAsterisk :one +SELECT users.id, users.name, users.age, id, name, age FROM users +` + +type WithAsteriskRow struct { + User User + ID int64 + Name string + Age sql.NullInt64 +} + +func (q *Queries) WithAsterisk(ctx context.Context) (WithAsteriskRow, error) { + row := q.db.QueryRowContext(ctx, withAsterisk) + var i WithAsteriskRow + err := row.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.ID, + &i.Name, + &i.Age, + ) + return i, err +} + +const withCrossSchema = `-- name: WithCrossSchema :many +SELECT u.id, u.name, u.age, bu.id, bu.name FROM users AS u +INNER JOIN baz.users bu ON u.id = bu.id +` + +type WithCrossSchemaRow struct { + User User + BazUser BazUser +} + +func (q *Queries) WithCrossSchema(ctx context.Context) ([]WithCrossSchemaRow, error) { + rows, err := q.db.QueryContext(ctx, withCrossSchema) + if err != nil { + return nil, err + } + defer rows.Close() + var items []WithCrossSchemaRow + for rows.Next() { + var i WithCrossSchemaRow + if err := rows.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.BazUser.ID, + &i.BazUser.Name, + ); 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 withSchema = `-- name: WithSchema :one +SELECT bu.id, bu.name FROM baz.users AS bu +` + +type WithSchemaRow struct { + BazUser BazUser +} + +func (q *Queries) WithSchema(ctx context.Context) (WithSchemaRow, error) { + row := q.db.QueryRowContext(ctx, withSchema) + var i WithSchemaRow + err := row.Scan(&i.BazUser.ID, &i.BazUser.Name) + return i, err +} + +const withSubquery = `-- name: WithSubquery :many +SELECT users.id, users.name, users.age, (SELECT count(*) FROM users) AS total_count FROM users +` + +type WithSubqueryRow struct { + User User + TotalCount int64 +} + +func (q *Queries) WithSubquery(ctx context.Context) ([]WithSubqueryRow, error) { + rows, err := q.db.QueryContext(ctx, withSubquery) + if err != nil { + return nil, err + } + defer rows.Close() + var items []WithSubqueryRow + for rows.Next() { + var i WithSubqueryRow + if err := rows.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.TotalCount, + ); 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/sqlc_embed/sqlite/query.sql b/internal/endtoend/testdata/sqlc_embed/sqlite/query.sql new file mode 100644 index 0000000..1d0a02f --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/sqlite/query.sql @@ -0,0 +1,25 @@ +-- name: Only :one +SELECT sqlc.embed(users) FROM users; + +-- name: WithAlias :one +SELECT sqlc.embed(u) FROM users AS u; + +-- name: WithSubquery :many +SELECT sqlc.embed(users), (SELECT count(*) FROM users) AS total_count FROM users; + +-- name: WithAsterisk :one +SELECT sqlc.embed(users), * FROM users; + +-- name: Duplicate :one +SELECT sqlc.embed(users), sqlc.embed(users) FROM users; + +-- name: Join :one +SELECT sqlc.embed(u), sqlc.embed(p) FROM posts AS p +INNER JOIN users AS u ON p.user_id = u.id; + +-- name: WithSchema :one +SELECT sqlc.embed(bu) FROM baz.users AS bu; + +-- name: WithCrossSchema :many +SELECT sqlc.embed(u), sqlc.embed(bu) FROM users AS u +INNER JOIN baz.users bu ON u.id = bu.id; diff --git a/internal/endtoend/testdata/sqlc_embed/sqlite/schema.sql b/internal/endtoend/testdata/sqlc_embed/sqlite/schema.sql new file mode 100644 index 0000000..5a1d371 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/sqlite/schema.sql @@ -0,0 +1,19 @@ +ATTACH ':memory:' AS baz; + +CREATE TABLE users ( + id integer PRIMARY KEY, + name text NOT NULL, + age integer +); + +CREATE TABLE posts ( + id integer PRIMARY KEY, + user_id integer NOT NULL +); + +CREATE TABLE baz.users ( + id integer PRIMARY KEY, + name text NOT NULL +); + + diff --git a/internal/endtoend/testdata/sqlc_embed/sqlite/sqlc.json b/internal/endtoend/testdata/sqlc_embed/sqlite/sqlc.json new file mode 100644 index 0000000..cd66df0 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/sqlc_narg/mysql/go/db.go b/internal/endtoend/testdata/sqlc_narg/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/sqlc_narg/mysql/go/models.go b/internal/endtoend/testdata/sqlc_narg/mysql/go/models.go new file mode 100644 index 0000000..31a60f1 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/mysql/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar string + MaybeBar sql.NullString +} diff --git a/internal/endtoend/testdata/sqlc_narg/mysql/go/query.sql.go b/internal/endtoend/testdata/sqlc_narg/mysql/go/query.sql.go new file mode 100644 index 0000000..e3b4bb8 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/mysql/go/query.sql.go @@ -0,0 +1,119 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const identOnNonNullable = `-- name: IdentOnNonNullable :many +SELECT bar FROM foo WHERE bar = ? +` + +func (q *Queries) IdentOnNonNullable(ctx context.Context, bar sql.NullString) ([]string, error) { + rows, err := q.db.QueryContext(ctx, identOnNonNullable, bar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var bar string + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const identOnNullable = `-- name: IdentOnNullable :many +SELECT maybe_bar FROM foo WHERE maybe_bar = ? +` + +func (q *Queries) IdentOnNullable(ctx context.Context, maybeBar sql.NullString) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, identOnNullable, maybeBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var maybe_bar sql.NullString + if err := rows.Scan(&maybe_bar); err != nil { + return nil, err + } + items = append(items, maybe_bar) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const stringOnNonNullable = `-- name: StringOnNonNullable :many +SELECT bar FROM foo WHERE bar = ? +` + +func (q *Queries) StringOnNonNullable(ctx context.Context, bar sql.NullString) ([]string, error) { + rows, err := q.db.QueryContext(ctx, stringOnNonNullable, bar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var bar string + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const stringOnNullable = `-- name: StringOnNullable :many +SELECT maybe_bar FROM foo WHERE maybe_bar = ? +` + +func (q *Queries) StringOnNullable(ctx context.Context, maybeBar sql.NullString) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, stringOnNullable, maybeBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var maybe_bar sql.NullString + if err := rows.Scan(&maybe_bar); err != nil { + return nil, err + } + items = append(items, maybe_bar) + } + 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/sqlc_narg/mysql/query.sql b/internal/endtoend/testdata/sqlc_narg/mysql/query.sql new file mode 100644 index 0000000..103c737 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/mysql/query.sql @@ -0,0 +1,11 @@ +-- name: IdentOnNonNullable :many +SELECT bar FROM foo WHERE bar = sqlc.narg(bar); + +-- name: IdentOnNullable :many +SELECT maybe_bar FROM foo WHERE maybe_bar = sqlc.narg(maybe_bar); + +-- name: StringOnNonNullable :many +SELECT bar FROM foo WHERE bar = sqlc.narg('bar'); + +-- name: StringOnNullable :many +SELECT maybe_bar FROM foo WHERE maybe_bar = sqlc.narg('maybe_bar'); diff --git a/internal/endtoend/testdata/sqlc_narg/mysql/schema.sql b/internal/endtoend/testdata/sqlc_narg/mysql/schema.sql new file mode 100644 index 0000000..787f890 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text not null, maybe_bar text); + diff --git a/internal/endtoend/testdata/sqlc_narg/mysql/sqlc.json b/internal/endtoend/testdata/sqlc_narg/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/sqlc_narg/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..31a60f1 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v4/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar string + MaybeBar sql.NullString +} diff --git a/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..aa6e821 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,107 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const identOnNonNullable = `-- name: IdentOnNonNullable :many +SELECT bar FROM foo WHERE bar = $1 +` + +func (q *Queries) IdentOnNonNullable(ctx context.Context, bar sql.NullString) ([]string, error) { + rows, err := q.db.Query(ctx, identOnNonNullable, bar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var bar string + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const identOnNullable = `-- name: IdentOnNullable :many +SELECT maybe_bar FROM foo WHERE maybe_bar = $1 +` + +func (q *Queries) IdentOnNullable(ctx context.Context, maybeBar sql.NullString) ([]sql.NullString, error) { + rows, err := q.db.Query(ctx, identOnNullable, maybeBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var maybe_bar sql.NullString + if err := rows.Scan(&maybe_bar); err != nil { + return nil, err + } + items = append(items, maybe_bar) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const stringOnNonNullable = `-- name: StringOnNonNullable :many +SELECT bar FROM foo WHERE bar = $1 +` + +func (q *Queries) StringOnNonNullable(ctx context.Context, bar sql.NullString) ([]string, error) { + rows, err := q.db.Query(ctx, stringOnNonNullable, bar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var bar string + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const stringOnNullable = `-- name: StringOnNullable :many +SELECT maybe_bar FROM foo WHERE maybe_bar = $1 +` + +func (q *Queries) StringOnNullable(ctx context.Context, maybeBar sql.NullString) ([]sql.NullString, error) { + rows, err := q.db.Query(ctx, stringOnNullable, maybeBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var maybe_bar sql.NullString + if err := rows.Scan(&maybe_bar); err != nil { + return nil, err + } + items = append(items, maybe_bar) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..103c737 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v4/query.sql @@ -0,0 +1,11 @@ +-- name: IdentOnNonNullable :many +SELECT bar FROM foo WHERE bar = sqlc.narg(bar); + +-- name: IdentOnNullable :many +SELECT maybe_bar FROM foo WHERE maybe_bar = sqlc.narg(maybe_bar); + +-- name: StringOnNonNullable :many +SELECT bar FROM foo WHERE bar = sqlc.narg('bar'); + +-- name: StringOnNullable :many +SELECT maybe_bar FROM foo WHERE maybe_bar = sqlc.narg('maybe_bar'); diff --git a/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..787f890 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text not null, maybe_bar text); + diff --git a/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/sqlc_narg/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..b1df5a4 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + Bar string + MaybeBar pgtype.Text +} diff --git a/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..ca55c35 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,108 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const identOnNonNullable = `-- name: IdentOnNonNullable :many +SELECT bar FROM foo WHERE bar = $1 +` + +func (q *Queries) IdentOnNonNullable(ctx context.Context, bar pgtype.Text) ([]string, error) { + rows, err := q.db.Query(ctx, identOnNonNullable, bar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var bar string + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const identOnNullable = `-- name: IdentOnNullable :many +SELECT maybe_bar FROM foo WHERE maybe_bar = $1 +` + +func (q *Queries) IdentOnNullable(ctx context.Context, maybeBar pgtype.Text) ([]pgtype.Text, error) { + rows, err := q.db.Query(ctx, identOnNullable, maybeBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []pgtype.Text + for rows.Next() { + var maybe_bar pgtype.Text + if err := rows.Scan(&maybe_bar); err != nil { + return nil, err + } + items = append(items, maybe_bar) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const stringOnNonNullable = `-- name: StringOnNonNullable :many +SELECT bar FROM foo WHERE bar = $1 +` + +func (q *Queries) StringOnNonNullable(ctx context.Context, bar pgtype.Text) ([]string, error) { + rows, err := q.db.Query(ctx, stringOnNonNullable, bar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var bar string + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const stringOnNullable = `-- name: StringOnNullable :many +SELECT maybe_bar FROM foo WHERE maybe_bar = $1 +` + +func (q *Queries) StringOnNullable(ctx context.Context, maybeBar pgtype.Text) ([]pgtype.Text, error) { + rows, err := q.db.Query(ctx, stringOnNullable, maybeBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []pgtype.Text + for rows.Next() { + var maybe_bar pgtype.Text + if err := rows.Scan(&maybe_bar); err != nil { + return nil, err + } + items = append(items, maybe_bar) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..103c737 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v5/query.sql @@ -0,0 +1,11 @@ +-- name: IdentOnNonNullable :many +SELECT bar FROM foo WHERE bar = sqlc.narg(bar); + +-- name: IdentOnNullable :many +SELECT maybe_bar FROM foo WHERE maybe_bar = sqlc.narg(maybe_bar); + +-- name: StringOnNonNullable :many +SELECT bar FROM foo WHERE bar = sqlc.narg('bar'); + +-- name: StringOnNullable :many +SELECT maybe_bar FROM foo WHERE maybe_bar = sqlc.narg('maybe_bar'); diff --git a/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..787f890 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text not null, maybe_bar text); + diff --git a/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/sqlc_narg/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..31a60f1 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar string + MaybeBar sql.NullString +} diff --git a/internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..a982882 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,119 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const identOnNonNullable = `-- name: IdentOnNonNullable :many +SELECT bar FROM foo WHERE bar = $1 +` + +func (q *Queries) IdentOnNonNullable(ctx context.Context, bar sql.NullString) ([]string, error) { + rows, err := q.db.QueryContext(ctx, identOnNonNullable, bar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var bar string + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const identOnNullable = `-- name: IdentOnNullable :many +SELECT maybe_bar FROM foo WHERE maybe_bar = $1 +` + +func (q *Queries) IdentOnNullable(ctx context.Context, maybeBar sql.NullString) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, identOnNullable, maybeBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var maybe_bar sql.NullString + if err := rows.Scan(&maybe_bar); err != nil { + return nil, err + } + items = append(items, maybe_bar) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const stringOnNonNullable = `-- name: StringOnNonNullable :many +SELECT bar FROM foo WHERE bar = $1 +` + +func (q *Queries) StringOnNonNullable(ctx context.Context, bar sql.NullString) ([]string, error) { + rows, err := q.db.QueryContext(ctx, stringOnNonNullable, bar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var bar string + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const stringOnNullable = `-- name: StringOnNullable :many +SELECT maybe_bar FROM foo WHERE maybe_bar = $1 +` + +func (q *Queries) StringOnNullable(ctx context.Context, maybeBar sql.NullString) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, stringOnNullable, maybeBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var maybe_bar sql.NullString + if err := rows.Scan(&maybe_bar); err != nil { + return nil, err + } + items = append(items, maybe_bar) + } + 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/sqlc_narg/postgresql/stdlib/go_strict/db.go b/internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/go_strict/db.go new file mode 100644 index 0000000..b205553 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/go_strict/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest_strict + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/sqlc_narg/postgresql/stdlib/go_strict/models.go b/internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/go_strict/models.go new file mode 100644 index 0000000..8c0b3d3 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/go_strict/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest_strict + +import ( + "database/sql" +) + +type Foo struct { + Bar string + MaybeBar sql.NullString +} diff --git a/internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/go_strict/query.sql.go b/internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/go_strict/query.sql.go new file mode 100644 index 0000000..1feb465 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/go_strict/query.sql.go @@ -0,0 +1,119 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest_strict + +import ( + "context" + "database/sql" +) + +const identOnNonNullable = `-- name: IdentOnNonNullable :many +SELECT bar FROM foo WHERE bar = $1 +` + +func (q *Queries) IdentOnNonNullable(ctx context.Context, bar sql.NullString) ([]string, error) { + rows, err := q.db.QueryContext(ctx, identOnNonNullable, bar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var bar string + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const identOnNullable = `-- name: IdentOnNullable :many +SELECT maybe_bar FROM foo WHERE maybe_bar = $1 +` + +func (q *Queries) IdentOnNullable(ctx context.Context, maybeBar sql.NullString) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, identOnNullable, maybeBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var maybe_bar sql.NullString + if err := rows.Scan(&maybe_bar); err != nil { + return nil, err + } + items = append(items, maybe_bar) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const stringOnNonNullable = `-- name: StringOnNonNullable :many +SELECT bar FROM foo WHERE bar = $1 +` + +func (q *Queries) StringOnNonNullable(ctx context.Context, bar sql.NullString) ([]string, error) { + rows, err := q.db.QueryContext(ctx, stringOnNonNullable, bar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var bar string + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const stringOnNullable = `-- name: StringOnNullable :many +SELECT maybe_bar FROM foo WHERE maybe_bar = $1 +` + +func (q *Queries) StringOnNullable(ctx context.Context, maybeBar sql.NullString) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, stringOnNullable, maybeBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var maybe_bar sql.NullString + if err := rows.Scan(&maybe_bar); err != nil { + return nil, err + } + items = append(items, maybe_bar) + } + 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/sqlc_narg/postgresql/stdlib/query.sql b/internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/query.sql new file mode 100644 index 0000000..103c737 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/query.sql @@ -0,0 +1,11 @@ +-- name: IdentOnNonNullable :many +SELECT bar FROM foo WHERE bar = sqlc.narg(bar); + +-- name: IdentOnNullable :many +SELECT maybe_bar FROM foo WHERE maybe_bar = sqlc.narg(maybe_bar); + +-- name: StringOnNonNullable :many +SELECT bar FROM foo WHERE bar = sqlc.narg('bar'); + +-- name: StringOnNullable :many +SELECT maybe_bar FROM foo WHERE maybe_bar = sqlc.narg('maybe_bar'); diff --git a/internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..cf73294 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (bar text not null, maybe_bar text); \ No newline at end of file diff --git a/internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f5873c1 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/postgresql/stdlib/sqlc.json @@ -0,0 +1,28 @@ +{ + "version": "2", + "sql": [ + { + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "gen": { + "go": { + "package": "querytest", + "out": "go" + } + } + }, + { + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "strict_function_checks": true, + "gen": { + "go": { + "package": "querytest_strict", + "out": "go_strict" + } + } + } + ] +} diff --git a/internal/endtoend/testdata/sqlc_narg/sqlite/go/db.go b/internal/endtoend/testdata/sqlc_narg/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/sqlc_narg/sqlite/go/models.go b/internal/endtoend/testdata/sqlc_narg/sqlite/go/models.go new file mode 100644 index 0000000..31a60f1 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/sqlite/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar string + MaybeBar sql.NullString +} diff --git a/internal/endtoend/testdata/sqlc_narg/sqlite/go/query.sql.go b/internal/endtoend/testdata/sqlc_narg/sqlite/go/query.sql.go new file mode 100644 index 0000000..a5fd45a --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/sqlite/go/query.sql.go @@ -0,0 +1,119 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const identOnNonNullable = `-- name: IdentOnNonNullable :many +SELECT bar FROM foo WHERE bar = ?1 +` + +func (q *Queries) IdentOnNonNullable(ctx context.Context, bar sql.NullString) ([]string, error) { + rows, err := q.db.QueryContext(ctx, identOnNonNullable, bar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var bar string + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const identOnNullable = `-- name: IdentOnNullable :many +SELECT maybe_bar FROM foo WHERE maybe_bar = ?1 +` + +func (q *Queries) IdentOnNullable(ctx context.Context, maybeBar sql.NullString) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, identOnNullable, maybeBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var maybe_bar sql.NullString + if err := rows.Scan(&maybe_bar); err != nil { + return nil, err + } + items = append(items, maybe_bar) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const stringOnNonNullable = `-- name: StringOnNonNullable :many +SELECT bar FROM foo WHERE bar = ?1 +` + +func (q *Queries) StringOnNonNullable(ctx context.Context, bar sql.NullString) ([]string, error) { + rows, err := q.db.QueryContext(ctx, stringOnNonNullable, bar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var bar string + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const stringOnNullable = `-- name: StringOnNullable :many +SELECT maybe_bar FROM foo WHERE maybe_bar = ?1 +` + +func (q *Queries) StringOnNullable(ctx context.Context, maybeBar sql.NullString) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, stringOnNullable, maybeBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var maybe_bar sql.NullString + if err := rows.Scan(&maybe_bar); err != nil { + return nil, err + } + items = append(items, maybe_bar) + } + 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/sqlc_narg/sqlite/query.sql b/internal/endtoend/testdata/sqlc_narg/sqlite/query.sql new file mode 100644 index 0000000..103c737 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/sqlite/query.sql @@ -0,0 +1,11 @@ +-- name: IdentOnNonNullable :many +SELECT bar FROM foo WHERE bar = sqlc.narg(bar); + +-- name: IdentOnNullable :many +SELECT maybe_bar FROM foo WHERE maybe_bar = sqlc.narg(maybe_bar); + +-- name: StringOnNonNullable :many +SELECT bar FROM foo WHERE bar = sqlc.narg('bar'); + +-- name: StringOnNullable :many +SELECT maybe_bar FROM foo WHERE maybe_bar = sqlc.narg('maybe_bar'); diff --git a/internal/endtoend/testdata/sqlc_narg/sqlite/schema.sql b/internal/endtoend/testdata/sqlc_narg/sqlite/schema.sql new file mode 100644 index 0000000..787f890 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/sqlite/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text not null, maybe_bar text); + diff --git a/internal/endtoend/testdata/sqlc_narg/sqlite/sqlc.json b/internal/endtoend/testdata/sqlc_narg/sqlite/sqlc.json new file mode 100644 index 0000000..e63bc00 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_narg/sqlite/sqlc.json @@ -0,0 +1,16 @@ +{ + "version": "2", + "sql": [ + { + "engine": "sqlite", + "schema": "schema.sql", + "queries": "query.sql", + "gen": { + "go": { + "package": "querytest", + "out": "go" + } + } + } + ] +} diff --git a/internal/endtoend/testdata/sqlc_slice/mysql/go/db.go b/internal/endtoend/testdata/sqlc_slice/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/sqlc_slice/mysql/go/models.go b/internal/endtoend/testdata/sqlc_slice/mysql/go/models.go new file mode 100644 index 0000000..b163196 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice/mysql/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + + "github.com/sqlc-dev/sqlc-testdata/mysql" +) + +type Foo struct { + ID int32 + Name string + Bar sql.NullString + Mystr mysql.ID +} diff --git a/internal/endtoend/testdata/sqlc_slice/mysql/go/query.sql.go b/internal/endtoend/testdata/sqlc_slice/mysql/go/query.sql.go new file mode 100644 index 0000000..0d213c5 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice/mysql/go/query.sql.go @@ -0,0 +1,282 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" + "strings" + + "github.com/sqlc-dev/sqlc-testdata/mysql" +) + +const funcNullable = `-- name: FuncNullable :many +SELECT bar FROM foo +WHERE id IN (/*SLICE:favourites*/?) +` + +func (q *Queries) FuncNullable(ctx context.Context, favourites []int32) ([]sql.NullString, error) { + query := funcNullable + var queryParams []any + if len(favourites) > 0 { + for _, v := range favourites { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(favourites))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) + } + rows, err := q.db.QueryContext(ctx, query, queryParams...) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var bar sql.NullString + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const funcNullableNot = `-- name: FuncNullableNot :many +SELECT bar FROM foo +WHERE id NOT IN (/*SLICE:favourites*/?) +` + +func (q *Queries) FuncNullableNot(ctx context.Context, favourites []int32) ([]sql.NullString, error) { + query := funcNullableNot + var queryParams []any + if len(favourites) > 0 { + for _, v := range favourites { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(favourites))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) + } + rows, err := q.db.QueryContext(ctx, query, queryParams...) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var bar sql.NullString + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const funcParamIdent = `-- name: FuncParamIdent :many +SELECT name FROM foo +WHERE name = ? + AND id IN (/*SLICE:favourites*/?) +` + +type FuncParamIdentParams struct { + Slug string + Favourites []int32 +} + +func (q *Queries) FuncParamIdent(ctx context.Context, arg FuncParamIdentParams) ([]string, error) { + query := funcParamIdent + var queryParams []any + queryParams = append(queryParams, arg.Slug) + if len(arg.Favourites) > 0 { + for _, v := range arg.Favourites { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(arg.Favourites))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) + } + rows, err := q.db.QueryContext(ctx, query, queryParams...) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const funcParamSoloArg = `-- name: FuncParamSoloArg :many +SELECT name FROM foo +WHERE id IN (/*SLICE:favourites*/?) +` + +func (q *Queries) FuncParamSoloArg(ctx context.Context, favourites []int32) ([]string, error) { + query := funcParamSoloArg + var queryParams []any + if len(favourites) > 0 { + for _, v := range favourites { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(favourites))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) + } + rows, err := q.db.QueryContext(ctx, query, queryParams...) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const funcParamString = `-- name: FuncParamString :many +SELECT name FROM foo +WHERE name = ? + AND id IN (/*SLICE:favourites*/?) +` + +type FuncParamStringParams struct { + Slug string + Favourites []int32 +} + +func (q *Queries) FuncParamString(ctx context.Context, arg FuncParamStringParams) ([]string, error) { + query := funcParamString + var queryParams []any + queryParams = append(queryParams, arg.Slug) + if len(arg.Favourites) > 0 { + for _, v := range arg.Favourites { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(arg.Favourites))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) + } + rows, err := q.db.QueryContext(ctx, query, queryParams...) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const sliceExec = `-- name: SliceExec :exec +UPDATE foo SET name = ? +WHERE id IN (/*SLICE:favourites*/?) +` + +type SliceExecParams struct { + Slug string + Favourites []int32 +} + +func (q *Queries) SliceExec(ctx context.Context, arg SliceExecParams) error { + query := sliceExec + var queryParams []any + queryParams = append(queryParams, arg.Slug) + if len(arg.Favourites) > 0 { + for _, v := range arg.Favourites { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(arg.Favourites))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) + } + _, err := q.db.ExecContext(ctx, query, queryParams...) + return err +} + +const typedMyStr = `-- name: TypedMyStr :many +SELECT bar FROM foo +WHERE mystr IN (/*SLICE:mystr*/?) +` + +func (q *Queries) TypedMyStr(ctx context.Context, mystr []mysql.ID) ([]sql.NullString, error) { + query := typedMyStr + var queryParams []any + if len(mystr) > 0 { + for _, v := range mystr { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:mystr*/?", strings.Repeat(",?", len(mystr))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:mystr*/?", "NULL", 1) + } + rows, err := q.db.QueryContext(ctx, query, queryParams...) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var bar sql.NullString + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + 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/sqlc_slice/mysql/query.sql b/internal/endtoend/testdata/sqlc_slice/mysql/query.sql new file mode 100644 index 0000000..6cf377d --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice/mysql/query.sql @@ -0,0 +1,29 @@ +/* name: FuncParamIdent :many */ +SELECT name FROM foo +WHERE name = sqlc.arg(slug) + AND id IN (sqlc.slice(favourites)); + +/* name: FuncParamString :many */ +SELECT name FROM foo +WHERE name = sqlc.arg('slug') + AND id IN (sqlc.slice('favourites')); + +/* name: FuncParamSoloArg :many */ +SELECT name FROM foo +WHERE id IN (sqlc.slice('favourites')); + +/* name: SliceExec :exec */ +UPDATE foo SET name = sqlc.arg(slug) +WHERE id IN (sqlc.slice(favourites)); + +/* name: FuncNullable :many */ +SELECT bar FROM foo +WHERE id IN (sqlc.slice('favourites')); + +/* name: FuncNullableNot :many */ +SELECT bar FROM foo +WHERE id NOT IN (sqlc.slice('favourites')); + +/* name: TypedMyStr :many */ +SELECT bar FROM foo +WHERE mystr IN (sqlc.slice(mystr)); diff --git a/internal/endtoend/testdata/sqlc_slice/mysql/schema.sql b/internal/endtoend/testdata/sqlc_slice/mysql/schema.sql new file mode 100644 index 0000000..9a803f2 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (id int not null, name text not null, bar text null, mystr text not null); + diff --git a/internal/endtoend/testdata/sqlc_slice/mysql/sqlc.json b/internal/endtoend/testdata/sqlc_slice/mysql/sqlc.json new file mode 100644 index 0000000..cd360d6 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice/mysql/sqlc.json @@ -0,0 +1,18 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ], + "overrides": [ + { + "column": "foo.mystr", + "go_type": "github.com/sqlc-dev/sqlc-testdata/mysql.ID" + } + ] +} diff --git a/internal/endtoend/testdata/sqlc_slice/postgresql/pgx/go/db.go b/internal/endtoend/testdata/sqlc_slice/postgresql/pgx/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/sqlc_slice/postgresql/pgx/go/models.go b/internal/endtoend/testdata/sqlc_slice/postgresql/pgx/go/models.go new file mode 100644 index 0000000..9399612 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice/postgresql/pgx/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + ID int32 + Name string +} diff --git a/internal/endtoend/testdata/sqlc_slice/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/sqlc_slice/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..e3f3dd5 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice/postgresql/pgx/go/query.sql.go @@ -0,0 +1,70 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const funcParamIdent = `-- name: FuncParamIdent :many +SELECT name FROM foo WHERE name = $1 + AND id IN ($2) +` + +type FuncParamIdentParams struct { + Slug string + Favourites []int32 +} + +func (q *Queries) FuncParamIdent(ctx context.Context, arg FuncParamIdentParams) ([]string, error) { + rows, err := q.db.Query(ctx, funcParamIdent, arg.Slug, arg.Favourites) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const funcParamString = `-- name: FuncParamString :many +SELECT name FROM foo WHERE name = $1 + AND id IN ($2) +` + +type FuncParamStringParams struct { + Slug string + Favourites []int32 +} + +func (q *Queries) FuncParamString(ctx context.Context, arg FuncParamStringParams) ([]string, error) { + rows, err := q.db.Query(ctx, funcParamString, arg.Slug, arg.Favourites) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/sqlc_slice/postgresql/pgx/query.sql b/internal/endtoend/testdata/sqlc_slice/postgresql/pgx/query.sql new file mode 100644 index 0000000..2a5fccf --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice/postgresql/pgx/query.sql @@ -0,0 +1,7 @@ +-- name: FuncParamIdent :many +SELECT name FROM foo WHERE name = sqlc.arg(slug) + AND id IN (sqlc.slice(favourites)); + +-- name: FuncParamString :many +SELECT name FROM foo WHERE name = sqlc.arg('slug') + AND id IN (sqlc.slice('favourites')); diff --git a/internal/endtoend/testdata/sqlc_slice/postgresql/pgx/schema.sql b/internal/endtoend/testdata/sqlc_slice/postgresql/pgx/schema.sql new file mode 100644 index 0000000..43e6433 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice/postgresql/pgx/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (id int not null, name text not null); + diff --git a/internal/endtoend/testdata/sqlc_slice/postgresql/pgx/sqlc.json b/internal/endtoend/testdata/sqlc_slice/postgresql/pgx/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice/postgresql/pgx/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/sqlc_slice/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/sqlc_slice/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/sqlc_slice/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/sqlc_slice/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..9399612 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice/postgresql/stdlib/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + ID int32 + Name string +} diff --git a/internal/endtoend/testdata/sqlc_slice/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/sqlc_slice/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..1c72c36 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,101 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "strings" +) + +const funcParamIdent = `-- name: FuncParamIdent :many +SELECT name FROM foo +WHERE name = $1 + AND id IN ($2) +` + +type FuncParamIdentParams struct { + Slug string + Favourites []int32 +} + +func (q *Queries) FuncParamIdent(ctx context.Context, arg FuncParamIdentParams) ([]string, error) { + query := funcParamIdent + var queryParams []any + queryParams = append(queryParams, arg.Slug) + if len(arg.Favourites) > 0 { + for _, v := range arg.Favourites { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(arg.Favourites))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) + } + rows, err := q.db.QueryContext(ctx, query, queryParams...) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const funcParamString = `-- name: FuncParamString :many +SELECT name FROM foo +WHERE name = $1 + AND id IN ($2) +` + +type FuncParamStringParams struct { + Slug string + Favourites []int32 +} + +func (q *Queries) FuncParamString(ctx context.Context, arg FuncParamStringParams) ([]string, error) { + query := funcParamString + var queryParams []any + queryParams = append(queryParams, arg.Slug) + if len(arg.Favourites) > 0 { + for _, v := range arg.Favourites { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(arg.Favourites))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) + } + rows, err := q.db.QueryContext(ctx, query, queryParams...) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + 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/sqlc_slice/postgresql/stdlib/query.sql b/internal/endtoend/testdata/sqlc_slice/postgresql/stdlib/query.sql new file mode 100644 index 0000000..3c762d3 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice/postgresql/stdlib/query.sql @@ -0,0 +1,11 @@ +/* name: FuncParamIdent :many */ +SELECT name FROM foo +WHERE name = sqlc.arg(slug) + AND id IN (sqlc.slice(favourites)); + + + +/* name: FuncParamString :many */ +SELECT name FROM foo +WHERE name = sqlc.arg('slug') + AND id IN (sqlc.slice('favourites')); diff --git a/internal/endtoend/testdata/sqlc_slice/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/sqlc_slice/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..43e6433 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (id int not null, name text not null); + diff --git a/internal/endtoend/testdata/sqlc_slice/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/sqlc_slice/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..cd51867 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/sqlc_slice/sqlite/go/db.go b/internal/endtoend/testdata/sqlc_slice/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/sqlc_slice/sqlite/go/models.go b/internal/endtoend/testdata/sqlc_slice/sqlite/go/models.go new file mode 100644 index 0000000..22b127c --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice/sqlite/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + ID int64 + Name string + Bar sql.NullString +} diff --git a/internal/endtoend/testdata/sqlc_slice/sqlite/go/query.sql.go b/internal/endtoend/testdata/sqlc_slice/sqlite/go/query.sql.go new file mode 100644 index 0000000..2f36290 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice/sqlite/go/query.sql.go @@ -0,0 +1,242 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" + "strings" +) + +const funcNullable = `-- name: FuncNullable :many +SELECT bar FROM foo +WHERE id IN (/*SLICE:favourites*/?) +` + +func (q *Queries) FuncNullable(ctx context.Context, favourites []int64) ([]sql.NullString, error) { + query := funcNullable + var queryParams []any + if len(favourites) > 0 { + for _, v := range favourites { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(favourites))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) + } + rows, err := q.db.QueryContext(ctx, query, queryParams...) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var bar sql.NullString + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const funcNullableNot = `-- name: FuncNullableNot :many +SELECT bar FROM foo +WHERE id NOT IN (/*SLICE:favourites*/?) +` + +func (q *Queries) FuncNullableNot(ctx context.Context, favourites []int64) ([]sql.NullString, error) { + query := funcNullableNot + var queryParams []any + if len(favourites) > 0 { + for _, v := range favourites { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(favourites))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) + } + rows, err := q.db.QueryContext(ctx, query, queryParams...) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var bar sql.NullString + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const funcParamIdent = `-- name: FuncParamIdent :many +SELECT name FROM foo +WHERE name = ?1 + AND id IN (/*SLICE:favourites*/?) +` + +type FuncParamIdentParams struct { + Slug string + Favourites []int64 +} + +func (q *Queries) FuncParamIdent(ctx context.Context, arg FuncParamIdentParams) ([]string, error) { + query := funcParamIdent + var queryParams []any + queryParams = append(queryParams, arg.Slug) + if len(arg.Favourites) > 0 { + for _, v := range arg.Favourites { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(arg.Favourites))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) + } + rows, err := q.db.QueryContext(ctx, query, queryParams...) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const funcParamSoloArg = `-- name: FuncParamSoloArg :many +SELECT name FROM foo +WHERE id IN (/*SLICE:favourites*/?) +` + +func (q *Queries) FuncParamSoloArg(ctx context.Context, favourites []int64) ([]string, error) { + query := funcParamSoloArg + var queryParams []any + if len(favourites) > 0 { + for _, v := range favourites { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(favourites))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) + } + rows, err := q.db.QueryContext(ctx, query, queryParams...) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const funcParamString = `-- name: FuncParamString :many +SELECT name FROM foo +WHERE name = ?1 + AND id IN (/*SLICE:favourites*/?) +` + +type FuncParamStringParams struct { + Slug string + Favourites []int64 +} + +func (q *Queries) FuncParamString(ctx context.Context, arg FuncParamStringParams) ([]string, error) { + query := funcParamString + var queryParams []any + queryParams = append(queryParams, arg.Slug) + if len(arg.Favourites) > 0 { + for _, v := range arg.Favourites { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(arg.Favourites))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) + } + rows, err := q.db.QueryContext(ctx, query, queryParams...) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const sliceExec = `-- name: SliceExec :exec +UPDATE foo SET name = ?1 +WHERE id IN (/*SLICE:favourites*/?) +` + +type SliceExecParams struct { + Slug string + Favourites []int64 +} + +func (q *Queries) SliceExec(ctx context.Context, arg SliceExecParams) error { + query := sliceExec + var queryParams []any + queryParams = append(queryParams, arg.Slug) + if len(arg.Favourites) > 0 { + for _, v := range arg.Favourites { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(arg.Favourites))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) + } + _, err := q.db.ExecContext(ctx, query, queryParams...) + return err +} diff --git a/internal/endtoend/testdata/sqlc_slice/sqlite/query.sql b/internal/endtoend/testdata/sqlc_slice/sqlite/query.sql new file mode 100644 index 0000000..710341e --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice/sqlite/query.sql @@ -0,0 +1,25 @@ +/* name: FuncParamIdent :many */ +SELECT name FROM foo +WHERE name = sqlc.arg(slug) + AND id IN (sqlc.slice(favourites)); + +/* name: FuncParamString :many */ +SELECT name FROM foo +WHERE name = sqlc.arg('slug') + AND id IN (sqlc.slice('favourites')); + +/* name: FuncParamSoloArg :many */ +SELECT name FROM foo +WHERE id IN (sqlc.slice('favourites')); + +/* name: SliceExec :exec */ +UPDATE foo SET name = sqlc.arg(slug) +WHERE id IN (sqlc.slice(favourites)); + +/* name: FuncNullable :many */ +SELECT bar FROM foo +WHERE id IN (sqlc.slice('favourites')); + +/* name: FuncNullableNot :many */ +SELECT bar FROM foo +WHERE id NOT IN (sqlc.slice('favourites')); \ No newline at end of file diff --git a/internal/endtoend/testdata/sqlc_slice/sqlite/schema.sql b/internal/endtoend/testdata/sqlc_slice/sqlite/schema.sql new file mode 100644 index 0000000..b01b6f5 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice/sqlite/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (id int not null, name text not null, bar text); + diff --git a/internal/endtoend/testdata/sqlc_slice/sqlite/sqlc.json b/internal/endtoend/testdata/sqlc_slice/sqlite/sqlc.json new file mode 100644 index 0000000..1f9d43d --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "sqlite", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/sqlc_slice_prepared/sqlite/go/db.go b/internal/endtoend/testdata/sqlc_slice_prepared/sqlite/go/db.go new file mode 100644 index 0000000..9ebfe37 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice_prepared/sqlite/go/db.go @@ -0,0 +1,88 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" + "fmt" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +func Prepare(ctx context.Context, db DBTX) (*Queries, error) { + q := Queries{db: db} + var err error + if q.funcParamIdentStmt, err = db.PrepareContext(ctx, funcParamIdent); err != nil { + return nil, fmt.Errorf("error preparing query FuncParamIdent: %w", err) + } + return &q, nil +} + +func (q *Queries) Close() error { + var err error + if q.funcParamIdentStmt != nil { + if cerr := q.funcParamIdentStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing funcParamIdentStmt: %w", cerr) + } + } + return err +} + +func (q *Queries) exec(ctx context.Context, stmt *sql.Stmt, query string, args ...any) (sql.Result, error) { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).ExecContext(ctx, args...) + case stmt != nil: + return stmt.ExecContext(ctx, args...) + default: + return q.db.ExecContext(ctx, query, args...) + } +} + +func (q *Queries) query(ctx context.Context, stmt *sql.Stmt, query string, args ...any) (*sql.Rows, error) { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).QueryContext(ctx, args...) + case stmt != nil: + return stmt.QueryContext(ctx, args...) + default: + return q.db.QueryContext(ctx, query, args...) + } +} + +func (q *Queries) queryRow(ctx context.Context, stmt *sql.Stmt, query string, args ...any) *sql.Row { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).QueryRowContext(ctx, args...) + case stmt != nil: + return stmt.QueryRowContext(ctx, args...) + default: + return q.db.QueryRowContext(ctx, query, args...) + } +} + +type Queries struct { + db DBTX + tx *sql.Tx + funcParamIdentStmt *sql.Stmt +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + tx: tx, + funcParamIdentStmt: q.funcParamIdentStmt, + } +} diff --git a/internal/endtoend/testdata/sqlc_slice_prepared/sqlite/go/models.go b/internal/endtoend/testdata/sqlc_slice_prepared/sqlite/go/models.go new file mode 100644 index 0000000..22b127c --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice_prepared/sqlite/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + ID int64 + Name string + Bar sql.NullString +} diff --git a/internal/endtoend/testdata/sqlc_slice_prepared/sqlite/go/query.sql.go b/internal/endtoend/testdata/sqlc_slice_prepared/sqlite/go/query.sql.go new file mode 100644 index 0000000..aec6437 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice_prepared/sqlite/go/query.sql.go @@ -0,0 +1,56 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "strings" +) + +const funcParamIdent = `-- name: FuncParamIdent :many +SELECT name FROM foo +WHERE name = ?1 + AND id IN (/*SLICE:favourites*/?) +` + +type FuncParamIdentParams struct { + Slug string + Favourites []int64 +} + +func (q *Queries) FuncParamIdent(ctx context.Context, arg FuncParamIdentParams) ([]string, error) { + query := funcParamIdent + var queryParams []any + queryParams = append(queryParams, arg.Slug) + if len(arg.Favourites) > 0 { + for _, v := range arg.Favourites { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(arg.Favourites))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) + } + rows, err := q.query(ctx, nil, query, queryParams...) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + 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/sqlc_slice_prepared/sqlite/query.sql b/internal/endtoend/testdata/sqlc_slice_prepared/sqlite/query.sql new file mode 100644 index 0000000..57b9857 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice_prepared/sqlite/query.sql @@ -0,0 +1,4 @@ +/* name: FuncParamIdent :many */ +SELECT name FROM foo +WHERE name = sqlc.arg(slug) + AND id IN (sqlc.slice(favourites)); diff --git a/internal/endtoend/testdata/sqlc_slice_prepared/sqlite/schema.sql b/internal/endtoend/testdata/sqlc_slice_prepared/sqlite/schema.sql new file mode 100644 index 0000000..b01b6f5 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice_prepared/sqlite/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (id int not null, name text not null, bar text); + diff --git a/internal/endtoend/testdata/sqlc_slice_prepared/sqlite/sqlc.json b/internal/endtoend/testdata/sqlc_slice_prepared/sqlite/sqlc.json new file mode 100644 index 0000000..fcb534e --- /dev/null +++ b/internal/endtoend/testdata/sqlc_slice_prepared/sqlite/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "engine": "sqlite", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_prepared_queries": true + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/sqlite_skip_todo/db/db.go b/internal/endtoend/testdata/sqlite_skip_todo/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/sqlite_skip_todo/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/sqlite_skip_todo/db/models.go b/internal/endtoend/testdata/sqlite_skip_todo/db/models.go new file mode 100644 index 0000000..d9ddf0a --- /dev/null +++ b/internal/endtoend/testdata/sqlite_skip_todo/db/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString +} diff --git a/internal/endtoend/testdata/sqlite_skip_todo/db/query.sql.go b/internal/endtoend/testdata/sqlite_skip_todo/db/query.sql.go new file mode 100644 index 0000000..2721172 --- /dev/null +++ b/internal/endtoend/testdata/sqlite_skip_todo/db/query.sql.go @@ -0,0 +1,67 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" + "database/sql" +) + +const getFoo = `-- name: GetFoo :many +SELECT bar +FROM foo +WHERE bar = ? +` + +func (q *Queries) GetFoo(ctx context.Context, bar sql.NullString) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, getFoo, bar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var bar sql.NullString + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listFoo = `-- name: ListFoo :many +SELECT bar FROM foo +` + +func (q *Queries) ListFoo(ctx context.Context) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, listFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var bar sql.NullString + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + 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/sqlite_skip_todo/query.sql b/internal/endtoend/testdata/sqlite_skip_todo/query.sql new file mode 100644 index 0000000..5e05522 --- /dev/null +++ b/internal/endtoend/testdata/sqlite_skip_todo/query.sql @@ -0,0 +1,16 @@ +-- name: PragmaForeignKeysEnable :exec +PRAGMA foreign_keys = 1; + +-- name: ListFoo :many +SELECT * FROM foo; + +-- name: PragmaForeignKeysDisable :exec +PRAGMA foreign_keys = 0; + +-- name: PragmaForeignKeysGet :one +PRAGMA foreign_keys; + +-- name: GetFoo :many +SELECT * +FROM foo +WHERE bar = ?; diff --git a/internal/endtoend/testdata/sqlite_skip_todo/schema.sql b/internal/endtoend/testdata/sqlite_skip_todo/schema.sql new file mode 100644 index 0000000..010d09e --- /dev/null +++ b/internal/endtoend/testdata/sqlite_skip_todo/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo ( + bar text +); diff --git a/internal/endtoend/testdata/sqlite_skip_todo/sqlc.json b/internal/endtoend/testdata/sqlite_skip_todo/sqlc.json new file mode 100644 index 0000000..cbd787d --- /dev/null +++ b/internal/endtoend/testdata/sqlite_skip_todo/sqlc.json @@ -0,0 +1,16 @@ +{ + "version": "2", + "sql": [ + { + "engine": "sqlite", + "queries": "query.sql", + "schema": "schema.sql", + "gen": { + "go": { + "package": "db", + "out": "db" + } + } + } + ] +} diff --git a/internal/endtoend/testdata/sqlite_table_options/sqlite/go/db.go b/internal/endtoend/testdata/sqlite_table_options/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/sqlite_table_options/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/sqlite_table_options/sqlite/go/models.go b/internal/endtoend/testdata/sqlite_table_options/sqlite/go/models.go new file mode 100644 index 0000000..8d40f61 --- /dev/null +++ b/internal/endtoend/testdata/sqlite_table_options/sqlite/go/models.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Authors1 struct { + ID int64 + Name string + Bio sql.NullString +} + +type Authors2 struct { + ID int64 + Name string + Bio sql.NullString +} + +type Authors3 struct { + ID int64 + Name string + Bio sql.NullString +} + +type Authors4 struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/sqlite_table_options/sqlite/go/query.sql.go b/internal/endtoend/testdata/sqlite_table_options/sqlite/go/query.sql.go new file mode 100644 index 0000000..6f1e81d --- /dev/null +++ b/internal/endtoend/testdata/sqlite_table_options/sqlite/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, bio +FROM authors1 +WHERE id = ?1 +LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Authors1, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Authors1 + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} diff --git a/internal/endtoend/testdata/sqlite_table_options/sqlite/query.sql b/internal/endtoend/testdata/sqlite_table_options/sqlite/query.sql new file mode 100644 index 0000000..2fe76dc --- /dev/null +++ b/internal/endtoend/testdata/sqlite_table_options/sqlite/query.sql @@ -0,0 +1,5 @@ +-- name: GetAuthor :one +SELECT * +FROM authors1 +WHERE id = ?1 +LIMIT 1; diff --git a/internal/endtoend/testdata/sqlite_table_options/sqlite/schema.sql b/internal/endtoend/testdata/sqlite_table_options/sqlite/schema.sql new file mode 100644 index 0000000..bb0741a --- /dev/null +++ b/internal/endtoend/testdata/sqlite_table_options/sqlite/schema.sql @@ -0,0 +1,24 @@ +CREATE TABLE authors1 ( + id INTEGER PRIMARY KEY, + name text NOT NULL, + bio text +) STRICT, WITHOUT ROWID; + +CREATE TABLE authors2 ( + id INTEGER PRIMARY KEY, + name text NOT NULL, + bio text +) WITHOUT ROWID, STRICT; + +CREATE TABLE authors3 ( + id INTEGER PRIMARY KEY, + name text NOT NULL, + bio text +) WITHOUT ROWID; + +CREATE TABLE authors4 ( + id INTEGER PRIMARY KEY, + name text NOT NULL, + bio text +) STRICT; + diff --git a/internal/endtoend/testdata/sqlite_table_options/sqlite/sqlc.json b/internal/endtoend/testdata/sqlite_table_options/sqlite/sqlc.json new file mode 100644 index 0000000..ea4a234 --- /dev/null +++ b/internal/endtoend/testdata/sqlite_table_options/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "schema": "schema.sql", + "queries": "query.sql", + "name": "querytest" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/star_expansion/mysql/go/db.go b/internal/endtoend/testdata/star_expansion/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/mysql/go/models.go b/internal/endtoend/testdata/star_expansion/mysql/go/models.go new file mode 100644 index 0000000..a26317d --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/mysql/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString + B sql.NullString +} diff --git a/internal/endtoend/testdata/star_expansion/mysql/go/query.sql.go b/internal/endtoend/testdata/star_expansion/mysql/go/query.sql.go new file mode 100644 index 0000000..b8abfb7 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/mysql/go/query.sql.go @@ -0,0 +1,81 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// 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/mysql/query.sql b/internal/endtoend/testdata/star_expansion/mysql/query.sql new file mode 100644 index 0000000..2461d01 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/mysql/query.sql @@ -0,0 +1,5 @@ +/* name: StarExpansion :many */ +SELECT *, *, foo.* FROM foo; + +/* name: StarQuotedExpansion :many */ +SELECT `t`.* FROM foo `t`; diff --git a/internal/endtoend/testdata/star_expansion/mysql/schema.sql b/internal/endtoend/testdata/star_expansion/mysql/schema.sql new file mode 100644 index 0000000..a68a0e4 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b text); + diff --git a/internal/endtoend/testdata/star_expansion/mysql/sqlc.json b/internal/endtoend/testdata/star_expansion/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/star_expansion/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a26317d --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString + B sql.NullString +} 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 new file mode 100644 index 0000000..5f01bff --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,75 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// 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.Query(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.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.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 new file mode 100644 index 0000000..9588332 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/query.sql @@ -0,0 +1,5 @@ +-- 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/v4/schema.sql b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..a68a0e4 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b text); + diff --git a/internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/star_expansion/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..463744d --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + A pgtype.Text + B pgtype.Text +} 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 new file mode 100644 index 0000000..4a3ce47 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,76 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const starExpansion = `-- name: StarExpansion :many +SELECT a, b, a, b, foo.a, foo.b FROM foo +` + +type StarExpansionRow struct { + A pgtype.Text + B pgtype.Text + A_2 pgtype.Text + B_2 pgtype.Text + A_3 pgtype.Text + B_3 pgtype.Text +} + +func (q *Queries) StarExpansion(ctx context.Context) ([]StarExpansionRow, error) { + rows, err := q.db.Query(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.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.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 new file mode 100644 index 0000000..9588332 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/query.sql @@ -0,0 +1,5 @@ +-- 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/schema.sql b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..a68a0e4 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b text); + diff --git a/internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/star_expansion/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/star_expansion/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/star_expansion/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a26317d --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/postgresql/stdlib/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString + B sql.NullString +} 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 new file mode 100644 index 0000000..b56411c --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,81 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// 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/postgresql/stdlib/query.sql b/internal/endtoend/testdata/star_expansion/postgresql/stdlib/query.sql new file mode 100644 index 0000000..9588332 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/postgresql/stdlib/query.sql @@ -0,0 +1,5 @@ +-- 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/schema.sql b/internal/endtoend/testdata/star_expansion/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..a68a0e4 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b text); + diff --git a/internal/endtoend/testdata/star_expansion/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/star_expansion/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..cd51867 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} 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 0000000..32faa9f --- /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.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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 0000000..a26317d --- /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.31.1 + +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 0000000..4730825 --- /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.31.1 +// 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 AS 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 0000000..1afa2b3 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/sqlite/query.sql @@ -0,0 +1,5 @@ +-- name: StarExpansion :many +SELECT *, *, foo.* FROM foo; + +-- name: StarQuotedExpansion :many +SELECT t.* FROM foo AS t; diff --git a/internal/endtoend/testdata/star_expansion/sqlite/schema.sql b/internal/endtoend/testdata/star_expansion/sqlite/schema.sql new file mode 100644 index 0000000..a68a0e4 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion/sqlite/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b text); + 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 0000000..1f9d43d --- /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": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/star_expansion_core/mysql/exec.json b/internal/endtoend/testdata/star_expansion_core/mysql/exec.json new file mode 100644 index 0000000..8da46d6 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_core/mysql/exec.json @@ -0,0 +1,6 @@ +{ + "command": "generate", + "env": { + "SQLCEXPERIMENT": "coreanalyzer" + } +} diff --git a/internal/endtoend/testdata/star_expansion_core/mysql/go/db.go b/internal/endtoend/testdata/star_expansion_core/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_core/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_core/mysql/go/models.go b/internal/endtoend/testdata/star_expansion_core/mysql/go/models.go new file mode 100644 index 0000000..3e874b1 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_core/mysql/go/models.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + A sql.NullString + C sql.NullString +} + +type Baz struct { + Z sql.NullString +} + +type Foo struct { + A sql.NullString + B sql.NullString + Group sql.NullString +} diff --git a/internal/endtoend/testdata/star_expansion_core/mysql/go/query.sql.go b/internal/endtoend/testdata/star_expansion_core/mysql/go/query.sql.go new file mode 100644 index 0000000..10c1e7b --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_core/mysql/go/query.sql.go @@ -0,0 +1,209 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const starExpansion = `-- name: StarExpansion :many +SELECT a, b, ` + "`" + `group` + "`" + `, a, b, ` + "`" + `group` + "`" + `, foo.a, foo.b, foo.` + "`" + `group` + "`" + ` FROM foo +` + +type StarExpansionRow struct { + A sql.NullString + B sql.NullString + Group sql.NullString + A_2 sql.NullString + B_2 sql.NullString + Group_2 sql.NullString + A_3 sql.NullString + B_3 sql.NullString + Group_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.Group, + &i.A_2, + &i.B_2, + &i.Group_2, + &i.A_3, + &i.B_3, + &i.Group_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 starExpansionAliasedSubquery = `-- name: StarExpansionAliasedSubquery :many +SELECT (SELECT z FROM baz LIMIT 1) AS x FROM foo GROUP BY x +` + +func (q *Queries) StarExpansionAliasedSubquery(ctx context.Context) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, starExpansionAliasedSubquery) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var x sql.NullString + if err := rows.Scan(&x); err != nil { + return nil, err + } + items = append(items, x) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const starExpansionCTE = `-- name: StarExpansionCTE :many +WITH t AS (SELECT a, c FROM bar) SELECT a, c FROM t +` + +func (q *Queries) StarExpansionCTE(ctx context.Context) ([]Bar, error) { + rows, err := q.db.QueryContext(ctx, starExpansionCTE) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Bar + for rows.Next() { + var i Bar + if err := rows.Scan(&i.A, &i.C); 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 starExpansionJoin = `-- name: StarExpansionJoin :many +SELECT foo.a, b, ` + "`" + `group` + "`" + `, bar.a, c FROM foo, bar +` + +type StarExpansionJoinRow struct { + A sql.NullString + B sql.NullString + Group sql.NullString + A_2 sql.NullString + C sql.NullString +} + +func (q *Queries) StarExpansionJoin(ctx context.Context) ([]StarExpansionJoinRow, error) { + rows, err := q.db.QueryContext(ctx, starExpansionJoin) + if err != nil { + return nil, err + } + defer rows.Close() + var items []StarExpansionJoinRow + for rows.Next() { + var i StarExpansionJoinRow + if err := rows.Scan( + &i.A, + &i.B, + &i.Group, + &i.A_2, + &i.C, + ); 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 starExpansionSubquery = `-- name: StarExpansionSubquery :many +SELECT a, c FROM (SELECT a, c FROM bar) sub +` + +func (q *Queries) StarExpansionSubquery(ctx context.Context) ([]Bar, error) { + rows, err := q.db.QueryContext(ctx, starExpansionSubquery) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Bar + for rows.Next() { + var i Bar + if err := rows.Scan(&i.A, &i.C); 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, t.` + "`" + `group` + "`" + ` 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, &i.Group); 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_core/mysql/query.sql b/internal/endtoend/testdata/star_expansion_core/mysql/query.sql new file mode 100644 index 0000000..89c1b25 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_core/mysql/query.sql @@ -0,0 +1,17 @@ +-- name: StarExpansion :many +SELECT *, *, foo.* FROM foo; + +-- name: StarQuotedExpansion :many +SELECT `t`.* FROM foo `t`; + +-- name: StarExpansionJoin :many +SELECT * FROM foo, bar; + +-- name: StarExpansionSubquery :many +SELECT * FROM (SELECT * FROM bar) sub; + +-- name: StarExpansionCTE :many +WITH t AS (SELECT * FROM bar) SELECT * FROM t; + +-- name: StarExpansionAliasedSubquery :many +SELECT (SELECT * FROM baz LIMIT 1) AS x FROM foo GROUP BY x; diff --git a/internal/endtoend/testdata/star_expansion_core/mysql/schema.sql b/internal/endtoend/testdata/star_expansion_core/mysql/schema.sql new file mode 100644 index 0000000..1a6957d --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_core/mysql/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (a text, b text, `group` text); +CREATE TABLE bar (a text, c text); +CREATE TABLE baz (z text); diff --git a/internal/endtoend/testdata/star_expansion_core/mysql/sqlc.json b/internal/endtoend/testdata/star_expansion_core/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_core/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/star_expansion_core/postgresql/exec.json b/internal/endtoend/testdata/star_expansion_core/postgresql/exec.json new file mode 100644 index 0000000..8da46d6 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_core/postgresql/exec.json @@ -0,0 +1,6 @@ +{ + "command": "generate", + "env": { + "SQLCEXPERIMENT": "coreanalyzer" + } +} diff --git a/internal/endtoend/testdata/star_expansion_core/postgresql/go/db.go b/internal/endtoend/testdata/star_expansion_core/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_core/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_core/postgresql/go/models.go b/internal/endtoend/testdata/star_expansion_core/postgresql/go/models.go new file mode 100644 index 0000000..3e874b1 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_core/postgresql/go/models.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + A sql.NullString + C sql.NullString +} + +type Baz struct { + Z sql.NullString +} + +type Foo struct { + A sql.NullString + B sql.NullString + Group sql.NullString +} diff --git a/internal/endtoend/testdata/star_expansion_core/postgresql/go/query.sql.go b/internal/endtoend/testdata/star_expansion_core/postgresql/go/query.sql.go new file mode 100644 index 0000000..3a688f9 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_core/postgresql/go/query.sql.go @@ -0,0 +1,225 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const starExpansion = `-- name: StarExpansion :many +SELECT a, b, "group", a, b, "group", foo.a, foo.b, foo."group" FROM foo +` + +type StarExpansionRow struct { + A sql.NullString + B sql.NullString + Group sql.NullString + A_2 sql.NullString + B_2 sql.NullString + Group_2 sql.NullString + A_3 sql.NullString + B_3 sql.NullString + Group_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.Group, + &i.A_2, + &i.B_2, + &i.Group_2, + &i.A_3, + &i.B_3, + &i.Group_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 starExpansionAliasedSubquery = `-- name: StarExpansionAliasedSubquery :many +SELECT (SELECT z FROM baz LIMIT 1) AS x FROM foo GROUP BY x +` + +func (q *Queries) StarExpansionAliasedSubquery(ctx context.Context) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, starExpansionAliasedSubquery) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var x sql.NullString + if err := rows.Scan(&x); err != nil { + return nil, err + } + items = append(items, x) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const starExpansionCTE = `-- name: StarExpansionCTE :many +WITH t AS (SELECT a, c FROM bar) SELECT a, c FROM t +` + +func (q *Queries) StarExpansionCTE(ctx context.Context) ([]Bar, error) { + rows, err := q.db.QueryContext(ctx, starExpansionCTE) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Bar + for rows.Next() { + var i Bar + if err := rows.Scan(&i.A, &i.C); 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 starExpansionJoin = `-- name: StarExpansionJoin :many +SELECT foo.a, b, "group", bar.a, c FROM foo, bar +` + +type StarExpansionJoinRow struct { + A sql.NullString + B sql.NullString + Group sql.NullString + A_2 sql.NullString + C sql.NullString +} + +func (q *Queries) StarExpansionJoin(ctx context.Context) ([]StarExpansionJoinRow, error) { + rows, err := q.db.QueryContext(ctx, starExpansionJoin) + if err != nil { + return nil, err + } + defer rows.Close() + var items []StarExpansionJoinRow + for rows.Next() { + var i StarExpansionJoinRow + if err := rows.Scan( + &i.A, + &i.B, + &i.Group, + &i.A_2, + &i.C, + ); 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 starExpansionReturning = `-- name: StarExpansionReturning :one +INSERT INTO bar (a, c) VALUES ($1, $2) RETURNING a, c +` + +type StarExpansionReturningParams struct { + A sql.NullString + C sql.NullString +} + +func (q *Queries) StarExpansionReturning(ctx context.Context, arg StarExpansionReturningParams) (Bar, error) { + row := q.db.QueryRowContext(ctx, starExpansionReturning, arg.A, arg.C) + var i Bar + err := row.Scan(&i.A, &i.C) + return i, err +} + +const starExpansionSubquery = `-- name: StarExpansionSubquery :many +SELECT a, c FROM (SELECT a, c FROM bar) sub +` + +func (q *Queries) StarExpansionSubquery(ctx context.Context) ([]Bar, error) { + rows, err := q.db.QueryContext(ctx, starExpansionSubquery) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Bar + for rows.Next() { + var i Bar + if err := rows.Scan(&i.A, &i.C); 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, t."group" 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, &i.Group); 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_core/postgresql/query.sql b/internal/endtoend/testdata/star_expansion_core/postgresql/query.sql new file mode 100644 index 0000000..099f54d --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_core/postgresql/query.sql @@ -0,0 +1,20 @@ +-- name: StarExpansion :many +SELECT *, *, foo.* FROM foo; + +-- name: StarQuotedExpansion :many +SELECT "t".* FROM foo "t"; + +-- name: StarExpansionJoin :many +SELECT * FROM foo, bar; + +-- name: StarExpansionSubquery :many +SELECT * FROM (SELECT * FROM bar) sub; + +-- name: StarExpansionCTE :many +WITH t AS (SELECT * FROM bar) SELECT * FROM t; + +-- name: StarExpansionReturning :one +INSERT INTO bar (a, c) VALUES ($1, $2) RETURNING *; + +-- name: StarExpansionAliasedSubquery :many +SELECT (SELECT * FROM baz LIMIT 1) AS x FROM foo GROUP BY x; diff --git a/internal/endtoend/testdata/star_expansion_core/postgresql/schema.sql b/internal/endtoend/testdata/star_expansion_core/postgresql/schema.sql new file mode 100644 index 0000000..1267831 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_core/postgresql/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (a text, b text, "group" text); +CREATE TABLE bar (a text, c text); +CREATE TABLE baz (z text); diff --git a/internal/endtoend/testdata/star_expansion_core/postgresql/sqlc.json b/internal/endtoend/testdata/star_expansion_core/postgresql/sqlc.json new file mode 100644 index 0000000..cd51867 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_core/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/star_expansion_core/sqlite/exec.json b/internal/endtoend/testdata/star_expansion_core/sqlite/exec.json new file mode 100644 index 0000000..8da46d6 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_core/sqlite/exec.json @@ -0,0 +1,6 @@ +{ + "command": "generate", + "env": { + "SQLCEXPERIMENT": "coreanalyzer" + } +} diff --git a/internal/endtoend/testdata/star_expansion_core/sqlite/go/db.go b/internal/endtoend/testdata/star_expansion_core/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_core/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_core/sqlite/go/models.go b/internal/endtoend/testdata/star_expansion_core/sqlite/go/models.go new file mode 100644 index 0000000..c19552a --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_core/sqlite/go/models.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + A sql.NullString + C sql.NullString +} + +type Baz struct { + Z sql.NullString +} + +type Foo struct { + A sql.NullString + B sql.NullString + Group sql.NullString +} + +type Recipe struct { + ID int64 + Name string +} + +type RecipesFt struct { + Name string +} diff --git a/internal/endtoend/testdata/star_expansion_core/sqlite/go/query.sql.go b/internal/endtoend/testdata/star_expansion_core/sqlite/go/query.sql.go new file mode 100644 index 0000000..4ed292f --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_core/sqlite/go/query.sql.go @@ -0,0 +1,279 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const starExpansion = `-- name: StarExpansion :many +SELECT a, b, "group", a, b, "group", foo.a, foo.b, foo."group" FROM foo +` + +type StarExpansionRow struct { + A sql.NullString + B sql.NullString + Group sql.NullString + A_2 sql.NullString + B_2 sql.NullString + Group_2 sql.NullString + A_3 sql.NullString + B_3 sql.NullString + Group_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.Group, + &i.A_2, + &i.B_2, + &i.Group_2, + &i.A_3, + &i.B_3, + &i.Group_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 starExpansionAliasedSubquery = `-- name: StarExpansionAliasedSubquery :many +SELECT (SELECT z FROM baz LIMIT 1) AS x FROM foo GROUP BY x +` + +func (q *Queries) StarExpansionAliasedSubquery(ctx context.Context) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, starExpansionAliasedSubquery) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var x sql.NullString + if err := rows.Scan(&x); err != nil { + return nil, err + } + items = append(items, x) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const starExpansionCTE = `-- name: StarExpansionCTE :many +WITH t AS (SELECT a, c FROM bar) SELECT a, c FROM t +` + +func (q *Queries) StarExpansionCTE(ctx context.Context) ([]Bar, error) { + rows, err := q.db.QueryContext(ctx, starExpansionCTE) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Bar + for rows.Next() { + var i Bar + if err := rows.Scan(&i.A, &i.C); 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 starExpansionHiddenColumns = `-- name: StarExpansionHiddenColumns :many +SELECT name FROM recipes_fts +` + +func (q *Queries) StarExpansionHiddenColumns(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, starExpansionHiddenColumns) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const starExpansionJoin = `-- name: StarExpansionJoin :many +SELECT foo.a, b, "group", bar.a, c FROM foo, bar +` + +type StarExpansionJoinRow struct { + A sql.NullString + B sql.NullString + Group sql.NullString + A_2 sql.NullString + C sql.NullString +} + +func (q *Queries) StarExpansionJoin(ctx context.Context) ([]StarExpansionJoinRow, error) { + rows, err := q.db.QueryContext(ctx, starExpansionJoin) + if err != nil { + return nil, err + } + defer rows.Close() + var items []StarExpansionJoinRow + for rows.Next() { + var i StarExpansionJoinRow + if err := rows.Scan( + &i.A, + &i.B, + &i.Group, + &i.A_2, + &i.C, + ); 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 starExpansionQualifiedHiddenColumns = `-- name: StarExpansionQualifiedHiddenColumns :many +SELECT recipes_fts.name FROM recipes_fts +` + +func (q *Queries) StarExpansionQualifiedHiddenColumns(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, starExpansionQualifiedHiddenColumns) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const starExpansionReturning = `-- name: StarExpansionReturning :one +INSERT INTO bar (a, c) VALUES (?, ?) RETURNING a, c +` + +type StarExpansionReturningParams struct { + A sql.NullString + C sql.NullString +} + +func (q *Queries) StarExpansionReturning(ctx context.Context, arg StarExpansionReturningParams) (Bar, error) { + row := q.db.QueryRowContext(ctx, starExpansionReturning, arg.A, arg.C) + var i Bar + err := row.Scan(&i.A, &i.C) + return i, err +} + +const starExpansionSubquery = `-- name: StarExpansionSubquery :many +SELECT a, c FROM (SELECT a, c FROM bar) AS sub +` + +func (q *Queries) StarExpansionSubquery(ctx context.Context) ([]Bar, error) { + rows, err := q.db.QueryContext(ctx, starExpansionSubquery) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Bar + for rows.Next() { + var i Bar + if err := rows.Scan(&i.A, &i.C); 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, t."group" FROM foo AS 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, &i.Group); 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_core/sqlite/query.sql b/internal/endtoend/testdata/star_expansion_core/sqlite/query.sql new file mode 100644 index 0000000..2fb7ec1 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_core/sqlite/query.sql @@ -0,0 +1,26 @@ +-- name: StarExpansion :many +SELECT *, *, foo.* FROM foo; + +-- name: StarQuotedExpansion :many +SELECT t.* FROM foo AS t; + +-- name: StarExpansionJoin :many +SELECT * FROM foo, bar; + +-- name: StarExpansionSubquery :many +SELECT * FROM (SELECT * FROM bar) AS sub; + +-- name: StarExpansionCTE :many +WITH t AS (SELECT * FROM bar) SELECT * FROM t; + +-- name: StarExpansionReturning :one +INSERT INTO bar (a, c) VALUES (?, ?) RETURNING *; + +-- name: StarExpansionAliasedSubquery :many +SELECT (SELECT * FROM baz LIMIT 1) AS x FROM foo GROUP BY x; + +-- name: StarExpansionHiddenColumns :many +SELECT * FROM recipes_fts; + +-- name: StarExpansionQualifiedHiddenColumns :many +SELECT recipes_fts.* FROM recipes_fts; diff --git a/internal/endtoend/testdata/star_expansion_core/sqlite/schema.sql b/internal/endtoend/testdata/star_expansion_core/sqlite/schema.sql new file mode 100644 index 0000000..0442abf --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_core/sqlite/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE foo (a text, b text, "group" text); +CREATE TABLE bar (a text, c text); +CREATE TABLE baz (z text); +CREATE TABLE recipes (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL); +CREATE VIRTUAL TABLE recipes_fts USING FTS5 (name, content='recipes', content_rowid='id'); diff --git a/internal/endtoend/testdata/star_expansion_core/sqlite/sqlc.json b/internal/endtoend/testdata/star_expansion_core/sqlite/sqlc.json new file mode 100644 index 0000000..1f9d43d --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_core/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "sqlite", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/star_expansion_cte/pgx/v4/go/db.go b/internal/endtoend/testdata/star_expansion_cte/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_cte/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/star_expansion_cte/pgx/v4/go/models.go b/internal/endtoend/testdata/star_expansion_cte/pgx/v4/go/models.go new file mode 100644 index 0000000..9f22e00 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_cte/pgx/v4/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + C sql.NullString + D sql.NullString +} + +type Foo struct { + A sql.NullString + B sql.NullString +} diff --git a/internal/endtoend/testdata/star_expansion_cte/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/star_expansion_cte/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..740b103 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_cte/pgx/v4/go/query.sql.go @@ -0,0 +1,68 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const starExpansionCTE = `-- name: StarExpansionCTE :many +WITH cte AS (SELECT a, b FROM foo) SELECT c, d FROM bar +` + +func (q *Queries) StarExpansionCTE(ctx context.Context) ([]Bar, error) { + rows, err := q.db.Query(ctx, starExpansionCTE) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Bar + for rows.Next() { + var i Bar + if err := rows.Scan(&i.C, &i.D); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const starExpansionTwoCTE = `-- name: StarExpansionTwoCTE :many +WITH + a AS (SELECT a, b FROM foo), + b AS (SELECT 1::int as bar, a, b FROM a) +SELECT bar, a, b FROM b +` + +type StarExpansionTwoCTERow struct { + Bar int32 + A sql.NullString + B sql.NullString +} + +func (q *Queries) StarExpansionTwoCTE(ctx context.Context) ([]StarExpansionTwoCTERow, error) { + rows, err := q.db.Query(ctx, starExpansionTwoCTE) + if err != nil { + return nil, err + } + defer rows.Close() + var items []StarExpansionTwoCTERow + for rows.Next() { + var i StarExpansionTwoCTERow + if err := rows.Scan(&i.Bar, &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_cte/pgx/v4/query.sql b/internal/endtoend/testdata/star_expansion_cte/pgx/v4/query.sql new file mode 100644 index 0000000..d7fb4cf --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_cte/pgx/v4/query.sql @@ -0,0 +1,8 @@ +-- name: StarExpansionCTE :many +WITH cte AS (SELECT * FROM foo) SELECT * FROM bar; + +-- name: StarExpansionTwoCTE :many +WITH + a AS (SELECT * FROM foo), + b AS (SELECT 1::int as bar, * FROM a) +SELECT * FROM b; diff --git a/internal/endtoend/testdata/star_expansion_cte/pgx/v4/schema.sql b/internal/endtoend/testdata/star_expansion_cte/pgx/v4/schema.sql new file mode 100644 index 0000000..423ca3d --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_cte/pgx/v4/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (a text, b text); +CREATE TABLE bar (c text, d text); + diff --git a/internal/endtoend/testdata/star_expansion_cte/pgx/v4/sqlc.json b/internal/endtoend/testdata/star_expansion_cte/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_cte/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/star_expansion_cte/pgx/v5/go/db.go b/internal/endtoend/testdata/star_expansion_cte/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_cte/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/star_expansion_cte/pgx/v5/go/models.go b/internal/endtoend/testdata/star_expansion_cte/pgx/v5/go/models.go new file mode 100644 index 0000000..516fecf --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_cte/pgx/v5/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Bar struct { + C pgtype.Text + D pgtype.Text +} + +type Foo struct { + A pgtype.Text + B pgtype.Text +} diff --git a/internal/endtoend/testdata/star_expansion_cte/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/star_expansion_cte/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..db22d0b --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_cte/pgx/v5/go/query.sql.go @@ -0,0 +1,69 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const starExpansionCTE = `-- name: StarExpansionCTE :many +WITH cte AS (SELECT a, b FROM foo) SELECT c, d FROM bar +` + +func (q *Queries) StarExpansionCTE(ctx context.Context) ([]Bar, error) { + rows, err := q.db.Query(ctx, starExpansionCTE) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Bar + for rows.Next() { + var i Bar + if err := rows.Scan(&i.C, &i.D); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const starExpansionTwoCTE = `-- name: StarExpansionTwoCTE :many +WITH + a AS (SELECT a, b FROM foo), + b AS (SELECT 1::int as bar, a, b FROM a) +SELECT bar, a, b FROM b +` + +type StarExpansionTwoCTERow struct { + Bar int32 + A pgtype.Text + B pgtype.Text +} + +func (q *Queries) StarExpansionTwoCTE(ctx context.Context) ([]StarExpansionTwoCTERow, error) { + rows, err := q.db.Query(ctx, starExpansionTwoCTE) + if err != nil { + return nil, err + } + defer rows.Close() + var items []StarExpansionTwoCTERow + for rows.Next() { + var i StarExpansionTwoCTERow + if err := rows.Scan(&i.Bar, &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_cte/pgx/v5/query.sql b/internal/endtoend/testdata/star_expansion_cte/pgx/v5/query.sql new file mode 100644 index 0000000..d7fb4cf --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_cte/pgx/v5/query.sql @@ -0,0 +1,8 @@ +-- name: StarExpansionCTE :many +WITH cte AS (SELECT * FROM foo) SELECT * FROM bar; + +-- name: StarExpansionTwoCTE :many +WITH + a AS (SELECT * FROM foo), + b AS (SELECT 1::int as bar, * FROM a) +SELECT * FROM b; diff --git a/internal/endtoend/testdata/star_expansion_cte/pgx/v5/schema.sql b/internal/endtoend/testdata/star_expansion_cte/pgx/v5/schema.sql new file mode 100644 index 0000000..423ca3d --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_cte/pgx/v5/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (a text, b text); +CREATE TABLE bar (c text, d text); + diff --git a/internal/endtoend/testdata/star_expansion_cte/pgx/v5/sqlc.json b/internal/endtoend/testdata/star_expansion_cte/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_cte/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/star_expansion_cte/stdlib/go/db.go b/internal/endtoend/testdata/star_expansion_cte/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_cte/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_cte/stdlib/go/models.go b/internal/endtoend/testdata/star_expansion_cte/stdlib/go/models.go new file mode 100644 index 0000000..9f22e00 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_cte/stdlib/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + C sql.NullString + D sql.NullString +} + +type Foo struct { + A sql.NullString + B sql.NullString +} diff --git a/internal/endtoend/testdata/star_expansion_cte/stdlib/go/query.sql.go b/internal/endtoend/testdata/star_expansion_cte/stdlib/go/query.sql.go new file mode 100644 index 0000000..1fe02a3 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_cte/stdlib/go/query.sql.go @@ -0,0 +1,74 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const starExpansionCTE = `-- name: StarExpansionCTE :many +WITH cte AS (SELECT a, b FROM foo) SELECT c, d FROM bar +` + +func (q *Queries) StarExpansionCTE(ctx context.Context) ([]Bar, error) { + rows, err := q.db.QueryContext(ctx, starExpansionCTE) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Bar + for rows.Next() { + var i Bar + if err := rows.Scan(&i.C, &i.D); 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 starExpansionTwoCTE = `-- name: StarExpansionTwoCTE :many +WITH + a AS (SELECT a, b FROM foo), + b AS (SELECT 1::int as bar, a, b FROM a) +SELECT bar, a, b FROM b +` + +type StarExpansionTwoCTERow struct { + Bar int32 + A sql.NullString + B sql.NullString +} + +func (q *Queries) StarExpansionTwoCTE(ctx context.Context) ([]StarExpansionTwoCTERow, error) { + rows, err := q.db.QueryContext(ctx, starExpansionTwoCTE) + if err != nil { + return nil, err + } + defer rows.Close() + var items []StarExpansionTwoCTERow + for rows.Next() { + var i StarExpansionTwoCTERow + if err := rows.Scan(&i.Bar, &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_cte/stdlib/query.sql b/internal/endtoend/testdata/star_expansion_cte/stdlib/query.sql new file mode 100644 index 0000000..d7fb4cf --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_cte/stdlib/query.sql @@ -0,0 +1,8 @@ +-- name: StarExpansionCTE :many +WITH cte AS (SELECT * FROM foo) SELECT * FROM bar; + +-- name: StarExpansionTwoCTE :many +WITH + a AS (SELECT * FROM foo), + b AS (SELECT 1::int as bar, * FROM a) +SELECT * FROM b; diff --git a/internal/endtoend/testdata/star_expansion_cte/stdlib/schema.sql b/internal/endtoend/testdata/star_expansion_cte/stdlib/schema.sql new file mode 100644 index 0000000..423ca3d --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_cte/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (a text, b text); +CREATE TABLE bar (c text, d text); + diff --git a/internal/endtoend/testdata/star_expansion_cte/stdlib/sqlc.json b/internal/endtoend/testdata/star_expansion_cte/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_cte/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/exec.json b/internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/go/db.go b/internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/star_expansion_failed/postgresql/pgx/go/models.go b/internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/go/models.go new file mode 100644 index 0000000..9662cea --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Version struct { + ID int64 + Name pgtype.Text + PreviousVersionID int64 +} diff --git a/internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..2782a00 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/go/query.sql.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getLatestVersionWithSubquery = `-- name: GetLatestVersionWithSubquery :one +SELECT * +FROM versions +WHERE versions.id IN ( + WITH RECURSIVE search_tree(id) AS ( + SELECT id, 0 as chain_id, 0 as chain_counter + FROM versions + ) + SELECT DISTINCT ON (search_tree.chain_id) + search_tree.id + FROM search_tree + ORDER BY search_tree.chain_id, chain_counter DESC +) +` + +func (q *Queries) GetLatestVersionWithSubquery(ctx context.Context) (Version, error) { + row := q.db.QueryRow(ctx, getLatestVersionWithSubquery) + var i Version + err := row.Scan(&i.ID, &i.Name, &i.PreviousVersionID) + return i, err +} diff --git a/internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/query.sql b/internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/query.sql new file mode 100644 index 0000000..4a66724 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/query.sql @@ -0,0 +1,13 @@ +-- name: GetLatestVersionWithSubquery :one +SELECT * +FROM versions +WHERE versions.id IN ( + WITH RECURSIVE search_tree(id) AS ( + SELECT id, 0 as chain_id, 0 as chain_counter + FROM versions + ) + SELECT DISTINCT ON (search_tree.chain_id) + search_tree.id + FROM search_tree + ORDER BY search_tree.chain_id, chain_counter DESC +); diff --git a/internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/schema.sql b/internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/schema.sql new file mode 100644 index 0000000..1825de4 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/schema.sql @@ -0,0 +1,6 @@ +-- Example queries for sqlc +CREATE TABLE versions ( + id BIGSERIAL PRIMARY KEY, + name TEXT, + previous_version_id bigint NOT NULL +); diff --git a/internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/stderr.txt b/internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/stderr.txt new file mode 100644 index 0000000..2a064b8 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_failed/postgresql/pgx/stderr.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:1:1: star expansion failed for query diff --git a/internal/endtoend/testdata/star_expansion_from_cte/pgx/v4/go/db.go b/internal/endtoend/testdata/star_expansion_from_cte/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_from_cte/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/star_expansion_from_cte/pgx/v4/go/models.go b/internal/endtoend/testdata/star_expansion_from_cte/pgx/v4/go/models.go new file mode 100644 index 0000000..9f22e00 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_from_cte/pgx/v4/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + C sql.NullString + D sql.NullString +} + +type Foo struct { + A sql.NullString + B sql.NullString +} diff --git a/internal/endtoend/testdata/star_expansion_from_cte/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/star_expansion_from_cte/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..6f26994 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_from_cte/pgx/v4/go/query.sql.go @@ -0,0 +1,40 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const starExpansionCTE = `-- name: StarExpansionCTE :many +WITH cte AS (SELECT a, b FROM foo) SELECT a, b FROM cte +` + +type StarExpansionCTERow struct { + A sql.NullString + B sql.NullString +} + +func (q *Queries) StarExpansionCTE(ctx context.Context) ([]StarExpansionCTERow, error) { + rows, err := q.db.Query(ctx, starExpansionCTE) + if err != nil { + return nil, err + } + defer rows.Close() + var items []StarExpansionCTERow + for rows.Next() { + var i StarExpansionCTERow + 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_from_cte/pgx/v4/query.sql b/internal/endtoend/testdata/star_expansion_from_cte/pgx/v4/query.sql new file mode 100644 index 0000000..f91c7b7 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_from_cte/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: StarExpansionCTE :many +WITH cte AS (SELECT * FROM foo) SELECT * FROM cte; diff --git a/internal/endtoend/testdata/star_expansion_from_cte/pgx/v4/schema.sql b/internal/endtoend/testdata/star_expansion_from_cte/pgx/v4/schema.sql new file mode 100644 index 0000000..786c5b6 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_from_cte/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b text); +CREATE TABLE bar (c text, d text); diff --git a/internal/endtoend/testdata/star_expansion_from_cte/pgx/v4/sqlc.json b/internal/endtoend/testdata/star_expansion_from_cte/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_from_cte/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/star_expansion_from_cte/pgx/v5/go/db.go b/internal/endtoend/testdata/star_expansion_from_cte/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_from_cte/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/star_expansion_from_cte/pgx/v5/go/models.go b/internal/endtoend/testdata/star_expansion_from_cte/pgx/v5/go/models.go new file mode 100644 index 0000000..516fecf --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_from_cte/pgx/v5/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Bar struct { + C pgtype.Text + D pgtype.Text +} + +type Foo struct { + A pgtype.Text + B pgtype.Text +} diff --git a/internal/endtoend/testdata/star_expansion_from_cte/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/star_expansion_from_cte/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..480bec0 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_from_cte/pgx/v5/go/query.sql.go @@ -0,0 +1,41 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const starExpansionCTE = `-- name: StarExpansionCTE :many +WITH cte AS (SELECT a, b FROM foo) SELECT a, b FROM cte +` + +type StarExpansionCTERow struct { + A pgtype.Text + B pgtype.Text +} + +func (q *Queries) StarExpansionCTE(ctx context.Context) ([]StarExpansionCTERow, error) { + rows, err := q.db.Query(ctx, starExpansionCTE) + if err != nil { + return nil, err + } + defer rows.Close() + var items []StarExpansionCTERow + for rows.Next() { + var i StarExpansionCTERow + 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_from_cte/pgx/v5/query.sql b/internal/endtoend/testdata/star_expansion_from_cte/pgx/v5/query.sql new file mode 100644 index 0000000..f91c7b7 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_from_cte/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: StarExpansionCTE :many +WITH cte AS (SELECT * FROM foo) SELECT * FROM cte; diff --git a/internal/endtoend/testdata/star_expansion_from_cte/pgx/v5/schema.sql b/internal/endtoend/testdata/star_expansion_from_cte/pgx/v5/schema.sql new file mode 100644 index 0000000..786c5b6 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_from_cte/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b text); +CREATE TABLE bar (c text, d text); diff --git a/internal/endtoend/testdata/star_expansion_from_cte/pgx/v5/sqlc.json b/internal/endtoend/testdata/star_expansion_from_cte/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_from_cte/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/star_expansion_from_cte/stdlib/go/db.go b/internal/endtoend/testdata/star_expansion_from_cte/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_from_cte/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_from_cte/stdlib/go/models.go b/internal/endtoend/testdata/star_expansion_from_cte/stdlib/go/models.go new file mode 100644 index 0000000..9f22e00 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_from_cte/stdlib/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + C sql.NullString + D sql.NullString +} + +type Foo struct { + A sql.NullString + B sql.NullString +} diff --git a/internal/endtoend/testdata/star_expansion_from_cte/stdlib/go/query.sql.go b/internal/endtoend/testdata/star_expansion_from_cte/stdlib/go/query.sql.go new file mode 100644 index 0000000..cc764fc --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_from_cte/stdlib/go/query.sql.go @@ -0,0 +1,43 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const starExpansionCTE = `-- name: StarExpansionCTE :many +WITH cte AS (SELECT a, b FROM foo) SELECT a, b FROM cte +` + +type StarExpansionCTERow struct { + A sql.NullString + B sql.NullString +} + +func (q *Queries) StarExpansionCTE(ctx context.Context) ([]StarExpansionCTERow, error) { + rows, err := q.db.QueryContext(ctx, starExpansionCTE) + if err != nil { + return nil, err + } + defer rows.Close() + var items []StarExpansionCTERow + for rows.Next() { + var i StarExpansionCTERow + 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_from_cte/stdlib/query.sql b/internal/endtoend/testdata/star_expansion_from_cte/stdlib/query.sql new file mode 100644 index 0000000..f91c7b7 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_from_cte/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: StarExpansionCTE :many +WITH cte AS (SELECT * FROM foo) SELECT * FROM cte; diff --git a/internal/endtoend/testdata/star_expansion_from_cte/stdlib/schema.sql b/internal/endtoend/testdata/star_expansion_from_cte/stdlib/schema.sql new file mode 100644 index 0000000..786c5b6 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_from_cte/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b text); +CREATE TABLE bar (c text, d text); diff --git a/internal/endtoend/testdata/star_expansion_from_cte/stdlib/sqlc.json b/internal/endtoend/testdata/star_expansion_from_cte/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_from_cte/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/star_expansion_join/mysql/go/db.go b/internal/endtoend/testdata/star_expansion_join/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_join/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_join/mysql/go/models.go b/internal/endtoend/testdata/star_expansion_join/mysql/go/models.go new file mode 100644 index 0000000..9f22e00 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_join/mysql/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + C sql.NullString + D sql.NullString +} + +type Foo struct { + A sql.NullString + B sql.NullString +} diff --git a/internal/endtoend/testdata/star_expansion_join/mysql/go/query.sql.go b/internal/endtoend/testdata/star_expansion_join/mysql/go/query.sql.go new file mode 100644 index 0000000..364a39a --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_join/mysql/go/query.sql.go @@ -0,0 +1,50 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const starExpansionJoin = `-- name: StarExpansionJoin :many +SELECT a, b, c, d FROM foo, bar +` + +type StarExpansionJoinRow struct { + A sql.NullString + B sql.NullString + C sql.NullString + D sql.NullString +} + +func (q *Queries) StarExpansionJoin(ctx context.Context) ([]StarExpansionJoinRow, error) { + rows, err := q.db.QueryContext(ctx, starExpansionJoin) + if err != nil { + return nil, err + } + defer rows.Close() + var items []StarExpansionJoinRow + for rows.Next() { + var i StarExpansionJoinRow + if err := rows.Scan( + &i.A, + &i.B, + &i.C, + &i.D, + ); 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_join/mysql/query.sql b/internal/endtoend/testdata/star_expansion_join/mysql/query.sql new file mode 100644 index 0000000..02da113 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_join/mysql/query.sql @@ -0,0 +1,2 @@ +/* name: StarExpansionJoin :many */ +SELECT * FROM foo, bar; diff --git a/internal/endtoend/testdata/star_expansion_join/mysql/schema.sql b/internal/endtoend/testdata/star_expansion_join/mysql/schema.sql new file mode 100644 index 0000000..423ca3d --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_join/mysql/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (a text, b text); +CREATE TABLE bar (c text, d text); + diff --git a/internal/endtoend/testdata/star_expansion_join/mysql/sqlc.json b/internal/endtoend/testdata/star_expansion_join/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_join/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/star_expansion_join/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..9f22e00 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v4/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + C sql.NullString + D sql.NullString +} + +type Foo struct { + A sql.NullString + B sql.NullString +} diff --git a/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..b1c4a10 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,47 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const starExpansionJoin = `-- name: StarExpansionJoin :many +SELECT a, b, c, d FROM foo, bar +` + +type StarExpansionJoinRow struct { + A sql.NullString + B sql.NullString + C sql.NullString + D sql.NullString +} + +func (q *Queries) StarExpansionJoin(ctx context.Context) ([]StarExpansionJoinRow, error) { + rows, err := q.db.Query(ctx, starExpansionJoin) + if err != nil { + return nil, err + } + defer rows.Close() + var items []StarExpansionJoinRow + for rows.Next() { + var i StarExpansionJoinRow + if err := rows.Scan( + &i.A, + &i.B, + &i.C, + &i.D, + ); 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_join/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..9322d7b --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: StarExpansionJoin :many +SELECT * FROM foo, bar; diff --git a/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..786c5b6 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b text); +CREATE TABLE bar (c text, d text); diff --git a/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/star_expansion_join/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..516fecf --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v5/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Bar struct { + C pgtype.Text + D pgtype.Text +} + +type Foo struct { + A pgtype.Text + B pgtype.Text +} diff --git a/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..ffb00f6 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,48 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const starExpansionJoin = `-- name: StarExpansionJoin :many +SELECT a, b, c, d FROM foo, bar +` + +type StarExpansionJoinRow struct { + A pgtype.Text + B pgtype.Text + C pgtype.Text + D pgtype.Text +} + +func (q *Queries) StarExpansionJoin(ctx context.Context) ([]StarExpansionJoinRow, error) { + rows, err := q.db.Query(ctx, starExpansionJoin) + if err != nil { + return nil, err + } + defer rows.Close() + var items []StarExpansionJoinRow + for rows.Next() { + var i StarExpansionJoinRow + if err := rows.Scan( + &i.A, + &i.B, + &i.C, + &i.D, + ); 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_join/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..9322d7b --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: StarExpansionJoin :many +SELECT * FROM foo, bar; diff --git a/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..786c5b6 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b text); +CREATE TABLE bar (c text, d text); diff --git a/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_join/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/star_expansion_join/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/star_expansion_join/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_join/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_join/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/star_expansion_join/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..9f22e00 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_join/postgresql/stdlib/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + C sql.NullString + D sql.NullString +} + +type Foo struct { + A sql.NullString + B sql.NullString +} diff --git a/internal/endtoend/testdata/star_expansion_join/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/star_expansion_join/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..364a39a --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_join/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,50 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const starExpansionJoin = `-- name: StarExpansionJoin :many +SELECT a, b, c, d FROM foo, bar +` + +type StarExpansionJoinRow struct { + A sql.NullString + B sql.NullString + C sql.NullString + D sql.NullString +} + +func (q *Queries) StarExpansionJoin(ctx context.Context) ([]StarExpansionJoinRow, error) { + rows, err := q.db.QueryContext(ctx, starExpansionJoin) + if err != nil { + return nil, err + } + defer rows.Close() + var items []StarExpansionJoinRow + for rows.Next() { + var i StarExpansionJoinRow + if err := rows.Scan( + &i.A, + &i.B, + &i.C, + &i.D, + ); 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_join/postgresql/stdlib/query.sql b/internal/endtoend/testdata/star_expansion_join/postgresql/stdlib/query.sql new file mode 100644 index 0000000..9322d7b --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_join/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: StarExpansionJoin :many +SELECT * FROM foo, bar; diff --git a/internal/endtoend/testdata/star_expansion_join/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/star_expansion_join/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..786c5b6 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_join/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b text); +CREATE TABLE bar (c text, d text); diff --git a/internal/endtoend/testdata/star_expansion_join/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/star_expansion_join/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..cd51867 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_join/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/star_expansion_reserved/mysql/go/db.go b/internal/endtoend/testdata/star_expansion_reserved/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_reserved/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_reserved/mysql/go/models.go b/internal/endtoend/testdata/star_expansion_reserved/mysql/go/models.go new file mode 100644 index 0000000..f1cb8da --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_reserved/mysql/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Group sql.NullString + Key sql.NullString +} diff --git a/internal/endtoend/testdata/star_expansion_reserved/mysql/go/query.sql.go b/internal/endtoend/testdata/star_expansion_reserved/mysql/go/query.sql.go new file mode 100644 index 0000000..3f9cd7a --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_reserved/mysql/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const starExpansionReserved = `-- name: StarExpansionReserved :many +SELECT ` + "`" + `group` + "`" + `, ` + "`" + `key` + "`" + ` FROM foo +` + +func (q *Queries) StarExpansionReserved(ctx context.Context) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, starExpansionReserved) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.Group, &i.Key); 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_reserved/mysql/query.sql b/internal/endtoend/testdata/star_expansion_reserved/mysql/query.sql new file mode 100644 index 0000000..e4cad82 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_reserved/mysql/query.sql @@ -0,0 +1,2 @@ +/* name: StarExpansionReserved :many */ +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/star_expansion_reserved/mysql/schema.sql b/internal/endtoend/testdata/star_expansion_reserved/mysql/schema.sql new file mode 100644 index 0000000..b340849 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_reserved/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (`group` text, `key` text); + diff --git a/internal/endtoend/testdata/star_expansion_reserved/mysql/sqlc.json b/internal/endtoend/testdata/star_expansion_reserved/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_reserved/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/star_expansion_reserved/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..f1cb8da --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v4/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Group sql.NullString + Key sql.NullString +} diff --git a/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..614cde9 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const starExpansionReserved = `-- name: StarExpansionReserved :many +SELECT "group", key FROM foo +` + +func (q *Queries) StarExpansionReserved(ctx context.Context) ([]Foo, error) { + rows, err := q.db.Query(ctx, starExpansionReserved) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.Group, &i.Key); 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_reserved/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..a97dd94 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: StarExpansionReserved :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..ba3ec0b --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v4/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo ("group" text, key text); diff --git a/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/star_expansion_reserved/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..49f34e6 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + Group pgtype.Text + Key pgtype.Text +} diff --git a/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..614cde9 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const starExpansionReserved = `-- name: StarExpansionReserved :many +SELECT "group", key FROM foo +` + +func (q *Queries) StarExpansionReserved(ctx context.Context) ([]Foo, error) { + rows, err := q.db.Query(ctx, starExpansionReserved) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.Group, &i.Key); 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_reserved/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..a97dd94 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: StarExpansionReserved :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..ba3ec0b --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v5/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo ("group" text, key text); diff --git a/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_reserved/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/star_expansion_reserved/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/star_expansion_reserved/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_reserved/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_reserved/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/star_expansion_reserved/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..f1cb8da --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_reserved/postgresql/stdlib/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Group sql.NullString + Key sql.NullString +} diff --git a/internal/endtoend/testdata/star_expansion_reserved/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/star_expansion_reserved/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..d3cee04 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_reserved/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const starExpansionReserved = `-- name: StarExpansionReserved :many +SELECT "group", key FROM foo +` + +func (q *Queries) StarExpansionReserved(ctx context.Context) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, starExpansionReserved) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.Group, &i.Key); 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_reserved/postgresql/stdlib/query.sql b/internal/endtoend/testdata/star_expansion_reserved/postgresql/stdlib/query.sql new file mode 100644 index 0000000..a97dd94 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_reserved/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: StarExpansionReserved :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/star_expansion_reserved/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/star_expansion_reserved/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..ba3ec0b --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_reserved/postgresql/stdlib/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo ("group" text, key text); diff --git a/internal/endtoend/testdata/star_expansion_reserved/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/star_expansion_reserved/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..cd51867 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_reserved/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/star_expansion_series/issue.md b/internal/endtoend/testdata/star_expansion_series/issue.md new file mode 100644 index 0000000..72e3e3a --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_series/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1995 diff --git a/internal/endtoend/testdata/star_expansion_series/postgresql/pgx/go/db.go b/internal/endtoend/testdata/star_expansion_series/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_series/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/star_expansion_series/postgresql/pgx/go/models.go b/internal/endtoend/testdata/star_expansion_series/postgresql/pgx/go/models.go new file mode 100644 index 0000000..4135201 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_series/postgresql/pgx/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Alertreport struct { + Eventdate pgtype.Date +} diff --git a/internal/endtoend/testdata/star_expansion_series/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/star_expansion_series/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..4da9cb4 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_series/postgresql/pgx/go/query.sql.go @@ -0,0 +1,56 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const countAlertReportBy = `-- name: CountAlertReportBy :many +select DATE_TRUNC($1,ts)::text as datetime,coalesce(count,0) as count from +( + SELECT DATE_TRUNC($1,eventdate) as hr ,count(*) + FROM alertreport + where eventdate between $2 and $3 + GROUP BY 1 +) AS cnt +right outer join ( SELECT ts FROM generate_series ( $2, $3, CONCAT('1 ',$1)::interval) AS ts ) as dte +on DATE_TRUNC($1, ts ) = cnt.hr +order by 1 asc +` + +type CountAlertReportByParams struct { + DateTrunc string + Eventdate pgtype.Date + Eventdate_2 pgtype.Date +} + +type CountAlertReportByRow struct { + Datetime string + Count int64 +} + +func (q *Queries) CountAlertReportBy(ctx context.Context, arg CountAlertReportByParams) ([]CountAlertReportByRow, error) { + rows, err := q.db.Query(ctx, countAlertReportBy, arg.DateTrunc, arg.Eventdate, arg.Eventdate_2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CountAlertReportByRow + for rows.Next() { + var i CountAlertReportByRow + if err := rows.Scan(&i.Datetime, &i.Count); 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_series/postgresql/pgx/query.sql b/internal/endtoend/testdata/star_expansion_series/postgresql/pgx/query.sql new file mode 100644 index 0000000..df13ae9 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_series/postgresql/pgx/query.sql @@ -0,0 +1,11 @@ +-- name: CountAlertReportBy :many +select DATE_TRUNC($1,ts)::text as datetime,coalesce(count,0) as count from +( + SELECT DATE_TRUNC($1,eventdate) as hr ,count(*) + FROM alertreport + where eventdate between $2 and $3 + GROUP BY 1 +) AS cnt +right outer join ( SELECT * FROM generate_series ( $2, $3, CONCAT('1 ',$1)::interval) AS ts ) as dte +on DATE_TRUNC($1, ts ) = cnt.hr +order by 1 asc; diff --git a/internal/endtoend/testdata/star_expansion_series/postgresql/pgx/schema.sql b/internal/endtoend/testdata/star_expansion_series/postgresql/pgx/schema.sql new file mode 100644 index 0000000..533757a --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_series/postgresql/pgx/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE alertreport ( + eventdate date +); diff --git a/internal/endtoend/testdata/star_expansion_series/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/star_expansion_series/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_series/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/star_expansion_subquery/mysql/go/db.go b/internal/endtoend/testdata/star_expansion_subquery/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_subquery/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_subquery/mysql/go/models.go b/internal/endtoend/testdata/star_expansion_subquery/mysql/go/models.go new file mode 100644 index 0000000..a26317d --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_subquery/mysql/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString + B sql.NullString +} diff --git a/internal/endtoend/testdata/star_expansion_subquery/mysql/go/query.sql.go b/internal/endtoend/testdata/star_expansion_subquery/mysql/go/query.sql.go new file mode 100644 index 0000000..5dff54c --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_subquery/mysql/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const starExpansionSubquery = `-- name: StarExpansionSubquery :many +SELECT a, b FROM foo WHERE EXISTS (SELECT a, b FROM foo) +` + +func (q *Queries) StarExpansionSubquery(ctx context.Context) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, starExpansionSubquery) + 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_subquery/mysql/query.sql b/internal/endtoend/testdata/star_expansion_subquery/mysql/query.sql new file mode 100644 index 0000000..0b66b9e --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_subquery/mysql/query.sql @@ -0,0 +1,2 @@ +/* name: StarExpansionSubquery :many */ +SELECT * FROM foo WHERE EXISTS (SELECT * FROM foo); diff --git a/internal/endtoend/testdata/star_expansion_subquery/mysql/schema.sql b/internal/endtoend/testdata/star_expansion_subquery/mysql/schema.sql new file mode 100644 index 0000000..a68a0e4 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_subquery/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b text); + diff --git a/internal/endtoend/testdata/star_expansion_subquery/mysql/sqlc.json b/internal/endtoend/testdata/star_expansion_subquery/mysql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_subquery/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/star_expansion_subquery/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a26317d --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v4/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString + B sql.NullString +} diff --git a/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..a44019c --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const starExpansionSubquery = `-- name: StarExpansionSubquery :many +SELECT a, b FROM foo WHERE EXISTS (SELECT a, b FROM foo) +` + +func (q *Queries) StarExpansionSubquery(ctx context.Context) ([]Foo, error) { + rows, err := q.db.Query(ctx, starExpansionSubquery) + 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_subquery/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..53110a5 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: StarExpansionSubquery :many +SELECT * FROM foo WHERE EXISTS (SELECT * FROM foo); diff --git a/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..a68a0e4 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b text); + diff --git a/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/star_expansion_subquery/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..463744d --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + A pgtype.Text + B pgtype.Text +} diff --git a/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..a44019c --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const starExpansionSubquery = `-- name: StarExpansionSubquery :many +SELECT a, b FROM foo WHERE EXISTS (SELECT a, b FROM foo) +` + +func (q *Queries) StarExpansionSubquery(ctx context.Context) ([]Foo, error) { + rows, err := q.db.Query(ctx, starExpansionSubquery) + 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_subquery/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..53110a5 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: StarExpansionSubquery :many +SELECT * FROM foo WHERE EXISTS (SELECT * FROM foo); diff --git a/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..a68a0e4 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b text); + diff --git a/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_subquery/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/star_expansion_subquery/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/star_expansion_subquery/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_subquery/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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_subquery/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/star_expansion_subquery/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a26317d --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_subquery/postgresql/stdlib/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString + B sql.NullString +} diff --git a/internal/endtoend/testdata/star_expansion_subquery/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/star_expansion_subquery/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..5dff54c --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_subquery/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const starExpansionSubquery = `-- name: StarExpansionSubquery :many +SELECT a, b FROM foo WHERE EXISTS (SELECT a, b FROM foo) +` + +func (q *Queries) StarExpansionSubquery(ctx context.Context) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, starExpansionSubquery) + 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_subquery/postgresql/stdlib/query.sql b/internal/endtoend/testdata/star_expansion_subquery/postgresql/stdlib/query.sql new file mode 100644 index 0000000..53110a5 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_subquery/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: StarExpansionSubquery :many +SELECT * FROM foo WHERE EXISTS (SELECT * FROM foo); diff --git a/internal/endtoend/testdata/star_expansion_subquery/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/star_expansion_subquery/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..a68a0e4 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_subquery/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a text, b text); + diff --git a/internal/endtoend/testdata/star_expansion_subquery/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/star_expansion_subquery/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..cd51867 --- /dev/null +++ b/internal/endtoend/testdata/star_expansion_subquery/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/strict_function_checks/postgresql/query.sql b/internal/endtoend/testdata/strict_function_checks/postgresql/query.sql new file mode 100644 index 0000000..aaadd52 --- /dev/null +++ b/internal/endtoend/testdata/strict_function_checks/postgresql/query.sql @@ -0,0 +1,2 @@ +-- name: F :exec +SELECT doesntexist(); diff --git a/internal/endtoend/testdata/strict_function_checks/postgresql/schema.sql b/internal/endtoend/testdata/strict_function_checks/postgresql/schema.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/endtoend/testdata/strict_function_checks/postgresql/sqlc.json b/internal/endtoend/testdata/strict_function_checks/postgresql/sqlc.json new file mode 100644 index 0000000..6cb9103 --- /dev/null +++ b/internal/endtoend/testdata/strict_function_checks/postgresql/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql", + "strict_function_checks": true + } + ] +} diff --git a/internal/endtoend/testdata/strict_function_checks/postgresql/stderr/base.txt b/internal/endtoend/testdata/strict_function_checks/postgresql/stderr/base.txt new file mode 100644 index 0000000..a897205 --- /dev/null +++ b/internal/endtoend/testdata/strict_function_checks/postgresql/stderr/base.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:1:1: function "doesntexist" does not exist diff --git a/internal/endtoend/testdata/strict_function_checks/postgresql/stderr/managed-db.txt b/internal/endtoend/testdata/strict_function_checks/postgresql/stderr/managed-db.txt new file mode 100644 index 0000000..16996b6 --- /dev/null +++ b/internal/endtoend/testdata/strict_function_checks/postgresql/stderr/managed-db.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:2:8: function doesntexist() does not exist diff --git a/internal/endtoend/testdata/subquery_calculated_column/mysql/go/db.go b/internal/endtoend/testdata/subquery_calculated_column/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/subquery_calculated_column/mysql/go/models.go b/internal/endtoend/testdata/subquery_calculated_column/mysql/go/models.go new file mode 100644 index 0000000..a3b713f --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/mysql/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullInt32 + B sql.NullInt32 +} diff --git a/internal/endtoend/testdata/subquery_calculated_column/mysql/go/query.sql.go b/internal/endtoend/testdata/subquery_calculated_column/mysql/go/query.sql.go new file mode 100644 index 0000000..1b7b4ef --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/mysql/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const subqueryCalcColumn = `-- name: SubqueryCalcColumn :many +SELECT sum FROM (SELECT a + b AS sum FROM foo) AS f +` + +func (q *Queries) SubqueryCalcColumn(ctx context.Context) ([]int32, error) { + rows, err := q.db.QueryContext(ctx, subqueryCalcColumn) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int32 + for rows.Next() { + var sum int32 + if err := rows.Scan(&sum); err != nil { + return nil, err + } + items = append(items, sum) + } + 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/subquery_calculated_column/mysql/query.sql b/internal/endtoend/testdata/subquery_calculated_column/mysql/query.sql new file mode 100644 index 0000000..16f1683 --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: SubqueryCalcColumn :many +SELECT sum FROM (SELECT a + b AS sum FROM foo) AS f; diff --git a/internal/endtoend/testdata/subquery_calculated_column/mysql/schema.sql b/internal/endtoend/testdata/subquery_calculated_column/mysql/schema.sql new file mode 100644 index 0000000..ac4621f --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a int, b int); + diff --git a/internal/endtoend/testdata/subquery_calculated_column/mysql/sqlc.json b/internal/endtoend/testdata/subquery_calculated_column/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/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/subquery_calculated_column/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/subquery_calculated_column/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..a3b713f --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v4/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullInt32 + B sql.NullInt32 +} diff --git a/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..3e5eac5 --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const subqueryCalcColumn = `-- name: SubqueryCalcColumn :many +SELECT sum FROM (SELECT a + b AS sum FROM foo) AS f +` + +func (q *Queries) SubqueryCalcColumn(ctx context.Context) ([]int32, error) { + rows, err := q.db.Query(ctx, subqueryCalcColumn) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int32 + for rows.Next() { + var sum int32 + if err := rows.Scan(&sum); err != nil { + return nil, err + } + items = append(items, sum) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..16f1683 --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: SubqueryCalcColumn :many +SELECT sum FROM (SELECT a + b AS sum FROM foo) AS f; diff --git a/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..ac4621f --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a int, b int); + diff --git a/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/subquery_calculated_column/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..baf8c54 --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v5/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Foo struct { + A pgtype.Int4 + B pgtype.Int4 +} diff --git a/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..3e5eac5 --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,34 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const subqueryCalcColumn = `-- name: SubqueryCalcColumn :many +SELECT sum FROM (SELECT a + b AS sum FROM foo) AS f +` + +func (q *Queries) SubqueryCalcColumn(ctx context.Context) ([]int32, error) { + rows, err := q.db.Query(ctx, subqueryCalcColumn) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int32 + for rows.Next() { + var sum int32 + if err := rows.Scan(&sum); err != nil { + return nil, err + } + items = append(items, sum) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..16f1683 --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: SubqueryCalcColumn :many +SELECT sum FROM (SELECT a + b AS sum FROM foo) AS f; diff --git a/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..ac4621f --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a int, b int); + diff --git a/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/subquery_calculated_column/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/subquery_calculated_column/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/subquery_calculated_column/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/subquery_calculated_column/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..a3b713f --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/postgresql/stdlib/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullInt32 + B sql.NullInt32 +} diff --git a/internal/endtoend/testdata/subquery_calculated_column/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/subquery_calculated_column/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..1b7b4ef --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const subqueryCalcColumn = `-- name: SubqueryCalcColumn :many +SELECT sum FROM (SELECT a + b AS sum FROM foo) AS f +` + +func (q *Queries) SubqueryCalcColumn(ctx context.Context) ([]int32, error) { + rows, err := q.db.QueryContext(ctx, subqueryCalcColumn) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int32 + for rows.Next() { + var sum int32 + if err := rows.Scan(&sum); err != nil { + return nil, err + } + items = append(items, sum) + } + 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/subquery_calculated_column/postgresql/stdlib/query.sql b/internal/endtoend/testdata/subquery_calculated_column/postgresql/stdlib/query.sql new file mode 100644 index 0000000..16f1683 --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: SubqueryCalcColumn :many +SELECT sum FROM (SELECT a + b AS sum FROM foo) AS f; diff --git a/internal/endtoend/testdata/subquery_calculated_column/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/subquery_calculated_column/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..ac4621f --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a int, b int); + diff --git a/internal/endtoend/testdata/subquery_calculated_column/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/subquery_calculated_column/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/subquery_calculated_column/sqlite/go/db.go b/internal/endtoend/testdata/subquery_calculated_column/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/subquery_calculated_column/sqlite/go/models.go b/internal/endtoend/testdata/subquery_calculated_column/sqlite/go/models.go new file mode 100644 index 0000000..90e3dcd --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/sqlite/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullInt64 + B sql.NullInt64 +} diff --git a/internal/endtoend/testdata/subquery_calculated_column/sqlite/go/query.sql.go b/internal/endtoend/testdata/subquery_calculated_column/sqlite/go/query.sql.go new file mode 100644 index 0000000..6e09c33 --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/sqlite/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const subqueryCalcColumn = `-- name: SubqueryCalcColumn :many +SELECT sum FROM (SELECT a + b AS sum FROM foo) AS f +` + +func (q *Queries) SubqueryCalcColumn(ctx context.Context) ([]int64, error) { + rows, err := q.db.QueryContext(ctx, subqueryCalcColumn) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var sum int64 + if err := rows.Scan(&sum); err != nil { + return nil, err + } + items = append(items, sum) + } + 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/subquery_calculated_column/sqlite/query.sql b/internal/endtoend/testdata/subquery_calculated_column/sqlite/query.sql new file mode 100644 index 0000000..16f1683 --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: SubqueryCalcColumn :many +SELECT sum FROM (SELECT a + b AS sum FROM foo) AS f; diff --git a/internal/endtoend/testdata/subquery_calculated_column/sqlite/schema.sql b/internal/endtoend/testdata/subquery_calculated_column/sqlite/schema.sql new file mode 100644 index 0000000..ac4621f --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/sqlite/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (a int, b int); + diff --git a/internal/endtoend/testdata/subquery_calculated_column/sqlite/sqlc.json b/internal/endtoend/testdata/subquery_calculated_column/sqlite/sqlc.json new file mode 100644 index 0000000..d4963e7 --- /dev/null +++ b/internal/endtoend/testdata/subquery_calculated_column/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/sum_type/issue.md b/internal/endtoend/testdata/sum_type/issue.md new file mode 100644 index 0000000..b125c05 --- /dev/null +++ b/internal/endtoend/testdata/sum_type/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1106 \ No newline at end of file diff --git a/internal/endtoend/testdata/sum_type/postgresql/pgx/exec.json b/internal/endtoend/testdata/sum_type/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/sum_type/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/sum_type/postgresql/pgx/go/db.go b/internal/endtoend/testdata/sum_type/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/sum_type/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/sum_type/postgresql/pgx/go/models.go b/internal/endtoend/testdata/sum_type/postgresql/pgx/go/models.go new file mode 100644 index 0000000..933c3cb --- /dev/null +++ b/internal/endtoend/testdata/sum_type/postgresql/pgx/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Order struct { + ID int64 + Quantity pgtype.Numeric + OrderCatalog pgtype.Int4 +} diff --git a/internal/endtoend/testdata/sum_type/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/sum_type/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..af828e1 --- /dev/null +++ b/internal/endtoend/testdata/sum_type/postgresql/pgx/go/query.sql.go @@ -0,0 +1,23 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const sumOrder = `-- name: SumOrder :one +SELECT SUM(quantity) FROM orders +` + +func (q *Queries) SumOrder(ctx context.Context) (pgtype.Numeric, error) { + row := q.db.QueryRow(ctx, sumOrder) + var sum pgtype.Numeric + err := row.Scan(&sum) + return sum, err +} diff --git a/internal/endtoend/testdata/sum_type/postgresql/pgx/query.sql b/internal/endtoend/testdata/sum_type/postgresql/pgx/query.sql new file mode 100644 index 0000000..7effc6e --- /dev/null +++ b/internal/endtoend/testdata/sum_type/postgresql/pgx/query.sql @@ -0,0 +1,2 @@ +-- name: SumOrder :one +SELECT SUM(quantity) FROM orders; \ No newline at end of file diff --git a/internal/endtoend/testdata/sum_type/postgresql/pgx/schema.sql b/internal/endtoend/testdata/sum_type/postgresql/pgx/schema.sql new file mode 100644 index 0000000..85df079 --- /dev/null +++ b/internal/endtoend/testdata/sum_type/postgresql/pgx/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE orders ( + id BIGSERIAL PRIMARY KEY, + quantity decimal NOT NULL, + order_catalog int +); \ No newline at end of file diff --git a/internal/endtoend/testdata/sum_type/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/sum_type/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..01489e0 --- /dev/null +++ b/internal/endtoend/testdata/sum_type/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" \ No newline at end of file diff --git a/internal/endtoend/testdata/syntax_errors/mysql/query/from.sql b/internal/endtoend/testdata/syntax_errors/mysql/query/from.sql new file mode 100644 index 0000000..e74097f --- /dev/null +++ b/internal/endtoend/testdata/syntax_errors/mysql/query/from.sql @@ -0,0 +1,2 @@ +/* name: TooManyFroms :one */ +select id, first_name from users from where id = ?; diff --git a/internal/endtoend/testdata/syntax_errors/mysql/query/select.sql b/internal/endtoend/testdata/syntax_errors/mysql/query/select.sql new file mode 100644 index 0000000..1d663f1 --- /dev/null +++ b/internal/endtoend/testdata/syntax_errors/mysql/query/select.sql @@ -0,0 +1,2 @@ +/* name: ExtraSelect :one */ +select id from users where select id; diff --git a/internal/endtoend/testdata/syntax_errors/mysql/query/typo.sql b/internal/endtoend/testdata/syntax_errors/mysql/query/typo.sql new file mode 100644 index 0000000..311e8b8 --- /dev/null +++ b/internal/endtoend/testdata/syntax_errors/mysql/query/typo.sql @@ -0,0 +1,4 @@ +/* name: MisspelledSelect :one */ +selectt id, first_name from users; + + diff --git a/internal/endtoend/testdata/syntax_errors/mysql/schema.sql b/internal/endtoend/testdata/syntax_errors/mysql/schema.sql new file mode 100644 index 0000000..f57533a --- /dev/null +++ b/internal/endtoend/testdata/syntax_errors/mysql/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE users ( + id integer NOT NULL AUTO_INCREMENT PRIMARY KEY, + first_name varchar(255) NOT NULL +) ENGINE=InnoDB; diff --git a/internal/endtoend/testdata/syntax_errors/mysql/sqlc.json b/internal/endtoend/testdata/syntax_errors/mysql/sqlc.json new file mode 100644 index 0000000..0bfa8b4 --- /dev/null +++ b/internal/endtoend/testdata/syntax_errors/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "schema.sql", + "queries": "query", + "engine": "mysql" + } + ] +} diff --git a/internal/endtoend/testdata/syntax_errors/mysql/stderr.txt b/internal/endtoend/testdata/syntax_errors/mysql/stderr.txt new file mode 100644 index 0000000..9d20497 --- /dev/null +++ b/internal/endtoend/testdata/syntax_errors/mysql/stderr.txt @@ -0,0 +1,4 @@ +# package querytest +query/from.sql:2:38: syntax error near "from where id = ?;" +query/select.sql:2:34: syntax error near "select id;" +query/typo.sql:2:8: syntax error near "selectt id, first_name from users;" diff --git a/internal/endtoend/testdata/syntax_errors/postgresql/query/from.sql b/internal/endtoend/testdata/syntax_errors/postgresql/query/from.sql new file mode 100644 index 0000000..872c38d --- /dev/null +++ b/internal/endtoend/testdata/syntax_errors/postgresql/query/from.sql @@ -0,0 +1,2 @@ +/* name: TooManyFroms :one */ +select id, first_name from users from where id = $1; diff --git a/internal/endtoend/testdata/syntax_errors/postgresql/query/select.sql b/internal/endtoend/testdata/syntax_errors/postgresql/query/select.sql new file mode 100644 index 0000000..1d663f1 --- /dev/null +++ b/internal/endtoend/testdata/syntax_errors/postgresql/query/select.sql @@ -0,0 +1,2 @@ +/* name: ExtraSelect :one */ +select id from users where select id; diff --git a/internal/endtoend/testdata/syntax_errors/postgresql/query/typo.sql b/internal/endtoend/testdata/syntax_errors/postgresql/query/typo.sql new file mode 100644 index 0000000..311e8b8 --- /dev/null +++ b/internal/endtoend/testdata/syntax_errors/postgresql/query/typo.sql @@ -0,0 +1,4 @@ +/* name: MisspelledSelect :one */ +selectt id, first_name from users; + + diff --git a/internal/endtoend/testdata/syntax_errors/postgresql/schema.sql b/internal/endtoend/testdata/syntax_errors/postgresql/schema.sql new file mode 100644 index 0000000..4711d22 --- /dev/null +++ b/internal/endtoend/testdata/syntax_errors/postgresql/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE users ( + id SERIAL PRIMARY KEY, + first_name varchar(255) NOT NULL +); diff --git a/internal/endtoend/testdata/syntax_errors/postgresql/sqlc.json b/internal/endtoend/testdata/syntax_errors/postgresql/sqlc.json new file mode 100644 index 0000000..ef84b16 --- /dev/null +++ b/internal/endtoend/testdata/syntax_errors/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "name": "querytest", + "path": "go", + "schema": "schema.sql", + "queries": "query", + "engine": "postgresql" + } + ] +} diff --git a/internal/endtoend/testdata/syntax_errors/postgresql/stderr.txt b/internal/endtoend/testdata/syntax_errors/postgresql/stderr.txt new file mode 100644 index 0000000..8f766d6 --- /dev/null +++ b/internal/endtoend/testdata/syntax_errors/postgresql/stderr.txt @@ -0,0 +1,4 @@ +# package querytest +query/from.sql:2:35: syntax error at or near "from" +query/select.sql:2:29: syntax error at or near "select" +query/typo.sql:2:2: syntax error at or near "selectt" diff --git a/internal/endtoend/testdata/table_function/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/table_function/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/table_function/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/table_function/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/table_function/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..3d963fd --- /dev/null +++ b/internal/endtoend/testdata/table_function/postgresql/pgx/v4/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgtype" +) + +type Transaction struct { + ID int64 + Uri string + ProgramID string + Data pgtype.JSONB +} diff --git a/internal/endtoend/testdata/table_function/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/table_function/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..1766c85 --- /dev/null +++ b/internal/endtoend/testdata/table_function/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,56 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgtype" +) + +const getTransaction = `-- name: GetTransaction :many +SELECT + jsonb_extract_path(transactions.data, '$.transaction.signatures[0]'), + jsonb_agg(instructions.value) +FROM + transactions, + jsonb_each(jsonb_extract_path(transactions.data, '$.transaction.message.instructions[0]')) AS instructions +WHERE + transactions.program_id = $1 + AND jsonb_extract_path(transactions.data, '$.transaction.signatures[0]') @> to_jsonb($2::text) + AND jsonb_extract_path(jsonb_extract_path(transactions.data, '$.transaction.message.accountKeys'), 'key') = to_jsonb(transactions.program_id) +GROUP BY transactions.id +` + +type GetTransactionParams struct { + ProgramID string + Data string +} + +type GetTransactionRow struct { + JsonbExtractPath pgtype.JSONB + JsonbAgg pgtype.JSONB +} + +func (q *Queries) GetTransaction(ctx context.Context, arg GetTransactionParams) ([]GetTransactionRow, error) { + rows, err := q.db.Query(ctx, getTransaction, arg.ProgramID, arg.Data) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetTransactionRow + for rows.Next() { + var i GetTransactionRow + if err := rows.Scan(&i.JsonbExtractPath, &i.JsonbAgg); 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/table_function/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/table_function/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..99f02a7 --- /dev/null +++ b/internal/endtoend/testdata/table_function/postgresql/pgx/v4/query.sql @@ -0,0 +1,12 @@ +/* name: GetTransaction :many */ +SELECT + jsonb_extract_path(transactions.data, '$.transaction.signatures[0]'), + jsonb_agg(instructions.value) +FROM + transactions, + jsonb_each(jsonb_extract_path(transactions.data, '$.transaction.message.instructions[0]')) AS instructions +WHERE + transactions.program_id = sqlc.arg('program_id') + AND jsonb_extract_path(transactions.data, '$.transaction.signatures[0]') @> to_jsonb(sqlc.arg('data')::text) + AND jsonb_extract_path(jsonb_extract_path(transactions.data, '$.transaction.message.accountKeys'), 'key') = to_jsonb(transactions.program_id) +GROUP BY transactions.id; \ No newline at end of file diff --git a/internal/endtoend/testdata/table_function/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/table_function/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..455651b --- /dev/null +++ b/internal/endtoend/testdata/table_function/postgresql/pgx/v4/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE transactions ( + id BIGSERIAL PRIMARY KEY, + uri TEXT NOT NULL, + program_id TEXT NOT NULL, + data JSONB NOT NULL +); + diff --git a/internal/endtoend/testdata/table_function/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/table_function/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/table_function/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/table_function/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/table_function/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/table_function/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/table_function/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/table_function/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..9e0054c --- /dev/null +++ b/internal/endtoend/testdata/table_function/postgresql/pgx/v5/go/models.go @@ -0,0 +1,12 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Transaction struct { + ID int64 + Uri string + ProgramID string + Data []byte +} diff --git a/internal/endtoend/testdata/table_function/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/table_function/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..1b791bc --- /dev/null +++ b/internal/endtoend/testdata/table_function/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,54 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getTransaction = `-- name: GetTransaction :many +SELECT + jsonb_extract_path(transactions.data, '$.transaction.signatures[0]'), + jsonb_agg(instructions.value) +FROM + transactions, + jsonb_each(jsonb_extract_path(transactions.data, '$.transaction.message.instructions[0]')) AS instructions +WHERE + transactions.program_id = $1 + AND jsonb_extract_path(transactions.data, '$.transaction.signatures[0]') @> to_jsonb($2::text) + AND jsonb_extract_path(jsonb_extract_path(transactions.data, '$.transaction.message.accountKeys'), 'key') = to_jsonb(transactions.program_id) +GROUP BY transactions.id +` + +type GetTransactionParams struct { + ProgramID string + Data string +} + +type GetTransactionRow struct { + JsonbExtractPath []byte + JsonbAgg []byte +} + +func (q *Queries) GetTransaction(ctx context.Context, arg GetTransactionParams) ([]GetTransactionRow, error) { + rows, err := q.db.Query(ctx, getTransaction, arg.ProgramID, arg.Data) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetTransactionRow + for rows.Next() { + var i GetTransactionRow + if err := rows.Scan(&i.JsonbExtractPath, &i.JsonbAgg); 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/table_function/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/table_function/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..99f02a7 --- /dev/null +++ b/internal/endtoend/testdata/table_function/postgresql/pgx/v5/query.sql @@ -0,0 +1,12 @@ +/* name: GetTransaction :many */ +SELECT + jsonb_extract_path(transactions.data, '$.transaction.signatures[0]'), + jsonb_agg(instructions.value) +FROM + transactions, + jsonb_each(jsonb_extract_path(transactions.data, '$.transaction.message.instructions[0]')) AS instructions +WHERE + transactions.program_id = sqlc.arg('program_id') + AND jsonb_extract_path(transactions.data, '$.transaction.signatures[0]') @> to_jsonb(sqlc.arg('data')::text) + AND jsonb_extract_path(jsonb_extract_path(transactions.data, '$.transaction.message.accountKeys'), 'key') = to_jsonb(transactions.program_id) +GROUP BY transactions.id; \ No newline at end of file diff --git a/internal/endtoend/testdata/table_function/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/table_function/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..455651b --- /dev/null +++ b/internal/endtoend/testdata/table_function/postgresql/pgx/v5/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE transactions ( + id BIGSERIAL PRIMARY KEY, + uri TEXT NOT NULL, + program_id TEXT NOT NULL, + data JSONB NOT NULL +); + diff --git a/internal/endtoend/testdata/table_function/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/table_function/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/table_function/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/table_function/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/table_function/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/table_function/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/table_function/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/table_function/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..dd9fffb --- /dev/null +++ b/internal/endtoend/testdata/table_function/postgresql/stdlib/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "encoding/json" +) + +type Transaction struct { + ID int64 + Uri string + ProgramID string + Data json.RawMessage +} diff --git a/internal/endtoend/testdata/table_function/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/table_function/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..5cd9637 --- /dev/null +++ b/internal/endtoend/testdata/table_function/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,58 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "encoding/json" +) + +const getTransaction = `-- name: GetTransaction :many +SELECT + jsonb_extract_path(transactions.data, '$.transaction.signatures[0]'), + jsonb_agg(instructions.value) +FROM + transactions, + jsonb_each(jsonb_extract_path(transactions.data, '$.transaction.message.instructions[0]')) AS instructions +WHERE + transactions.program_id = $1 + AND jsonb_extract_path(transactions.data, '$.transaction.signatures[0]') @> to_jsonb($2::text) + AND jsonb_extract_path(jsonb_extract_path(transactions.data, '$.transaction.message.accountKeys'), 'key') = to_jsonb(transactions.program_id) +GROUP BY transactions.id +` + +type GetTransactionParams struct { + ProgramID string + Data string +} + +type GetTransactionRow struct { + JsonbExtractPath json.RawMessage + JsonbAgg json.RawMessage +} + +func (q *Queries) GetTransaction(ctx context.Context, arg GetTransactionParams) ([]GetTransactionRow, error) { + rows, err := q.db.QueryContext(ctx, getTransaction, arg.ProgramID, arg.Data) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetTransactionRow + for rows.Next() { + var i GetTransactionRow + if err := rows.Scan(&i.JsonbExtractPath, &i.JsonbAgg); 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/table_function/postgresql/stdlib/query.sql b/internal/endtoend/testdata/table_function/postgresql/stdlib/query.sql new file mode 100644 index 0000000..99f02a7 --- /dev/null +++ b/internal/endtoend/testdata/table_function/postgresql/stdlib/query.sql @@ -0,0 +1,12 @@ +/* name: GetTransaction :many */ +SELECT + jsonb_extract_path(transactions.data, '$.transaction.signatures[0]'), + jsonb_agg(instructions.value) +FROM + transactions, + jsonb_each(jsonb_extract_path(transactions.data, '$.transaction.message.instructions[0]')) AS instructions +WHERE + transactions.program_id = sqlc.arg('program_id') + AND jsonb_extract_path(transactions.data, '$.transaction.signatures[0]') @> to_jsonb(sqlc.arg('data')::text) + AND jsonb_extract_path(jsonb_extract_path(transactions.data, '$.transaction.message.accountKeys'), 'key') = to_jsonb(transactions.program_id) +GROUP BY transactions.id; \ No newline at end of file diff --git a/internal/endtoend/testdata/table_function/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/table_function/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..455651b --- /dev/null +++ b/internal/endtoend/testdata/table_function/postgresql/stdlib/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE transactions ( + id BIGSERIAL PRIMARY KEY, + uri TEXT NOT NULL, + program_id TEXT NOT NULL, + data JSONB NOT NULL +); + diff --git a/internal/endtoend/testdata/table_function/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/table_function/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/table_function/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/table_function/sqlite/go/db.go b/internal/endtoend/testdata/table_function/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/table_function/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/table_function/sqlite/go/models.go b/internal/endtoend/testdata/table_function/sqlite/go/models.go new file mode 100644 index 0000000..1b78427 --- /dev/null +++ b/internal/endtoend/testdata/table_function/sqlite/go/models.go @@ -0,0 +1,11 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Transaction struct { + Uri string + ProgramID string + Data string +} diff --git a/internal/endtoend/testdata/table_function/sqlite/go/query.sql.go b/internal/endtoend/testdata/table_function/sqlite/go/query.sql.go new file mode 100644 index 0000000..345333f --- /dev/null +++ b/internal/endtoend/testdata/table_function/sqlite/go/query.sql.go @@ -0,0 +1,56 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getTransaction = `-- name: GetTransaction :many +SELECT + json_extract(transactions.data, '$.transaction.signatures[0]'), + json_group_array(instructions.value) +FROM transactions, json_each(json_extract(transactions.data, '$.transaction.message.instructions')) AS instructions +WHERE transactions.program_id = ? + AND json_extract(transactions.data, '$.transaction.signatures[0]') > ? + AND json_extract(json_extract(transactions.data, '$.transaction.message.accountKeys'), '$[' || json_extract(instructions.value, '$.programIdIndex') || ']') = transactions.program_id +GROUP BY transactions.rowid +LIMIT ? +` + +type GetTransactionParams struct { + ProgramID string + Data string + Limit int64 +} + +type GetTransactionRow struct { + JsonExtract any + JsonGroupArray string +} + +func (q *Queries) GetTransaction(ctx context.Context, arg GetTransactionParams) ([]GetTransactionRow, error) { + rows, err := q.db.QueryContext(ctx, getTransaction, arg.ProgramID, arg.Data, arg.Limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetTransactionRow + for rows.Next() { + var i GetTransactionRow + if err := rows.Scan(&i.JsonExtract, &i.JsonGroupArray); 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/table_function/sqlite/query.sql b/internal/endtoend/testdata/table_function/sqlite/query.sql new file mode 100644 index 0000000..6b79cdc --- /dev/null +++ b/internal/endtoend/testdata/table_function/sqlite/query.sql @@ -0,0 +1,10 @@ +/* name: GetTransaction :many */ +SELECT + json_extract(transactions.data, '$.transaction.signatures[0]'), + json_group_array(instructions.value) +FROM transactions, json_each(json_extract(transactions.data, '$.transaction.message.instructions')) AS instructions +WHERE transactions.program_id = ? + AND json_extract(transactions.data, '$.transaction.signatures[0]') > ? + AND json_extract(json_extract(transactions.data, '$.transaction.message.accountKeys'), '$[' || json_extract(instructions.value, '$.programIdIndex') || ']') = transactions.program_id +GROUP BY transactions.rowid +LIMIT ?; diff --git a/internal/endtoend/testdata/table_function/sqlite/schema.sql b/internal/endtoend/testdata/table_function/sqlite/schema.sql new file mode 100644 index 0000000..90741e7 --- /dev/null +++ b/internal/endtoend/testdata/table_function/sqlite/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE transactions ( + uri text NOT NULL, + program_id text NOT NULL, + data text NOT NULL +); + diff --git a/internal/endtoend/testdata/table_function/sqlite/sqlc.json b/internal/endtoend/testdata/table_function/sqlite/sqlc.json new file mode 100644 index 0000000..d4963e7 --- /dev/null +++ b/internal/endtoend/testdata/table_function/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/table_name_case_sensitivity/sqlite/go/db.go b/internal/endtoend/testdata/table_name_case_sensitivity/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/table_name_case_sensitivity/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/table_name_case_sensitivity/sqlite/go/models.go b/internal/endtoend/testdata/table_name_case_sensitivity/sqlite/go/models.go new file mode 100644 index 0000000..b1b575c --- /dev/null +++ b/internal/endtoend/testdata/table_name_case_sensitivity/sqlite/go/models.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name sql.NullString +} + +type Book struct { + ID int64 + Title sql.NullString +} + +type User struct { + ID int64 + Name sql.NullString +} diff --git a/internal/endtoend/testdata/table_name_case_sensitivity/sqlite/go/query.sql.go b/internal/endtoend/testdata/table_name_case_sensitivity/sqlite/go/query.sql.go new file mode 100644 index 0000000..6963209 --- /dev/null +++ b/internal/endtoend/testdata/table_name_case_sensitivity/sqlite/go/query.sql.go @@ -0,0 +1,183 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const deleteAuthor = `-- name: DeleteAuthor :exec +DELETE FROM "Authors" WHERE id = ? +` + +func (q *Queries) DeleteAuthor(ctx context.Context, id int64) error { + _, err := q.db.ExecContext(ctx, deleteAuthor, id) + return err +} + +const deleteBook = `-- name: DeleteBook :exec +DELETE FROM books WHERE id = ? +` + +func (q *Queries) DeleteBook(ctx context.Context, id int64) error { + _, err := q.db.ExecContext(ctx, deleteBook, id) + return err +} + +const deleteUser = `-- name: DeleteUser :exec +DELETE FROM users WHERE id = ? +` + +func (q *Queries) DeleteUser(ctx context.Context, id int64) error { + _, err := q.db.ExecContext(ctx, deleteUser, id) + return err +} + +const deleteUserMixedCase = `-- name: DeleteUserMixedCase :exec +DELETE FROM users WHERE id = ? +` + +func (q *Queries) DeleteUserMixedCase(ctx context.Context, id int64) error { + _, err := q.db.ExecContext(ctx, deleteUserMixedCase, id) + return err +} + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name FROM "Authors" WHERE id = ? +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Author + err := row.Scan(&i.ID, &i.Name) + return i, err +} + +const getBook = `-- name: GetBook :one +SELECT id, title FROM books WHERE id = ? +` + +func (q *Queries) GetBook(ctx context.Context, id int64) (Book, error) { + row := q.db.QueryRowContext(ctx, getBook, id) + var i Book + err := row.Scan(&i.ID, &i.Title) + return i, err +} + +const getUser = `-- name: GetUser :one +SELECT id, name FROM users WHERE id = ? +` + +func (q *Queries) GetUser(ctx context.Context, id int64) (User, error) { + row := q.db.QueryRowContext(ctx, getUser, id) + var i User + err := row.Scan(&i.ID, &i.Name) + return i, err +} + +const getUserMixedCase = `-- name: GetUserMixedCase :one +SELECT id, name FROM users WHERE id = ? +` + +func (q *Queries) GetUserMixedCase(ctx context.Context, id int64) (User, error) { + row := q.db.QueryRowContext(ctx, getUserMixedCase, id) + var i User + err := row.Scan(&i.ID, &i.Name) + return i, err +} + +const insertAuthor = `-- name: InsertAuthor :exec +INSERT INTO "Authors" (name) VALUES (?) +` + +func (q *Queries) InsertAuthor(ctx context.Context, name sql.NullString) error { + _, err := q.db.ExecContext(ctx, insertAuthor, name) + return err +} + +const insertBook = `-- name: InsertBook :exec +INSERT INTO books (title) VALUES (?) +` + +func (q *Queries) InsertBook(ctx context.Context, title sql.NullString) error { + _, err := q.db.ExecContext(ctx, insertBook, title) + return err +} + +const insertUser = `-- name: InsertUser :exec +INSERT INTO users (name) VALUES (?) +` + +func (q *Queries) InsertUser(ctx context.Context, name sql.NullString) error { + _, err := q.db.ExecContext(ctx, insertUser, name) + return err +} + +const insertUserMixedCase = `-- name: InsertUserMixedCase :exec +INSERT INTO users (name) VALUES (?) +` + +func (q *Queries) InsertUserMixedCase(ctx context.Context, name sql.NullString) error { + _, err := q.db.ExecContext(ctx, insertUserMixedCase, name) + return err +} + +const updateAuthor = `-- name: UpdateAuthor :exec +UPDATE "Authors" SET name = ? WHERE id = ? +` + +type UpdateAuthorParams struct { + Name sql.NullString + ID int64 +} + +func (q *Queries) UpdateAuthor(ctx context.Context, arg UpdateAuthorParams) error { + _, err := q.db.ExecContext(ctx, updateAuthor, arg.Name, arg.ID) + return err +} + +const updateBook = `-- name: UpdateBook :exec +UPDATE books SET title = ? WHERE id = ? +` + +type UpdateBookParams struct { + Title sql.NullString + ID int64 +} + +func (q *Queries) UpdateBook(ctx context.Context, arg UpdateBookParams) error { + _, err := q.db.ExecContext(ctx, updateBook, arg.Title, arg.ID) + return err +} + +const updateUser = `-- name: UpdateUser :exec +UPDATE users SET name = ? WHERE id = ? +` + +type UpdateUserParams struct { + Name sql.NullString + ID int64 +} + +func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) error { + _, err := q.db.ExecContext(ctx, updateUser, arg.Name, arg.ID) + return err +} + +const updateUserMixedCase = `-- name: UpdateUserMixedCase :exec +UPDATE users SET name = ? WHERE id = ? +` + +type UpdateUserMixedCaseParams struct { + Name sql.NullString + ID int64 +} + +func (q *Queries) UpdateUserMixedCase(ctx context.Context, arg UpdateUserMixedCaseParams) error { + _, err := q.db.ExecContext(ctx, updateUserMixedCase, arg.Name, arg.ID) + return err +} diff --git a/internal/endtoend/testdata/table_name_case_sensitivity/sqlite/query.sql b/internal/endtoend/testdata/table_name_case_sensitivity/sqlite/query.sql new file mode 100644 index 0000000..daaa164 --- /dev/null +++ b/internal/endtoend/testdata/table_name_case_sensitivity/sqlite/query.sql @@ -0,0 +1,47 @@ +-- name: InsertUser :exec +INSERT INTO users (name) VALUES (?); + +-- name: InsertUserMixedCase :exec +INSERT INTO users (name) VALUES (?); + +-- name: InsertAuthor :exec +INSERT INTO "Authors" (name) VALUES (?); + +-- name: InsertBook :exec +INSERT INTO books (title) VALUES (?); + +-- name: UpdateUser :exec +UPDATE users SET name = ? WHERE id = ?; + +-- name: UpdateUserMixedCase :exec +UPDATE users SET name = ? WHERE id = ?; + +-- name: UpdateAuthor :exec +UPDATE "Authors" SET name = ? WHERE id = ?; + +-- name: UpdateBook :exec +UPDATE books SET title = ? WHERE id = ?; + +-- name: DeleteUser :exec +DELETE FROM users WHERE id = ?; + +-- name: DeleteUserMixedCase :exec +DELETE FROM users WHERE id = ?; + +-- name: DeleteAuthor :exec +DELETE FROM "Authors" WHERE id = ?; + +-- name: DeleteBook :exec +DELETE FROM books WHERE id = ?; + +-- name: GetUser :one +SELECT * FROM users WHERE id = ?; + +-- name: GetUserMixedCase :one +SELECT * FROM users WHERE id = ?; + +-- name: GetAuthor :one +SELECT * FROM "Authors" WHERE id = ?; + +-- name: GetBook :one +SELECT * FROM books WHERE id = ?; diff --git a/internal/endtoend/testdata/table_name_case_sensitivity/sqlite/schema.sql b/internal/endtoend/testdata/table_name_case_sensitivity/sqlite/schema.sql new file mode 100644 index 0000000..3c43ae1 --- /dev/null +++ b/internal/endtoend/testdata/table_name_case_sensitivity/sqlite/schema.sql @@ -0,0 +1,13 @@ +-- Test table name case sensitivity handling across different SQLite operations +-- Create tables with different case patterns to verify consistent name resolution +CREATE TABLE users (id integer primary key, name text); +CREATE TABLE "Authors" (id integer primary key, name text); +CREATE TABLE Books (id integer primary key, title text); + +-- Create a temporary table to test drop operations +CREATE TABLE temp_orders (id integer primary key); +DROP TABLE temp_orders; + +-- Create another temp table with quoted identifier +CREATE TABLE "temp_products" (id integer primary key); +DROP TABLE "temp_products"; diff --git a/internal/endtoend/testdata/table_name_case_sensitivity/sqlite/sqlc.json b/internal/endtoend/testdata/table_name_case_sensitivity/sqlite/sqlc.json new file mode 100644 index 0000000..cd66df0 --- /dev/null +++ b/internal/endtoend/testdata/table_name_case_sensitivity/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/truncate/mysql/go/db.go b/internal/endtoend/testdata/truncate/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/truncate/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/truncate/mysql/go/models.go b/internal/endtoend/testdata/truncate/mysql/go/models.go new file mode 100644 index 0000000..9ac222a --- /dev/null +++ b/internal/endtoend/testdata/truncate/mysql/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID uint64 +} diff --git a/internal/endtoend/testdata/truncate/mysql/go/query.sql.go b/internal/endtoend/testdata/truncate/mysql/go/query.sql.go new file mode 100644 index 0000000..b0369ef --- /dev/null +++ b/internal/endtoend/testdata/truncate/mysql/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const truncate = `-- name: Truncate :exec +TRUNCATE bar +` + +func (q *Queries) Truncate(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, truncate) + return err +} diff --git a/internal/endtoend/testdata/truncate/mysql/query.sql b/internal/endtoend/testdata/truncate/mysql/query.sql new file mode 100644 index 0000000..47b8985 --- /dev/null +++ b/internal/endtoend/testdata/truncate/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: Truncate :exec +TRUNCATE bar; diff --git a/internal/endtoend/testdata/truncate/mysql/schema.sql b/internal/endtoend/testdata/truncate/mysql/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/truncate/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/truncate/mysql/sqlc.json b/internal/endtoend/testdata/truncate/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/truncate/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/truncate/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/truncate/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/truncate/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/truncate/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/truncate/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/truncate/postgresql/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/truncate/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/truncate/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..6061120 --- /dev/null +++ b/internal/endtoend/testdata/truncate/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const truncate = `-- name: Truncate :exec +TRUNCATE bar +` + +func (q *Queries) Truncate(ctx context.Context) error { + _, err := q.db.Exec(ctx, truncate) + return err +} diff --git a/internal/endtoend/testdata/truncate/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/truncate/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..47b8985 --- /dev/null +++ b/internal/endtoend/testdata/truncate/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: Truncate :exec +TRUNCATE bar; diff --git a/internal/endtoend/testdata/truncate/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/truncate/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/truncate/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/truncate/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/truncate/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/truncate/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/truncate/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/truncate/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/truncate/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/truncate/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/truncate/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/truncate/postgresql/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/truncate/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/truncate/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..6061120 --- /dev/null +++ b/internal/endtoend/testdata/truncate/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const truncate = `-- name: Truncate :exec +TRUNCATE bar +` + +func (q *Queries) Truncate(ctx context.Context) error { + _, err := q.db.Exec(ctx, truncate) + return err +} diff --git a/internal/endtoend/testdata/truncate/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/truncate/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..47b8985 --- /dev/null +++ b/internal/endtoend/testdata/truncate/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: Truncate :exec +TRUNCATE bar; diff --git a/internal/endtoend/testdata/truncate/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/truncate/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/truncate/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/truncate/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/truncate/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/truncate/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/truncate/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/truncate/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/truncate/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/truncate/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/truncate/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..39cdf56 --- /dev/null +++ b/internal/endtoend/testdata/truncate/postgresql/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/truncate/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/truncate/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..b0369ef --- /dev/null +++ b/internal/endtoend/testdata/truncate/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const truncate = `-- name: Truncate :exec +TRUNCATE bar +` + +func (q *Queries) Truncate(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, truncate) + return err +} diff --git a/internal/endtoend/testdata/truncate/postgresql/stdlib/query.sql b/internal/endtoend/testdata/truncate/postgresql/stdlib/query.sql new file mode 100644 index 0000000..47b8985 --- /dev/null +++ b/internal/endtoend/testdata/truncate/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Truncate :exec +TRUNCATE bar; diff --git a/internal/endtoend/testdata/truncate/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/truncate/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..638370a --- /dev/null +++ b/internal/endtoend/testdata/truncate/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE bar (id serial not null); + diff --git a/internal/endtoend/testdata/truncate/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/truncate/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/truncate/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/types_uuid/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/types_uuid/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/types_uuid/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/types_uuid/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/types_uuid/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..4c24667 --- /dev/null +++ b/internal/endtoend/testdata/types_uuid/postgresql/stdlib/go/models.go @@ -0,0 +1,17 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + + "github.com/google/uuid" +) + +type Foo struct { + Description sql.NullString + Bar uuid.NullUUID + Baz uuid.UUID +} diff --git a/internal/endtoend/testdata/types_uuid/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/types_uuid/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..2f36a6e --- /dev/null +++ b/internal/endtoend/testdata/types_uuid/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,50 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/google/uuid" +) + +const find = `-- name: Find :one +SELECT bar FROM foo WHERE baz = $1 +` + +func (q *Queries) Find(ctx context.Context, baz uuid.UUID) (uuid.NullUUID, error) { + row := q.db.QueryRowContext(ctx, find, baz) + var bar uuid.NullUUID + err := row.Scan(&bar) + return bar, err +} + +const list = `-- name: List :many +SELECT description, bar, baz FROM foo +` + +func (q *Queries) List(ctx context.Context) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, list) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.Description, &i.Bar, &i.Baz); 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/types_uuid/postgresql/stdlib/query.sql b/internal/endtoend/testdata/types_uuid/postgresql/stdlib/query.sql new file mode 100644 index 0000000..b94846f --- /dev/null +++ b/internal/endtoend/testdata/types_uuid/postgresql/stdlib/query.sql @@ -0,0 +1,5 @@ +-- name: List :many +SELECT * FROM foo; + +-- name: Find :one +SELECT bar FROM foo WHERE baz = $1; diff --git a/internal/endtoend/testdata/types_uuid/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/types_uuid/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..b6ff9d1 --- /dev/null +++ b/internal/endtoend/testdata/types_uuid/postgresql/stdlib/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE foo ( + description text, + bar uuid, + baz uuid not null +); + diff --git a/internal/endtoend/testdata/types_uuid/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/types_uuid/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/types_uuid/postgresql/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/unknown_func/pganalyze/exec.json b/internal/endtoend/testdata/unknown_func/pganalyze/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/pganalyze/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/unknown_func/pganalyze/query.sql b/internal/endtoend/testdata/unknown_func/pganalyze/query.sql new file mode 100644 index 0000000..36b697c --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/pganalyze/query.sql @@ -0,0 +1,2 @@ +-- name: ListFoos :one +SELECT id FROM foo WHERE id = frobnicate($1); diff --git a/internal/endtoend/testdata/unknown_func/pganalyze/schema.sql b/internal/endtoend/testdata/unknown_func/pganalyze/schema.sql new file mode 100644 index 0000000..15fe209 --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/pganalyze/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (id text not null); diff --git a/internal/endtoend/testdata/unknown_func/pganalyze/sqlc.json b/internal/endtoend/testdata/unknown_func/pganalyze/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/pganalyze/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/unknown_func/pganalyze/stderr.txt b/internal/endtoend/testdata/unknown_func/pganalyze/stderr.txt new file mode 100644 index 0000000..8e63375 --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/pganalyze/stderr.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:2:31: function frobnicate(unknown) does not exist \ No newline at end of file diff --git a/internal/endtoend/testdata/unknown_func/pgx/v4/exec.json b/internal/endtoend/testdata/unknown_func/pgx/v4/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/pgx/v4/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/unknown_func/pgx/v4/go/db.go b/internal/endtoend/testdata/unknown_func/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/unknown_func/pgx/v4/go/models.go b/internal/endtoend/testdata/unknown_func/pgx/v4/go/models.go new file mode 100644 index 0000000..e954fe1 --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/pgx/v4/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + ID string +} diff --git a/internal/endtoend/testdata/unknown_func/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/unknown_func/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..617353d --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/pgx/v4/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listFoos = `-- name: ListFoos :one +SELECT id FROM foo WHERE id = frobnicate($1) +` + +func (q *Queries) ListFoos(ctx context.Context, frobnicate any) (string, error) { + row := q.db.QueryRow(ctx, listFoos, frobnicate) + var id string + err := row.Scan(&id) + return id, err +} diff --git a/internal/endtoend/testdata/unknown_func/pgx/v4/query.sql b/internal/endtoend/testdata/unknown_func/pgx/v4/query.sql new file mode 100644 index 0000000..36b697c --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: ListFoos :one +SELECT id FROM foo WHERE id = frobnicate($1); diff --git a/internal/endtoend/testdata/unknown_func/pgx/v4/schema.sql b/internal/endtoend/testdata/unknown_func/pgx/v4/schema.sql new file mode 100644 index 0000000..15fe209 --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/pgx/v4/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (id text not null); diff --git a/internal/endtoend/testdata/unknown_func/pgx/v4/sqlc.json b/internal/endtoend/testdata/unknown_func/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/unknown_func/pgx/v5/exec.json b/internal/endtoend/testdata/unknown_func/pgx/v5/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/pgx/v5/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/unknown_func/pgx/v5/go/db.go b/internal/endtoend/testdata/unknown_func/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/unknown_func/pgx/v5/go/models.go b/internal/endtoend/testdata/unknown_func/pgx/v5/go/models.go new file mode 100644 index 0000000..e954fe1 --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/pgx/v5/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + ID string +} diff --git a/internal/endtoend/testdata/unknown_func/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/unknown_func/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..617353d --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/pgx/v5/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listFoos = `-- name: ListFoos :one +SELECT id FROM foo WHERE id = frobnicate($1) +` + +func (q *Queries) ListFoos(ctx context.Context, frobnicate any) (string, error) { + row := q.db.QueryRow(ctx, listFoos, frobnicate) + var id string + err := row.Scan(&id) + return id, err +} diff --git a/internal/endtoend/testdata/unknown_func/pgx/v5/query.sql b/internal/endtoend/testdata/unknown_func/pgx/v5/query.sql new file mode 100644 index 0000000..36b697c --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: ListFoos :one +SELECT id FROM foo WHERE id = frobnicate($1); diff --git a/internal/endtoend/testdata/unknown_func/pgx/v5/schema.sql b/internal/endtoend/testdata/unknown_func/pgx/v5/schema.sql new file mode 100644 index 0000000..15fe209 --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/pgx/v5/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (id text not null); diff --git a/internal/endtoend/testdata/unknown_func/pgx/v5/sqlc.json b/internal/endtoend/testdata/unknown_func/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/unknown_func/stdlib/exec.json b/internal/endtoend/testdata/unknown_func/stdlib/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/stdlib/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/unknown_func/stdlib/go/db.go b/internal/endtoend/testdata/unknown_func/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/unknown_func/stdlib/go/models.go b/internal/endtoend/testdata/unknown_func/stdlib/go/models.go new file mode 100644 index 0000000..e954fe1 --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + ID string +} diff --git a/internal/endtoend/testdata/unknown_func/stdlib/go/query.sql.go b/internal/endtoend/testdata/unknown_func/stdlib/go/query.sql.go new file mode 100644 index 0000000..79dce10 --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/stdlib/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listFoos = `-- name: ListFoos :one +SELECT id FROM foo WHERE id = frobnicate($1) +` + +func (q *Queries) ListFoos(ctx context.Context, frobnicate any) (string, error) { + row := q.db.QueryRowContext(ctx, listFoos, frobnicate) + var id string + err := row.Scan(&id) + return id, err +} diff --git a/internal/endtoend/testdata/unknown_func/stdlib/query.sql b/internal/endtoend/testdata/unknown_func/stdlib/query.sql new file mode 100644 index 0000000..36b697c --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: ListFoos :one +SELECT id FROM foo WHERE id = frobnicate($1); diff --git a/internal/endtoend/testdata/unknown_func/stdlib/schema.sql b/internal/endtoend/testdata/unknown_func/stdlib/schema.sql new file mode 100644 index 0000000..15fe209 --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/stdlib/schema.sql @@ -0,0 +1 @@ +CREATE TABLE foo (id text not null); diff --git a/internal/endtoend/testdata/unknown_func/stdlib/sqlc.json b/internal/endtoend/testdata/unknown_func/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/unknown_func/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/unnest/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/unnest/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/unnest/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/unnest/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/unnest/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..7d9643e --- /dev/null +++ b/internal/endtoend/testdata/unnest/postgresql/pgx/v4/go/models.go @@ -0,0 +1,23 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + "time" + + "github.com/google/uuid" +) + +type Memory struct { + ID uuid.UUID + VampireID uuid.UUID + CreatedAt time.Time + UpdatedAt sql.NullTime +} + +type Vampire struct { + ID uuid.UUID +} diff --git a/internal/endtoend/testdata/unnest/postgresql/pgx/v4/go/querier.go b/internal/endtoend/testdata/unnest/postgresql/pgx/v4/go/querier.go new file mode 100644 index 0000000..4d4e005 --- /dev/null +++ b/internal/endtoend/testdata/unnest/postgresql/pgx/v4/go/querier.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/google/uuid" +) + +type Querier interface { + CreateMemories(ctx context.Context, vampireID []uuid.UUID) ([]Memory, error) + GetVampireIDs(ctx context.Context, vampireID []uuid.UUID) ([]uuid.UUID, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/unnest/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/unnest/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..9296f7b --- /dev/null +++ b/internal/endtoend/testdata/unnest/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,69 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/google/uuid" +) + +const createMemories = `-- name: CreateMemories :many +INSERT INTO memories (vampire_id) +SELECT + unnest($1::uuid[]) AS vampire_id +RETURNING + id, vampire_id, created_at, updated_at +` + +func (q *Queries) CreateMemories(ctx context.Context, vampireID []uuid.UUID) ([]Memory, error) { + rows, err := q.db.Query(ctx, createMemories, vampireID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Memory + for rows.Next() { + var i Memory + if err := rows.Scan( + &i.ID, + &i.VampireID, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getVampireIDs = `-- name: GetVampireIDs :many +SELECT vampires.id::uuid FROM unnest($1::uuid[]) AS vampires (id) +` + +func (q *Queries) GetVampireIDs(ctx context.Context, vampireID []uuid.UUID) ([]uuid.UUID, error) { + rows, err := q.db.Query(ctx, getVampireIDs, vampireID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []uuid.UUID + for rows.Next() { + var vampires_id uuid.UUID + if err := rows.Scan(&vampires_id); err != nil { + return nil, err + } + items = append(items, vampires_id) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/unnest/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/unnest/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..d06a057 --- /dev/null +++ b/internal/endtoend/testdata/unnest/postgresql/pgx/v4/query.sql @@ -0,0 +1,9 @@ +-- name: CreateMemories :many +INSERT INTO memories (vampire_id) +SELECT + unnest(@vampire_id::uuid[]) AS vampire_id +RETURNING + *; + +-- name: GetVampireIDs :many +SELECT vampires.id::uuid FROM unnest(@vampire_id::uuid[]) AS vampires (id); diff --git a/internal/endtoend/testdata/unnest/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/unnest/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..5f539d7 --- /dev/null +++ b/internal/endtoend/testdata/unnest/postgresql/pgx/v4/schema.sql @@ -0,0 +1,10 @@ +CREATE TABLE vampires ( + id uuid PRIMARY KEY DEFAULT gen_random_uuid () +); + +CREATE TABLE memories ( + id uuid PRIMARY KEY DEFAULT gen_random_uuid (), + vampire_id uuid REFERENCES vampires (id) NOT NULL, + created_at timestamp NOT NULL DEFAULT NOW(), + updated_at timestamp +); diff --git a/internal/endtoend/testdata/unnest/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/unnest/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..e0530db --- /dev/null +++ b/internal/endtoend/testdata/unnest/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_interface": true + } + ] +} diff --git a/internal/endtoend/testdata/unnest/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/unnest/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/unnest/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/unnest/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/unnest/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..07a26f8 --- /dev/null +++ b/internal/endtoend/testdata/unnest/postgresql/pgx/v5/go/models.go @@ -0,0 +1,20 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Memory struct { + ID pgtype.UUID + VampireID pgtype.UUID + CreatedAt pgtype.Timestamp + UpdatedAt pgtype.Timestamp +} + +type Vampire struct { + ID pgtype.UUID +} diff --git a/internal/endtoend/testdata/unnest/postgresql/pgx/v5/go/querier.go b/internal/endtoend/testdata/unnest/postgresql/pgx/v5/go/querier.go new file mode 100644 index 0000000..9df09c9 --- /dev/null +++ b/internal/endtoend/testdata/unnest/postgresql/pgx/v5/go/querier.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +type Querier interface { + CreateMemories(ctx context.Context, vampireID []pgtype.UUID) ([]Memory, error) + GetVampireIDs(ctx context.Context, vampireID []pgtype.UUID) ([]pgtype.UUID, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/unnest/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/unnest/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..0b4d288 --- /dev/null +++ b/internal/endtoend/testdata/unnest/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,69 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const createMemories = `-- name: CreateMemories :many +INSERT INTO memories (vampire_id) +SELECT + unnest($1::uuid[]) AS vampire_id +RETURNING + id, vampire_id, created_at, updated_at +` + +func (q *Queries) CreateMemories(ctx context.Context, vampireID []pgtype.UUID) ([]Memory, error) { + rows, err := q.db.Query(ctx, createMemories, vampireID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Memory + for rows.Next() { + var i Memory + if err := rows.Scan( + &i.ID, + &i.VampireID, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getVampireIDs = `-- name: GetVampireIDs :many +SELECT vampires.id::uuid FROM unnest($1::uuid[]) AS vampires (id) +` + +func (q *Queries) GetVampireIDs(ctx context.Context, vampireID []pgtype.UUID) ([]pgtype.UUID, error) { + rows, err := q.db.Query(ctx, getVampireIDs, vampireID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []pgtype.UUID + for rows.Next() { + var vampires_id pgtype.UUID + if err := rows.Scan(&vampires_id); err != nil { + return nil, err + } + items = append(items, vampires_id) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/unnest/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/unnest/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..d06a057 --- /dev/null +++ b/internal/endtoend/testdata/unnest/postgresql/pgx/v5/query.sql @@ -0,0 +1,9 @@ +-- name: CreateMemories :many +INSERT INTO memories (vampire_id) +SELECT + unnest(@vampire_id::uuid[]) AS vampire_id +RETURNING + *; + +-- name: GetVampireIDs :many +SELECT vampires.id::uuid FROM unnest(@vampire_id::uuid[]) AS vampires (id); diff --git a/internal/endtoend/testdata/unnest/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/unnest/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..5f539d7 --- /dev/null +++ b/internal/endtoend/testdata/unnest/postgresql/pgx/v5/schema.sql @@ -0,0 +1,10 @@ +CREATE TABLE vampires ( + id uuid PRIMARY KEY DEFAULT gen_random_uuid () +); + +CREATE TABLE memories ( + id uuid PRIMARY KEY DEFAULT gen_random_uuid (), + vampire_id uuid REFERENCES vampires (id) NOT NULL, + created_at timestamp NOT NULL DEFAULT NOW(), + updated_at timestamp +); diff --git a/internal/endtoend/testdata/unnest/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/unnest/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..007fb85 --- /dev/null +++ b/internal/endtoend/testdata/unnest/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_interface": true + } + ] +} diff --git a/internal/endtoend/testdata/unnest/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/unnest/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/unnest/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/unnest/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/unnest/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..7d9643e --- /dev/null +++ b/internal/endtoend/testdata/unnest/postgresql/stdlib/go/models.go @@ -0,0 +1,23 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + "time" + + "github.com/google/uuid" +) + +type Memory struct { + ID uuid.UUID + VampireID uuid.UUID + CreatedAt time.Time + UpdatedAt sql.NullTime +} + +type Vampire struct { + ID uuid.UUID +} diff --git a/internal/endtoend/testdata/unnest/postgresql/stdlib/go/querier.go b/internal/endtoend/testdata/unnest/postgresql/stdlib/go/querier.go new file mode 100644 index 0000000..4d4e005 --- /dev/null +++ b/internal/endtoend/testdata/unnest/postgresql/stdlib/go/querier.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/google/uuid" +) + +type Querier interface { + CreateMemories(ctx context.Context, vampireID []uuid.UUID) ([]Memory, error) + GetVampireIDs(ctx context.Context, vampireID []uuid.UUID) ([]uuid.UUID, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/unnest/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/unnest/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..110208d --- /dev/null +++ b/internal/endtoend/testdata/unnest/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,76 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/google/uuid" + "github.com/lib/pq" +) + +const createMemories = `-- name: CreateMemories :many +INSERT INTO memories (vampire_id) +SELECT + unnest($1::uuid[]) AS vampire_id +RETURNING + id, vampire_id, created_at, updated_at +` + +func (q *Queries) CreateMemories(ctx context.Context, vampireID []uuid.UUID) ([]Memory, error) { + rows, err := q.db.QueryContext(ctx, createMemories, pq.Array(vampireID)) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Memory + for rows.Next() { + var i Memory + if err := rows.Scan( + &i.ID, + &i.VampireID, + &i.CreatedAt, + &i.UpdatedAt, + ); 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 getVampireIDs = `-- name: GetVampireIDs :many +SELECT vampires.id::uuid FROM unnest($1::uuid[]) AS vampires (id) +` + +func (q *Queries) GetVampireIDs(ctx context.Context, vampireID []uuid.UUID) ([]uuid.UUID, error) { + rows, err := q.db.QueryContext(ctx, getVampireIDs, pq.Array(vampireID)) + if err != nil { + return nil, err + } + defer rows.Close() + var items []uuid.UUID + for rows.Next() { + var vampires_id uuid.UUID + if err := rows.Scan(&vampires_id); err != nil { + return nil, err + } + items = append(items, vampires_id) + } + 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/unnest/postgresql/stdlib/query.sql b/internal/endtoend/testdata/unnest/postgresql/stdlib/query.sql new file mode 100644 index 0000000..d06a057 --- /dev/null +++ b/internal/endtoend/testdata/unnest/postgresql/stdlib/query.sql @@ -0,0 +1,9 @@ +-- name: CreateMemories :many +INSERT INTO memories (vampire_id) +SELECT + unnest(@vampire_id::uuid[]) AS vampire_id +RETURNING + *; + +-- name: GetVampireIDs :many +SELECT vampires.id::uuid FROM unnest(@vampire_id::uuid[]) AS vampires (id); diff --git a/internal/endtoend/testdata/unnest/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/unnest/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..5f539d7 --- /dev/null +++ b/internal/endtoend/testdata/unnest/postgresql/stdlib/schema.sql @@ -0,0 +1,10 @@ +CREATE TABLE vampires ( + id uuid PRIMARY KEY DEFAULT gen_random_uuid () +); + +CREATE TABLE memories ( + id uuid PRIMARY KEY DEFAULT gen_random_uuid (), + vampire_id uuid REFERENCES vampires (id) NOT NULL, + created_at timestamp NOT NULL DEFAULT NOW(), + updated_at timestamp +); diff --git a/internal/endtoend/testdata/unnest/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/unnest/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..36f98f9 --- /dev/null +++ b/internal/endtoend/testdata/unnest/postgresql/stdlib/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_interface": true + } + ] +} diff --git a/internal/endtoend/testdata/unnest_star/issue.md b/internal/endtoend/testdata/unnest_star/issue.md new file mode 100644 index 0000000..d0aede5 --- /dev/null +++ b/internal/endtoend/testdata/unnest_star/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1185 \ No newline at end of file diff --git a/internal/endtoend/testdata/unnest_star/postgresql/pgx/exec.json b/internal/endtoend/testdata/unnest_star/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/unnest_star/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/unnest_star/postgresql/pgx/go/db.go b/internal/endtoend/testdata/unnest_star/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/unnest_star/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/unnest_star/postgresql/pgx/go/models.go b/internal/endtoend/testdata/unnest_star/postgresql/pgx/go/models.go new file mode 100644 index 0000000..858f2fd --- /dev/null +++ b/internal/endtoend/testdata/unnest_star/postgresql/pgx/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Item struct { + ItemID int64 +} + +type Plan struct { + PlanID int64 +} + +type PlanItem struct { + PlanItemID int64 + PlanID int64 + ItemID int64 +} diff --git a/internal/endtoend/testdata/unnest_star/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/unnest_star/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..fc8ca8e --- /dev/null +++ b/internal/endtoend/testdata/unnest_star/postgresql/pgx/go/query.sql.go @@ -0,0 +1,57 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const getPlanItems = `-- name: GetPlanItems :many +SELECT p.plan_id, p.item_id +FROM (SELECT unnest FROM unnest($1::bigint[])) AS i(req_item_id), +LATERAL ( + SELECT plan_id, item_id + FROM plan_items + WHERE + item_id = i.req_item_id AND + ($2 = 0 OR plan_id < $2) + ORDER BY plan_id DESC + LIMIT $3 +) p +` + +type GetPlanItemsParams struct { + Ids []int64 + After pgtype.Int4 + LimitCount int64 +} + +type GetPlanItemsRow struct { + PlanID int64 + ItemID int64 +} + +func (q *Queries) GetPlanItems(ctx context.Context, arg GetPlanItemsParams) ([]GetPlanItemsRow, error) { + rows, err := q.db.Query(ctx, getPlanItems, arg.Ids, arg.After, arg.LimitCount) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetPlanItemsRow + for rows.Next() { + var i GetPlanItemsRow + if err := rows.Scan(&i.PlanID, &i.ItemID); 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/unnest_star/postgresql/pgx/query.sql b/internal/endtoend/testdata/unnest_star/postgresql/pgx/query.sql new file mode 100644 index 0000000..01b5c77 --- /dev/null +++ b/internal/endtoend/testdata/unnest_star/postgresql/pgx/query.sql @@ -0,0 +1,12 @@ +-- name: GetPlanItems :many +SELECT p.plan_id, p.item_id +FROM (SELECT * FROM unnest(@ids::bigint[])) AS i(req_item_id), +LATERAL ( + SELECT plan_id, item_id + FROM plan_items + WHERE + item_id = i.req_item_id AND + (@after = 0 OR plan_id < @after) + ORDER BY plan_id DESC + LIMIT @limit_count +) p; \ No newline at end of file diff --git a/internal/endtoend/testdata/unnest_star/postgresql/pgx/schema.sql b/internal/endtoend/testdata/unnest_star/postgresql/pgx/schema.sql new file mode 100644 index 0000000..787caf8 --- /dev/null +++ b/internal/endtoend/testdata/unnest_star/postgresql/pgx/schema.sql @@ -0,0 +1,13 @@ +create table plans ( + plan_id bigint generated by default as identity primary key +); + +create table items ( + item_id bigint generated by default as identity primary key +); + +create table plan_items ( + plan_item_id bigint generated by default as identity primary key, + plan_id bigint not null REFERENCES plans, + item_id bigint not null REFERENCES items +); \ No newline at end of file diff --git a/internal/endtoend/testdata/unnest_star/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/unnest_star/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..01489e0 --- /dev/null +++ b/internal/endtoend/testdata/unnest_star/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" \ No newline at end of file diff --git a/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/unnest_with_ordinality/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..82ed0a7 --- /dev/null +++ b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type ArrayValue struct { + ID int64 + Values []string +} diff --git a/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/go/querier.go b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/go/querier.go new file mode 100644 index 0000000..f92fe57 --- /dev/null +++ b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/go/querier.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" +) + +type Querier interface { + GetValues(ctx context.Context) ([]GetValuesRow, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..bebb7c9 --- /dev/null +++ b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,41 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getValues = `-- name: GetValues :many +SELECT id, index::bigint, value::text +FROM array_values AS x, unnest(values) WITH ORDINALITY AS y (value, index) +` + +type GetValuesRow struct { + ID int64 + Index int64 + Value string +} + +func (q *Queries) GetValues(ctx context.Context) ([]GetValuesRow, error) { + rows, err := q.db.Query(ctx, getValues) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetValuesRow + for rows.Next() { + var i GetValuesRow + if err := rows.Scan(&i.ID, &i.Index, &i.Value); 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/unnest_with_ordinality/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..8bed8bd --- /dev/null +++ b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/query.sql @@ -0,0 +1,3 @@ +-- name: GetValues :many +SELECT id, index::bigint, value::text +FROM array_values AS x, unnest(values) WITH ORDINALITY AS y (value, index); diff --git a/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..2a9a261 --- /dev/null +++ b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE array_values ( + id bigserial PRIMARY KEY, + values text[] NOT NULL +); diff --git a/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..e0530db --- /dev/null +++ b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_interface": true + } + ] +} diff --git a/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/unnest_with_ordinality/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..82ed0a7 --- /dev/null +++ b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type ArrayValue struct { + ID int64 + Values []string +} diff --git a/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/go/querier.go b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/go/querier.go new file mode 100644 index 0000000..f92fe57 --- /dev/null +++ b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/go/querier.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" +) + +type Querier interface { + GetValues(ctx context.Context) ([]GetValuesRow, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..bebb7c9 --- /dev/null +++ b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,41 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getValues = `-- name: GetValues :many +SELECT id, index::bigint, value::text +FROM array_values AS x, unnest(values) WITH ORDINALITY AS y (value, index) +` + +type GetValuesRow struct { + ID int64 + Index int64 + Value string +} + +func (q *Queries) GetValues(ctx context.Context) ([]GetValuesRow, error) { + rows, err := q.db.Query(ctx, getValues) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetValuesRow + for rows.Next() { + var i GetValuesRow + if err := rows.Scan(&i.ID, &i.Index, &i.Value); 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/unnest_with_ordinality/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..8bed8bd --- /dev/null +++ b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/query.sql @@ -0,0 +1,3 @@ +-- name: GetValues :many +SELECT id, index::bigint, value::text +FROM array_values AS x, unnest(values) WITH ORDINALITY AS y (value, index); diff --git a/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..2a9a261 --- /dev/null +++ b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE array_values ( + id bigserial PRIMARY KEY, + values text[] NOT NULL +); diff --git a/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..007fb85 --- /dev/null +++ b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,14 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_interface": true + } + ] +} diff --git a/internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/unnest_with_ordinality/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..82ed0a7 --- /dev/null +++ b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type ArrayValue struct { + ID int64 + Values []string +} diff --git a/internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/go/querier.go b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/go/querier.go new file mode 100644 index 0000000..f92fe57 --- /dev/null +++ b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/go/querier.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" +) + +type Querier interface { + GetValues(ctx context.Context) ([]GetValuesRow, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..8578cc6 --- /dev/null +++ b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,44 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getValues = `-- name: GetValues :many +SELECT id, index::bigint, value::text +FROM array_values AS x, unnest(values) WITH ORDINALITY AS y (value, index) +` + +type GetValuesRow struct { + ID int64 + Index int64 + Value string +} + +func (q *Queries) GetValues(ctx context.Context) ([]GetValuesRow, error) { + rows, err := q.db.QueryContext(ctx, getValues) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetValuesRow + for rows.Next() { + var i GetValuesRow + if err := rows.Scan(&i.ID, &i.Index, &i.Value); 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/unnest_with_ordinality/postgresql/stdlib/query.sql b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/query.sql new file mode 100644 index 0000000..8bed8bd --- /dev/null +++ b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/query.sql @@ -0,0 +1,3 @@ +-- name: GetValues :many +SELECT id, index::bigint, value::text +FROM array_values AS x, unnest(values) WITH ORDINALITY AS y (value, index); diff --git a/internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..2a9a261 --- /dev/null +++ b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE array_values ( + id bigserial PRIMARY KEY, + values text[] NOT NULL +); diff --git a/internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..36f98f9 --- /dev/null +++ b/internal/endtoend/testdata/unnest_with_ordinality/postgresql/stdlib/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_interface": true + } + ] +} diff --git a/internal/endtoend/testdata/unsigned_params/mysql/go/db.go b/internal/endtoend/testdata/unsigned_params/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/unsigned_params/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/unsigned_params/mysql/go/models.go b/internal/endtoend/testdata/unsigned_params/mysql/go/models.go new file mode 100644 index 0000000..574d298 --- /dev/null +++ b/internal/endtoend/testdata/unsigned_params/mysql/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + ID uint32 +} diff --git a/internal/endtoend/testdata/unsigned_params/mysql/go/query.sql.go b/internal/endtoend/testdata/unsigned_params/mysql/go/query.sql.go new file mode 100644 index 0000000..6b29beb --- /dev/null +++ b/internal/endtoend/testdata/unsigned_params/mysql/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const createFoo = `-- name: CreateFoo :exec +INSERT INTO foo (id) VALUES (?) +` + +func (q *Queries) CreateFoo(ctx context.Context, id uint32) error { + _, err := q.db.ExecContext(ctx, createFoo, id) + return err +} diff --git a/internal/endtoend/testdata/unsigned_params/mysql/query.sql b/internal/endtoend/testdata/unsigned_params/mysql/query.sql new file mode 100644 index 0000000..75f888c --- /dev/null +++ b/internal/endtoend/testdata/unsigned_params/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: CreateFoo :exec +INSERT INTO foo (id) VALUES (?); diff --git a/internal/endtoend/testdata/unsigned_params/mysql/schema.sql b/internal/endtoend/testdata/unsigned_params/mysql/schema.sql new file mode 100644 index 0000000..e1d9224 --- /dev/null +++ b/internal/endtoend/testdata/unsigned_params/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (id INT UNSIGNED NOT NULL); + diff --git a/internal/endtoend/testdata/unsigned_params/mysql/sqlc.json b/internal/endtoend/testdata/unsigned_params/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/unsigned_params/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/untyped_columns/sqlite/stdlib/db/db.go b/internal/endtoend/testdata/untyped_columns/sqlite/stdlib/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/untyped_columns/sqlite/stdlib/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/untyped_columns/sqlite/stdlib/db/models.go b/internal/endtoend/testdata/untyped_columns/sqlite/stdlib/db/models.go new file mode 100644 index 0000000..4f5ee4e --- /dev/null +++ b/internal/endtoend/testdata/untyped_columns/sqlite/stdlib/db/models.go @@ -0,0 +1,11 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +type Repro struct { + ID any + Name any + Seq any +} diff --git a/internal/endtoend/testdata/untyped_columns/sqlite/stdlib/db/query.sql.go b/internal/endtoend/testdata/untyped_columns/sqlite/stdlib/db/query.sql.go new file mode 100644 index 0000000..faef316 --- /dev/null +++ b/internal/endtoend/testdata/untyped_columns/sqlite/stdlib/db/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" +) + +const getRepro = `-- name: GetRepro :one +SELECT id, name, seq FROM repro WHERE id = ? LIMIT 1 +` + +func (q *Queries) GetRepro(ctx context.Context, id any) (Repro, error) { + row := q.db.QueryRowContext(ctx, getRepro, id) + var i Repro + err := row.Scan(&i.ID, &i.Name, &i.Seq) + return i, err +} diff --git a/internal/endtoend/testdata/untyped_columns/sqlite/stdlib/query.sql b/internal/endtoend/testdata/untyped_columns/sqlite/stdlib/query.sql new file mode 100644 index 0000000..b3923f2 --- /dev/null +++ b/internal/endtoend/testdata/untyped_columns/sqlite/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: GetRepro :one +SELECT * FROM repro WHERE id = ? LIMIT 1; diff --git a/internal/endtoend/testdata/untyped_columns/sqlite/stdlib/schema.sql b/internal/endtoend/testdata/untyped_columns/sqlite/stdlib/schema.sql new file mode 100644 index 0000000..5a98bb0 --- /dev/null +++ b/internal/endtoend/testdata/untyped_columns/sqlite/stdlib/schema.sql @@ -0,0 +1,3 @@ +-- original table name in sqlite schema was sqlite_sequence, rest of def is identical +create table repro(id, name, seq); + diff --git a/internal/endtoend/testdata/untyped_columns/sqlite/stdlib/sqlc.json b/internal/endtoend/testdata/untyped_columns/sqlite/stdlib/sqlc.json new file mode 100644 index 0000000..58ea3c6 --- /dev/null +++ b/internal/endtoend/testdata/untyped_columns/sqlite/stdlib/sqlc.json @@ -0,0 +1,16 @@ +{ + "version": "2", + "sql": [ + { + "engine": "sqlite", + "schema": "schema.sql", + "queries": "query.sql", + "gen": { + "go": { + "package": "db", + "out": "db" + } + } + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/update_array_index/issue.md b/internal/endtoend/testdata/update_array_index/issue.md new file mode 100644 index 0000000..d86fb5d --- /dev/null +++ b/internal/endtoend/testdata/update_array_index/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1532 diff --git a/internal/endtoend/testdata/update_array_index/postgresql/pgx/exec.json b/internal/endtoend/testdata/update_array_index/postgresql/pgx/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/update_array_index/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/update_array_index/postgresql/pgx/go/db.go b/internal/endtoend/testdata/update_array_index/postgresql/pgx/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/update_array_index/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/update_array_index/postgresql/pgx/go/models.go b/internal/endtoend/testdata/update_array_index/postgresql/pgx/go/models.go new file mode 100644 index 0000000..f7de8cd --- /dev/null +++ b/internal/endtoend/testdata/update_array_index/postgresql/pgx/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Author struct { + ID int64 + Names []string +} diff --git a/internal/endtoend/testdata/update_array_index/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/update_array_index/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000..3ec4407 --- /dev/null +++ b/internal/endtoend/testdata/update_array_index/postgresql/pgx/go/query.sql.go @@ -0,0 +1,30 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const updateAuthor = `-- name: UpdateAuthor :one +update authors +set names[$1] = $2 +where id=$3 +RETURNING id, names +` + +type UpdateAuthorParams struct { + Names int32 + Names_2 string + ID int64 +} + +func (q *Queries) UpdateAuthor(ctx context.Context, arg UpdateAuthorParams) (Author, error) { + row := q.db.QueryRow(ctx, updateAuthor, arg.Names, arg.Names_2, arg.ID) + var i Author + err := row.Scan(&i.ID, &i.Names) + return i, err +} diff --git a/internal/endtoend/testdata/update_array_index/postgresql/pgx/query.sql b/internal/endtoend/testdata/update_array_index/postgresql/pgx/query.sql new file mode 100644 index 0000000..32b4e9c --- /dev/null +++ b/internal/endtoend/testdata/update_array_index/postgresql/pgx/query.sql @@ -0,0 +1,5 @@ +-- name: UpdateAuthor :one +update authors +set names[$1] = $2 +where id=$3 +RETURNING *; diff --git a/internal/endtoend/testdata/update_array_index/postgresql/pgx/schema.sql b/internal/endtoend/testdata/update_array_index/postgresql/pgx/schema.sql new file mode 100644 index 0000000..286ab79 --- /dev/null +++ b/internal/endtoend/testdata/update_array_index/postgresql/pgx/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + names text[] NOT NULL +); diff --git a/internal/endtoend/testdata/update_array_index/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/update_array_index/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5dc63e3 --- /dev/null +++ b/internal/endtoend/testdata/update_array_index/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/update_cte/pgx/v4/go/db.go b/internal/endtoend/testdata/update_cte/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/update_cte/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/update_cte/pgx/v4/go/models.go b/internal/endtoend/testdata/update_cte/pgx/v4/go/models.go new file mode 100644 index 0000000..97ccea3 --- /dev/null +++ b/internal/endtoend/testdata/update_cte/pgx/v4/go/models.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + "time" +) + +type Td3Code struct { + ID int32 + TsCreated time.Time + TsUpdated time.Time + CreatedBy string + UpdatedBy string + Code sql.NullString + Hash sql.NullString + IsPrivate sql.NullBool +} + +type Td3TestCode struct { + ID int32 + TsCreated time.Time + TsUpdated time.Time + CreatedBy string + UpdatedBy string + TestID int32 + CodeHash string +} diff --git a/internal/endtoend/testdata/update_cte/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/update_cte/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..9325d9a --- /dev/null +++ b/internal/endtoend/testdata/update_cte/pgx/v4/go/query.sql.go @@ -0,0 +1,72 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" + "time" +) + +const updateCode = `-- name: UpdateCode :one +WITH cc AS ( + UPDATE td3.codes + SET + created_by = $1, + updated_by = $1, + code = $2, + hash = $3, + is_private = false + RETURNING hash +) +UPDATE td3.test_codes +SET + created_by = $1, + updated_by = $1, + test_id = $4, + code_hash = cc.hash + FROM cc +RETURNING hash, id, ts_created, ts_updated, created_by, updated_by, test_id, code_hash +` + +type UpdateCodeParams struct { + CreatedBy string + Code sql.NullString + Hash sql.NullString + TestID int32 +} + +type UpdateCodeRow struct { + Hash sql.NullString + ID int32 + TsCreated time.Time + TsUpdated time.Time + CreatedBy string + UpdatedBy string + TestID int32 + CodeHash string +} + +func (q *Queries) UpdateCode(ctx context.Context, arg UpdateCodeParams) (UpdateCodeRow, error) { + row := q.db.QueryRow(ctx, updateCode, + arg.CreatedBy, + arg.Code, + arg.Hash, + arg.TestID, + ) + var i UpdateCodeRow + err := row.Scan( + &i.Hash, + &i.ID, + &i.TsCreated, + &i.TsUpdated, + &i.CreatedBy, + &i.UpdatedBy, + &i.TestID, + &i.CodeHash, + ) + return i, err +} diff --git a/internal/endtoend/testdata/update_cte/pgx/v4/query.sql b/internal/endtoend/testdata/update_cte/pgx/v4/query.sql new file mode 100644 index 0000000..d1f8ffa --- /dev/null +++ b/internal/endtoend/testdata/update_cte/pgx/v4/query.sql @@ -0,0 +1,19 @@ +-- name: UpdateCode :one +WITH cc AS ( + UPDATE td3.codes + SET + created_by = $1, + updated_by = $1, + code = $2, + hash = $3, + is_private = false + RETURNING hash +) +UPDATE td3.test_codes +SET + created_by = $1, + updated_by = $1, + test_id = $4, + code_hash = cc.hash + FROM cc +RETURNING *; diff --git a/internal/endtoend/testdata/update_cte/pgx/v4/schema.sql b/internal/endtoend/testdata/update_cte/pgx/v4/schema.sql new file mode 100644 index 0000000..1eb3dcf --- /dev/null +++ b/internal/endtoend/testdata/update_cte/pgx/v4/schema.sql @@ -0,0 +1,31 @@ +-- FILE: schema.sql + +DROP SCHEMA IF EXISTS td3 CASCADE; +CREATE SCHEMA td3; + +CREATE TABLE td3.codes ( + id SERIAL PRIMARY KEY, + ts_created timestamptz DEFAULT now() NOT NULL, + ts_updated timestamptz DEFAULT now() NOT NULL, + created_by text NOT NULL, + updated_by text NOT NULL, + + code text, + hash text, + is_private boolean +); + + +CREATE TABLE td3.test_codes ( + id SERIAL PRIMARY KEY, + ts_created timestamptz DEFAULT now() NOT NULL, + ts_updated timestamptz DEFAULT now() NOT NULL, + created_by text NOT NULL, + updated_by text NOT NULL, + + test_id integer NOT NULL, + code_hash text NOT NULL +); + +-- FILE: query.sql + diff --git a/internal/endtoend/testdata/update_cte/pgx/v4/sqlc.json b/internal/endtoend/testdata/update_cte/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/update_cte/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/update_cte/pgx/v5/go/db.go b/internal/endtoend/testdata/update_cte/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/update_cte/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/update_cte/pgx/v5/go/models.go b/internal/endtoend/testdata/update_cte/pgx/v5/go/models.go new file mode 100644 index 0000000..6aae2a6 --- /dev/null +++ b/internal/endtoend/testdata/update_cte/pgx/v5/go/models.go @@ -0,0 +1,30 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Td3Code struct { + ID int32 + TsCreated pgtype.Timestamptz + TsUpdated pgtype.Timestamptz + CreatedBy string + UpdatedBy string + Code pgtype.Text + Hash pgtype.Text + IsPrivate pgtype.Bool +} + +type Td3TestCode struct { + ID int32 + TsCreated pgtype.Timestamptz + TsUpdated pgtype.Timestamptz + CreatedBy string + UpdatedBy string + TestID int32 + CodeHash string +} diff --git a/internal/endtoend/testdata/update_cte/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/update_cte/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..cabcf2f --- /dev/null +++ b/internal/endtoend/testdata/update_cte/pgx/v5/go/query.sql.go @@ -0,0 +1,72 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const updateCode = `-- name: UpdateCode :one +WITH cc AS ( + UPDATE td3.codes + SET + created_by = $1, + updated_by = $1, + code = $2, + hash = $3, + is_private = false + RETURNING hash +) +UPDATE td3.test_codes +SET + created_by = $1, + updated_by = $1, + test_id = $4, + code_hash = cc.hash + FROM cc +RETURNING hash, id, ts_created, ts_updated, created_by, updated_by, test_id, code_hash +` + +type UpdateCodeParams struct { + CreatedBy string + Code pgtype.Text + Hash pgtype.Text + TestID int32 +} + +type UpdateCodeRow struct { + Hash pgtype.Text + ID int32 + TsCreated pgtype.Timestamptz + TsUpdated pgtype.Timestamptz + CreatedBy string + UpdatedBy string + TestID int32 + CodeHash string +} + +func (q *Queries) UpdateCode(ctx context.Context, arg UpdateCodeParams) (UpdateCodeRow, error) { + row := q.db.QueryRow(ctx, updateCode, + arg.CreatedBy, + arg.Code, + arg.Hash, + arg.TestID, + ) + var i UpdateCodeRow + err := row.Scan( + &i.Hash, + &i.ID, + &i.TsCreated, + &i.TsUpdated, + &i.CreatedBy, + &i.UpdatedBy, + &i.TestID, + &i.CodeHash, + ) + return i, err +} diff --git a/internal/endtoend/testdata/update_cte/pgx/v5/query.sql b/internal/endtoend/testdata/update_cte/pgx/v5/query.sql new file mode 100644 index 0000000..d1f8ffa --- /dev/null +++ b/internal/endtoend/testdata/update_cte/pgx/v5/query.sql @@ -0,0 +1,19 @@ +-- name: UpdateCode :one +WITH cc AS ( + UPDATE td3.codes + SET + created_by = $1, + updated_by = $1, + code = $2, + hash = $3, + is_private = false + RETURNING hash +) +UPDATE td3.test_codes +SET + created_by = $1, + updated_by = $1, + test_id = $4, + code_hash = cc.hash + FROM cc +RETURNING *; diff --git a/internal/endtoend/testdata/update_cte/pgx/v5/schema.sql b/internal/endtoend/testdata/update_cte/pgx/v5/schema.sql new file mode 100644 index 0000000..1eb3dcf --- /dev/null +++ b/internal/endtoend/testdata/update_cte/pgx/v5/schema.sql @@ -0,0 +1,31 @@ +-- FILE: schema.sql + +DROP SCHEMA IF EXISTS td3 CASCADE; +CREATE SCHEMA td3; + +CREATE TABLE td3.codes ( + id SERIAL PRIMARY KEY, + ts_created timestamptz DEFAULT now() NOT NULL, + ts_updated timestamptz DEFAULT now() NOT NULL, + created_by text NOT NULL, + updated_by text NOT NULL, + + code text, + hash text, + is_private boolean +); + + +CREATE TABLE td3.test_codes ( + id SERIAL PRIMARY KEY, + ts_created timestamptz DEFAULT now() NOT NULL, + ts_updated timestamptz DEFAULT now() NOT NULL, + created_by text NOT NULL, + updated_by text NOT NULL, + + test_id integer NOT NULL, + code_hash text NOT NULL +); + +-- FILE: query.sql + diff --git a/internal/endtoend/testdata/update_cte/pgx/v5/sqlc.json b/internal/endtoend/testdata/update_cte/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/update_cte/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/update_cte/stdlib/go/db.go b/internal/endtoend/testdata/update_cte/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/update_cte/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/update_cte/stdlib/go/models.go b/internal/endtoend/testdata/update_cte/stdlib/go/models.go new file mode 100644 index 0000000..97ccea3 --- /dev/null +++ b/internal/endtoend/testdata/update_cte/stdlib/go/models.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + "time" +) + +type Td3Code struct { + ID int32 + TsCreated time.Time + TsUpdated time.Time + CreatedBy string + UpdatedBy string + Code sql.NullString + Hash sql.NullString + IsPrivate sql.NullBool +} + +type Td3TestCode struct { + ID int32 + TsCreated time.Time + TsUpdated time.Time + CreatedBy string + UpdatedBy string + TestID int32 + CodeHash string +} diff --git a/internal/endtoend/testdata/update_cte/stdlib/go/query.sql.go b/internal/endtoend/testdata/update_cte/stdlib/go/query.sql.go new file mode 100644 index 0000000..b62455f --- /dev/null +++ b/internal/endtoend/testdata/update_cte/stdlib/go/query.sql.go @@ -0,0 +1,72 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" + "time" +) + +const updateCode = `-- name: UpdateCode :one +WITH cc AS ( + UPDATE td3.codes + SET + created_by = $1, + updated_by = $1, + code = $2, + hash = $3, + is_private = false + RETURNING hash +) +UPDATE td3.test_codes +SET + created_by = $1, + updated_by = $1, + test_id = $4, + code_hash = cc.hash + FROM cc +RETURNING hash, id, ts_created, ts_updated, created_by, updated_by, test_id, code_hash +` + +type UpdateCodeParams struct { + CreatedBy string + Code sql.NullString + Hash sql.NullString + TestID int32 +} + +type UpdateCodeRow struct { + Hash sql.NullString + ID int32 + TsCreated time.Time + TsUpdated time.Time + CreatedBy string + UpdatedBy string + TestID int32 + CodeHash string +} + +func (q *Queries) UpdateCode(ctx context.Context, arg UpdateCodeParams) (UpdateCodeRow, error) { + row := q.db.QueryRowContext(ctx, updateCode, + arg.CreatedBy, + arg.Code, + arg.Hash, + arg.TestID, + ) + var i UpdateCodeRow + err := row.Scan( + &i.Hash, + &i.ID, + &i.TsCreated, + &i.TsUpdated, + &i.CreatedBy, + &i.UpdatedBy, + &i.TestID, + &i.CodeHash, + ) + return i, err +} diff --git a/internal/endtoend/testdata/update_cte/stdlib/query.sql b/internal/endtoend/testdata/update_cte/stdlib/query.sql new file mode 100644 index 0000000..d1f8ffa --- /dev/null +++ b/internal/endtoend/testdata/update_cte/stdlib/query.sql @@ -0,0 +1,19 @@ +-- name: UpdateCode :one +WITH cc AS ( + UPDATE td3.codes + SET + created_by = $1, + updated_by = $1, + code = $2, + hash = $3, + is_private = false + RETURNING hash +) +UPDATE td3.test_codes +SET + created_by = $1, + updated_by = $1, + test_id = $4, + code_hash = cc.hash + FROM cc +RETURNING *; diff --git a/internal/endtoend/testdata/update_cte/stdlib/schema.sql b/internal/endtoend/testdata/update_cte/stdlib/schema.sql new file mode 100644 index 0000000..1eb3dcf --- /dev/null +++ b/internal/endtoend/testdata/update_cte/stdlib/schema.sql @@ -0,0 +1,31 @@ +-- FILE: schema.sql + +DROP SCHEMA IF EXISTS td3 CASCADE; +CREATE SCHEMA td3; + +CREATE TABLE td3.codes ( + id SERIAL PRIMARY KEY, + ts_created timestamptz DEFAULT now() NOT NULL, + ts_updated timestamptz DEFAULT now() NOT NULL, + created_by text NOT NULL, + updated_by text NOT NULL, + + code text, + hash text, + is_private boolean +); + + +CREATE TABLE td3.test_codes ( + id SERIAL PRIMARY KEY, + ts_created timestamptz DEFAULT now() NOT NULL, + ts_updated timestamptz DEFAULT now() NOT NULL, + created_by text NOT NULL, + updated_by text NOT NULL, + + test_id integer NOT NULL, + code_hash text NOT NULL +); + +-- FILE: query.sql + diff --git a/internal/endtoend/testdata/update_cte/stdlib/sqlc.json b/internal/endtoend/testdata/update_cte/stdlib/sqlc.json new file mode 100644 index 0000000..dbe55e6 --- /dev/null +++ b/internal/endtoend/testdata/update_cte/stdlib/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/update_inner_join/db/db.go b/internal/endtoend/testdata/update_inner_join/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/update_inner_join/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/update_inner_join/db/models.go b/internal/endtoend/testdata/update_inner_join/db/models.go new file mode 100644 index 0000000..7be04ec --- /dev/null +++ b/internal/endtoend/testdata/update_inner_join/db/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "database/sql" +) + +type X struct { + A sql.NullString + B sql.NullString +} + +type Y struct { + A sql.NullString + B sql.NullString +} diff --git a/internal/endtoend/testdata/update_inner_join/db/query.sql.go b/internal/endtoend/testdata/update_inner_join/db/query.sql.go new file mode 100644 index 0000000..7ffb4ae --- /dev/null +++ b/internal/endtoend/testdata/update_inner_join/db/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" +) + +const updateXWithY = `-- name: UpdateXWithY :exec +UPDATE x INNER JOIN y ON y.a = x.a SET x.b = y.b +` + +func (q *Queries) UpdateXWithY(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, updateXWithY) + return err +} diff --git a/internal/endtoend/testdata/update_inner_join/query.sql b/internal/endtoend/testdata/update_inner_join/query.sql new file mode 100644 index 0000000..2e88d46 --- /dev/null +++ b/internal/endtoend/testdata/update_inner_join/query.sql @@ -0,0 +1,2 @@ +-- name: UpdateXWithY :exec +UPDATE x INNER JOIN y ON y.a = x.a SET x.b = y.b; diff --git a/internal/endtoend/testdata/update_inner_join/schema.sql b/internal/endtoend/testdata/update_inner_join/schema.sql new file mode 100644 index 0000000..d8c6d8d --- /dev/null +++ b/internal/endtoend/testdata/update_inner_join/schema.sql @@ -0,0 +1,10 @@ +CREATE TABLE x ( + a text, + b text +); + +CREATE TABLE y ( + a text, + b text +); + diff --git a/internal/endtoend/testdata/update_inner_join/sqlc.json b/internal/endtoend/testdata/update_inner_join/sqlc.json new file mode 100644 index 0000000..32a13d6 --- /dev/null +++ b/internal/endtoend/testdata/update_inner_join/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "db", + "engine": "mysql", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/update_join/mysql/db/db.go b/internal/endtoend/testdata/update_join/mysql/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/update_join/mysql/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/update_join/mysql/db/models.go b/internal/endtoend/testdata/update_join/mysql/db/models.go new file mode 100644 index 0000000..73ac86f --- /dev/null +++ b/internal/endtoend/testdata/update_join/mysql/db/models.go @@ -0,0 +1,17 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +type JoinTable struct { + ID uint64 + PrimaryTableID uint64 + OtherTableID uint64 + IsActive bool +} + +type PrimaryTable struct { + ID uint64 + UserID uint64 +} diff --git a/internal/endtoend/testdata/update_join/mysql/db/query.sql.go b/internal/endtoend/testdata/update_join/mysql/db/query.sql.go new file mode 100644 index 0000000..0450bfe --- /dev/null +++ b/internal/endtoend/testdata/update_join/mysql/db/query.sql.go @@ -0,0 +1,70 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" +) + +const updateJoin = `-- name: UpdateJoin :exec +UPDATE join_table as jt + JOIN primary_table as pt + ON jt.primary_table_id = pt.id +SET jt.is_active = ? +WHERE jt.id = ? + AND pt.user_id = ? +` + +type UpdateJoinParams struct { + IsActive bool + ID uint64 + UserID uint64 +} + +func (q *Queries) UpdateJoin(ctx context.Context, arg UpdateJoinParams) error { + _, err := q.db.ExecContext(ctx, updateJoin, arg.IsActive, arg.ID, arg.UserID) + return err +} + +const updateLeftJoin = `-- name: UpdateLeftJoin :exec +UPDATE join_table as jt + LEFT JOIN primary_table as pt + ON jt.primary_table_id = pt.id +SET jt.is_active = ? +WHERE jt.id = ? + AND pt.user_id = ? +` + +type UpdateLeftJoinParams struct { + IsActive bool + ID uint64 + UserID uint64 +} + +func (q *Queries) UpdateLeftJoin(ctx context.Context, arg UpdateLeftJoinParams) error { + _, err := q.db.ExecContext(ctx, updateLeftJoin, arg.IsActive, arg.ID, arg.UserID) + return err +} + +const updateRightJoin = `-- name: UpdateRightJoin :exec +UPDATE join_table as jt + RIGHT JOIN primary_table as pt + ON jt.primary_table_id = pt.id +SET jt.is_active = ? +WHERE jt.id = ? + AND pt.user_id = ? +` + +type UpdateRightJoinParams struct { + IsActive bool + ID uint64 + UserID uint64 +} + +func (q *Queries) UpdateRightJoin(ctx context.Context, arg UpdateRightJoinParams) error { + _, err := q.db.ExecContext(ctx, updateRightJoin, arg.IsActive, arg.ID, arg.UserID) + return err +} diff --git a/internal/endtoend/testdata/update_join/mysql/query.sql b/internal/endtoend/testdata/update_join/mysql/query.sql new file mode 100644 index 0000000..cf7cf36 --- /dev/null +++ b/internal/endtoend/testdata/update_join/mysql/query.sql @@ -0,0 +1,23 @@ +-- name: UpdateJoin :exec +UPDATE join_table as jt + JOIN primary_table as pt + ON jt.primary_table_id = pt.id +SET jt.is_active = ? +WHERE jt.id = ? + AND pt.user_id = ?; + +-- name: UpdateLeftJoin :exec +UPDATE join_table as jt + LEFT JOIN primary_table as pt + ON jt.primary_table_id = pt.id +SET jt.is_active = ? +WHERE jt.id = ? + AND pt.user_id = ?; + +-- name: UpdateRightJoin :exec +UPDATE join_table as jt + RIGHT JOIN primary_table as pt + ON jt.primary_table_id = pt.id +SET jt.is_active = ? +WHERE jt.id = ? + AND pt.user_id = ?; diff --git a/internal/endtoend/testdata/update_join/mysql/schema.sql b/internal/endtoend/testdata/update_join/mysql/schema.sql new file mode 100644 index 0000000..89d517e --- /dev/null +++ b/internal/endtoend/testdata/update_join/mysql/schema.sql @@ -0,0 +1,14 @@ +CREATE TABLE primary_table ( + id bigint(20) unsigned NOT NULL AUTO_INCREMENT, + user_id bigint(20) unsigned NOT NULL, + PRIMARY KEY (id) +); + +CREATE TABLE join_table ( + id bigint(20) unsigned NOT NULL AUTO_INCREMENT, + primary_table_id bigint(20) unsigned NOT NULL, + other_table_id bigint(20) unsigned NOT NULL, + is_active tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (id) +); + diff --git a/internal/endtoend/testdata/update_join/mysql/sqlc.json b/internal/endtoend/testdata/update_join/mysql/sqlc.json new file mode 100644 index 0000000..4217706 --- /dev/null +++ b/internal/endtoend/testdata/update_join/mysql/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "db", + "engine": "mysql", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/update_join/postgresql/db/db.go b/internal/endtoend/testdata/update_join/postgresql/db/db.go new file mode 100644 index 0000000..93a0b7e --- /dev/null +++ b/internal/endtoend/testdata/update_join/postgresql/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/update_join/postgresql/db/models.go b/internal/endtoend/testdata/update_join/postgresql/db/models.go new file mode 100644 index 0000000..35a88fb --- /dev/null +++ b/internal/endtoend/testdata/update_join/postgresql/db/models.go @@ -0,0 +1,17 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +type JoinTable struct { + ID int32 + PrimaryTableID int32 + OtherTableID int32 + IsActive bool +} + +type PrimaryTable struct { + ID int32 + UserID int32 +} diff --git a/internal/endtoend/testdata/update_join/postgresql/db/query.sql.go b/internal/endtoend/testdata/update_join/postgresql/db/query.sql.go new file mode 100644 index 0000000..0e1edda --- /dev/null +++ b/internal/endtoend/testdata/update_join/postgresql/db/query.sql.go @@ -0,0 +1,30 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package db + +import ( + "context" +) + +const updateJoin = `-- name: UpdateJoin :exec +UPDATE join_table +SET is_active = $1 +FROM primary_table +WHERE join_table.id = $2 + AND primary_table.user_id = $3 + AND join_table.primary_table_id = primary_table.id +` + +type UpdateJoinParams struct { + IsActive bool + ID int32 + UserID int32 +} + +func (q *Queries) UpdateJoin(ctx context.Context, arg UpdateJoinParams) error { + _, err := q.db.ExecContext(ctx, updateJoin, arg.IsActive, arg.ID, arg.UserID) + return err +} diff --git a/internal/endtoend/testdata/update_join/postgresql/query.sql b/internal/endtoend/testdata/update_join/postgresql/query.sql new file mode 100644 index 0000000..57bfb22 --- /dev/null +++ b/internal/endtoend/testdata/update_join/postgresql/query.sql @@ -0,0 +1,7 @@ +-- name: UpdateJoin :exec +UPDATE join_table +SET is_active = $1 +FROM primary_table +WHERE join_table.id = $2 + AND primary_table.user_id = $3 + AND join_table.primary_table_id = primary_table.id; diff --git a/internal/endtoend/testdata/update_join/postgresql/schema.sql b/internal/endtoend/testdata/update_join/postgresql/schema.sql new file mode 100644 index 0000000..49e27f8 --- /dev/null +++ b/internal/endtoend/testdata/update_join/postgresql/schema.sql @@ -0,0 +1,12 @@ +CREATE TABLE primary_table ( + id INT PRIMARY KEY, + user_id INT NOT NULL +); + +CREATE TABLE join_table ( + id INT PRIMARY KEY, + primary_table_id INT NOT NULL, + other_table_id INT NOT NULL, + is_active BOOLEAN NOT NULL +); + diff --git a/internal/endtoend/testdata/update_join/postgresql/sqlc.json b/internal/endtoend/testdata/update_join/postgresql/sqlc.json new file mode 100644 index 0000000..ba0fc24 --- /dev/null +++ b/internal/endtoend/testdata/update_join/postgresql/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "db", + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/update_set/myql/go/db.go b/internal/endtoend/testdata/update_set/myql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/update_set/myql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/update_set/myql/go/models.go b/internal/endtoend/testdata/update_set/myql/go/models.go new file mode 100644 index 0000000..d6f5637 --- /dev/null +++ b/internal/endtoend/testdata/update_set/myql/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Name string + Slug string +} diff --git a/internal/endtoend/testdata/update_set/myql/go/query.sql.go b/internal/endtoend/testdata/update_set/myql/go/query.sql.go new file mode 100644 index 0000000..bf7810d --- /dev/null +++ b/internal/endtoend/testdata/update_set/myql/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const updateSet = `-- name: UpdateSet :exec +UPDATE foo SET name = ? WHERE slug = ? +` + +type UpdateSetParams struct { + Name string + Slug string +} + +func (q *Queries) UpdateSet(ctx context.Context, arg UpdateSetParams) error { + _, err := q.db.ExecContext(ctx, updateSet, arg.Name, arg.Slug) + return err +} diff --git a/internal/endtoend/testdata/update_set/myql/query.sql b/internal/endtoend/testdata/update_set/myql/query.sql new file mode 100644 index 0000000..0f6603f --- /dev/null +++ b/internal/endtoend/testdata/update_set/myql/query.sql @@ -0,0 +1,2 @@ +/* name: UpdateSet :exec */ +UPDATE foo SET name = ? WHERE slug = ?; diff --git a/internal/endtoend/testdata/update_set/myql/schema.sql b/internal/endtoend/testdata/update_set/myql/schema.sql new file mode 100644 index 0000000..d1bc5fa --- /dev/null +++ b/internal/endtoend/testdata/update_set/myql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (name text not null, slug text not null); + diff --git a/internal/endtoend/testdata/update_set/myql/sqlc.json b/internal/endtoend/testdata/update_set/myql/sqlc.json new file mode 100644 index 0000000..974aa9f --- /dev/null +++ b/internal/endtoend/testdata/update_set/myql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "mysql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/update_set/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/update_set/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/update_set/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/update_set/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/update_set/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..d6f5637 --- /dev/null +++ b/internal/endtoend/testdata/update_set/postgresql/pgx/v4/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Name string + Slug string +} diff --git a/internal/endtoend/testdata/update_set/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/update_set/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..4849f16 --- /dev/null +++ b/internal/endtoend/testdata/update_set/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const updateSet = `-- name: UpdateSet :exec +UPDATE foo SET name = $2 WHERE slug = $1 +` + +type UpdateSetParams struct { + Slug string + Name string +} + +func (q *Queries) UpdateSet(ctx context.Context, arg UpdateSetParams) error { + _, err := q.db.Exec(ctx, updateSet, arg.Slug, arg.Name) + return err +} diff --git a/internal/endtoend/testdata/update_set/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/update_set/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..a414198 --- /dev/null +++ b/internal/endtoend/testdata/update_set/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: UpdateSet :exec +UPDATE foo SET name = $2 WHERE slug = $1; diff --git a/internal/endtoend/testdata/update_set/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/update_set/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..d1bc5fa --- /dev/null +++ b/internal/endtoend/testdata/update_set/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (name text not null, slug text not null); + diff --git a/internal/endtoend/testdata/update_set/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/update_set/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/update_set/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/update_set/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/update_set/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/update_set/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/update_set/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/update_set/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..d6f5637 --- /dev/null +++ b/internal/endtoend/testdata/update_set/postgresql/pgx/v5/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Name string + Slug string +} diff --git a/internal/endtoend/testdata/update_set/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/update_set/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..4849f16 --- /dev/null +++ b/internal/endtoend/testdata/update_set/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const updateSet = `-- name: UpdateSet :exec +UPDATE foo SET name = $2 WHERE slug = $1 +` + +type UpdateSetParams struct { + Slug string + Name string +} + +func (q *Queries) UpdateSet(ctx context.Context, arg UpdateSetParams) error { + _, err := q.db.Exec(ctx, updateSet, arg.Slug, arg.Name) + return err +} diff --git a/internal/endtoend/testdata/update_set/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/update_set/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..a414198 --- /dev/null +++ b/internal/endtoend/testdata/update_set/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: UpdateSet :exec +UPDATE foo SET name = $2 WHERE slug = $1; diff --git a/internal/endtoend/testdata/update_set/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/update_set/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..d1bc5fa --- /dev/null +++ b/internal/endtoend/testdata/update_set/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (name text not null, slug text not null); + diff --git a/internal/endtoend/testdata/update_set/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/update_set/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/update_set/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/update_set/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/update_set/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/update_set/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/update_set/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/update_set/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..d6f5637 --- /dev/null +++ b/internal/endtoend/testdata/update_set/postgresql/stdlib/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Name string + Slug string +} diff --git a/internal/endtoend/testdata/update_set/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/update_set/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..f9b0709 --- /dev/null +++ b/internal/endtoend/testdata/update_set/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const updateSet = `-- name: UpdateSet :exec +UPDATE foo SET name = $2 WHERE slug = $1 +` + +type UpdateSetParams struct { + Slug string + Name string +} + +func (q *Queries) UpdateSet(ctx context.Context, arg UpdateSetParams) error { + _, err := q.db.ExecContext(ctx, updateSet, arg.Slug, arg.Name) + return err +} diff --git a/internal/endtoend/testdata/update_set/postgresql/stdlib/query.sql b/internal/endtoend/testdata/update_set/postgresql/stdlib/query.sql new file mode 100644 index 0000000..a414198 --- /dev/null +++ b/internal/endtoend/testdata/update_set/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: UpdateSet :exec +UPDATE foo SET name = $2 WHERE slug = $1; diff --git a/internal/endtoend/testdata/update_set/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/update_set/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..d1bc5fa --- /dev/null +++ b/internal/endtoend/testdata/update_set/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (name text not null, slug text not null); + diff --git a/internal/endtoend/testdata/update_set/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/update_set/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..cd51867 --- /dev/null +++ b/internal/endtoend/testdata/update_set/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "postgresql", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/update_set/sqlite/go/db.go b/internal/endtoend/testdata/update_set/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/update_set/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/update_set/sqlite/go/models.go b/internal/endtoend/testdata/update_set/sqlite/go/models.go new file mode 100644 index 0000000..d6f5637 --- /dev/null +++ b/internal/endtoend/testdata/update_set/sqlite/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Name string + Slug string +} diff --git a/internal/endtoend/testdata/update_set/sqlite/go/query.sql.go b/internal/endtoend/testdata/update_set/sqlite/go/query.sql.go new file mode 100644 index 0000000..bf7810d --- /dev/null +++ b/internal/endtoend/testdata/update_set/sqlite/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const updateSet = `-- name: UpdateSet :exec +UPDATE foo SET name = ? WHERE slug = ? +` + +type UpdateSetParams struct { + Name string + Slug string +} + +func (q *Queries) UpdateSet(ctx context.Context, arg UpdateSetParams) error { + _, err := q.db.ExecContext(ctx, updateSet, arg.Name, arg.Slug) + return err +} diff --git a/internal/endtoend/testdata/update_set/sqlite/query.sql b/internal/endtoend/testdata/update_set/sqlite/query.sql new file mode 100644 index 0000000..0f6603f --- /dev/null +++ b/internal/endtoend/testdata/update_set/sqlite/query.sql @@ -0,0 +1,2 @@ +/* name: UpdateSet :exec */ +UPDATE foo SET name = ? WHERE slug = ?; diff --git a/internal/endtoend/testdata/update_set/sqlite/schema.sql b/internal/endtoend/testdata/update_set/sqlite/schema.sql new file mode 100644 index 0000000..d1bc5fa --- /dev/null +++ b/internal/endtoend/testdata/update_set/sqlite/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (name text not null, slug text not null); + diff --git a/internal/endtoend/testdata/update_set/sqlite/sqlc.json b/internal/endtoend/testdata/update_set/sqlite/sqlc.json new file mode 100644 index 0000000..f8e8051 --- /dev/null +++ b/internal/endtoend/testdata/update_set/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "sqlite", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/update_set_multiple/mysql/go/db.go b/internal/endtoend/testdata/update_set_multiple/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/update_set_multiple/mysql/go/models.go b/internal/endtoend/testdata/update_set_multiple/mysql/go/models.go new file mode 100644 index 0000000..d6f5637 --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/mysql/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Name string + Slug string +} diff --git a/internal/endtoend/testdata/update_set_multiple/mysql/go/query.sql.go b/internal/endtoend/testdata/update_set_multiple/mysql/go/query.sql.go new file mode 100644 index 0000000..b39667e --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/mysql/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const updateSetMultiple = `-- name: UpdateSetMultiple :exec +UPDATE foo SET name = ?, slug = ? +` + +type UpdateSetMultipleParams struct { + Name string + Slug string +} + +func (q *Queries) UpdateSetMultiple(ctx context.Context, arg UpdateSetMultipleParams) error { + _, err := q.db.ExecContext(ctx, updateSetMultiple, arg.Name, arg.Slug) + return err +} diff --git a/internal/endtoend/testdata/update_set_multiple/mysql/query.sql b/internal/endtoend/testdata/update_set_multiple/mysql/query.sql new file mode 100644 index 0000000..4ea1be4 --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/mysql/query.sql @@ -0,0 +1,2 @@ +-- name: UpdateSetMultiple :exec +UPDATE foo SET name = ?, slug = ?; diff --git a/internal/endtoend/testdata/update_set_multiple/mysql/schema.sql b/internal/endtoend/testdata/update_set_multiple/mysql/schema.sql new file mode 100644 index 0000000..d1bc5fa --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (name text not null, slug text not null); + diff --git a/internal/endtoend/testdata/update_set_multiple/mysql/sqlc.json b/internal/endtoend/testdata/update_set_multiple/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/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/update_set_multiple/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000..9ca5876 --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/update_set_multiple/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000..d6f5637 --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v4/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Name string + Slug string +} diff --git a/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000..9afe0b2 --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const updateSetMultiple = `-- name: UpdateSetMultiple :exec +UPDATE foo SET (name, slug) = ($2, $1) +` + +type UpdateSetMultipleParams struct { + Slug string + Name string +} + +func (q *Queries) UpdateSetMultiple(ctx context.Context, arg UpdateSetMultipleParams) error { + _, err := q.db.Exec(ctx, updateSetMultiple, arg.Slug, arg.Name) + return err +} diff --git a/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000..c5e471f --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v4/query.sql @@ -0,0 +1,2 @@ +-- name: UpdateSetMultiple :exec +UPDATE foo SET (name, slug) = ($2, $1); diff --git a/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000..d1bc5fa --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v4/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (name text not null, slug text not null); + diff --git a/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000..d1244c9 --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000..2666c1c --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/update_set_multiple/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000..d6f5637 --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v5/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Name string + Slug string +} diff --git a/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000..9afe0b2 --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const updateSetMultiple = `-- name: UpdateSetMultiple :exec +UPDATE foo SET (name, slug) = ($2, $1) +` + +type UpdateSetMultipleParams struct { + Slug string + Name string +} + +func (q *Queries) UpdateSetMultiple(ctx context.Context, arg UpdateSetMultipleParams) error { + _, err := q.db.Exec(ctx, updateSetMultiple, arg.Slug, arg.Name) + return err +} diff --git a/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000..c5e471f --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v5/query.sql @@ -0,0 +1,2 @@ +-- name: UpdateSetMultiple :exec +UPDATE foo SET (name, slug) = ($2, $1); diff --git a/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000..d1bc5fa --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v5/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (name text not null, slug text not null); + diff --git a/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000..32ede07 --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/update_set_multiple/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/update_set_multiple/postgresql/stdlib/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/update_set_multiple/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/update_set_multiple/postgresql/stdlib/go/models.go new file mode 100644 index 0000000..d6f5637 --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/postgresql/stdlib/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Name string + Slug string +} diff --git a/internal/endtoend/testdata/update_set_multiple/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/update_set_multiple/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000..cbbf909 --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const updateSetMultiple = `-- name: UpdateSetMultiple :exec +UPDATE foo SET (name, slug) = ($2, $1) +` + +type UpdateSetMultipleParams struct { + Slug string + Name string +} + +func (q *Queries) UpdateSetMultiple(ctx context.Context, arg UpdateSetMultipleParams) error { + _, err := q.db.ExecContext(ctx, updateSetMultiple, arg.Slug, arg.Name) + return err +} diff --git a/internal/endtoend/testdata/update_set_multiple/postgresql/stdlib/query.sql b/internal/endtoend/testdata/update_set_multiple/postgresql/stdlib/query.sql new file mode 100644 index 0000000..c5e471f --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: UpdateSetMultiple :exec +UPDATE foo SET (name, slug) = ($2, $1); diff --git a/internal/endtoend/testdata/update_set_multiple/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/update_set_multiple/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..d1bc5fa --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (name text not null, slug text not null); + diff --git a/internal/endtoend/testdata/update_set_multiple/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/update_set_multiple/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000..f717ca2 --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/update_set_multiple/sqlite/go/db.go b/internal/endtoend/testdata/update_set_multiple/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/update_set_multiple/sqlite/go/models.go b/internal/endtoend/testdata/update_set_multiple/sqlite/go/models.go new file mode 100644 index 0000000..d6f5637 --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/sqlite/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Foo struct { + Name string + Slug string +} diff --git a/internal/endtoend/testdata/update_set_multiple/sqlite/go/query.sql.go b/internal/endtoend/testdata/update_set_multiple/sqlite/go/query.sql.go new file mode 100644 index 0000000..b39667e --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/sqlite/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const updateSetMultiple = `-- name: UpdateSetMultiple :exec +UPDATE foo SET name = ?, slug = ? +` + +type UpdateSetMultipleParams struct { + Name string + Slug string +} + +func (q *Queries) UpdateSetMultiple(ctx context.Context, arg UpdateSetMultipleParams) error { + _, err := q.db.ExecContext(ctx, updateSetMultiple, arg.Name, arg.Slug) + return err +} diff --git a/internal/endtoend/testdata/update_set_multiple/sqlite/query.sql b/internal/endtoend/testdata/update_set_multiple/sqlite/query.sql new file mode 100644 index 0000000..4ea1be4 --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/sqlite/query.sql @@ -0,0 +1,2 @@ +-- name: UpdateSetMultiple :exec +UPDATE foo SET name = ?, slug = ?; diff --git a/internal/endtoend/testdata/update_set_multiple/sqlite/schema.sql b/internal/endtoend/testdata/update_set_multiple/sqlite/schema.sql new file mode 100644 index 0000000..d1bc5fa --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/sqlite/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (name text not null, slug text not null); + diff --git a/internal/endtoend/testdata/update_set_multiple/sqlite/sqlc.json b/internal/endtoend/testdata/update_set_multiple/sqlite/sqlc.json new file mode 100644 index 0000000..d4963e7 --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/update_set_on_conflict/issue.md b/internal/endtoend/testdata/update_set_on_conflict/issue.md new file mode 100644 index 0000000..27f06c0 --- /dev/null +++ b/internal/endtoend/testdata/update_set_on_conflict/issue.md @@ -0,0 +1 @@ +https://github.com/sqlc-dev/sqlc/issues/1128 \ No newline at end of file diff --git a/internal/endtoend/testdata/update_set_on_conflict/postgresql/pgx/exec.json b/internal/endtoend/testdata/update_set_on_conflict/postgresql/pgx/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/update_set_on_conflict/postgresql/pgx/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/update_set_on_conflict/postgresql/pgx/query.sql b/internal/endtoend/testdata/update_set_on_conflict/postgresql/pgx/query.sql new file mode 100644 index 0000000..2484d99 --- /dev/null +++ b/internal/endtoend/testdata/update_set_on_conflict/postgresql/pgx/query.sql @@ -0,0 +1,23 @@ +-- name: UpsertServerSetColumnTypo :exec +INSERT INTO servers(code, name) VALUES ($1, $2) +ON CONFLICT (code) +DO UPDATE SET name_typo = 1111; + +-- name: UpsertServerConflictTargetTypo :exec +INSERT INTO servers(code, name) VALUES ($1, $2) +ON CONFLICT (code_typo) +DO UPDATE SET name = 1111; + +-- name: UpsertServerExcludedColumnTypo :exec +INSERT INTO servers(code, name) VALUES ($1, $2) +ON CONFLICT (code) +DO UPDATE SET name = EXCLUDED.name_typo; + +-- name: UpsertServerMissingConflictTarget :exec +INSERT INTO servers(code, name) VALUES ($1, $2) +ON CONFLICT DO UPDATE SET name = EXCLUDED.name; + +-- name: UpsertServerOnConstraintExcludedTypo :exec +INSERT INTO servers(code, name) VALUES ($1, $2) +ON CONFLICT ON CONSTRAINT servers_pkey DO UPDATE SET name = EXCLUDED.name_typo; + diff --git a/internal/endtoend/testdata/update_set_on_conflict/postgresql/pgx/schema.sql b/internal/endtoend/testdata/update_set_on_conflict/postgresql/pgx/schema.sql new file mode 100644 index 0000000..c3dec12 --- /dev/null +++ b/internal/endtoend/testdata/update_set_on_conflict/postgresql/pgx/schema.sql @@ -0,0 +1,4 @@ +CREATE TABLE servers ( + code varchar PRIMARY KEY, + name text NOT NULL +); diff --git a/internal/endtoend/testdata/update_set_on_conflict/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/update_set_on_conflict/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..01489e0 --- /dev/null +++ b/internal/endtoend/testdata/update_set_on_conflict/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" \ No newline at end of file diff --git a/internal/endtoend/testdata/update_set_on_conflict/postgresql/pgx/stderr.txt b/internal/endtoend/testdata/update_set_on_conflict/postgresql/pgx/stderr.txt new file mode 100644 index 0000000..b9692da --- /dev/null +++ b/internal/endtoend/testdata/update_set_on_conflict/postgresql/pgx/stderr.txt @@ -0,0 +1,6 @@ +# package querytest +query.sql:4:15: column "name_typo" of relation "servers" does not exist +query.sql:8:13: column "code_typo" of relation "servers" does not exist +query.sql:14:22: column "name_typo" of relation "EXCLUDED" does not exist +query.sql:17:1: ON CONFLICT DO UPDATE requires inference specification or constraint name +query.sql:22:61: column "name_typo" of relation "EXCLUDED" does not exist diff --git a/internal/endtoend/testdata/update_two_table/mysql/go/db.go b/internal/endtoend/testdata/update_two_table/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/update_two_table/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/update_two_table/mysql/go/models.go b/internal/endtoend/testdata/update_two_table/mysql/go/models.go new file mode 100644 index 0000000..84bd886 --- /dev/null +++ b/internal/endtoend/testdata/update_two_table/mysql/go/models.go @@ -0,0 +1,23 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "time" +) + +type Author struct { + Name string + DeletedAt time.Time + CreatedAt time.Time + UpdatedAt time.Time +} + +type Book struct { + IsAmazing bool + DeletedAt time.Time + CreatedAt time.Time + UpdatedAt time.Time +} diff --git a/internal/endtoend/testdata/update_two_table/mysql/go/query.sql.go b/internal/endtoend/testdata/update_two_table/mysql/go/query.sql.go new file mode 100644 index 0000000..2083790 --- /dev/null +++ b/internal/endtoend/testdata/update_two_table/mysql/go/query.sql.go @@ -0,0 +1,27 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const deleteAuthor = `-- name: DeleteAuthor :exec +UPDATE + authors, + books +SET + authors.deleted_at = now(), + books.deleted_at = now() +WHERE + books.is_amazing = 1 + AND authors.name = ? +` + +func (q *Queries) DeleteAuthor(ctx context.Context, name string) error { + _, err := q.db.ExecContext(ctx, deleteAuthor, name) + return err +} diff --git a/internal/endtoend/testdata/update_two_table/mysql/query.sql b/internal/endtoend/testdata/update_two_table/mysql/query.sql new file mode 100644 index 0000000..3f5c5de --- /dev/null +++ b/internal/endtoend/testdata/update_two_table/mysql/query.sql @@ -0,0 +1,10 @@ +-- name: DeleteAuthor :exec +UPDATE + authors, + books +SET + authors.deleted_at = now(), + books.deleted_at = now() +WHERE + books.is_amazing = 1 + AND authors.name = sqlc.arg(name); \ No newline at end of file diff --git a/internal/endtoend/testdata/update_two_table/mysql/schema.sql b/internal/endtoend/testdata/update_two_table/mysql/schema.sql new file mode 100644 index 0000000..ae7e761 --- /dev/null +++ b/internal/endtoend/testdata/update_two_table/mysql/schema.sql @@ -0,0 +1,15 @@ +-- https://github.com/sqlc-dev/sqlc/issues/1590 +CREATE TABLE authors ( + name text NOT NULL, + deleted_at datetime NOT NULL, + created_at datetime NOT NULL, + updated_at datetime NOT NULL +); + +CREATE TABLE books ( + is_amazing tinyint(1) NOT NULL, + deleted_at datetime NOT NULL, + created_at datetime NOT NULL, + updated_at datetime NOT NULL +); + diff --git a/internal/endtoend/testdata/update_two_table/mysql/sqlc.json b/internal/endtoend/testdata/update_two_table/mysql/sqlc.json new file mode 100644 index 0000000..e41c39e --- /dev/null +++ b/internal/endtoend/testdata/update_two_table/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/upsert/sqlite/go/db.go b/internal/endtoend/testdata/upsert/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/upsert/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/upsert/sqlite/go/models.go b/internal/endtoend/testdata/upsert/sqlite/go/models.go new file mode 100644 index 0000000..fe22d3d --- /dev/null +++ b/internal/endtoend/testdata/upsert/sqlite/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Location struct { + ID int64 + Name string + Address string + ZipCode int64 + Latitude float64 + Longitude float64 +} diff --git a/internal/endtoend/testdata/upsert/sqlite/go/query.sql.go b/internal/endtoend/testdata/upsert/sqlite/go/query.sql.go new file mode 100644 index 0000000..8a5227d --- /dev/null +++ b/internal/endtoend/testdata/upsert/sqlite/go/query.sql.go @@ -0,0 +1,46 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const upsertLocation = `-- name: UpsertLocation :exec +INSERT INTO locations ( + name, + address, + zip_code, + latitude, + longitude +) +VALUES (?, ?, ?, ?, ?) +ON CONFLICT (name) DO UPDATE SET + name = excluded.name, + address = excluded.address, + zip_code = excluded.zip_code, + latitude = excluded.latitude, + longitude = excluded.longitude +` + +type UpsertLocationParams struct { + Name string + Address string + ZipCode int64 + Latitude float64 + Longitude float64 +} + +func (q *Queries) UpsertLocation(ctx context.Context, arg UpsertLocationParams) error { + _, err := q.db.ExecContext(ctx, upsertLocation, + arg.Name, + arg.Address, + arg.ZipCode, + arg.Latitude, + arg.Longitude, + ) + return err +} diff --git a/internal/endtoend/testdata/upsert/sqlite/query.sql b/internal/endtoend/testdata/upsert/sqlite/query.sql new file mode 100644 index 0000000..2bcc902 --- /dev/null +++ b/internal/endtoend/testdata/upsert/sqlite/query.sql @@ -0,0 +1,15 @@ +/* name: UpsertLocation :exec */ +INSERT INTO locations ( + name, + address, + zip_code, + latitude, + longitude +) +VALUES (?, ?, ?, ?, ?) +ON CONFLICT (name) DO UPDATE SET + name = excluded.name, + address = excluded.address, + zip_code = excluded.zip_code, + latitude = excluded.latitude, + longitude = excluded.longitude; diff --git a/internal/endtoend/testdata/upsert/sqlite/schema.sql b/internal/endtoend/testdata/upsert/sqlite/schema.sql new file mode 100644 index 0000000..0ed6d04 --- /dev/null +++ b/internal/endtoend/testdata/upsert/sqlite/schema.sql @@ -0,0 +1,12 @@ +-- https://github.com/sqlc-dev/sqlc/issues/1728 + +CREATE TABLE IF NOT EXISTS locations ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL, + address TEXT NOT NULL, + zip_code INT NOT NULL, + latitude REAL NOT NULL, + longitude REAL NOT NULL, + UNIQUE(name) +); + diff --git a/internal/endtoend/testdata/upsert/sqlite/sqlc.json b/internal/endtoend/testdata/upsert/sqlite/sqlc.json new file mode 100644 index 0000000..f8e8051 --- /dev/null +++ b/internal/endtoend/testdata/upsert/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "sqlite", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/valid_group_by_reference/mysql/go/db.go b/internal/endtoend/testdata/valid_group_by_reference/mysql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/valid_group_by_reference/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/valid_group_by_reference/mysql/go/models.go b/internal/endtoend/testdata/valid_group_by_reference/mysql/go/models.go new file mode 100644 index 0000000..a448d73 --- /dev/null +++ b/internal/endtoend/testdata/valid_group_by_reference/mysql/go/models.go @@ -0,0 +1,36 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + "time" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} + +type WeatherMetric struct { + Time time.Time + TimezoneShift sql.NullInt32 + CityName sql.NullString + TempC sql.NullFloat64 + FeelsLikeC sql.NullFloat64 + TempMinC sql.NullFloat64 + TempMaxC sql.NullFloat64 + PressureHpa sql.NullFloat64 + HumidityPercent sql.NullFloat64 + WindSpeedMs sql.NullFloat64 + WindDeg sql.NullInt32 + Rain1hMm sql.NullFloat64 + Rain3hMm sql.NullFloat64 + Snow1hMm sql.NullFloat64 + Snow3hMm sql.NullFloat64 + CloudsPercent sql.NullInt32 + WeatherTypeID sql.NullInt32 +} diff --git a/internal/endtoend/testdata/valid_group_by_reference/mysql/go/query.sql.go b/internal/endtoend/testdata/valid_group_by_reference/mysql/go/query.sql.go new file mode 100644 index 0000000..ca1bd3e --- /dev/null +++ b/internal/endtoend/testdata/valid_group_by_reference/mysql/go/query.sql.go @@ -0,0 +1,112 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name as full_name, bio +FROM authors +GROUP BY full_name +` + +type ListAuthorsRow struct { + ID int64 + FullName string + Bio sql.NullString +} + +func (q *Queries) ListAuthors(ctx context.Context) ([]ListAuthorsRow, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListAuthorsRow + for rows.Next() { + var i ListAuthorsRow + if err := rows.Scan(&i.ID, &i.FullName, &i.Bio); 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 listAuthorsIdenticalAlias = `-- name: ListAuthorsIdenticalAlias :many +SELECT id, name as name, bio +FROM authors +GROUP BY name +` + +func (q *Queries) ListAuthorsIdenticalAlias(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthorsIdenticalAlias) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); 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 listMetrics = `-- name: ListMetrics :many +SELECT time_bucket('15 days', time) AS bucket, city_name, AVG(temp_c) +FROM weather_metrics +WHERE DATE_SUB(NOW(), INTERVAL 6 MONTH) +GROUP BY bucket, city_name +ORDER BY bucket DESC +` + +type ListMetricsRow struct { + Bucket any + CityName sql.NullString + Avg any +} + +func (q *Queries) ListMetrics(ctx context.Context) ([]ListMetricsRow, error) { + rows, err := q.db.QueryContext(ctx, listMetrics) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListMetricsRow + for rows.Next() { + var i ListMetricsRow + if err := rows.Scan(&i.Bucket, &i.CityName, &i.Avg); 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/valid_group_by_reference/mysql/query.sql b/internal/endtoend/testdata/valid_group_by_reference/mysql/query.sql new file mode 100644 index 0000000..9776cb0 --- /dev/null +++ b/internal/endtoend/testdata/valid_group_by_reference/mysql/query.sql @@ -0,0 +1,16 @@ +-- name: ListAuthors :many +SELECT id, name as full_name, bio +FROM authors +GROUP BY full_name; + +-- name: ListAuthorsIdenticalAlias :many +SELECT id, name as name, bio +FROM authors +GROUP BY name; + +-- name: ListMetrics :many +SELECT time_bucket('15 days', time) AS bucket, city_name, AVG(temp_c) +FROM weather_metrics +WHERE DATE_SUB(NOW(), INTERVAL 6 MONTH) +GROUP BY bucket, city_name +ORDER BY bucket DESC; diff --git a/internal/endtoend/testdata/valid_group_by_reference/mysql/schema.sql b/internal/endtoend/testdata/valid_group_by_reference/mysql/schema.sql new file mode 100644 index 0000000..db03e0d --- /dev/null +++ b/internal/endtoend/testdata/valid_group_by_reference/mysql/schema.sql @@ -0,0 +1,26 @@ +CREATE TABLE authors ( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(10) NOT NULL, + bio text +); + +CREATE TABLE IF NOT EXISTS weather_metrics +( + time TIMESTAMP NOT NULL, + timezone_shift INT NULL, + city_name TEXT NULL, + temp_c FLOAT NULL, + feels_like_c FLOAT NULL, + temp_min_c FLOAT NULL, + temp_max_c FLOAT NULL, + pressure_hpa FLOAT NULL, + humidity_percent FLOAT NULL, + wind_speed_ms FLOAT NULL, + wind_deg INT NULL, + rain_1h_mm FLOAT NULL, + rain_3h_mm FLOAT NULL, + snow_1h_mm FLOAT NULL, + snow_3h_mm FLOAT NULL, + clouds_percent INT NULL, + weather_type_id INT NULL +); diff --git a/internal/endtoend/testdata/valid_group_by_reference/mysql/sqlc.json b/internal/endtoend/testdata/valid_group_by_reference/mysql/sqlc.json new file mode 100644 index 0000000..0390f67 --- /dev/null +++ b/internal/endtoend/testdata/valid_group_by_reference/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/valid_group_by_reference/pganalyzer/exec.json b/internal/endtoend/testdata/valid_group_by_reference/pganalyzer/exec.json new file mode 100644 index 0000000..ee1b7ec --- /dev/null +++ b/internal/endtoend/testdata/valid_group_by_reference/pganalyzer/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["managed-db"] +} diff --git a/internal/endtoend/testdata/valid_group_by_reference/pganalyzer/go/db.go b/internal/endtoend/testdata/valid_group_by_reference/pganalyzer/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/valid_group_by_reference/pganalyzer/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/valid_group_by_reference/pganalyzer/go/models.go b/internal/endtoend/testdata/valid_group_by_reference/pganalyzer/go/models.go new file mode 100644 index 0000000..a448d73 --- /dev/null +++ b/internal/endtoend/testdata/valid_group_by_reference/pganalyzer/go/models.go @@ -0,0 +1,36 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + "time" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} + +type WeatherMetric struct { + Time time.Time + TimezoneShift sql.NullInt32 + CityName sql.NullString + TempC sql.NullFloat64 + FeelsLikeC sql.NullFloat64 + TempMinC sql.NullFloat64 + TempMaxC sql.NullFloat64 + PressureHpa sql.NullFloat64 + HumidityPercent sql.NullFloat64 + WindSpeedMs sql.NullFloat64 + WindDeg sql.NullInt32 + Rain1hMm sql.NullFloat64 + Rain3hMm sql.NullFloat64 + Snow1hMm sql.NullFloat64 + Snow3hMm sql.NullFloat64 + CloudsPercent sql.NullInt32 + WeatherTypeID sql.NullInt32 +} diff --git a/internal/endtoend/testdata/valid_group_by_reference/pganalyzer/go/query.sql.go b/internal/endtoend/testdata/valid_group_by_reference/pganalyzer/go/query.sql.go new file mode 100644 index 0000000..71edbc9 --- /dev/null +++ b/internal/endtoend/testdata/valid_group_by_reference/pganalyzer/go/query.sql.go @@ -0,0 +1,105 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" + "time" +) + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name as name, bio +FROM authors +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); 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 listAuthorsIdenticalAlias = `-- name: ListAuthorsIdenticalAlias :many +SELECT id, name as name, bio +FROM authors +` + +func (q *Queries) ListAuthorsIdenticalAlias(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthorsIdenticalAlias) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); 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 listMetrics = `-- name: ListMetrics :many +SELECT date_trunc('day', time) AS bucket, city_name, AVG(temp_c) +FROM weather_metrics +WHERE time > NOW() - (6 * INTERVAL '1 month') +GROUP BY bucket, city_name +ORDER BY bucket DESC +` + +type ListMetricsRow struct { + Bucket time.Time + CityName sql.NullString + Avg float64 +} + +func (q *Queries) ListMetrics(ctx context.Context) ([]ListMetricsRow, error) { + rows, err := q.db.QueryContext(ctx, listMetrics) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListMetricsRow + for rows.Next() { + var i ListMetricsRow + if err := rows.Scan(&i.Bucket, &i.CityName, &i.Avg); 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/valid_group_by_reference/pganalyzer/query.sql b/internal/endtoend/testdata/valid_group_by_reference/pganalyzer/query.sql new file mode 100644 index 0000000..839f541 --- /dev/null +++ b/internal/endtoend/testdata/valid_group_by_reference/pganalyzer/query.sql @@ -0,0 +1,14 @@ +-- name: ListAuthors :many +SELECT id, name as name, bio +FROM authors; + +-- name: ListAuthorsIdenticalAlias :many +SELECT id, name as name, bio +FROM authors; + +-- name: ListMetrics :many +SELECT date_trunc('day', time) AS bucket, city_name, AVG(temp_c) +FROM weather_metrics +WHERE time > NOW() - (6 * INTERVAL '1 month') +GROUP BY bucket, city_name +ORDER BY bucket DESC; diff --git a/internal/endtoend/testdata/valid_group_by_reference/pganalyzer/schema.sql b/internal/endtoend/testdata/valid_group_by_reference/pganalyzer/schema.sql new file mode 100644 index 0000000..910e1da --- /dev/null +++ b/internal/endtoend/testdata/valid_group_by_reference/pganalyzer/schema.sql @@ -0,0 +1,26 @@ +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); + +CREATE TABLE IF NOT EXISTS weather_metrics +( + time TIMESTAMP WITHOUT TIME ZONE NOT NULL, + timezone_shift INT NULL, + city_name TEXT NULL, + temp_c DOUBLE PRECISION NULL, + feels_like_c DOUBLE PRECISION NULL, + temp_min_c DOUBLE PRECISION NULL, + temp_max_c DOUBLE PRECISION NULL, + pressure_hpa DOUBLE PRECISION NULL, + humidity_percent DOUBLE PRECISION NULL, + wind_speed_ms DOUBLE PRECISION NULL, + wind_deg INT NULL, + rain_1h_mm DOUBLE PRECISION NULL, + rain_3h_mm DOUBLE PRECISION NULL, + snow_1h_mm DOUBLE PRECISION NULL, + snow_3h_mm DOUBLE PRECISION NULL, + clouds_percent INT NULL, + weather_type_id INT NULL +); diff --git a/internal/endtoend/testdata/valid_group_by_reference/pganalyzer/sqlc.json b/internal/endtoend/testdata/valid_group_by_reference/pganalyzer/sqlc.json new file mode 100644 index 0000000..a590361 --- /dev/null +++ b/internal/endtoend/testdata/valid_group_by_reference/pganalyzer/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/valid_group_by_reference/postgresql/exec.json b/internal/endtoend/testdata/valid_group_by_reference/postgresql/exec.json new file mode 100644 index 0000000..2e996ca --- /dev/null +++ b/internal/endtoend/testdata/valid_group_by_reference/postgresql/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["base"] +} diff --git a/internal/endtoend/testdata/valid_group_by_reference/postgresql/go/db.go b/internal/endtoend/testdata/valid_group_by_reference/postgresql/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/valid_group_by_reference/postgresql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/valid_group_by_reference/postgresql/go/models.go b/internal/endtoend/testdata/valid_group_by_reference/postgresql/go/models.go new file mode 100644 index 0000000..a448d73 --- /dev/null +++ b/internal/endtoend/testdata/valid_group_by_reference/postgresql/go/models.go @@ -0,0 +1,36 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" + "time" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} + +type WeatherMetric struct { + Time time.Time + TimezoneShift sql.NullInt32 + CityName sql.NullString + TempC sql.NullFloat64 + FeelsLikeC sql.NullFloat64 + TempMinC sql.NullFloat64 + TempMaxC sql.NullFloat64 + PressureHpa sql.NullFloat64 + HumidityPercent sql.NullFloat64 + WindSpeedMs sql.NullFloat64 + WindDeg sql.NullInt32 + Rain1hMm sql.NullFloat64 + Rain3hMm sql.NullFloat64 + Snow1hMm sql.NullFloat64 + Snow3hMm sql.NullFloat64 + CloudsPercent sql.NullInt32 + WeatherTypeID sql.NullInt32 +} diff --git a/internal/endtoend/testdata/valid_group_by_reference/postgresql/go/query.sql.go b/internal/endtoend/testdata/valid_group_by_reference/postgresql/go/query.sql.go new file mode 100644 index 0000000..712d116 --- /dev/null +++ b/internal/endtoend/testdata/valid_group_by_reference/postgresql/go/query.sql.go @@ -0,0 +1,104 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name as name, bio +FROM authors +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); 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 listAuthorsIdenticalAlias = `-- name: ListAuthorsIdenticalAlias :many +SELECT id, name as name, bio +FROM authors +` + +func (q *Queries) ListAuthorsIdenticalAlias(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthorsIdenticalAlias) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); 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 listMetrics = `-- name: ListMetrics :many +SELECT date_trunc('day', time) AS bucket, city_name, AVG(temp_c) +FROM weather_metrics +WHERE time > NOW() - (6 * INTERVAL '1 month') +GROUP BY bucket, city_name +ORDER BY bucket DESC +` + +type ListMetricsRow struct { + Bucket int64 + CityName sql.NullString + Avg float64 +} + +func (q *Queries) ListMetrics(ctx context.Context) ([]ListMetricsRow, error) { + rows, err := q.db.QueryContext(ctx, listMetrics) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListMetricsRow + for rows.Next() { + var i ListMetricsRow + if err := rows.Scan(&i.Bucket, &i.CityName, &i.Avg); 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/valid_group_by_reference/postgresql/query.sql b/internal/endtoend/testdata/valid_group_by_reference/postgresql/query.sql new file mode 100644 index 0000000..839f541 --- /dev/null +++ b/internal/endtoend/testdata/valid_group_by_reference/postgresql/query.sql @@ -0,0 +1,14 @@ +-- name: ListAuthors :many +SELECT id, name as name, bio +FROM authors; + +-- name: ListAuthorsIdenticalAlias :many +SELECT id, name as name, bio +FROM authors; + +-- name: ListMetrics :many +SELECT date_trunc('day', time) AS bucket, city_name, AVG(temp_c) +FROM weather_metrics +WHERE time > NOW() - (6 * INTERVAL '1 month') +GROUP BY bucket, city_name +ORDER BY bucket DESC; diff --git a/internal/endtoend/testdata/valid_group_by_reference/postgresql/schema.sql b/internal/endtoend/testdata/valid_group_by_reference/postgresql/schema.sql new file mode 100644 index 0000000..910e1da --- /dev/null +++ b/internal/endtoend/testdata/valid_group_by_reference/postgresql/schema.sql @@ -0,0 +1,26 @@ +CREATE TABLE authors ( + id BIGSERIAL PRIMARY KEY, + name text NOT NULL, + bio text +); + +CREATE TABLE IF NOT EXISTS weather_metrics +( + time TIMESTAMP WITHOUT TIME ZONE NOT NULL, + timezone_shift INT NULL, + city_name TEXT NULL, + temp_c DOUBLE PRECISION NULL, + feels_like_c DOUBLE PRECISION NULL, + temp_min_c DOUBLE PRECISION NULL, + temp_max_c DOUBLE PRECISION NULL, + pressure_hpa DOUBLE PRECISION NULL, + humidity_percent DOUBLE PRECISION NULL, + wind_speed_ms DOUBLE PRECISION NULL, + wind_deg INT NULL, + rain_1h_mm DOUBLE PRECISION NULL, + rain_3h_mm DOUBLE PRECISION NULL, + snow_1h_mm DOUBLE PRECISION NULL, + snow_3h_mm DOUBLE PRECISION NULL, + clouds_percent INT NULL, + weather_type_id INT NULL +); diff --git a/internal/endtoend/testdata/valid_group_by_reference/postgresql/sqlc.json b/internal/endtoend/testdata/valid_group_by_reference/postgresql/sqlc.json new file mode 100644 index 0000000..a590361 --- /dev/null +++ b/internal/endtoend/testdata/valid_group_by_reference/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/vet_disable/exec.json b/internal/endtoend/testdata/vet_disable/exec.json new file mode 100644 index 0000000..0775363 --- /dev/null +++ b/internal/endtoend/testdata/vet_disable/exec.json @@ -0,0 +1,3 @@ +{ + "command": "vet" +} diff --git a/internal/endtoend/testdata/vet_disable/query.sql b/internal/endtoend/testdata/vet_disable/query.sql new file mode 100644 index 0000000..50052de --- /dev/null +++ b/internal/endtoend/testdata/vet_disable/query.sql @@ -0,0 +1,29 @@ +-- name: RunVetAll :exec +SELECT true; + +-- name: SkipVetAll :exec +-- @sqlc-vet-disable +SELECT true; + +-- name: SkipVetSingleLine :exec +-- @sqlc-vet-disable always-fail no-exec +SELECT true; + +-- name: SkipVetMultiLine :exec +-- @sqlc-vet-disable always-fail +-- @sqlc-vet-disable no-exec +SELECT true; + +-- name: SkipVet_always_fail :exec +-- @sqlc-vet-disable always-fail +SELECT true; + +-- name: SkipVet_no_exec :exec +-- @sqlc-vet-disable no-exec +SELECT true; + +-- name: SkipVetInvalidRule :exec +-- @sqlc-vet-disable always-fail +-- @sqlc-vet-disable block-delete +-- @sqlc-vet-disable no-exec +SELECT true; \ No newline at end of file diff --git a/internal/endtoend/testdata/vet_disable/sqlc.yaml b/internal/endtoend/testdata/vet_disable/sqlc.yaml new file mode 100644 index 0000000..1e53bd7 --- /dev/null +++ b/internal/endtoend/testdata/vet_disable/sqlc.yaml @@ -0,0 +1,21 @@ +version: 2 +sql: + - schema: "query.sql" + queries: "query.sql" + engine: "postgresql" + gen: + go: + package: "db" + out: "db" + rules: + - always-fail + - no-exec +rules: + - name: always-fail + message: "Fail" + rule: "true" + + - name: no-exec + message: "don't use exec" + rule: | + query.cmd == "exec" diff --git a/internal/endtoend/testdata/vet_disable/stderr.txt b/internal/endtoend/testdata/vet_disable/stderr.txt new file mode 100644 index 0000000..3d9a616 --- /dev/null +++ b/internal/endtoend/testdata/vet_disable/stderr.txt @@ -0,0 +1,5 @@ +query.sql: RunVetAll: always-fail: Fail +query.sql: RunVetAll: no-exec: don't use exec +query.sql: SkipVet_always_fail: no-exec: don't use exec +query.sql: SkipVet_no_exec: always-fail: Fail +query.sql: SkipVetInvalidRule: rule-check error: rule "block-delete" does not exist in the config file \ No newline at end of file diff --git a/internal/endtoend/testdata/vet_explain/mysql/db/db.go b/internal/endtoend/testdata/vet_explain/mysql/db/db.go new file mode 100644 index 0000000..bd61ca7 --- /dev/null +++ b/internal/endtoend/testdata/vet_explain/mysql/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package test + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/vet_explain/mysql/db/models.go b/internal/endtoend/testdata/vet_explain/mysql/db/models.go new file mode 100644 index 0000000..204359e --- /dev/null +++ b/internal/endtoend/testdata/vet_explain/mysql/db/models.go @@ -0,0 +1,137 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package test + +import ( + "database/sql/driver" + "encoding/json" + "fmt" + "time" +) + +type DebugCenum string + +const ( + DebugCenumOne DebugCenum = "one" + DebugCenumTwo DebugCenum = "two" + DebugCenumThree DebugCenum = "three" +) + +func (e *DebugCenum) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = DebugCenum(s) + case string: + *e = DebugCenum(s) + default: + return fmt.Errorf("unsupported scan type for DebugCenum: %T", src) + } + return nil +} + +type NullDebugCenum struct { + DebugCenum DebugCenum + Valid bool // Valid is true if DebugCenum is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullDebugCenum) Scan(value any) error { + if value == nil { + ns.DebugCenum, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.DebugCenum.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullDebugCenum) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.DebugCenum), nil +} + +type DebugCset string + +const ( + DebugCsetOne DebugCset = "one" + DebugCsetTwo DebugCset = "two" + DebugCsetThree DebugCset = "three" +) + +func (e *DebugCset) Scan(src any) error { + switch s := src.(type) { + case []byte: + *e = DebugCset(s) + case string: + *e = DebugCset(s) + default: + return fmt.Errorf("unsupported scan type for DebugCset: %T", src) + } + return nil +} + +type NullDebugCset struct { + DebugCset DebugCset + Valid bool // Valid is true if DebugCset is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullDebugCset) Scan(value any) error { + if value == nil { + ns.DebugCset, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.DebugCset.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullDebugCset) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.DebugCset), nil +} + +type Debug struct { + ID int64 + Csmallint int16 + Cint int32 + Cinteger int32 + Cdecimal string + Cnumeric string + Cfloat float64 + Creal float64 + Cdoubleprecision float64 + Cdouble float64 + Cdec string + Cfixed string + Ctinyint int8 + Cbool bool + Cmediumint int32 + Cbit any + Cdate time.Time + Cdatetime time.Time + Ctimestamp time.Time + Ctime time.Time + Cyear int16 + Cchar string + Cvarchar string + Cbinary []byte + Cvarbinary []byte + Ctinyblob []byte + Cblob []byte + Cmediumblob []byte + Clongblob []byte + Ctinytext string + Ctext string + Cmediumtext string + Clongtext string + Cenum NullDebugCenum + Cset DebugCset + Cjson json.RawMessage +} diff --git a/internal/endtoend/testdata/vet_explain/mysql/db/query.sql.go b/internal/endtoend/testdata/vet_explain/mysql/db/query.sql.go new file mode 100644 index 0000000..8fe59c2 --- /dev/null +++ b/internal/endtoend/testdata/vet_explain/mysql/db/query.sql.go @@ -0,0 +1,444 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package test + +import ( + "context" + "encoding/json" + "time" +) + +const selectByCbinary = `-- name: SelectByCbinary :one +SELECT id FROM debug +WHERE Cbinary = ? LIMIT 1 +` + +func (q *Queries) SelectByCbinary(ctx context.Context, cbinary []byte) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCbinary, cbinary) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCbit = `-- name: SelectByCbit :one +SELECT id FROM debug +WHERE Cbit = ? LIMIT 1 +` + +func (q *Queries) SelectByCbit(ctx context.Context, cbit any) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCbit, cbit) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCblob = `-- name: SelectByCblob :one +SELECT id FROM debug +WHERE Cblob = ? LIMIT 1 +` + +func (q *Queries) SelectByCblob(ctx context.Context, cblob []byte) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCblob, cblob) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCbool = `-- name: SelectByCbool :one +SELECT id FROM debug +WHERE Cbool = ? LIMIT 1 +` + +func (q *Queries) SelectByCbool(ctx context.Context, cbool bool) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCbool, cbool) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCchar = `-- name: SelectByCchar :one +SELECT id FROM debug +WHERE Cchar = ? LIMIT 1 +` + +func (q *Queries) SelectByCchar(ctx context.Context, cchar string) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCchar, cchar) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCdate = `-- name: SelectByCdate :one +SELECT id FROM debug +WHERE Cdate = ? LIMIT 1 +` + +func (q *Queries) SelectByCdate(ctx context.Context, cdate time.Time) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCdate, cdate) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCdatetime = `-- name: SelectByCdatetime :one +SELECT id FROM debug +WHERE Cdatetime = ? LIMIT 1 +` + +func (q *Queries) SelectByCdatetime(ctx context.Context, cdatetime time.Time) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCdatetime, cdatetime) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCdec = `-- name: SelectByCdec :one +SELECT id FROM debug +WHERE Cdec = ? LIMIT 1 +` + +func (q *Queries) SelectByCdec(ctx context.Context, cdec string) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCdec, cdec) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCdecimal = `-- name: SelectByCdecimal :one +SELECT id FROM debug +WHERE Cdecimal = ? LIMIT 1 +` + +func (q *Queries) SelectByCdecimal(ctx context.Context, cdecimal string) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCdecimal, cdecimal) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCdouble = `-- name: SelectByCdouble :one +SELECT id FROM debug +WHERE Cdouble = ? LIMIT 1 +` + +func (q *Queries) SelectByCdouble(ctx context.Context, cdouble float64) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCdouble, cdouble) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCdoubleprecision = `-- name: SelectByCdoubleprecision :one +SELECT id FROM debug +WHERE Cdoubleprecision = ? LIMIT 1 +` + +func (q *Queries) SelectByCdoubleprecision(ctx context.Context, cdoubleprecision float64) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCdoubleprecision, cdoubleprecision) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCenum = `-- name: SelectByCenum :one +SELECT id FROM debug +WHERE Cenum = ? LIMIT 1 +` + +func (q *Queries) SelectByCenum(ctx context.Context, cenum NullDebugCenum) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCenum, cenum) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCfixed = `-- name: SelectByCfixed :one +SELECT id FROM debug +WHERE Cfixed = ? LIMIT 1 +` + +func (q *Queries) SelectByCfixed(ctx context.Context, cfixed string) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCfixed, cfixed) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCfloat = `-- name: SelectByCfloat :one +SELECT id FROM debug +WHERE Cfloat = ? LIMIT 1 +` + +func (q *Queries) SelectByCfloat(ctx context.Context, cfloat float64) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCfloat, cfloat) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCint = `-- name: SelectByCint :one +SELECT id FROM debug +WHERE Cint = ? LIMIT 1 +` + +func (q *Queries) SelectByCint(ctx context.Context, cint int32) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCint, cint) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCinteger = `-- name: SelectByCinteger :one +SELECT id FROM debug +WHERE Cinteger = ? LIMIT 1 +` + +func (q *Queries) SelectByCinteger(ctx context.Context, cinteger int32) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCinteger, cinteger) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCjson = `-- name: SelectByCjson :one +SELECT id FROM debug +WHERE Cjson = ? LIMIT 1 +` + +func (q *Queries) SelectByCjson(ctx context.Context, cjson json.RawMessage) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCjson, cjson) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByClongblob = `-- name: SelectByClongblob :one +SELECT id FROM debug +WHERE Clongblob = ? LIMIT 1 +` + +func (q *Queries) SelectByClongblob(ctx context.Context, clongblob []byte) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByClongblob, clongblob) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByClongtext = `-- name: SelectByClongtext :one +SELECT id FROM debug +WHERE Clongtext = ? LIMIT 1 +` + +func (q *Queries) SelectByClongtext(ctx context.Context, clongtext string) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByClongtext, clongtext) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCmediumblob = `-- name: SelectByCmediumblob :one +SELECT id FROM debug +WHERE Cmediumblob = ? LIMIT 1 +` + +func (q *Queries) SelectByCmediumblob(ctx context.Context, cmediumblob []byte) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCmediumblob, cmediumblob) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCmediumint = `-- name: SelectByCmediumint :one +SELECT id FROM debug +WHERE Cmediumint = ? LIMIT 1 +` + +func (q *Queries) SelectByCmediumint(ctx context.Context, cmediumint int32) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCmediumint, cmediumint) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCmediumtext = `-- name: SelectByCmediumtext :one +SELECT id FROM debug +WHERE Cmediumtext = ? LIMIT 1 +` + +func (q *Queries) SelectByCmediumtext(ctx context.Context, cmediumtext string) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCmediumtext, cmediumtext) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCnumeric = `-- name: SelectByCnumeric :one +SELECT id FROM debug +WHERE Cnumeric = ? LIMIT 1 +` + +func (q *Queries) SelectByCnumeric(ctx context.Context, cnumeric string) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCnumeric, cnumeric) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCreal = `-- name: SelectByCreal :one +SELECT id FROM debug +WHERE Creal = ? LIMIT 1 +` + +func (q *Queries) SelectByCreal(ctx context.Context, creal float64) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCreal, creal) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCset = `-- name: SelectByCset :one +SELECT id FROM debug +WHERE Cset = ? LIMIT 1 +` + +func (q *Queries) SelectByCset(ctx context.Context, cset DebugCset) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCset, cset) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCsmallint = `-- name: SelectByCsmallint :one +SELECT id FROM debug +WHERE Csmallint = ? LIMIT 1 +` + +func (q *Queries) SelectByCsmallint(ctx context.Context, csmallint int16) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCsmallint, csmallint) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCtext = `-- name: SelectByCtext :one +SELECT id FROM debug +WHERE Ctext = ? LIMIT 1 +` + +func (q *Queries) SelectByCtext(ctx context.Context, ctext string) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCtext, ctext) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCtime = `-- name: SelectByCtime :one +SELECT id FROM debug +WHERE Ctime = ? LIMIT 1 +` + +func (q *Queries) SelectByCtime(ctx context.Context, ctime time.Time) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCtime, ctime) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCtimestamp = `-- name: SelectByCtimestamp :one +SELECT id FROM debug +WHERE Ctimestamp = ? LIMIT 1 +` + +func (q *Queries) SelectByCtimestamp(ctx context.Context, ctimestamp time.Time) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCtimestamp, ctimestamp) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCtinyblob = `-- name: SelectByCtinyblob :one +SELECT id FROM debug +WHERE Ctinyblob = ? LIMIT 1 +` + +func (q *Queries) SelectByCtinyblob(ctx context.Context, ctinyblob []byte) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCtinyblob, ctinyblob) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCtinyint = `-- name: SelectByCtinyint :one +SELECT id FROM debug +WHERE Ctinyint = ? LIMIT 1 +` + +func (q *Queries) SelectByCtinyint(ctx context.Context, ctinyint int8) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCtinyint, ctinyint) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCtinytext = `-- name: SelectByCtinytext :one +SELECT id FROM debug +WHERE Ctinytext = ? LIMIT 1 +` + +func (q *Queries) SelectByCtinytext(ctx context.Context, ctinytext string) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCtinytext, ctinytext) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCvarbinary = `-- name: SelectByCvarbinary :one +SELECT id FROM debug +WHERE Cvarbinary = ? LIMIT 1 +` + +func (q *Queries) SelectByCvarbinary(ctx context.Context, cvarbinary []byte) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCvarbinary, cvarbinary) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCvarchar = `-- name: SelectByCvarchar :one +SELECT id FROM debug +WHERE Cvarchar = ? LIMIT 1 +` + +func (q *Queries) SelectByCvarchar(ctx context.Context, cvarchar string) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCvarchar, cvarchar) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectByCyear = `-- name: SelectByCyear :one +SELECT id FROM debug +WHERE Cyear = ? LIMIT 1 +` + +func (q *Queries) SelectByCyear(ctx context.Context, cyear int16) (int64, error) { + row := q.db.QueryRowContext(ctx, selectByCyear, cyear) + var id int64 + err := row.Scan(&id) + return id, err +} + +const selectById = `-- name: SelectById :one +SELECT id FROM debug +WHERE id = ? LIMIT 1 +` + +func (q *Queries) SelectById(ctx context.Context, id int64) (int64, error) { + row := q.db.QueryRowContext(ctx, selectById, id) + var id_2 int64 + err := row.Scan(&id_2) + return id_2, err +} diff --git a/internal/endtoend/testdata/vet_explain/mysql/query.sql b/internal/endtoend/testdata/vet_explain/mysql/query.sql new file mode 100644 index 0000000..9712dd7 --- /dev/null +++ b/internal/endtoend/testdata/vet_explain/mysql/query.sql @@ -0,0 +1,290 @@ +-- name: SelectById :one +SELECT id FROM debug +WHERE id = ? LIMIT 1; + +-- name: SelectByCsmallint :one +SELECT id FROM debug +WHERE Csmallint = ? LIMIT 1; + +-- name: SelectByCint :one +SELECT id FROM debug +WHERE Cint = ? LIMIT 1; + +-- name: SelectByCinteger :one +SELECT id FROM debug +WHERE Cinteger = ? LIMIT 1; + +-- name: SelectByCdecimal :one +SELECT id FROM debug +WHERE Cdecimal = ? LIMIT 1; + +-- name: SelectByCnumeric :one +SELECT id FROM debug +WHERE Cnumeric = ? LIMIT 1; + +-- name: SelectByCfloat :one +SELECT id FROM debug +WHERE Cfloat = ? LIMIT 1; + +-- name: SelectByCreal :one +SELECT id FROM debug +WHERE Creal = ? LIMIT 1; + +-- name: SelectByCdoubleprecision :one +SELECT id FROM debug +WHERE Cdoubleprecision = ? LIMIT 1; + +-- name: SelectByCdouble :one +SELECT id FROM debug +WHERE Cdouble = ? LIMIT 1; + +-- name: SelectByCdec :one +SELECT id FROM debug +WHERE Cdec = ? LIMIT 1; + +-- name: SelectByCfixed :one +SELECT id FROM debug +WHERE Cfixed = ? LIMIT 1; + +-- name: SelectByCtinyint :one +SELECT id FROM debug +WHERE Ctinyint = ? LIMIT 1; + +-- name: SelectByCbool :one +SELECT id FROM debug +WHERE Cbool = ? LIMIT 1; + +-- name: SelectByCmediumint :one +SELECT id FROM debug +WHERE Cmediumint = ? LIMIT 1; + +-- name: SelectByCbit :one +SELECT id FROM debug +WHERE Cbit = ? LIMIT 1; + +-- name: SelectByCdate :one +SELECT id FROM debug +WHERE Cdate = ? LIMIT 1; + +-- name: SelectByCdatetime :one +SELECT id FROM debug +WHERE Cdatetime = ? LIMIT 1; + +-- name: SelectByCtimestamp :one +SELECT id FROM debug +WHERE Ctimestamp = ? LIMIT 1; + +-- name: SelectByCtime :one +SELECT id FROM debug +WHERE Ctime = ? LIMIT 1; + +-- name: SelectByCyear :one +SELECT id FROM debug +WHERE Cyear = ? LIMIT 1; + +-- name: SelectByCchar :one +SELECT id FROM debug +WHERE Cchar = ? LIMIT 1; + +-- name: SelectByCvarchar :one +SELECT id FROM debug +WHERE Cvarchar = ? LIMIT 1; + +-- name: SelectByCbinary :one +SELECT id FROM debug +WHERE Cbinary = ? LIMIT 1; + +-- name: SelectByCvarbinary :one +SELECT id FROM debug +WHERE Cvarbinary = ? LIMIT 1; + +-- name: SelectByCtinyblob :one +SELECT id FROM debug +WHERE Ctinyblob = ? LIMIT 1; + +-- name: SelectByCblob :one +SELECT id FROM debug +WHERE Cblob = ? LIMIT 1; + +-- name: SelectByCmediumblob :one +SELECT id FROM debug +WHERE Cmediumblob = ? LIMIT 1; + +-- name: SelectByClongblob :one +SELECT id FROM debug +WHERE Clongblob = ? LIMIT 1; + +-- name: SelectByCtinytext :one +SELECT id FROM debug +WHERE Ctinytext = ? LIMIT 1; + +-- name: SelectByCtext :one +SELECT id FROM debug +WHERE Ctext = ? LIMIT 1; + +-- name: SelectByCmediumtext :one +SELECT id FROM debug +WHERE Cmediumtext = ? LIMIT 1; + +-- name: SelectByClongtext :one +SELECT id FROM debug +WHERE Clongtext = ? LIMIT 1; + +-- name: SelectByCenum :one +SELECT id FROM debug +WHERE Cenum = ? LIMIT 1; + +-- name: SelectByCset :one +SELECT id FROM debug +WHERE Cset = ? LIMIT 1; + +-- name: SelectByCjson :one +SELECT id FROM debug +WHERE Cjson = ? LIMIT 1; + +-- +-- + +-- -- name: DeleteById :exec +-- DELETE FROM debug +-- WHERE id = ?; + +-- -- name: DeleteByCsmallint :exec +-- DELETE FROM debug +-- WHERE Csmallint = ? LIMIT 1; + +-- -- name: DeleteByCint :exec +-- DELETE FROM debug +-- WHERE Cint = ? LIMIT 1; + +-- -- name: DeleteByCinteger :exec +-- DELETE FROM debug +-- WHERE Cinteger = ? LIMIT 1; + +-- -- name: DeleteByCdecimal :exec +-- DELETE FROM debug +-- WHERE Cdecimal = ? LIMIT 1; + +-- -- name: DeleteByCnumeric :exec +-- DELETE FROM debug +-- WHERE Cnumeric = ? LIMIT 1; + +-- -- name: DeleteByCfloat :exec +-- DELETE FROM debug +-- WHERE Cfloat = ? LIMIT 1; + +-- -- name: DeleteByCreal :exec +-- DELETE FROM debug +-- WHERE Creal = ? LIMIT 1; + +-- -- name: DeleteByCdoubleprecision :exec +-- DELETE FROM debug +-- WHERE Cdoubleprecision = ? LIMIT 1; + +-- -- name: DeleteByCdouble :exec +-- DELETE FROM debug +-- WHERE Cdouble = ? LIMIT 1; + +-- -- name: DeleteByCdec :exec +-- DELETE FROM debug +-- WHERE Cdec = ? LIMIT 1; + +-- -- name: DeleteByCfixed :exec +-- DELETE FROM debug +-- WHERE Cfixed = ? LIMIT 1; + +-- -- name: DeleteByCtinyint :exec +-- DELETE FROM debug +-- WHERE Ctinyint = ? LIMIT 1; + +-- -- name: DeleteByCbool :exec +-- DELETE FROM debug +-- WHERE Cbool = ? LIMIT 1; + +-- -- name: DeleteByCmediumint :exec +-- DELETE FROM debug +-- WHERE Cmediumint = ? LIMIT 1; + +-- -- name: DeleteByCbit :exec +-- DELETE FROM debug +-- WHERE Cbit = ? LIMIT 1; + +-- -- name: DeleteByCdate :exec +-- DELETE FROM debug +-- WHERE Cdate = ? LIMIT 1; + +-- -- name: DeleteByCdatetime :exec +-- DELETE FROM debug +-- WHERE Cdatetime = ? LIMIT 1; + +-- -- name: DeleteByCtimestamp :exec +-- DELETE FROM debug +-- WHERE Ctimestamp = ? LIMIT 1; + +-- -- name: DeleteByCtime :exec +-- DELETE FROM debug +-- WHERE Ctime = ? LIMIT 1; + +-- -- name: DeleteByCyear :exec +-- DELETE FROM debug +-- WHERE Cyear = ? LIMIT 1; + +-- -- name: DeleteByCchar :exec +-- DELETE FROM debug +-- WHERE Cchar = ? LIMIT 1; + +-- -- name: DeleteByCvarchar :exec +-- DELETE FROM debug +-- WHERE Cvarchar = ?; + +-- -- name: DeleteByCbinary :exec +-- DELETE FROM debug +-- WHERE Cbinary = ? LIMIT 1; + +-- -- name: DeleteByCvarbinary :exec +-- DELETE FROM debug +-- WHERE Cvarbinary = ? LIMIT 1; + +-- -- name: DeleteByCtinyblob :exec +-- DELETE FROM debug +-- WHERE Ctinyblob = ? LIMIT 1; + +-- -- name: DeleteByCblob :exec +-- DELETE FROM debug +-- WHERE Cblob = ? LIMIT 1; + +-- -- name: DeleteByCmediumblob :exec +-- DELETE FROM debug +-- WHERE Cmediumblob = ? LIMIT 1; + +-- -- name: DeleteByClongblob :exec +-- DELETE FROM debug +-- WHERE Clongblob = ? LIMIT 1; + +-- -- name: DeleteByCtinytext :exec +-- DELETE FROM debug +-- WHERE Ctinytext = ? LIMIT 1; + +-- -- name: DeleteByCtext :exec +-- DELETE FROM debug +-- WHERE Ctext = ? LIMIT 1; + +-- -- name: DeleteByCmediumtext :exec +-- DELETE FROM debug +-- WHERE Cmediumtext = ? LIMIT 1; + +-- -- name: DeleteByClongtext :exec +-- DELETE FROM debug +-- WHERE Clongtext = ? LIMIT 1; + +-- -- name: DeleteByCenum :exec +-- DELETE FROM debug +-- WHERE Cenum = ? LIMIT 1; + +-- -- name: DeleteByCset :exec +-- DELETE FROM debug +-- WHERE Cset = ? LIMIT 1; + +-- -- name: DeleteByCjson :exec +-- DELETE FROM debug +-- WHERE Cjson = ? LIMIT 1; diff --git a/internal/endtoend/testdata/vet_explain/mysql/schema.sql b/internal/endtoend/testdata/vet_explain/mysql/schema.sql new file mode 100644 index 0000000..3a7476b --- /dev/null +++ b/internal/endtoend/testdata/vet_explain/mysql/schema.sql @@ -0,0 +1,38 @@ +CREATE TABLE debug ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + Csmallint smallint not null, + Cint int not null, + Cinteger integer not null, + Cdecimal decimal(1,1) not null, + Cnumeric numeric(2,1) not null, + Cfloat float not null, + Creal real not null, + Cdoubleprecision double precision not null, + Cdouble double not null, + Cdec dec(3,2) not null, + Cfixed fixed(5,5) not null, + Ctinyint tinyint not null, + Cbool bool not null, + Cmediumint mediumint not null, + Cbit bit not null, + Cdate date not null, + Cdatetime datetime not null, + Ctimestamp timestamp not null, + Ctime time not null, + Cyear year not null, + Cchar char(1) not null, + Cvarchar varchar(1) not null, + Cbinary binary(1) not null, + Cvarbinary varbinary(1) not null, + Ctinyblob tinyblob not null, + Cblob blob not null, + Cmediumblob mediumblob not null, + Clongblob longblob not null, + Ctinytext tinytext NOT NULL, + Ctext text NOT NULL, + Cmediumtext mediumtext NOT NULL, + Clongtext longtext NOT NULL, + Cenum ENUM('one', 'two', 'three'), + Cset SET('one', 'two', 'three') NOT NULL, + Cjson JSON NOT NULL +); \ No newline at end of file diff --git a/internal/endtoend/testdata/vet_explain/mysql/sqlc.yaml b/internal/endtoend/testdata/vet_explain/mysql/sqlc.yaml new file mode 100644 index 0000000..8e83a1c --- /dev/null +++ b/internal/endtoend/testdata/vet_explain/mysql/sqlc.yaml @@ -0,0 +1,16 @@ +version: 2 +sql: + - schema: "schema.sql" + queries: "query.sql" + engine: "mysql" + database: + uri: root:${MYSQL_ROOT_PASSWORD}@tcp(${MYSQL_HOST}:${MYSQL_PORT})/test?multiStatements=true&parseTime=true + gen: + go: + package: "test" + out: "db" + rules: + - test +rules: + - name: test + rule: "!has(mysql.explain)" diff --git a/internal/endtoend/testdata/vet_failures/exec.json b/internal/endtoend/testdata/vet_failures/exec.json new file mode 100644 index 0000000..0775363 --- /dev/null +++ b/internal/endtoend/testdata/vet_failures/exec.json @@ -0,0 +1,3 @@ +{ + "command": "vet" +} diff --git a/internal/endtoend/testdata/vet_failures/query.sql b/internal/endtoend/testdata/vet_failures/query.sql new file mode 100644 index 0000000..75e38b2 --- /dev/null +++ b/internal/endtoend/testdata/vet_failures/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/vet_failures/schema.sql b/internal/endtoend/testdata/vet_failures/schema.sql new file mode 100644 index 0000000..b4fad78 --- /dev/null +++ b/internal/endtoend/testdata/vet_failures/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/vet_failures/sqlc.yaml b/internal/endtoend/testdata/vet_failures/sqlc.yaml new file mode 100644 index 0000000..b1cff78 --- /dev/null +++ b/internal/endtoend/testdata/vet_failures/sqlc.yaml @@ -0,0 +1,31 @@ +version: 2 +sql: + - schema: "schema.sql" + queries: "query.sql" + engine: "postgresql" + gen: + go: + package: "authors" + out: "db" + rules: + - no-pg + - no-delete + - only-one-param + - no-exec +rules: + - name: no-pg + message: "invalid engine: postgresql" + rule: | + config.engine == "postgresql" + - name: no-delete + message: "don't use delete statements" + rule: | + query.sql.contains("DELETE") + - name: only-one-param + message: "too many parameters" + rule: | + query.params.size() > 1 + - name: no-exec + message: "don't use exec" + rule: | + query.cmd == "exec" diff --git a/internal/endtoend/testdata/vet_failures/stderr.txt b/internal/endtoend/testdata/vet_failures/stderr.txt new file mode 100644 index 0000000..584c460 --- /dev/null +++ b/internal/endtoend/testdata/vet_failures/stderr.txt @@ -0,0 +1,7 @@ +query.sql: GetAuthor: no-pg: invalid engine: postgresql +query.sql: ListAuthors: no-pg: invalid engine: postgresql +query.sql: CreateAuthor: no-pg: invalid engine: postgresql +query.sql: CreateAuthor: only-one-param: too many parameters +query.sql: DeleteAuthor: no-pg: invalid engine: postgresql +query.sql: DeleteAuthor: no-delete: don't use delete statements +query.sql: DeleteAuthor: no-exec: don't use exec diff --git a/internal/endtoend/testdata/virtual_table/sqlite/go/db.go b/internal/endtoend/testdata/virtual_table/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/virtual_table/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/virtual_table/sqlite/go/models.go b/internal/endtoend/testdata/virtual_table/sqlite/go/models.go new file mode 100644 index 0000000..9c0bffb --- /dev/null +++ b/internal/endtoend/testdata/virtual_table/sqlite/go/models.go @@ -0,0 +1,26 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "database/sql" +) + +type Ft struct { + B string +} + +type Tbl struct { + A int64 + B sql.NullString + C sql.NullString + D sql.NullString + E sql.NullInt64 +} + +type TblFt struct { + B string + C string +} diff --git a/internal/endtoend/testdata/virtual_table/sqlite/go/query.sql.go b/internal/endtoend/testdata/virtual_table/sqlite/go/query.sql.go new file mode 100644 index 0000000..b042473 --- /dev/null +++ b/internal/endtoend/testdata/virtual_table/sqlite/go/query.sql.go @@ -0,0 +1,255 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const deleteTblFt = `-- name: DeleteTblFt :exec +DELETE FROM tbl_ft WHERE b = ? +` + +func (q *Queries) DeleteTblFt(ctx context.Context, b string) error { + _, err := q.db.ExecContext(ctx, deleteTblFt, b) + return err +} + +const insertTblFt = `-- name: InsertTblFt :exec +INSERT INTO tbl_ft (b, c) VALUES (?, ?) +` + +type InsertTblFtParams struct { + B string + C string +} + +func (q *Queries) InsertTblFt(ctx context.Context, arg InsertTblFtParams) error { + _, err := q.db.ExecContext(ctx, insertTblFt, arg.B, arg.C) + return err +} + +const selectAllColsFt = `-- name: SelectAllColsFt :many +SELECT b +FROM ft +WHERE b MATCH ? +` + +func (q *Queries) SelectAllColsFt(ctx context.Context, b string) ([]string, error) { + rows, err := q.db.QueryContext(ctx, selectAllColsFt, b) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var b string + if err := rows.Scan(&b); err != nil { + return nil, err + } + items = append(items, b) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const selectAllColsTblFt = `-- name: SelectAllColsTblFt :many +SELECT b, c +FROM tbl_ft +WHERE b MATCH ? +` + +func (q *Queries) SelectAllColsTblFt(ctx context.Context, b string) ([]TblFt, error) { + rows, err := q.db.QueryContext(ctx, selectAllColsTblFt, b) + if err != nil { + return nil, err + } + defer rows.Close() + var items []TblFt + for rows.Next() { + var i TblFt + if err := rows.Scan(&i.B, &i.C); 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 selectBm25Func = `-- name: SelectBm25Func :many +SELECT b, c, bm25(tbl_ft, 2.0) +FROM tbl_ft +WHERE b MATCH ? +ORDER BY bm25(tbl_ft) +` + +type SelectBm25FuncRow struct { + B string + C string + Bm25 float64 +} + +func (q *Queries) SelectBm25Func(ctx context.Context, b string) ([]SelectBm25FuncRow, error) { + rows, err := q.db.QueryContext(ctx, selectBm25Func, b) + if err != nil { + return nil, err + } + defer rows.Close() + var items []SelectBm25FuncRow + for rows.Next() { + var i SelectBm25FuncRow + if err := rows.Scan(&i.B, &i.C, &i.Bm25); 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 selectHightlighFunc = `-- name: SelectHightlighFunc :many +SELECT highlight(tbl_ft, 0, '', '') +FROM tbl_ft +WHERE b MATCH ? +` + +func (q *Queries) SelectHightlighFunc(ctx context.Context, b string) ([]string, error) { + rows, err := q.db.QueryContext(ctx, selectHightlighFunc, b) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var highlight string + if err := rows.Scan(&highlight); err != nil { + return nil, err + } + items = append(items, highlight) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const selectOneColFt = `-- name: SelectOneColFt :many +SELECT b +FROM ft +WHERE b = ? +` + +func (q *Queries) SelectOneColFt(ctx context.Context, b string) ([]string, error) { + rows, err := q.db.QueryContext(ctx, selectOneColFt, b) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var b string + if err := rows.Scan(&b); err != nil { + return nil, err + } + items = append(items, b) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const selectOneColTblFt = `-- name: SelectOneColTblFt :many +SELECT c +FROM tbl_ft +WHERE b = ? +` + +func (q *Queries) SelectOneColTblFt(ctx context.Context, b string) ([]string, error) { + rows, err := q.db.QueryContext(ctx, selectOneColTblFt, b) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var c string + if err := rows.Scan(&c); err != nil { + return nil, err + } + items = append(items, c) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const selectSnippetFunc = `-- name: SelectSnippetFunc :many +SELECT snippet(tbl_ft, 0, '', '', 'aa', ?) FROM tbl_ft +` + +func (q *Queries) SelectSnippetFunc(ctx context.Context, snippet int64) ([]string, error) { + rows, err := q.db.QueryContext(ctx, selectSnippetFunc, snippet) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var snippet string + if err := rows.Scan(&snippet); err != nil { + return nil, err + } + items = append(items, snippet) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateTblFt = `-- name: UpdateTblFt :exec +UPDATE tbl_ft SET c = ? WHERE b = ? +` + +type UpdateTblFtParams struct { + C string + B string +} + +func (q *Queries) UpdateTblFt(ctx context.Context, arg UpdateTblFtParams) error { + _, err := q.db.ExecContext(ctx, updateTblFt, arg.C, arg.B) + return err +} diff --git a/internal/endtoend/testdata/virtual_table/sqlite/query.sql b/internal/endtoend/testdata/virtual_table/sqlite/query.sql new file mode 100644 index 0000000..002e90f --- /dev/null +++ b/internal/endtoend/testdata/virtual_table/sqlite/query.sql @@ -0,0 +1,42 @@ +-- name: SelectAllColsFt :many +SELECT b +FROM ft +WHERE b MATCH ?; + +-- name: SelectAllColsTblFt :many +SELECT b, c +FROM tbl_ft +WHERE b MATCH ?; + +-- name: SelectOneColFt :many +SELECT b +FROM ft +WHERE b = ?; + +-- name: SelectOneColTblFt :many +SELECT c +FROM tbl_ft +WHERE b = ?; + +-- name: SelectHightlighFunc :many +SELECT highlight(tbl_ft, 0, '', '') +FROM tbl_ft +WHERE b MATCH ?; + +-- name: SelectSnippetFunc :many +SELECT snippet(tbl_ft, 0, '', '', 'aa', ?) FROM tbl_ft; + +-- name: SelectBm25Func :many +SELECT b, c, bm25(tbl_ft, 2.0) +FROM tbl_ft +WHERE b MATCH ? +ORDER BY bm25(tbl_ft); + +-- name: UpdateTblFt :exec +UPDATE tbl_ft SET c = ? WHERE b = ?; + +-- name: DeleteTblFt :exec +DELETE FROM tbl_ft WHERE b = ?; + +-- name: InsertTblFt :exec +INSERT INTO tbl_ft (b, c) VALUES (?, ?); diff --git a/internal/endtoend/testdata/virtual_table/sqlite/schema.sql b/internal/endtoend/testdata/virtual_table/sqlite/schema.sql new file mode 100644 index 0000000..5d3e0a3 --- /dev/null +++ b/internal/endtoend/testdata/virtual_table/sqlite/schema.sql @@ -0,0 +1,15 @@ +CREATE TABLE tbl(a INTEGER PRIMARY KEY, b TEXT, c TEXT, d TEXT, e INTEGER); + +CREATE VIRTUAL TABLE tbl_ft USING fts5(b, c UNINDEXED, content='tbl', content_rowid='a'); + +CREATE VIRTUAL TABLE ft USING fts5(b); + +CREATE TRIGGER tbl_ai AFTER INSERT ON tbl BEGIN + INSERT INTO tbl_ft(rowid, b, c) VALUES (new.a, new.b, new.c); +END; + +INSERT INTO tbl VALUES(1, 'xx yy cc', 't', 'a', 11); +INSERT INTO tbl VALUES(2, 'aa bb', 't', 'a', 22); + +INSERT INTO ft VALUES('xx cc'); +INSERT INTO ft VALUES('cc bb'); diff --git a/internal/endtoend/testdata/virtual_table/sqlite/sqlc.yaml b/internal/endtoend/testdata/virtual_table/sqlite/sqlc.yaml new file mode 100644 index 0000000..50f9bba --- /dev/null +++ b/internal/endtoend/testdata/virtual_table/sqlite/sqlc.yaml @@ -0,0 +1,9 @@ +version: '2' +sql: +- schema: schema.sql + queries: query.sql + engine: sqlite + gen: + go: + package: querytest + out: go \ No newline at end of file diff --git a/internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/exec.json b/internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/exec.json new file mode 100644 index 0000000..8a7ecd2 --- /dev/null +++ b/internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/exec.json @@ -0,0 +1,3 @@ +{ + "contexts": ["core"] +} diff --git a/internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/go/db.go b/internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/virtual_table_fts5_hidden/sqlite/go/models.go b/internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/go/models.go new file mode 100644 index 0000000..98b7ec9 --- /dev/null +++ b/internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Recipe struct { + ID int64 + Name string +} + +type RecipesFt struct { + Name string +} diff --git a/internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/go/query.sql.go b/internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/go/query.sql.go new file mode 100644 index 0000000..7fe6d32 --- /dev/null +++ b/internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/go/query.sql.go @@ -0,0 +1,81 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const searchRecipes = `-- name: SearchRecipes :many +SELECT rowid, name +FROM recipes_fts +WHERE recipes_fts MATCH ? +` + +type SearchRecipesRow struct { + Rowid int64 + Name string +} + +func (q *Queries) SearchRecipes(ctx context.Context, recipesFts string) ([]SearchRecipesRow, error) { + rows, err := q.db.QueryContext(ctx, searchRecipes, recipesFts) + if err != nil { + return nil, err + } + defer rows.Close() + var items []SearchRecipesRow + for rows.Next() { + var i SearchRecipesRow + if err := rows.Scan(&i.Rowid, &i.Name); 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 searchRecipesRanked = `-- name: SearchRecipesRanked :many +SELECT rowid, name, rank +FROM recipes_fts +WHERE recipes_fts MATCH ? +ORDER BY rank +` + +type SearchRecipesRankedRow struct { + Rowid int64 + Name string + Rank sql.NullFloat64 +} + +func (q *Queries) SearchRecipesRanked(ctx context.Context, recipesFts string) ([]SearchRecipesRankedRow, error) { + rows, err := q.db.QueryContext(ctx, searchRecipesRanked, recipesFts) + if err != nil { + return nil, err + } + defer rows.Close() + var items []SearchRecipesRankedRow + for rows.Next() { + var i SearchRecipesRankedRow + if err := rows.Scan(&i.Rowid, &i.Name, &i.Rank); 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/virtual_table_fts5_hidden/sqlite/query.sql b/internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/query.sql new file mode 100644 index 0000000..0b5785a --- /dev/null +++ b/internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/query.sql @@ -0,0 +1,10 @@ +-- name: SearchRecipes :many +SELECT rowid, name +FROM recipes_fts +WHERE recipes_fts MATCH ?; + +-- name: SearchRecipesRanked :many +SELECT rowid, name, rank +FROM recipes_fts +WHERE recipes_fts MATCH ? +ORDER BY rank; diff --git a/internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/schema.sql b/internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/schema.sql new file mode 100644 index 0000000..498824e --- /dev/null +++ b/internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/schema.sql @@ -0,0 +1,10 @@ +CREATE TABLE recipes ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL +); + +CREATE VIRTUAL TABLE recipes_fts USING FTS5 ( + name, + content='recipes', + content_rowid='id' +); diff --git a/internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/sqlc.yaml b/internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/sqlc.yaml new file mode 100644 index 0000000..77e7a3d --- /dev/null +++ b/internal/endtoend/testdata/virtual_table_fts5_hidden/sqlite/sqlc.yaml @@ -0,0 +1,9 @@ +version: '2' +sql: +- schema: schema.sql + queries: query.sql + engine: sqlite + gen: + go: + package: querytest + out: go diff --git a/internal/endtoend/testdata/wasm_plugin_sqlc_gen_greeter/gen/hello.txt b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_greeter/gen/hello.txt new file mode 100644 index 0000000..5e1c309 --- /dev/null +++ b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_greeter/gen/hello.txt @@ -0,0 +1 @@ +Hello World \ No newline at end of file diff --git a/internal/endtoend/testdata/wasm_plugin_sqlc_gen_greeter/query.sql b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_greeter/query.sql new file mode 100644 index 0000000..75e38b2 --- /dev/null +++ b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_greeter/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_greeter/schema.sql b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_greeter/schema.sql new file mode 100644 index 0000000..b4fad78 --- /dev/null +++ b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_greeter/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_greeter/sqlc.json b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_greeter/sqlc.json new file mode 100644 index 0000000..2385cc5 --- /dev/null +++ b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_greeter/sqlc.json @@ -0,0 +1,25 @@ +{ + "version": "2", + "sql": [ + { + "schema": "schema.sql", + "queries": "query.sql", + "engine": "postgresql", + "codegen": [ + { + "out": "gen", + "plugin": "greeter" + } + ] + } + ], + "plugins": [ + { + "name": "greeter", + "wasm": { + "url": "https://github.com/sqlc-dev/sqlc-gen-greeter/releases/download/v0.1.0/sqlc-gen-greeter.wasm", + "sha256": "afc486dac2068d741d7a4110146559d12a013fd0286f42a2fc7dcd802424ad07" + } + } + ] +} 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 0000000..48e316b --- /dev/null +++ b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_test/gen/env.json @@ -0,0 +1,6 @@ +{ + "env": [ + "SQLC_VERSION=v1.31.1", + "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 0000000..75e38b2 --- /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 0000000..b4fad78 --- /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 0000000..38e6773 --- /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 diff --git a/internal/endtoend/testdata/wasm_plugin_sqlc_gen_unsafe_paths/query.sql b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_unsafe_paths/query.sql new file mode 100644 index 0000000..75e38b2 --- /dev/null +++ b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_unsafe_paths/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_unsafe_paths/schema.sql b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_unsafe_paths/schema.sql new file mode 100644 index 0000000..b4fad78 --- /dev/null +++ b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_unsafe_paths/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_unsafe_paths/sqlc.json b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_unsafe_paths/sqlc.json new file mode 100644 index 0000000..bb84bdd --- /dev/null +++ b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_unsafe_paths/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", + "wasm": { + "url": "https://github.com/sqlc-dev/sqlc-gen-unsafe-paths/releases/download/v0.1.1/sqlc-gen-unsafe-paths.wasm", + "sha256": "e53ac951dd41b1e4c365e757d9735886f7c8e92f2056ce0be9a5cfcf677c45d9" + } + } + ] +} diff --git a/internal/endtoend/testdata/wasm_plugin_sqlc_gen_unsafe_paths/stderr.txt b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_unsafe_paths/stderr.txt new file mode 100644 index 0000000..8d664b0 --- /dev/null +++ b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_unsafe_paths/stderr.txt @@ -0,0 +1,2 @@ +# package test +error generating code: invalid file output path: /tmp/unsafe.txt diff --git a/internal/endtoend/testdata/wasm_plugin_sqlc_gen_unsafe_paths/stderr_windows.txt b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_unsafe_paths/stderr_windows.txt new file mode 100644 index 0000000..33d32af --- /dev/null +++ b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_unsafe_paths/stderr_windows.txt @@ -0,0 +1,2 @@ +# package test +error generating code: invalid file output path: D:/tmp/unsafe.txt diff --git a/internal/endtoend/testdata/where_collate/sqlite/go/db.go b/internal/endtoend/testdata/where_collate/sqlite/go/db.go new file mode 100644 index 0000000..32faa9f --- /dev/null +++ b/internal/endtoend/testdata/where_collate/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/where_collate/sqlite/go/models.go b/internal/endtoend/testdata/where_collate/sqlite/go/models.go new file mode 100644 index 0000000..9ae2486 --- /dev/null +++ b/internal/endtoend/testdata/where_collate/sqlite/go/models.go @@ -0,0 +1,10 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package querytest + +type Account struct { + ID string + Name string +} diff --git a/internal/endtoend/testdata/where_collate/sqlite/go/query.sql.go b/internal/endtoend/testdata/where_collate/sqlite/go/query.sql.go new file mode 100644 index 0000000..1f40224 --- /dev/null +++ b/internal/endtoend/testdata/where_collate/sqlite/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAccountByName = `-- name: GetAccountByName :one +SELECT id, name +FROM accounts +WHERE name = ? COLLATE nocase +LIMIT 1 +` + +func (q *Queries) GetAccountByName(ctx context.Context, name string) (Account, error) { + row := q.db.QueryRowContext(ctx, getAccountByName, name) + var i Account + err := row.Scan(&i.ID, &i.Name) + return i, err +} diff --git a/internal/endtoend/testdata/where_collate/sqlite/query.sql b/internal/endtoend/testdata/where_collate/sqlite/query.sql new file mode 100644 index 0000000..88568bf --- /dev/null +++ b/internal/endtoend/testdata/where_collate/sqlite/query.sql @@ -0,0 +1,5 @@ +-- name: GetAccountByName :one +SELECT * +FROM accounts +WHERE name = ? COLLATE nocase +LIMIT 1; diff --git a/internal/endtoend/testdata/where_collate/sqlite/schema.sql b/internal/endtoend/testdata/where_collate/sqlite/schema.sql new file mode 100644 index 0000000..00a9def --- /dev/null +++ b/internal/endtoend/testdata/where_collate/sqlite/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE accounts ( + id TEXT NOT NULL PRIMARY KEY, + name TEXT NOT NULL UNIQUE, + + UNIQUE (name COLLATE NOCASE) +); + diff --git a/internal/endtoend/testdata/where_collate/sqlite/sqlc.json b/internal/endtoend/testdata/where_collate/sqlite/sqlc.json new file mode 100644 index 0000000..ea4a234 --- /dev/null +++ b/internal/endtoend/testdata/where_collate/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "schema": "schema.sql", + "queries": "query.sql", + "name": "querytest" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/wrap_errors/mysql/db/db.go b/internal/endtoend/testdata/wrap_errors/mysql/db/db.go new file mode 100644 index 0000000..32f660c --- /dev/null +++ b/internal/endtoend/testdata/wrap_errors/mysql/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package authors + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/wrap_errors/mysql/db/models.go b/internal/endtoend/testdata/wrap_errors/mysql/db/models.go new file mode 100644 index 0000000..62bacd8 --- /dev/null +++ b/internal/endtoend/testdata/wrap_errors/mysql/db/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package authors + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/wrap_errors/mysql/db/query.sql.go b/internal/endtoend/testdata/wrap_errors/mysql/db/query.sql.go new file mode 100644 index 0000000..cd9e3a0 --- /dev/null +++ b/internal/endtoend/testdata/wrap_errors/mysql/db/query.sql.go @@ -0,0 +1,123 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package authors + +import ( + "context" + "database/sql" + "fmt" +) + +const createAuthor = `-- name: CreateAuthor :execlastid +INSERT INTO authors ( + name, bio +) VALUES ( + $1, $2 +) +` + +func (q *Queries) CreateAuthor(ctx context.Context) (int64, error) { + result, err := q.db.ExecContext(ctx, createAuthor) + if err != nil { + return 0, fmt.Errorf("query CreateAuthor: %w", err) + } + return result.LastInsertId() +} + +const deleteAuthorExec = `-- name: DeleteAuthorExec :exec +DELETE FROM authors +WHERE id = $1 +` + +func (q *Queries) DeleteAuthorExec(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, deleteAuthorExec) + if err != nil { + err = fmt.Errorf("query DeleteAuthorExec: %w", err) + } + return err +} + +const deleteAuthorExecLastID = `-- name: DeleteAuthorExecLastID :execlastid +DELETE FROM authors +WHERE id = $1 +` + +func (q *Queries) DeleteAuthorExecLastID(ctx context.Context) (int64, error) { + result, err := q.db.ExecContext(ctx, deleteAuthorExecLastID) + if err != nil { + return 0, fmt.Errorf("query DeleteAuthorExecLastID: %w", err) + } + return result.LastInsertId() +} + +const deleteAuthorExecResult = `-- name: DeleteAuthorExecResult :execresult +DELETE FROM authors +WHERE id = $1 +` + +func (q *Queries) DeleteAuthorExecResult(ctx context.Context) (sql.Result, error) { + result, err := q.db.ExecContext(ctx, deleteAuthorExecResult) + if err != nil { + err = fmt.Errorf("query DeleteAuthorExecResult: %w", err) + } + return result, err +} + +const deleteAuthorExecRows = `-- name: DeleteAuthorExecRows :execrows +DELETE FROM authors +WHERE id = $1 +` + +func (q *Queries) DeleteAuthorExecRows(ctx context.Context) (int64, error) { + result, err := q.db.ExecContext(ctx, deleteAuthorExecRows) + if err != nil { + return 0, fmt.Errorf("query DeleteAuthorExecRows: %w", err) + } + return result.RowsAffected() +} + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, bio FROM authors +WHERE id = $1 LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + if err != nil { + err = fmt.Errorf("query GetAuthor: %w", err) + } + return i, err +} + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name, bio FROM authors +ORDER BY name +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, fmt.Errorf("query ListAuthors: %w", err) + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); err != nil { + return nil, fmt.Errorf("query ListAuthors: %w", err) + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, fmt.Errorf("query ListAuthors: %w", err) + } + if err := rows.Err(); err != nil { + return nil, fmt.Errorf("query ListAuthors: %w", err) + } + return items, nil +} diff --git a/internal/endtoend/testdata/wrap_errors/mysql/query.sql b/internal/endtoend/testdata/wrap_errors/mysql/query.sql new file mode 100644 index 0000000..3f9971d --- /dev/null +++ b/internal/endtoend/testdata/wrap_errors/mysql/query.sql @@ -0,0 +1,30 @@ +-- name: GetAuthor :one +SELECT * FROM authors +WHERE id = $1 LIMIT 1; + +-- name: ListAuthors :many +SELECT * FROM authors +ORDER BY name; + +-- name: CreateAuthor :execlastid +INSERT INTO authors ( + name, bio +) VALUES ( + $1, $2 +); + +-- name: DeleteAuthorExec :exec +DELETE FROM authors +WHERE id = $1; + +-- name: DeleteAuthorExecRows :execrows +DELETE FROM authors +WHERE id = $1; + +-- name: DeleteAuthorExecLastID :execlastid +DELETE FROM authors +WHERE id = $1; + +-- name: DeleteAuthorExecResult :execresult +DELETE FROM authors +WHERE id = $1; diff --git a/internal/endtoend/testdata/wrap_errors/mysql/schema.sql b/internal/endtoend/testdata/wrap_errors/mysql/schema.sql new file mode 100644 index 0000000..8d65cdb --- /dev/null +++ b/internal/endtoend/testdata/wrap_errors/mysql/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE authors ( + id BIGINT PRIMARY KEY, + name text NOT NULL, + bio text +); diff --git a/internal/endtoend/testdata/wrap_errors/mysql/sqlc.yaml b/internal/endtoend/testdata/wrap_errors/mysql/sqlc.yaml new file mode 100644 index 0000000..5b3b1dd --- /dev/null +++ b/internal/endtoend/testdata/wrap_errors/mysql/sqlc.yaml @@ -0,0 +1,10 @@ +version: 2 +sql: + - schema: "schema.sql" + queries: "query.sql" + engine: "mysql" + gen: + go: + package: "authors" + out: "db" + wrap_errors: true diff --git a/internal/endtoend/testdata/wrap_errors/postgresql/pgx/db/db.go b/internal/endtoend/testdata/wrap_errors/postgresql/pgx/db/db.go new file mode 100644 index 0000000..fc39dda --- /dev/null +++ b/internal/endtoend/testdata/wrap_errors/postgresql/pgx/db/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package authors + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...any) (pgconn.CommandTag, error) + Query(context.Context, string, ...any) (pgx.Rows, error) + QueryRow(context.Context, string, ...any) 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/wrap_errors/postgresql/pgx/db/models.go b/internal/endtoend/testdata/wrap_errors/postgresql/pgx/db/models.go new file mode 100644 index 0000000..d3f6eaa --- /dev/null +++ b/internal/endtoend/testdata/wrap_errors/postgresql/pgx/db/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package authors + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Author struct { + ID int64 + Name string + Bio pgtype.Text +} diff --git a/internal/endtoend/testdata/wrap_errors/postgresql/pgx/db/query.sql.go b/internal/endtoend/testdata/wrap_errors/postgresql/pgx/db/query.sql.go new file mode 100644 index 0000000..e11566e --- /dev/null +++ b/internal/endtoend/testdata/wrap_errors/postgresql/pgx/db/query.sql.go @@ -0,0 +1,122 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package authors + +import ( + "context" + "fmt" + + "github.com/jackc/pgx/v5/pgconn" + "github.com/jackc/pgx/v5/pgtype" +) + +const createAuthor = `-- name: CreateAuthor :one +INSERT INTO authors ( + name, bio +) VALUES ( + $1, $2 +) +RETURNING id, name, bio +` + +type CreateAuthorParams struct { + Name string + Bio pgtype.Text +} + +func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (Author, error) { + row := q.db.QueryRow(ctx, createAuthor, arg.Name, arg.Bio) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + if err != nil { + err = fmt.Errorf("query CreateAuthor: %w", err) + } + return i, err +} + +const deleteAuthorExec = `-- name: DeleteAuthorExec :exec +DELETE FROM authors +WHERE id = $1 +` + +func (q *Queries) DeleteAuthorExec(ctx context.Context, id int64) error { + _, err := q.db.Exec(ctx, deleteAuthorExec, id) + if err != nil { + return fmt.Errorf("query DeleteAuthorExec: %w", err) + } + return nil +} + +const deleteAuthorExecLastID = `-- name: DeleteAuthorExecLastID :execlastid +DELETE FROM authors +WHERE id = $1 +` + +const deleteAuthorExecResult = `-- name: DeleteAuthorExecResult :execresult +DELETE FROM authors +WHERE id = $1 +` + +func (q *Queries) DeleteAuthorExecResult(ctx context.Context, id int64) (pgconn.CommandTag, error) { + result, err := q.db.Exec(ctx, deleteAuthorExecResult, id) + if err != nil { + err = fmt.Errorf("query DeleteAuthorExecResult: %w", err) + } + return result, err +} + +const deleteAuthorExecRows = `-- name: DeleteAuthorExecRows :execrows +DELETE FROM authors +WHERE id = $1 +` + +func (q *Queries) DeleteAuthorExecRows(ctx context.Context, id int64) (int64, error) { + result, err := q.db.Exec(ctx, deleteAuthorExecRows, id) + if err != nil { + return 0, fmt.Errorf("query DeleteAuthorExecRows: %w", err) + } + return result.RowsAffected(), nil +} + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, bio FROM authors +WHERE id = $1 LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRow(ctx, getAuthor, id) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + if err != nil { + err = fmt.Errorf("query GetAuthor: %w", err) + } + return i, err +} + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name, bio FROM authors +ORDER BY name +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.Query(ctx, listAuthors) + if err != nil { + return nil, fmt.Errorf("query ListAuthors: %w", err) + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); err != nil { + return nil, fmt.Errorf("query ListAuthors: %w", err) + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, fmt.Errorf("query ListAuthors: %w", err) + } + return items, nil +} diff --git a/internal/endtoend/testdata/wrap_errors/postgresql/pgx/query.sql b/internal/endtoend/testdata/wrap_errors/postgresql/pgx/query.sql new file mode 100644 index 0000000..e0310a2 --- /dev/null +++ b/internal/endtoend/testdata/wrap_errors/postgresql/pgx/query.sql @@ -0,0 +1,31 @@ +-- 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: DeleteAuthorExec :exec +DELETE FROM authors +WHERE id = $1; + +-- name: DeleteAuthorExecRows :execrows +DELETE FROM authors +WHERE id = $1; + +-- name: DeleteAuthorExecLastID :execlastid +DELETE FROM authors +WHERE id = $1; + +-- name: DeleteAuthorExecResult :execresult +DELETE FROM authors +WHERE id = $1; diff --git a/internal/endtoend/testdata/wrap_errors/postgresql/pgx/schema.sql b/internal/endtoend/testdata/wrap_errors/postgresql/pgx/schema.sql new file mode 100644 index 0000000..b4fad78 --- /dev/null +++ b/internal/endtoend/testdata/wrap_errors/postgresql/pgx/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/wrap_errors/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/wrap_errors/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000..5a2adcd --- /dev/null +++ b/internal/endtoend/testdata/wrap_errors/postgresql/pgx/sqlc.yaml @@ -0,0 +1,11 @@ +version: 2 +sql: + - schema: "schema.sql" + queries: "query.sql" + engine: "postgresql" + gen: + go: + package: "authors" + sql_package: "pgx/v5" + out: "db" + wrap_errors: true diff --git a/internal/endtoend/testdata/wrap_errors/postgresql/stdlib/db/db.go b/internal/endtoend/testdata/wrap_errors/postgresql/stdlib/db/db.go new file mode 100644 index 0000000..32f660c --- /dev/null +++ b/internal/endtoend/testdata/wrap_errors/postgresql/stdlib/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package authors + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/wrap_errors/postgresql/stdlib/db/models.go b/internal/endtoend/testdata/wrap_errors/postgresql/stdlib/db/models.go new file mode 100644 index 0000000..62bacd8 --- /dev/null +++ b/internal/endtoend/testdata/wrap_errors/postgresql/stdlib/db/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package authors + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/wrap_errors/postgresql/stdlib/db/query.sql.go b/internal/endtoend/testdata/wrap_errors/postgresql/stdlib/db/query.sql.go new file mode 100644 index 0000000..b954a61 --- /dev/null +++ b/internal/endtoend/testdata/wrap_errors/postgresql/stdlib/db/query.sql.go @@ -0,0 +1,131 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package authors + +import ( + "context" + "database/sql" + "fmt" +) + +const createAuthor = `-- name: CreateAuthor :one +INSERT INTO authors ( + name, bio +) VALUES ( + $1, $2 +) +RETURNING id, name, bio +` + +type CreateAuthorParams struct { + Name string + Bio sql.NullString +} + +func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (Author, error) { + row := q.db.QueryRowContext(ctx, createAuthor, arg.Name, arg.Bio) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + if err != nil { + err = fmt.Errorf("query CreateAuthor: %w", err) + } + return i, err +} + +const deleteAuthorExec = `-- name: DeleteAuthorExec :exec +DELETE FROM authors +WHERE id = $1 +` + +func (q *Queries) DeleteAuthorExec(ctx context.Context, id int64) error { + _, err := q.db.ExecContext(ctx, deleteAuthorExec, id) + if err != nil { + err = fmt.Errorf("query DeleteAuthorExec: %w", err) + } + return err +} + +const deleteAuthorExecLastID = `-- name: DeleteAuthorExecLastID :execlastid +DELETE FROM authors +WHERE id = $1 +` + +func (q *Queries) DeleteAuthorExecLastID(ctx context.Context, id int64) (int64, error) { + result, err := q.db.ExecContext(ctx, deleteAuthorExecLastID, id) + if err != nil { + return 0, fmt.Errorf("query DeleteAuthorExecLastID: %w", err) + } + return result.LastInsertId() +} + +const deleteAuthorExecResult = `-- name: DeleteAuthorExecResult :execresult +DELETE FROM authors +WHERE id = $1 +` + +func (q *Queries) DeleteAuthorExecResult(ctx context.Context, id int64) (sql.Result, error) { + result, err := q.db.ExecContext(ctx, deleteAuthorExecResult, id) + if err != nil { + err = fmt.Errorf("query DeleteAuthorExecResult: %w", err) + } + return result, err +} + +const deleteAuthorExecRows = `-- name: DeleteAuthorExecRows :execrows +DELETE FROM authors +WHERE id = $1 +` + +func (q *Queries) DeleteAuthorExecRows(ctx context.Context, id int64) (int64, error) { + result, err := q.db.ExecContext(ctx, deleteAuthorExecRows, id) + if err != nil { + return 0, fmt.Errorf("query DeleteAuthorExecRows: %w", err) + } + return result.RowsAffected() +} + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, bio FROM authors +WHERE id = $1 LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + if err != nil { + err = fmt.Errorf("query GetAuthor: %w", err) + } + return i, err +} + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name, bio FROM authors +ORDER BY name +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, fmt.Errorf("query ListAuthors: %w", err) + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); err != nil { + return nil, fmt.Errorf("query ListAuthors: %w", err) + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, fmt.Errorf("query ListAuthors: %w", err) + } + if err := rows.Err(); err != nil { + return nil, fmt.Errorf("query ListAuthors: %w", err) + } + return items, nil +} diff --git a/internal/endtoend/testdata/wrap_errors/postgresql/stdlib/query.sql b/internal/endtoend/testdata/wrap_errors/postgresql/stdlib/query.sql new file mode 100644 index 0000000..e0310a2 --- /dev/null +++ b/internal/endtoend/testdata/wrap_errors/postgresql/stdlib/query.sql @@ -0,0 +1,31 @@ +-- 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: DeleteAuthorExec :exec +DELETE FROM authors +WHERE id = $1; + +-- name: DeleteAuthorExecRows :execrows +DELETE FROM authors +WHERE id = $1; + +-- name: DeleteAuthorExecLastID :execlastid +DELETE FROM authors +WHERE id = $1; + +-- name: DeleteAuthorExecResult :execresult +DELETE FROM authors +WHERE id = $1; diff --git a/internal/endtoend/testdata/wrap_errors/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/wrap_errors/postgresql/stdlib/schema.sql new file mode 100644 index 0000000..b4fad78 --- /dev/null +++ b/internal/endtoend/testdata/wrap_errors/postgresql/stdlib/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/wrap_errors/postgresql/stdlib/sqlc.yaml b/internal/endtoend/testdata/wrap_errors/postgresql/stdlib/sqlc.yaml new file mode 100644 index 0000000..6827bf7 --- /dev/null +++ b/internal/endtoend/testdata/wrap_errors/postgresql/stdlib/sqlc.yaml @@ -0,0 +1,10 @@ +version: 2 +sql: + - schema: "schema.sql" + queries: "query.sql" + engine: "postgresql" + gen: + go: + package: "authors" + out: "db" + wrap_errors: true diff --git a/internal/endtoend/testdata/wrap_errors/sqlite/db/db.go b/internal/endtoend/testdata/wrap_errors/sqlite/db/db.go new file mode 100644 index 0000000..32f660c --- /dev/null +++ b/internal/endtoend/testdata/wrap_errors/sqlite/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package authors + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/wrap_errors/sqlite/db/models.go b/internal/endtoend/testdata/wrap_errors/sqlite/db/models.go new file mode 100644 index 0000000..62bacd8 --- /dev/null +++ b/internal/endtoend/testdata/wrap_errors/sqlite/db/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package authors + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/internal/endtoend/testdata/wrap_errors/sqlite/db/query.sql.go b/internal/endtoend/testdata/wrap_errors/sqlite/db/query.sql.go new file mode 100644 index 0000000..11b72d8 --- /dev/null +++ b/internal/endtoend/testdata/wrap_errors/sqlite/db/query.sql.go @@ -0,0 +1,128 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package authors + +import ( + "context" + "database/sql" + "fmt" +) + +const createAuthor = `-- name: CreateAuthor :execlastid +INSERT INTO authors ( + name, bio +) VALUES ( + ?1, ?2 +) +` + +type CreateAuthorParams struct { + Name string + Bio sql.NullString +} + +func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (int64, error) { + result, err := q.db.ExecContext(ctx, createAuthor, arg.Name, arg.Bio) + if err != nil { + return 0, fmt.Errorf("query CreateAuthor: %w", err) + } + return result.LastInsertId() +} + +const deleteAuthorExec = `-- name: DeleteAuthorExec :exec +DELETE FROM authors +WHERE id = ?1 +` + +func (q *Queries) DeleteAuthorExec(ctx context.Context, id int64) error { + _, err := q.db.ExecContext(ctx, deleteAuthorExec, id) + if err != nil { + err = fmt.Errorf("query DeleteAuthorExec: %w", err) + } + return err +} + +const deleteAuthorExecLastID = `-- name: DeleteAuthorExecLastID :execlastid +DELETE FROM authors +WHERE id = ?1 +` + +func (q *Queries) DeleteAuthorExecLastID(ctx context.Context, id int64) (int64, error) { + result, err := q.db.ExecContext(ctx, deleteAuthorExecLastID, id) + if err != nil { + return 0, fmt.Errorf("query DeleteAuthorExecLastID: %w", err) + } + return result.LastInsertId() +} + +const deleteAuthorExecResult = `-- name: DeleteAuthorExecResult :execresult +DELETE FROM authors +WHERE id = ?1 +` + +func (q *Queries) DeleteAuthorExecResult(ctx context.Context, id int64) (sql.Result, error) { + result, err := q.db.ExecContext(ctx, deleteAuthorExecResult, id) + if err != nil { + err = fmt.Errorf("query DeleteAuthorExecResult: %w", err) + } + return result, err +} + +const deleteAuthorExecRows = `-- name: DeleteAuthorExecRows :execrows +DELETE FROM authors +WHERE id = ?1 +` + +func (q *Queries) DeleteAuthorExecRows(ctx context.Context, id int64) (int64, error) { + result, err := q.db.ExecContext(ctx, deleteAuthorExecRows, id) + if err != nil { + return 0, fmt.Errorf("query DeleteAuthorExecRows: %w", err) + } + return result.RowsAffected() +} + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, bio FROM authors +WHERE id = ?1 LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + if err != nil { + err = fmt.Errorf("query GetAuthor: %w", err) + } + return i, err +} + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name, bio FROM authors +ORDER BY name +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, fmt.Errorf("query ListAuthors: %w", err) + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); err != nil { + return nil, fmt.Errorf("query ListAuthors: %w", err) + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, fmt.Errorf("query ListAuthors: %w", err) + } + if err := rows.Err(); err != nil { + return nil, fmt.Errorf("query ListAuthors: %w", err) + } + return items, nil +} diff --git a/internal/endtoend/testdata/wrap_errors/sqlite/query.sql b/internal/endtoend/testdata/wrap_errors/sqlite/query.sql new file mode 100644 index 0000000..2db6403 --- /dev/null +++ b/internal/endtoend/testdata/wrap_errors/sqlite/query.sql @@ -0,0 +1,30 @@ +-- name: GetAuthor :one +SELECT * FROM authors +WHERE id = ?1 LIMIT 1; + +-- name: ListAuthors :many +SELECT * FROM authors +ORDER BY name; + +-- name: CreateAuthor :execlastid +INSERT INTO authors ( + name, bio +) VALUES ( + ?1, ?2 +); + +-- name: DeleteAuthorExec :exec +DELETE FROM authors +WHERE id = ?1; + +-- name: DeleteAuthorExecRows :execrows +DELETE FROM authors +WHERE id = ?1; + +-- name: DeleteAuthorExecLastID :execlastid +DELETE FROM authors +WHERE id = ?1; + +-- name: DeleteAuthorExecResult :execresult +DELETE FROM authors +WHERE id = ?1; diff --git a/internal/endtoend/testdata/wrap_errors/sqlite/schema.sql b/internal/endtoend/testdata/wrap_errors/sqlite/schema.sql new file mode 100644 index 0000000..8d65cdb --- /dev/null +++ b/internal/endtoend/testdata/wrap_errors/sqlite/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE authors ( + id BIGINT PRIMARY KEY, + name text NOT NULL, + bio text +); diff --git a/internal/endtoend/testdata/wrap_errors/sqlite/sqlc.yaml b/internal/endtoend/testdata/wrap_errors/sqlite/sqlc.yaml new file mode 100644 index 0000000..de72629 --- /dev/null +++ b/internal/endtoend/testdata/wrap_errors/sqlite/sqlc.yaml @@ -0,0 +1,10 @@ +version: 2 +sql: + - schema: "schema.sql" + queries: "query.sql" + engine: "sqlite" + gen: + go: + package: "authors" + out: "db" + wrap_errors: true diff --git a/internal/endtoend/testdata/yaml_overrides/go/db.go b/internal/endtoend/testdata/yaml_overrides/go/db.go new file mode 100644 index 0000000..3e4ebb9 --- /dev/null +++ b/internal/endtoend/testdata/yaml_overrides/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...any) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *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/yaml_overrides/go/models.go b/internal/endtoend/testdata/yaml_overrides/go/models.go new file mode 100644 index 0000000..94d1878 --- /dev/null +++ b/internal/endtoend/testdata/yaml_overrides/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package override + +import ( + "github.com/lib/pq" + "github.com/sqlc-dev/sqlc-testdata/pkg" +) + +type Foo struct { + Other string + Total int64 + Tags []string + ByteSeq []byte + Retyped pkg.CustomType + Langs pq.StringArray +} diff --git a/internal/endtoend/testdata/yaml_overrides/go/query.sql.go b/internal/endtoend/testdata/yaml_overrides/go/query.sql.go new file mode 100644 index 0000000..0a94a43 --- /dev/null +++ b/internal/endtoend/testdata/yaml_overrides/go/query.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package override + +import ( + "context" +) + +const test = `-- name: Test :one +SELECT 1 +` + +func (q *Queries) Test(ctx context.Context) (int32, error) { + row := q.db.QueryRowContext(ctx, test) + var column_1 int32 + err := row.Scan(&column_1) + return column_1, err +} diff --git a/internal/endtoend/testdata/yaml_overrides/sql/query.sql b/internal/endtoend/testdata/yaml_overrides/sql/query.sql new file mode 100644 index 0000000..9da604b --- /dev/null +++ b/internal/endtoend/testdata/yaml_overrides/sql/query.sql @@ -0,0 +1,2 @@ +-- name: Test :one +SELECT 1; diff --git a/internal/endtoend/testdata/yaml_overrides/sql/schema.sql b/internal/endtoend/testdata/yaml_overrides/sql/schema.sql new file mode 100644 index 0000000..fc3a13e --- /dev/null +++ b/internal/endtoend/testdata/yaml_overrides/sql/schema.sql @@ -0,0 +1,8 @@ +CREATE TABLE foo ( + other text NOT NULL, + total bigint NOT NULL, + tags text[] NOT NULL, + byte_seq bytea NOT NULL, + retyped text NOT NULL, + langs text[] +); diff --git a/internal/endtoend/testdata/yaml_overrides/sqlc.yaml b/internal/endtoend/testdata/yaml_overrides/sqlc.yaml new file mode 100644 index 0000000..3bc1c1f --- /dev/null +++ b/internal/endtoend/testdata/yaml_overrides/sqlc.yaml @@ -0,0 +1,11 @@ +version: 1 +packages: + - path: "go" + name: "override" + schema: "sql/" + queries: "sql/" + overrides: + - go_type: "github.com/sqlc-dev/sqlc-testdata/pkg.CustomType" + column: "foo.retyped" + - go_type: "github.com/lib/pq.StringArray" + column: "foo.langs" diff --git a/internal/endtoend/vet_test.go b/internal/endtoend/vet_test.go new file mode 100644 index 0000000..011c032 --- /dev/null +++ b/internal/endtoend/vet_test.go @@ -0,0 +1,82 @@ +//go:build examples + +package main + +import ( + "bytes" + "context" + "fmt" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/sqlc-dev/sqlc/internal/cmd" + "github.com/sqlc-dev/sqlc/internal/sqltest" + "github.com/sqlc-dev/sqlc/internal/sqltest/local" +) + +func findSchema(t *testing.T, path string) (string, bool) { + schemaFile := filepath.Join(path, "schema.sql") + if _, err := os.Stat(schemaFile); !os.IsNotExist(err) { + return schemaFile, true + } + schemaDir := filepath.Join(path, "schema") + if _, err := os.Stat(schemaDir); !os.IsNotExist(err) { + return schemaDir, true + } + return "", false +} + +func TestExamplesVet(t *testing.T) { + t.Parallel() + ctx := context.Background() + + examples, err := filepath.Abs(filepath.Join("..", "..", "examples")) + if err != nil { + t.Fatal(err) + } + + files, err := os.ReadDir(examples) + if err != nil { + t.Fatal(err) + } + + for _, replay := range files { + if !replay.IsDir() { + continue + } + tc := replay.Name() + t.Run(tc, func(t *testing.T) { + t.Parallel() + path := filepath.Join(examples, tc) + + if tc != "kotlin" && tc != "python" { + if s, found := findSchema(t, filepath.Join(path, "sqlite")); found { + dsn := fmt.Sprintf("file:%s?mode=memory&cache=shared", tc) + db, cleanup := sqltest.CreateSQLiteDatabase(t, dsn, []string{s}) + defer db.Close() + defer cleanup() + } + if s, found := findSchema(t, filepath.Join(path, "mysql")); found { + uri := local.MySQL(t, []string{s}) + os.Setenv(fmt.Sprintf("VET_TEST_EXAMPLES_MYSQL_%s", strings.ToUpper(tc)), uri) + } + if s, found := findSchema(t, filepath.Join(path, "postgresql")); found { + uri := local.PostgreSQL(t, []string{s}) + os.Setenv(fmt.Sprintf("VET_TEST_EXAMPLES_POSTGRES_%s", strings.ToUpper(tc)), uri) + } + } + + var stderr bytes.Buffer + opts := &cmd.Options{ + Stderr: &stderr, + Env: cmd.Env{}, + } + err := cmd.Vet(ctx, path, "", opts) + if err != nil { + t.Fatalf("sqlc vet failed: %s %s", err, stderr.String()) + } + }) + } +} diff --git a/internal/engine/clickhouse/catalog.go b/internal/engine/clickhouse/catalog.go new file mode 100644 index 0000000..fb0511f --- /dev/null +++ b/internal/engine/clickhouse/catalog.go @@ -0,0 +1,16 @@ +package clickhouse + +import ( + "github.com/sqlc-dev/sqlc/internal/sql/catalog" +) + +func NewCatalog() *catalog.Catalog { + def := "default" // ClickHouse default database + return &catalog.Catalog{ + DefaultSchema: def, + Schemas: []*catalog.Schema{ + defaultSchema(def), + }, + Extensions: map[string]struct{}{}, + } +} diff --git a/internal/engine/clickhouse/convert.go b/internal/engine/clickhouse/convert.go new file mode 100644 index 0000000..f1505c0 --- /dev/null +++ b/internal/engine/clickhouse/convert.go @@ -0,0 +1,1398 @@ +package clickhouse + +import ( + "fmt" + "sort" + "strconv" + "strings" + + chast "github.com/sqlc-dev/doubleclick/ast" + "github.com/sqlc-dev/doubleclick/token" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +type cc struct { + paramCount int +} + +// pos is a node's byte offset in the query. doubleclick counts positions +// from one; the rest of sqlc counts from zero. +func pos(n interface{ Pos() token.Position }) int { + if n == nil { + return 0 + } + if off := n.Pos().Offset; off > 0 { + return off - 1 + } + return 0 +} + +func (c *cc) convert(node chast.Node) ast.Node { + switch n := node.(type) { + case *chast.SelectWithUnionQuery: + return c.convertSelectWithUnionQuery(n) + case *chast.SelectQuery: + return c.convertSelectQuery(n) + case *chast.InsertQuery: + return c.convertInsertQuery(n) + case *chast.CreateQuery: + return c.convertCreateQuery(n) + case *chast.UpdateQuery: + return c.convertUpdateQuery(n) + case *chast.DeleteQuery: + return c.convertDeleteQuery(n) + case *chast.DropQuery: + return c.convertDropQuery(n) + case *chast.AlterQuery: + return c.convertAlterQuery(n) + case *chast.TruncateQuery: + return c.convertTruncateQuery(n) + default: + return todo(n) + } +} + +func (c *cc) convertSelectWithUnionQuery(n *chast.SelectWithUnionQuery) ast.Node { + if len(n.Selects) == 0 { + return &ast.TODO{} + } + + // Single select without union + if len(n.Selects) == 1 { + return c.convert(n.Selects[0]) + } + + // Build a chain of SelectStmt with UNION operations + var result *ast.SelectStmt + for i, sel := range n.Selects { + stmt, ok := c.convert(sel).(*ast.SelectStmt) + if !ok { + continue + } + if i == 0 { + result = stmt + } else { + unionMode := ast.Union + if i-1 < len(n.UnionModes) { + switch strings.ToUpper(n.UnionModes[i-1]) { + case "ALL": + unionMode = ast.Union + case "DISTINCT": + unionMode = ast.Union + } + } + result = &ast.SelectStmt{ + Op: unionMode, + All: n.UnionAll || (i-1 < len(n.UnionModes) && strings.ToUpper(n.UnionModes[i-1]) == "ALL"), + Larg: result, + Rarg: stmt, + } + } + } + return result +} + +func (c *cc) convertSelectQuery(n *chast.SelectQuery) *ast.SelectStmt { + stmt := &ast.SelectStmt{} + + // Convert target list (SELECT columns) + if len(n.Columns) > 0 { + stmt.TargetList = &ast.List{} + for _, col := range n.Columns { + target := c.convertToResTarget(col) + if target != nil { + stmt.TargetList.Items = append(stmt.TargetList.Items, target) + } + } + } + + // Convert FROM clause + if n.From != nil { + stmt.FromClause = c.convertTablesInSelectQuery(n.From) + } + + // Convert WHERE clause + if n.Where != nil { + stmt.WhereClause = c.convertExpr(n.Where) + } + + // Convert GROUP BY clause + if len(n.GroupBy) > 0 { + stmt.GroupClause = &ast.List{} + for _, expr := range n.GroupBy { + stmt.GroupClause.Items = append(stmt.GroupClause.Items, c.convertExpr(expr)) + } + } + + // Convert HAVING clause + if n.Having != nil { + stmt.HavingClause = c.convertExpr(n.Having) + } + + // Convert ORDER BY clause + if len(n.OrderBy) > 0 { + stmt.SortClause = &ast.List{} + for _, orderBy := range n.OrderBy { + stmt.SortClause.Items = append(stmt.SortClause.Items, c.convertOrderByElement(orderBy)) + } + } + + // Convert LIMIT clause + if n.Limit != nil { + stmt.LimitCount = c.convertExpr(n.Limit) + } + + // Convert OFFSET clause + if n.Offset != nil { + stmt.LimitOffset = c.convertExpr(n.Offset) + } + + // Convert DISTINCT clause + if n.Distinct { + stmt.DistinctClause = &ast.List{} + } + + // Convert DISTINCT ON clause + if len(n.DistinctOn) > 0 { + stmt.DistinctClause = &ast.List{} + for _, expr := range n.DistinctOn { + stmt.DistinctClause.Items = append(stmt.DistinctClause.Items, c.convertExpr(expr)) + } + } + + // Convert WITH clause (CTEs) + if len(n.With) > 0 { + stmt.WithClause = &ast.WithClause{ + Ctes: &ast.List{}, + } + for _, cte := range n.With { + var name string + var query chast.Expression + switch w := cte.(type) { + case *chast.WithElement: + // "name AS (SELECT ...)" or a scalar "(expr) AS name". + name, query = w.Name, w.Query + case *chast.AliasedExpr: + name, query = w.Alias, w.Expr + default: + continue + } + cteNode := &ast.CommonTableExpr{Ctename: &name} + if subq, ok := query.(*chast.Subquery); ok { + cteNode.Ctequery = c.convert(subq.Query) + } else { + cteNode.Ctequery = c.convertExpr(query) + } + stmt.WithClause.Ctes.Items = append(stmt.WithClause.Ctes.Items, cteNode) + } + } + + return stmt +} + +func (c *cc) convertToResTarget(expr chast.Expression) *ast.ResTarget { + res := &ast.ResTarget{ + Location: pos(expr), + } + + switch e := expr.(type) { + case *chast.Asterisk: + if e.Table != "" { + // table.* + res.Val = &ast.ColumnRef{ + Fields: &ast.List{ + Items: []ast.Node{ + NewIdentifier(e.Table), + &ast.A_Star{}, + }, + }, + } + } else { + // Just * + res.Val = &ast.ColumnRef{ + Fields: &ast.List{ + Items: []ast.Node{&ast.A_Star{}}, + }, + } + } + return res + case *chast.AliasedExpr: + res.Name = &e.Alias + res.Val = c.convertExpr(e.Expr) + return res + case *chast.Identifier: + if e.Alias != "" { + res.Name = &e.Alias + } + res.Val = c.convertIdentifier(e) + return res + } + + res.Val = c.convertExpr(expr) + if alias := exprAlias(expr); alias != "" { + res.Name = &alias + } else if name := columnName(expr); name != "" { + // ClickHouse names an unaliased expression column after the + // expression itself, written in its canonical function form. + res.Name = &name + } + return res +} + +// exprAlias returns the alias the parser attached to an expression, for +// the node kinds that carry one directly. +func exprAlias(expr chast.Expression) string { + switch e := expr.(type) { + case *chast.AliasedExpr: + return e.Alias + case *chast.Identifier: + return e.Alias + case *chast.FunctionCall: + return e.Alias + case *chast.CaseExpr: + return e.Alias + case *chast.CastExpr: + return e.Alias + case *chast.LikeExpr: + return e.Alias + case *chast.ExtractExpr: + return e.Alias + case *chast.Subquery: + return e.Alias + } + return "" +} + +// binaryFunctions are the function names ClickHouse gives its operators when +// it names a column after an expression. +var binaryFunctions = map[string]string{ + "+": "plus", "-": "minus", "*": "multiply", "/": "divide", "%": "modulo", + "=": "equals", "==": "equals", "!=": "notEquals", "<>": "notEquals", + "<": "less", ">": "greater", "<=": "lessOrEquals", ">=": "greaterOrEquals", + "AND": "and", "OR": "or", "||": "concat", +} + +// columnName writes an expression the way ClickHouse names a result column +// that has no alias: a function call with its arguments, an operator as the +// function it stands for, an identifier or literal as written. It returns "" +// for an expression it cannot write, which then keeps sqlc's own name. +func columnName(expr chast.Expression) string { + switch e := expr.(type) { + case *chast.Identifier: + return e.Name() + case *chast.Literal: + return literalText(e) + case *chast.FunctionCall: + if e.Over != nil || e.Filter != nil || e.Distinct { + return "" + } + var params, args []string + for _, p := range e.Parameters { + s := columnName(p) + if s == "" { + return "" + } + params = append(params, s) + } + for _, a := range e.Arguments { + s := columnName(a) + if s == "" { + return "" + } + args = append(args, s) + } + name := e.Name + if len(e.Parameters) > 0 { + name += "(" + strings.Join(params, ", ") + ")" + } + return name + "(" + strings.Join(args, ", ") + ")" + case *chast.BinaryExpr: + fn, ok := binaryFunctions[strings.ToUpper(e.Op)] + if !ok { + return "" + } + left, right := columnName(e.Left), columnName(e.Right) + if left == "" || right == "" { + return "" + } + return fn + "(" + left + ", " + right + ")" + case *chast.UnaryExpr: + operand := columnName(e.Operand) + if operand == "" { + return "" + } + switch strings.ToUpper(e.Op) { + case "-": + return "negate(" + operand + ")" + case "NOT": + return "not(" + operand + ")" + } + return "" + case *chast.IsNullExpr: + arg := columnName(e.Expr) + if arg == "" { + return "" + } + if e.Not { + return "isNotNull(" + arg + ")" + } + return "isNull(" + arg + ")" + case *chast.TernaryExpr: + cond, then, els := columnName(e.Condition), columnName(e.Then), columnName(e.Else) + if cond == "" || then == "" || els == "" { + return "" + } + return "if(" + cond + ", " + then + ", " + els + ")" + } + return "" +} + +// literalText writes a literal as ClickHouse prints it in a column name. +func literalText(l *chast.Literal) string { + switch l.Type { + case chast.LiteralString: + return quoteString(fmt.Sprint(l.Value)) + case chast.LiteralNull: + return "NULL" + case chast.LiteralBoolean: + return fmt.Sprint(l.Value) + case chast.LiteralInteger, chast.LiteralFloat: + if l.Source != "" { + return l.Source + } + return fmt.Sprint(l.Value) + } + return "" +} + +func quoteString(s string) string { + s = strings.ReplaceAll(s, `\`, `\\`) + s = strings.ReplaceAll(s, "'", `\'`) + return "'" + s + "'" +} + +func (c *cc) convertTablesInSelectQuery(n *chast.TablesInSelectQuery) *ast.List { + if n == nil || len(n.Tables) == 0 { + return nil + } + + result := &ast.List{} + + for i, elem := range n.Tables { + if elem.Table != nil { + tableExpr := c.convertTableExpression(elem.Table) + if i == 0 { + result.Items = append(result.Items, tableExpr) + } else if elem.Join != nil { + // This element has a join + joinExpr := c.convertTableJoin(elem.Join, result.Items[len(result.Items)-1], tableExpr) + result.Items[len(result.Items)-1] = joinExpr + } else { + result.Items = append(result.Items, tableExpr) + } + } else if elem.Join != nil && len(result.Items) > 0 { + // Join without table (should not happen normally) + continue + } + } + + return result +} + +func (c *cc) convertTableExpression(n *chast.TableExpression) ast.Node { + var result ast.Node + + switch t := n.Table.(type) { + case *chast.TableIdentifier: + rv := parseTableIdentifierToRangeVar(t) + if n.Alias != "" { + alias := n.Alias + rv.Alias = &ast.Alias{Aliasname: &alias} + } + result = rv + case *chast.Subquery: + subselect := &ast.RangeSubselect{ + Subquery: c.convert(t.Query), + } + alias := n.Alias + if alias == "" && t.Alias != "" { + alias = t.Alias + } + if alias != "" { + subselect.Alias = &ast.Alias{Aliasname: &alias} + } + result = subselect + case *chast.FunctionCall: + // Table function like file(), url(), etc. + rf := &ast.RangeFunction{ + Functions: &ast.List{ + Items: []ast.Node{c.convertFunctionCall(t)}, + }, + } + if n.Alias != "" { + alias := n.Alias + rf.Alias = &ast.Alias{Aliasname: &alias} + } + result = rf + default: + result = &ast.TODO{} + } + + return result +} + +func (c *cc) convertTableJoin(n *chast.TableJoin, left, right ast.Node) *ast.JoinExpr { + join := &ast.JoinExpr{ + Larg: left, + Rarg: right, + } + + // Convert join type + switch n.Type { + case chast.JoinInner: + join.Jointype = ast.JoinTypeInner + case chast.JoinLeft: + join.Jointype = ast.JoinTypeLeft + case chast.JoinRight: + join.Jointype = ast.JoinTypeRight + case chast.JoinFull: + join.Jointype = ast.JoinTypeFull + case chast.JoinCross: + join.Jointype = ast.JoinTypeInner + join.IsNatural = false + default: + join.Jointype = ast.JoinTypeInner + } + + // Convert ON clause + if n.On != nil { + join.Quals = c.convertExpr(n.On) + } + + // Convert USING clause + if len(n.Using) > 0 { + join.UsingClause = &ast.List{} + for _, u := range n.Using { + if id, ok := u.(*chast.Identifier); ok { + join.UsingClause.Items = append(join.UsingClause.Items, NewIdentifier(id.Name())) + } + } + } + + return join +} + +func (c *cc) convertExpr(expr chast.Expression) ast.Node { + if expr == nil { + return nil + } + + switch e := expr.(type) { + case *chast.Identifier: + return c.convertIdentifier(e) + case *chast.Literal: + return c.convertLiteral(e) + case *chast.BinaryExpr: + return c.convertBinaryExpr(e) + case *chast.FunctionCall: + switch strings.ToLower(e.Name) { + case "coalesce", "ifnull": + // COALESCE is null only when every argument is, which a seeded + // function signature cannot say. + args := &ast.List{} + for _, arg := range e.Arguments { + args.Items = append(args.Items, c.convertExpr(arg)) + } + return &ast.CoalesceExpr{Args: args, Location: pos(e)} + } + return c.convertFunctionCall(e) + case *chast.ExistsExpr: + return &ast.SubLink{ + SubLinkType: ast.EXISTS_SUBLINK, + Subselect: c.convert(e.Query), + Location: pos(e), + } + case *chast.AliasedExpr: + return c.convertExpr(e.Expr) + case *chast.Parameter: + return c.convertParameter(e) + case *chast.Asterisk: + return c.convertAsterisk(e) + case *chast.CaseExpr: + return c.convertCaseExpr(e) + case *chast.CastExpr: + return c.convertCastExpr(e) + case *chast.BetweenExpr: + return c.convertBetweenExpr(e) + case *chast.InExpr: + return c.convertInExpr(e) + case *chast.IsNullExpr: + return c.convertIsNullExpr(e) + case *chast.LikeExpr: + return c.convertLikeExpr(e) + case *chast.Subquery: + return c.convertSubquery(e) + case *chast.ArrayAccess: + return c.convertArrayAccess(e) + case *chast.UnaryExpr: + return c.convertUnaryExpr(e) + case *chast.Lambda: + // Lambda expressions are ClickHouse-specific, return as-is for now + return &ast.TODO{} + default: + return &ast.TODO{} + } +} + +func (c *cc) convertIdentifier(n *chast.Identifier) *ast.ColumnRef { + fields := &ast.List{} + for _, part := range n.Parts { + fields.Items = append(fields.Items, NewIdentifier(part)) + } + return &ast.ColumnRef{ + Fields: fields, + Location: pos(n), + } +} + +func (c *cc) convertLiteral(n *chast.Literal) *ast.A_Const { + switch n.Type { + case chast.LiteralString: + str := n.Value.(string) + return &ast.A_Const{ + Val: &ast.String{Str: str}, + Location: pos(n), + } + case chast.LiteralInteger: + var ival int64 + switch v := n.Value.(type) { + case int64: + ival = v + case int: + ival = int64(v) + case float64: + ival = int64(v) + case string: + ival, _ = strconv.ParseInt(v, 10, 64) + } + return &ast.A_Const{ + Val: &ast.Integer{Ival: ival}, + Location: pos(n), + } + case chast.LiteralFloat: + var fval float64 + switch v := n.Value.(type) { + case float64: + fval = v + case string: + fval, _ = strconv.ParseFloat(v, 64) + } + str := strconv.FormatFloat(fval, 'f', -1, 64) + return &ast.A_Const{ + Val: &ast.Float{Str: str}, + Location: pos(n), + } + case chast.LiteralBoolean: + // ClickHouse booleans are typically 0/1 + bval := n.Value.(bool) + if bval { + return &ast.A_Const{ + Val: &ast.Integer{Ival: 1}, + Location: pos(n), + } + } + return &ast.A_Const{ + Val: &ast.Integer{Ival: 0}, + Location: pos(n), + } + case chast.LiteralNull: + return &ast.A_Const{ + Val: &ast.Null{}, + Location: pos(n), + } + default: + return &ast.A_Const{ + Location: pos(n), + } + } +} + +func (c *cc) convertBinaryExpr(n *chast.BinaryExpr) ast.Node { + op := strings.ToUpper(n.Op) + + // Handle logical operators + if op == "AND" || op == "OR" { + var boolop ast.BoolExprType + if op == "AND" { + boolop = ast.BoolExprTypeAnd + } else { + boolop = ast.BoolExprTypeOr + } + return &ast.BoolExpr{ + Boolop: boolop, + Args: &ast.List{ + Items: []ast.Node{ + c.convertExpr(n.Left), + c.convertExpr(n.Right), + }, + }, + Location: pos(n), + } + } + + // Handle other operators + return &ast.A_Expr{ + Kind: ast.A_Expr_Kind_OP, + Name: &ast.List{ + Items: []ast.Node{&ast.String{Str: n.Op}}, + }, + Lexpr: c.convertExpr(n.Left), + Rexpr: c.convertExpr(n.Right), + Location: pos(n), + } +} + +func (c *cc) convertFunctionCall(n *chast.FunctionCall) *ast.FuncCall { + fc := &ast.FuncCall{ + Funcname: &ast.List{ + Items: []ast.Node{&ast.String{Str: n.Name}}, + }, + Location: pos(n), + AggDistinct: n.Distinct, + } + + // Convert arguments + if len(n.Arguments) > 0 { + fc.Args = &ast.List{} + for _, arg := range n.Arguments { + fc.Args.Items = append(fc.Args.Items, c.convertExpr(arg)) + } + } + + // Convert window function + if n.Over != nil { + fc.Over = &ast.WindowDef{} + if len(n.Over.PartitionBy) > 0 { + fc.Over.PartitionClause = &ast.List{} + for _, p := range n.Over.PartitionBy { + fc.Over.PartitionClause.Items = append(fc.Over.PartitionClause.Items, c.convertExpr(p)) + } + } + if len(n.Over.OrderBy) > 0 { + fc.Over.OrderClause = &ast.List{} + for _, o := range n.Over.OrderBy { + fc.Over.OrderClause.Items = append(fc.Over.OrderClause.Items, c.convertOrderByElement(o)) + } + } + } + + return fc +} + +func (c *cc) convertParameter(n *chast.Parameter) ast.Node { + c.paramCount++ + ref := &ast.ParamRef{ + Number: c.paramCount, + Name: n.Name, + Location: pos(n), + } + // A parameter written {name:Type} declares its type, which is what a + // cast of a placeholder says. + if n.Type != nil { + spelling := renderDataType(n.Type) + base, _, _ := unwrapTypeString(spelling) + return &ast.TypeCast{ + Arg: ref, + TypeName: &ast.TypeName{Name: base, Spelling: spelling, Canonical: canonicalDataType(n.Type)}, + Location: pos(n), + } + } + return ref +} + +func (c *cc) convertAsterisk(n *chast.Asterisk) *ast.ColumnRef { + fields := &ast.List{} + if n.Table != "" { + fields.Items = append(fields.Items, NewIdentifier(n.Table)) + } + fields.Items = append(fields.Items, &ast.A_Star{}) + return &ast.ColumnRef{ + Fields: fields, + Location: pos(n), + } +} + +func (c *cc) convertCaseExpr(n *chast.CaseExpr) *ast.CaseExpr { + ce := &ast.CaseExpr{ + Location: pos(n), + } + + // Convert test expression (CASE expr WHEN ...) + if n.Operand != nil { + ce.Arg = c.convertExpr(n.Operand) + } + + // Convert WHEN clauses + if len(n.Whens) > 0 { + ce.Args = &ast.List{} + for _, when := range n.Whens { + caseWhen := &ast.CaseWhen{ + Expr: c.convertExpr(when.Condition), + Result: c.convertExpr(when.Result), + } + ce.Args.Items = append(ce.Args.Items, caseWhen) + } + } + + // Convert ELSE clause + if n.Else != nil { + ce.Defresult = c.convertExpr(n.Else) + } + + return ce +} + +func (c *cc) convertCastExpr(n *chast.CastExpr) *ast.TypeCast { + tc := &ast.TypeCast{ + Arg: c.convertExpr(n.Expr), + Location: pos(n), + } + + if n.Type != nil { + // The whole type is handed over as its spelling, arguments and + // nesting included, the way a column's is. + spelling := renderDataType(n.Type) + base, _, _ := unwrapTypeString(spelling) + tc.TypeName = &ast.TypeName{Name: base, Spelling: spelling, Canonical: canonicalDataType(n.Type)} + } + + return tc +} + +func (c *cc) convertBetweenExpr(n *chast.BetweenExpr) *ast.BetweenExpr { + return &ast.BetweenExpr{ + Expr: c.convertExpr(n.Expr), + Left: c.convertExpr(n.Low), + Right: c.convertExpr(n.High), + Not: n.Not, + Location: pos(n), + } +} + +func (c *cc) convertInExpr(n *chast.InExpr) *ast.In { + in := &ast.In{ + Expr: c.convertExpr(n.Expr), + Not: n.Not, + Location: pos(n), + } + + // Convert the list + if len(n.List) > 0 { + in.List = make([]ast.Node, 0, len(n.List)) + for _, item := range n.List { + in.List = append(in.List, c.convertExpr(item)) + } + } + + // Handle subquery + if n.Query != nil { + in.Sel = c.convert(n.Query) + } + + return in +} + +func (c *cc) convertIsNullExpr(n *chast.IsNullExpr) *ast.NullTest { + nullTest := &ast.NullTest{ + Arg: c.convertExpr(n.Expr), + Location: pos(n), + } + if n.Not { + nullTest.Nulltesttype = ast.NullTestTypeIsNotNull + } else { + nullTest.Nulltesttype = ast.NullTestTypeIsNull + } + return nullTest +} + +func (c *cc) convertLikeExpr(n *chast.LikeExpr) *ast.A_Expr { + kind := ast.A_Expr_Kind(0) + opName := "~~" + if n.CaseInsensitive { + opName = "~~*" + } + if n.Not { + opName = "!~~" + if n.CaseInsensitive { + opName = "!~~*" + } + } + + return &ast.A_Expr{ + Kind: kind, + Name: &ast.List{ + Items: []ast.Node{&ast.String{Str: opName}}, + }, + Lexpr: c.convertExpr(n.Expr), + Rexpr: c.convertExpr(n.Pattern), + Location: pos(n), + } +} + +// convertSubquery converts a subquery used as a value: a scalar subquery. +// EXISTS is its own node. +func (c *cc) convertSubquery(n *chast.Subquery) *ast.SubLink { + return &ast.SubLink{ + SubLinkType: ast.EXPR_SUBLINK, + Subselect: c.convert(n.Query), + Location: pos(n), + } +} + +func (c *cc) convertArrayAccess(n *chast.ArrayAccess) *ast.A_Indirection { + return &ast.A_Indirection{ + Arg: c.convertExpr(n.Array), + Indirection: &ast.List{ + Items: []ast.Node{ + &ast.A_Indices{ + Uidx: c.convertExpr(n.Index), + }, + }, + }, + } +} + +func (c *cc) convertUnaryExpr(n *chast.UnaryExpr) ast.Node { + op := strings.ToUpper(n.Op) + + if op == "NOT" { + return &ast.BoolExpr{ + Boolop: ast.BoolExprTypeNot, + Args: &ast.List{ + Items: []ast.Node{c.convertExpr(n.Operand)}, + }, + Location: pos(n), + } + } + + return &ast.A_Expr{ + Kind: ast.A_Expr_Kind_OP, + Name: &ast.List{ + Items: []ast.Node{&ast.String{Str: n.Op}}, + }, + Rexpr: c.convertExpr(n.Operand), + Location: pos(n), + } +} + +func (c *cc) convertOrderByElement(n *chast.OrderByElement) *ast.SortBy { + sortBy := &ast.SortBy{ + Node: c.convertExpr(n.Expression), + Location: pos(n.Expression), + } + + if n.Descending { + sortBy.SortbyDir = ast.SortByDirDesc + } else { + sortBy.SortbyDir = ast.SortByDirAsc + } + + if n.NullsFirst != nil { + if *n.NullsFirst { + sortBy.SortbyNulls = ast.SortByNullsFirst + } else { + sortBy.SortbyNulls = ast.SortByNullsLast + } + } + + return sortBy +} + +func (c *cc) convertInsertQuery(n *chast.InsertQuery) *ast.InsertStmt { + stmt := &ast.InsertStmt{ + Relation: &ast.RangeVar{ + Relname: &n.Table, + }, + } + + if n.Database != "" { + stmt.Relation.Schemaname = &n.Database + } + + // Convert column list + if len(n.Columns) > 0 { + stmt.Cols = &ast.List{} + for _, col := range n.Columns { + name := col.Name() + stmt.Cols.Items = append(stmt.Cols.Items, &ast.ResTarget{ + Name: &name, + }) + } + } + + // Convert SELECT subquery if present + if n.Select != nil { + stmt.SelectStmt = c.convert(n.Select) + } + + // Convert VALUES clause + if len(n.Values) > 0 { + selectStmt := &ast.SelectStmt{ + ValuesLists: &ast.List{}, + } + for _, row := range n.Values { + rowList := &ast.List{} + for _, val := range row { + rowList.Items = append(rowList.Items, c.convertExpr(val)) + } + selectStmt.ValuesLists.Items = append(selectStmt.ValuesLists.Items, rowList) + } + stmt.SelectStmt = selectStmt + } + + return stmt +} + +func (c *cc) convertCreateQuery(n *chast.CreateQuery) ast.Node { + // Handle CREATE DATABASE + if n.CreateDatabase { + return &ast.CreateSchemaStmt{ + Name: &n.Database, + IfNotExists: n.IfNotExists, + } + } + + // Handle CREATE TABLE + if n.Table != "" { + stmt := &ast.CreateTableStmt{ + Name: &ast.TableName{ + Name: identifier(n.Table), + }, + IfNotExists: n.IfNotExists, + } + + if n.Database != "" { + stmt.Name.Schema = identifier(n.Database) + } + + // Convert columns. A Nested column is what ClickHouse stores as + // one array column per element, named n.a, and reports as those. + for _, col := range n.Columns { + if cols, ok := c.convertNestedColumn(col); ok { + stmt.Cols = append(stmt.Cols, cols...) + continue + } + colDef := c.convertColumnDeclaration(col) + stmt.Cols = append(stmt.Cols, colDef) + } + + // Convert AS SELECT + if n.AsSelect != nil { + // This is a CREATE TABLE ... AS SELECT + // The AsSelect field contains the SELECT statement + } + + return stmt + } + + // Handle CREATE VIEW + if n.View != "" { + return &ast.ViewStmt{ + View: &ast.RangeVar{ + Relname: &n.View, + }, + Query: c.convert(n.AsSelect), + Replace: n.OrReplace, + } + } + + return &ast.TODO{} +} + +// convertNestedColumn expands a column declared Nested(a T, b U) into the +// columns n.a Array(T) and n.b Array(U), which is how ClickHouse's +// system.columns lists it and what a query selects. +func (c *cc) convertNestedColumn(n *chast.ColumnDeclaration) ([]*ast.ColumnDef, bool) { + if n.Type == nil || !strings.EqualFold(n.Type.Name, "Nested") { + return nil, false + } + var cols []*ast.ColumnDef + for _, p := range n.Type.Parameters { + pair, ok := p.(*chast.NameTypePair) + if !ok { + continue + } + spelling := "Array(" + renderDataType(pair.Type) + ")" + cols = append(cols, &ast.ColumnDef{ + Colname: identifier(n.Name) + "." + identifier(pair.Name), + TypeName: &ast.TypeName{Name: "array", Spelling: spelling, Canonical: "Array(" + canonicalDataType(pair.Type) + ")"}, + IsArray: true, + IsNotNull: true, + }) + } + return cols, len(cols) > 0 +} + +func (c *cc) convertColumnDeclaration(n *chast.ColumnDeclaration) *ast.ColumnDef { + colDef := &ast.ColumnDef{ + Colname: identifier(n.Name), + IsNotNull: isNotNull(n), + } + + if n.Type != nil { + spelling := renderDataType(n.Type) + base, isArray, nullable := unwrapTypeString(spelling) + // The catalog resolves the base type; the full spelling, with its + // arguments and nesting, is kept for the analysis to report. + colDef.TypeName = &ast.TypeName{Name: base, Spelling: spelling, Canonical: canonicalDataType(n.Type)} + colDef.IsArray = isArray + if nullable { + colDef.IsNotNull = false + } + } + + // Handle PRIMARY KEY constraint + if n.PrimaryKey { + colDef.PrimaryKey = true + } + + // Handle DEFAULT + if n.Default != nil { + // colDef.RawDefault = c.convertExpr(n.Default) + } + + // Handle comment + if n.Comment != "" { + colDef.Comment = n.Comment + } + + return colDef +} + +// renderDataType spells a type as the author wrote it, which the formatter +// prints back. +func renderDataType(dt *chast.DataType) string { + return renderType(dt, false) +} + +// canonicalDataType spells a type the way ClickHouse stores it, which the +// analysis core reads: an Enum's members are numbered and the family +// sized by their count, a Variant's members are sorted, and a named +// element is written label first, so that Enum('a', 'b') is Enum8('a' = +// 1, 'b' = 2), Variant(String, Int64) is Variant(Int64, String) and +// Tuple(lat Float64) is Tuple(lat: Float64). +func canonicalDataType(dt *chast.DataType) string { + return renderType(dt, true) +} + +func renderType(dt *chast.DataType, canonical bool) string { + if dt == nil { + return "" + } + if len(dt.Parameters) == 0 { + return dt.Name + } + name := dt.Name + parts := make([]string, 0, len(dt.Parameters)) + switch lower := strings.ToLower(name); { + case canonical && (lower == "enum" || lower == "enum8" || lower == "enum16"): + if lower == "enum" { + name = "Enum8" + if len(dt.Parameters) > 127 { + name = "Enum16" + } + } + next := int64(1) + for _, p := range dt.Parameters { + switch v := p.(type) { + case *chast.BinaryExpr: + // 'a' = 3 numbers itself, and the next bare member follows it. + parts = append(parts, renderParam(v, canonical)) + if lit, ok := v.Right.(*chast.Literal); ok { + if n, err := strconv.ParseInt(fmt.Sprint(lit.Value), 10, 64); err == nil { + next = n + 1 + } + } + default: + parts = append(parts, renderParam(p, canonical)+" = "+strconv.FormatInt(next, 10)) + next++ + } + } + case canonical && lower == "lowcardinality" && len(dt.Parameters) == 1: + // ClickHouse spells a nullable low-cardinality column as + // LowCardinality(Nullable(T)), the only order it accepts. The + // nullability is the column's, so the canonical form is + // Nullable(LowCardinality(T)), which reads as a nullable + // LowCardinality(T). + if inner, ok := dt.Parameters[0].(*chast.DataType); ok && strings.EqualFold(inner.Name, "nullable") && len(inner.Parameters) == 1 { + return "Nullable(LowCardinality(" + renderParam(inner.Parameters[0], canonical) + "))" + } + parts = append(parts, renderParam(dt.Parameters[0], canonical)) + case canonical && lower == "variant": + for _, p := range dt.Parameters { + parts = append(parts, renderParam(p, canonical)) + } + sort.Strings(parts) + default: + for _, p := range dt.Parameters { + parts = append(parts, renderParam(p, canonical)) + } + } + return name + "(" + strings.Join(parts, ", ") + ")" +} + +func renderTypeParam(e chast.Expression) string { + return renderParam(e, false) +} + +func renderParam(e chast.Expression, canonical bool) string { + switch v := e.(type) { + case *chast.DataType: + return renderType(v, canonical) + case *chast.Literal: + if v.Type == chast.LiteralString { + return quoteString(fmt.Sprint(v.Value)) + } + if v.Source != "" { + return v.Source + } + return fmt.Sprintf("%v", v.Value) + case *chast.Identifier: + return strings.Join(v.Parts, ".") + case *chast.NameTypePair: + // A named tuple or nested element: `lat Float64`, or `lat: Float64` + // in the canonical form. + if canonical { + return v.Name + ": " + renderType(v.Type, canonical) + } + return v.Name + " " + renderType(v.Type, canonical) + case *chast.BinaryExpr: + // An enum member: `'active' = 1`. + return renderParam(v.Left, canonical) + " " + v.Op + " " + renderParam(v.Right, canonical) + default: + return "" + } +} + +func unwrapTypeString(s string) (name string, isArray, nullable bool) { + base, args := splitType(s) + switch strings.ToLower(base) { + case "nullable": + if len(args) == 1 { + inner, arr, _ := unwrapTypeString(args[0]) + return inner, arr, true + } + return strings.ToLower(base), false, true + case "lowcardinality": + // LowCardinality is an encoding of the type it wraps, and a + // column of LowCardinality(Nullable(String)) holds NULLs. + if len(args) == 1 { + return unwrapTypeString(args[0]) + } + return strings.ToLower(base), false, false + case "array": + if len(args) == 1 { + inner, _, _ := unwrapTypeString(args[0]) + return inner, true, false + } + return strings.ToLower(base), true, false + default: + if strings.TrimSpace(base) == "" { + return "nothing", false, false + } + return strings.ToLower(base), false, false + } +} + +func splitType(s string) (base string, args []string) { + s = strings.TrimSpace(s) + open := strings.IndexByte(s, '(') + if open < 0 || !strings.HasSuffix(s, ")") { + return s, nil + } + base = strings.TrimSpace(s[:open]) + inner := s[open+1 : len(s)-1] + depth, start := 0, 0 + for i := 0; i < len(inner); i++ { + switch inner[i] { + case '(': + depth++ + case ')': + depth-- + case ',': + if depth == 0 { + args = append(args, strings.TrimSpace(inner[start:i])) + start = i + 1 + } + } + } + if last := strings.TrimSpace(inner[start:]); last != "" { + args = append(args, last) + } + return base, args +} + +func (c *cc) convertUpdateQuery(n *chast.UpdateQuery) *ast.UpdateStmt { + rv := &ast.RangeVar{ + Relname: &n.Table, + } + if n.Database != "" { + rv.Schemaname = &n.Database + } + stmt := &ast.UpdateStmt{ + Relations: &ast.List{ + Items: []ast.Node{rv}, + }, + } + + // Convert assignments + if len(n.Assignments) > 0 { + stmt.TargetList = &ast.List{} + for _, assign := range n.Assignments { + name := identifier(assign.Column) + stmt.TargetList.Items = append(stmt.TargetList.Items, &ast.ResTarget{ + Name: &name, + Val: c.convertExpr(assign.Value), + }) + } + } + + // Convert WHERE clause + if n.Where != nil { + stmt.WhereClause = c.convertExpr(n.Where) + } + + return stmt +} + +func (c *cc) convertDeleteQuery(n *chast.DeleteQuery) *ast.DeleteStmt { + rv := &ast.RangeVar{ + Relname: &n.Table, + } + if n.Database != "" { + rv.Schemaname = &n.Database + } + stmt := &ast.DeleteStmt{ + Relations: &ast.List{ + Items: []ast.Node{rv}, + }, + } + + // Convert WHERE clause + if n.Where != nil { + stmt.WhereClause = c.convertExpr(n.Where) + } + + return stmt +} + +func (c *cc) convertDropQuery(n *chast.DropQuery) ast.Node { + // Handle DROP TABLE + if n.Table != "" { + tableName := &ast.TableName{ + Name: identifier(n.Table), + } + if n.Database != "" { + tableName.Schema = identifier(n.Database) + } + return &ast.DropTableStmt{ + IfExists: n.IfExists, + Tables: []*ast.TableName{tableName}, + } + } + + // Handle DROP TABLE with multiple tables + if len(n.Tables) > 0 { + tables := make([]*ast.TableName, 0, len(n.Tables)) + for _, t := range n.Tables { + tables = append(tables, parseTableName(t)) + } + return &ast.DropTableStmt{ + IfExists: n.IfExists, + Tables: tables, + } + } + + // Handle DROP DATABASE - return TODO for now + // Handle DROP VIEW - return TODO for now + return &ast.TODO{} +} + +func (c *cc) convertAlterQuery(n *chast.AlterQuery) ast.Node { + alt := &ast.AlterTableStmt{ + Table: &ast.TableName{ + Name: identifier(n.Table), + }, + Cmds: &ast.List{}, + } + + if n.Database != "" { + alt.Table.Schema = identifier(n.Database) + } + + for _, cmd := range n.Commands { + switch cmd.Type { + case chast.AlterAddColumn: + if cmd.Column != nil { + name := cmd.Column.Name + alt.Cmds.Items = append(alt.Cmds.Items, &ast.AlterTableCmd{ + Name: &name, + Subtype: ast.AT_AddColumn, + Def: c.convertColumnDeclaration(cmd.Column), + }) + } + case chast.AlterDropColumn: + name := cmd.ColumnName + alt.Cmds.Items = append(alt.Cmds.Items, &ast.AlterTableCmd{ + Name: &name, + Subtype: ast.AT_DropColumn, + MissingOk: cmd.IfExists, + }) + case chast.AlterModifyColumn: + if cmd.Column != nil { + name := cmd.Column.Name + // Drop and re-add to simulate modify + alt.Cmds.Items = append(alt.Cmds.Items, &ast.AlterTableCmd{ + Name: &name, + Subtype: ast.AT_DropColumn, + }) + alt.Cmds.Items = append(alt.Cmds.Items, &ast.AlterTableCmd{ + Name: &name, + Subtype: ast.AT_AddColumn, + Def: c.convertColumnDeclaration(cmd.Column), + }) + } + case chast.AlterRenameColumn: + oldName := cmd.ColumnName + newName := cmd.NewName + return &ast.RenameColumnStmt{ + Table: alt.Table, + Col: &ast.ColumnRef{Name: oldName}, + NewName: &newName, + } + } + } + + return alt +} + +func (c *cc) convertTruncateQuery(n *chast.TruncateQuery) *ast.TruncateStmt { + stmt := &ast.TruncateStmt{ + Relations: &ast.List{}, + } + + tableName := n.Table + schemaName := n.Database + + rv := &ast.RangeVar{ + Relname: &tableName, + } + if schemaName != "" { + rv.Schemaname = &schemaName + } + + stmt.Relations.Items = append(stmt.Relations.Items, rv) + + return stmt +} diff --git a/internal/engine/clickhouse/dialect/dialect.json b/internal/engine/clickhouse/dialect/dialect.json new file mode 100644 index 0000000..51cb0b6 --- /dev/null +++ b/internal/engine/clickhouse/dialect/dialect.json @@ -0,0 +1,41 @@ +{ + "dialect": "clickhouse", + "default_schema": "default", + "const": { + "integer": "Int64", + "float": "Float64", + "string": "String", + "bool": "Bool" + }, + "bool": "UInt8", + "limit": "UInt64", + "untyped": "Nothing", + "propagate_nullable": true, + "qualify_duplicate_columns": true, + "comparison": ["=", "==", "<>", "!=", "<", "<=", ">", ">="], + "comparison_categories": "NBSDU", + "arithmetic": ["+", "-", "*", "/", "%"], + "arithmetic_categories": "N", + "rewrites": [ + { + "from": "Decimal32($1)", + "to": "Decimal(9, $1)" + }, + { + "from": "Decimal64($1)", + "to": "Decimal(18, $1)" + }, + { + "from": "Decimal128($1)", + "to": "Decimal(38, $1)" + }, + { + "from": "Decimal256($1)", + "to": "Decimal(76, $1)" + } + ], + "ident_args": { + "AggregateFunction": [1], + "SimpleAggregateFunction": [1] + } +} diff --git a/internal/engine/clickhouse/dialect/functions.jsonl b/internal/engine/clickhouse/dialect/functions.jsonl new file mode 100644 index 0000000..c0ca140 --- /dev/null +++ b/internal/engine/clickhouse/dialect/functions.jsonl @@ -0,0 +1,581 @@ +{"name": "count", "kind": "a", "returns": "UInt64", "never_null": true} +{"name": "count", "kind": "a", "args": [{"type": "any"}], "returns": "UInt64", "never_null": true} +{"name": "countIf", "kind": "a", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt64", "never_null": true} +{"name": "sum", "kind": "a", "args": [{"type": "UInt8"}], "returns": "UInt64"} +{"name": "sum", "kind": "a", "args": [{"type": "UInt16"}], "returns": "UInt64"} +{"name": "sum", "kind": "a", "args": [{"type": "UInt32"}], "returns": "UInt64"} +{"name": "sum", "kind": "a", "args": [{"type": "Int8"}], "returns": "Int64"} +{"name": "sum", "kind": "a", "args": [{"type": "Int16"}], "returns": "Int64"} +{"name": "sum", "kind": "a", "args": [{"type": "Int32"}], "returns": "Int64"} +{"name": "sum", "kind": "a", "args": [{"type": "Float32"}], "returns": "Float64"} +{"name": "sum", "kind": "a", "args": [{"type": "any"}], "returns": "$1"} +{"name": "sumIf", "kind": "a", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "avg", "kind": "a", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "avgIf", "kind": "a", "args": [{"type": "any"}, {"type": "any"}], "returns": "Float64"} +{"name": "min", "kind": "a", "args": [{"type": "any"}], "returns": "$1"} +{"name": "max", "kind": "a", "args": [{"type": "any"}], "returns": "$1"} +{"name": "any", "kind": "a", "args": [{"type": "any"}], "returns": "$1"} +{"name": "anyLast", "kind": "a", "args": [{"type": "any"}], "returns": "$1"} +{"name": "minIf", "kind": "a", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "maxIf", "kind": "a", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "anyIf", "kind": "a", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "uniq", "kind": "a", "args": [{"type": "any"}], "returns": "UInt64", "never_null": true} +{"name": "uniqExact", "kind": "a", "args": [{"type": "any"}], "returns": "UInt64", "never_null": true} +{"name": "uniqCombined", "kind": "a", "args": [{"type": "any"}], "returns": "UInt64", "never_null": true} +{"name": "uniqHLL12", "kind": "a", "args": [{"type": "any"}], "returns": "UInt64", "never_null": true} +{"name": "uniqIf", "kind": "a", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt64", "never_null": true} +{"name": "argMin", "kind": "a", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "argMax", "kind": "a", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "stddevPop", "kind": "a", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "stddevSamp", "kind": "a", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "varPop", "kind": "a", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "varSamp", "kind": "a", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "median", "kind": "a", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "quantile", "kind": "a", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "quantile", "kind": "a", "args": [{"type": "any"}, {"type": "any"}], "returns": "Float64"} +{"name": "row_number", "kind": "w", "returns": "UInt64", "never_null": true} +{"name": "rank", "kind": "w", "returns": "UInt64", "never_null": true} +{"name": "dense_rank", "kind": "w", "returns": "UInt64", "never_null": true} +{"name": "plus", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "minus", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "multiply", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "intDiv", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "intDivOrZero", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "modulo", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "moduloOrZero", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "gcd", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "lcm", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "bitAnd", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "bitOr", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "bitXor", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "bitShiftLeft", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "bitShiftRight", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "greatest", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "least", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "divide", "args": [{"type": "any"}, {"type": "any"}], "returns": "Float64"} +{"name": "negate", "args": [{"type": "any"}], "returns": "$1"} +{"name": "abs", "args": [{"type": "any"}], "returns": "$1"} +{"name": "round", "args": [{"type": "any"}], "returns": "$1"} +{"name": "floor", "args": [{"type": "any"}], "returns": "$1"} +{"name": "ceil", "args": [{"type": "any"}], "returns": "$1"} +{"name": "ceiling", "args": [{"type": "any"}], "returns": "$1"} +{"name": "trunc", "args": [{"type": "any"}], "returns": "$1"} +{"name": "truncate", "args": [{"type": "any"}], "returns": "$1"} +{"name": "identity", "args": [{"type": "any"}], "returns": "$1"} +{"name": "bitNot", "args": [{"type": "any"}], "returns": "$1"} +{"name": "round", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "floor", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "ceil", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "trunc", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "exp", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "log", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "ln", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "exp2", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "log2", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "exp10", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "log10", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "sqrt", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "cbrt", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "sin", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "cos", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "tan", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "asin", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "acos", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "atan", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "sigmoid", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "erf", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "lgamma", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "tgamma", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "pow", "args": [{"type": "any"}, {"type": "any"}], "returns": "Float64"} +{"name": "power", "args": [{"type": "any"}, {"type": "any"}], "returns": "Float64"} +{"name": "atan2", "args": [{"type": "any"}, {"type": "any"}], "returns": "Float64"} +{"name": "hypot", "args": [{"type": "any"}, {"type": "any"}], "returns": "Float64"} +{"name": "e", "returns": "Float64", "never_null": true} +{"name": "pi", "returns": "Float64", "never_null": true} +{"name": "sign", "args": [{"type": "any"}], "returns": "Int8"} +{"name": "isFinite", "args": [{"type": "any"}], "returns": "UInt8"} +{"name": "isInfinite", "args": [{"type": "any"}], "returns": "UInt8"} +{"name": "isNaN", "args": [{"type": "any"}], "returns": "UInt8"} +{"name": "rand", "returns": "UInt32", "never_null": true} +{"name": "rand32", "returns": "UInt32", "never_null": true} +{"name": "rand64", "returns": "UInt64", "never_null": true} +{"name": "randCanonical", "returns": "Float64", "never_null": true} +{"name": "equals", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "notEquals", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "less", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "greater", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "lessOrEquals", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "greaterOrEquals", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "and", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "or", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "xor", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "like", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "notLike", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "ilike", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "notILike", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "match", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "startsWith", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "endsWith", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "has", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "hasAll", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "hasAny", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "mapContains", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "multiSearchAny", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "in", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "notIn", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "not", "args": [{"type": "any"}], "returns": "UInt8"} +{"name": "isNull", "args": [{"type": "any"}], "returns": "UInt8", "never_null": true} +{"name": "isNotNull", "args": [{"type": "any"}], "returns": "UInt8", "never_null": true} +{"name": "isZeroOrNull", "args": [{"type": "any"}], "returns": "UInt8", "never_null": true} +{"name": "assumeNotNull", "args": [{"type": "any"}], "returns": "$1", "never_null": true} +{"name": "toNullable", "args": [{"type": "any"}], "returns": "$1", "nullable": true} +{"name": "nullIf", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1", "nullable": true} +{"name": "if", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$2"} +{"name": "empty", "args": [{"type": "any"}], "returns": "UInt8"} +{"name": "notEmpty", "args": [{"type": "any"}], "returns": "UInt8"} +{"name": "length", "args": [{"type": "any"}], "returns": "UInt64"} +{"name": "lengthUTF8", "args": [{"type": "any"}], "returns": "UInt64"} +{"name": "char_length", "args": [{"type": "any"}], "returns": "UInt64"} +{"name": "character_length", "args": [{"type": "any"}], "returns": "UInt64"} +{"name": "position", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt64"} +{"name": "positionUTF8", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt64"} +{"name": "positionCaseInsensitive", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt64"} +{"name": "countSubstrings", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt64"} +{"name": "indexOf", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt64"} +{"name": "countEqual", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt64"} +{"name": "ngramSearch", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt64"} +{"name": "lower", "args": [{"type": "any"}], "returns": "String"} +{"name": "upper", "args": [{"type": "any"}], "returns": "String"} +{"name": "lowerUTF8", "args": [{"type": "any"}], "returns": "String"} +{"name": "upperUTF8", "args": [{"type": "any"}], "returns": "String"} +{"name": "toString", "args": [{"type": "any"}], "returns": "String"} +{"name": "toValidUTF8", "args": [{"type": "any"}], "returns": "String"} +{"name": "trim", "args": [{"type": "any"}], "returns": "String"} +{"name": "trimLeft", "args": [{"type": "any"}], "returns": "String"} +{"name": "trimRight", "args": [{"type": "any"}], "returns": "String"} +{"name": "trimBoth", "args": [{"type": "any"}], "returns": "String"} +{"name": "ltrim", "args": [{"type": "any"}], "returns": "String"} +{"name": "rtrim", "args": [{"type": "any"}], "returns": "String"} +{"name": "hex", "args": [{"type": "any"}], "returns": "String"} +{"name": "unhex", "args": [{"type": "any"}], "returns": "String"} +{"name": "bin", "args": [{"type": "any"}], "returns": "String"} +{"name": "base64Encode", "args": [{"type": "any"}], "returns": "String"} +{"name": "base64Decode", "args": [{"type": "any"}], "returns": "String"} +{"name": "tryBase64Decode", "args": [{"type": "any"}], "returns": "String"} +{"name": "reverseUTF8", "args": [{"type": "any"}], "returns": "String"} +{"name": "initcap", "args": [{"type": "any"}], "returns": "String"} +{"name": "normalizeQuery", "args": [{"type": "any"}], "returns": "String"} +{"name": "typeName", "args": [{"type": "any"}], "returns": "String"} +{"name": "dumpColumnStructure", "args": [{"type": "any"}], "returns": "String"} +{"name": "urlDecode", "args": [{"type": "any"}], "returns": "String"} +{"name": "encodeURLComponent", "args": [{"type": "any"}], "returns": "String"} +{"name": "decodeURLComponent", "args": [{"type": "any"}], "returns": "String"} +{"name": "domain", "args": [{"type": "any"}], "returns": "String"} +{"name": "topLevelDomain", "args": [{"type": "any"}], "returns": "String"} +{"name": "path", "args": [{"type": "any"}], "returns": "String"} +{"name": "pathFull", "args": [{"type": "any"}], "returns": "String"} +{"name": "protocol", "args": [{"type": "any"}], "returns": "String"} +{"name": "queryString", "args": [{"type": "any"}], "returns": "String"} +{"name": "fragment", "args": [{"type": "any"}], "returns": "String"} +{"name": "cutQueryString", "args": [{"type": "any"}], "returns": "String"} +{"name": "cutFragment", "args": [{"type": "any"}], "returns": "String"} +{"name": "cutWWW", "args": [{"type": "any"}], "returns": "String"} +{"name": "firstSignificantSubdomain", "args": [{"type": "any"}], "returns": "String"} +{"name": "IPv4NumToString", "args": [{"type": "any"}], "returns": "String"} +{"name": "IPv6NumToString", "args": [{"type": "any"}], "returns": "String"} +{"name": "formatReadableSize", "args": [{"type": "any"}], "returns": "String"} +{"name": "formatReadableQuantity", "args": [{"type": "any"}], "returns": "String"} +{"name": "formatReadableDecimalSize", "args": [{"type": "any"}], "returns": "String"} +{"name": "formatReadableTimeDelta", "args": [{"type": "any"}], "returns": "String"} +{"name": "toDecimalString", "args": [{"type": "any"}], "returns": "String"} +{"name": "monthName", "args": [{"type": "any"}], "returns": "String"} +{"name": "toJSONString", "args": [{"type": "any"}], "returns": "String"} +{"name": "toTypeName", "args": [{"type": "any"}], "returns": "String", "never_null": true} +{"name": "hostName", "returns": "String", "never_null": true} +{"name": "version", "returns": "String", "never_null": true} +{"name": "currentDatabase", "returns": "String", "never_null": true} +{"name": "currentUser", "returns": "String", "never_null": true} +{"name": "FQDN", "returns": "String", "never_null": true} +{"name": "queryID", "returns": "String", "never_null": true} +{"name": "generateULID", "returns": "String", "never_null": true} +{"name": "concat", "args": [{"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "substring", "args": [{"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "substr", "args": [{"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "mid", "args": [{"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "substringUTF8", "args": [{"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "repeat", "args": [{"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "leftPad", "args": [{"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "rightPad", "args": [{"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "left", "args": [{"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "right", "args": [{"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "extract", "args": [{"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "formatDateTime", "args": [{"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "formatDateTimeInJodaSyntax", "args": [{"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "dateName", "args": [{"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "JSONExtractString", "args": [{"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "JSONExtractRaw", "args": [{"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "visitParamExtractString", "args": [{"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "simpleJSONExtractString", "args": [{"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "arrayStringConcat", "args": [{"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "regexpExtract", "args": [{"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "translate", "args": [{"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "format", "args": [{"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "toDecimalString", "args": [{"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "concat", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "substring", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "substr", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "mid", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "substringUTF8", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "leftPad", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "rightPad", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "replaceOne", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "replaceAll", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "replaceRegexpOne", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "replaceRegexpAll", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "translate", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "format", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "concatWithSeparator", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "regexpExtract", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "formatDateTime", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "JSONExtractString", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "JSONExtractRaw", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "concat", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "concat", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "concat", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}, {"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "arrayStringConcat", "args": [{"type": "any"}], "returns": "String"} +{"name": "splitByChar", "args": [{"type": "any"}, {"type": "any"}], "returns": "Array(String)"} +{"name": "splitByString", "args": [{"type": "any"}, {"type": "any"}], "returns": "Array(String)"} +{"name": "splitByRegexp", "args": [{"type": "any"}, {"type": "any"}], "returns": "Array(String)"} +{"name": "splitByWhitespace", "args": [{"type": "any"}, {"type": "any"}], "returns": "Array(String)"} +{"name": "alphaTokens", "args": [{"type": "any"}, {"type": "any"}], "returns": "Array(String)"} +{"name": "extractAll", "args": [{"type": "any"}, {"type": "any"}], "returns": "Array(String)"} +{"name": "tokens", "args": [{"type": "any"}, {"type": "any"}], "returns": "Array(String)"} +{"name": "splitByWhitespace", "args": [{"type": "any"}], "returns": "Array(String)"} +{"name": "alphaTokens", "args": [{"type": "any"}], "returns": "Array(String)"} +{"name": "tokens", "args": [{"type": "any"}], "returns": "Array(String)"} +{"name": "reverse", "args": [{"type": "any"}], "returns": "$1"} +{"name": "md5", "args": [{"type": "any"}], "returns": "FixedString(16)"} +{"name": "MD5", "args": [{"type": "any"}], "returns": "FixedString(16)"} +{"name": "sipHash128", "args": [{"type": "any"}], "returns": "FixedString(16)"} +{"name": "murmurHash3_128", "args": [{"type": "any"}], "returns": "FixedString(16)"} +{"name": "cityHash128", "args": [{"type": "any"}], "returns": "FixedString(16)"} +{"name": "SHA1", "args": [{"type": "any"}], "returns": "FixedString(20)"} +{"name": "SHA224", "args": [{"type": "any"}], "returns": "FixedString(28)"} +{"name": "SHA256", "args": [{"type": "any"}], "returns": "FixedString(32)"} +{"name": "SHA512", "args": [{"type": "any"}], "returns": "FixedString(64)"} +{"name": "sipHash64", "args": [{"type": "any"}], "returns": "UInt64", "never_null": true} +{"name": "cityHash64", "args": [{"type": "any"}], "returns": "UInt64", "never_null": true} +{"name": "xxHash64", "args": [{"type": "any"}], "returns": "UInt64", "never_null": true} +{"name": "halfMD5", "args": [{"type": "any"}], "returns": "UInt64", "never_null": true} +{"name": "farmHash64", "args": [{"type": "any"}], "returns": "UInt64", "never_null": true} +{"name": "javaHash", "args": [{"type": "any"}], "returns": "UInt64", "never_null": true} +{"name": "intHash64", "args": [{"type": "any"}], "returns": "UInt64", "never_null": true} +{"name": "murmurHash2_64", "args": [{"type": "any"}], "returns": "UInt64", "never_null": true} +{"name": "murmurHash3_64", "args": [{"type": "any"}], "returns": "UInt64", "never_null": true} +{"name": "metroHash64", "args": [{"type": "any"}], "returns": "UInt64", "never_null": true} +{"name": "xxh3", "args": [{"type": "any"}], "returns": "UInt64", "never_null": true} +{"name": "wyHash64", "args": [{"type": "any"}], "returns": "UInt64", "never_null": true} +{"name": "xxHash32", "args": [{"type": "any"}], "returns": "UInt32", "never_null": true} +{"name": "intHash32", "args": [{"type": "any"}], "returns": "UInt32", "never_null": true} +{"name": "murmurHash2_32", "args": [{"type": "any"}], "returns": "UInt32", "never_null": true} +{"name": "murmurHash3_32", "args": [{"type": "any"}], "returns": "UInt32", "never_null": true} +{"name": "crc32", "args": [{"type": "any"}], "returns": "UInt32", "never_null": true} +{"name": "CRC32", "args": [{"type": "any"}], "returns": "UInt32", "never_null": true} +{"name": "javaHash", "args": [{"type": "any"}], "returns": "UInt32", "never_null": true} +{"name": "levenshteinDistance", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt64"} +{"name": "editDistance", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt64"} +{"name": "ngramDistance", "args": [{"type": "any"}, {"type": "any"}], "returns": "Float32"} +{"name": "ngramSearch", "args": [{"type": "any"}, {"type": "any"}], "returns": "Float32"} +{"name": "jaroSimilarity", "args": [{"type": "any"}, {"type": "any"}], "returns": "Float32"} +{"name": "jaroWinklerSimilarity", "args": [{"type": "any"}, {"type": "any"}], "returns": "Float32"} +{"name": "toInt8", "args": [{"type": "any"}], "returns": "Int8"} +{"name": "toInt8OrZero", "args": [{"type": "any"}], "returns": "Int8"} +{"name": "toInt8OrNull", "args": [{"type": "any"}], "returns": "Int8", "nullable": true} +{"name": "toInt16", "args": [{"type": "any"}], "returns": "Int16"} +{"name": "toInt16OrZero", "args": [{"type": "any"}], "returns": "Int16"} +{"name": "toInt16OrNull", "args": [{"type": "any"}], "returns": "Int16", "nullable": true} +{"name": "toInt32", "args": [{"type": "any"}], "returns": "Int32"} +{"name": "toInt32OrZero", "args": [{"type": "any"}], "returns": "Int32"} +{"name": "toInt32OrNull", "args": [{"type": "any"}], "returns": "Int32", "nullable": true} +{"name": "toInt64", "args": [{"type": "any"}], "returns": "Int64"} +{"name": "toInt64OrZero", "args": [{"type": "any"}], "returns": "Int64"} +{"name": "toInt64OrNull", "args": [{"type": "any"}], "returns": "Int64", "nullable": true} +{"name": "toInt128", "args": [{"type": "any"}], "returns": "Int128"} +{"name": "toInt128OrZero", "args": [{"type": "any"}], "returns": "Int128"} +{"name": "toInt128OrNull", "args": [{"type": "any"}], "returns": "Int128", "nullable": true} +{"name": "toInt256", "args": [{"type": "any"}], "returns": "Int256"} +{"name": "toInt256OrZero", "args": [{"type": "any"}], "returns": "Int256"} +{"name": "toInt256OrNull", "args": [{"type": "any"}], "returns": "Int256", "nullable": true} +{"name": "toUInt8", "args": [{"type": "any"}], "returns": "UInt8"} +{"name": "toUInt8OrZero", "args": [{"type": "any"}], "returns": "UInt8"} +{"name": "toUInt8OrNull", "args": [{"type": "any"}], "returns": "UInt8", "nullable": true} +{"name": "toUInt16", "args": [{"type": "any"}], "returns": "UInt16"} +{"name": "toUInt16OrZero", "args": [{"type": "any"}], "returns": "UInt16"} +{"name": "toUInt16OrNull", "args": [{"type": "any"}], "returns": "UInt16", "nullable": true} +{"name": "toUInt32", "args": [{"type": "any"}], "returns": "UInt32"} +{"name": "toUInt32OrZero", "args": [{"type": "any"}], "returns": "UInt32"} +{"name": "toUInt32OrNull", "args": [{"type": "any"}], "returns": "UInt32", "nullable": true} +{"name": "toUInt64", "args": [{"type": "any"}], "returns": "UInt64"} +{"name": "toUInt64OrZero", "args": [{"type": "any"}], "returns": "UInt64"} +{"name": "toUInt64OrNull", "args": [{"type": "any"}], "returns": "UInt64", "nullable": true} +{"name": "toUInt128", "args": [{"type": "any"}], "returns": "UInt128"} +{"name": "toUInt128OrZero", "args": [{"type": "any"}], "returns": "UInt128"} +{"name": "toUInt128OrNull", "args": [{"type": "any"}], "returns": "UInt128", "nullable": true} +{"name": "toUInt256", "args": [{"type": "any"}], "returns": "UInt256"} +{"name": "toUInt256OrZero", "args": [{"type": "any"}], "returns": "UInt256"} +{"name": "toUInt256OrNull", "args": [{"type": "any"}], "returns": "UInt256", "nullable": true} +{"name": "toFloat32", "args": [{"type": "any"}], "returns": "Float32"} +{"name": "toFloat32OrZero", "args": [{"type": "any"}], "returns": "Float32"} +{"name": "toFloat32OrNull", "args": [{"type": "any"}], "returns": "Float32", "nullable": true} +{"name": "toFloat64", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "toFloat64OrZero", "args": [{"type": "any"}], "returns": "Float64"} +{"name": "toFloat64OrNull", "args": [{"type": "any"}], "returns": "Float64", "nullable": true} +{"name": "toDate", "args": [{"type": "any"}], "returns": "Date"} +{"name": "toDateOrZero", "args": [{"type": "any"}], "returns": "Date"} +{"name": "toDateOrNull", "args": [{"type": "any"}], "returns": "Date", "nullable": true} +{"name": "toDate32", "args": [{"type": "any"}], "returns": "Date32"} +{"name": "toDate32OrZero", "args": [{"type": "any"}], "returns": "Date32"} +{"name": "toDate32OrNull", "args": [{"type": "any"}], "returns": "Date32", "nullable": true} +{"name": "toDateTime", "args": [{"type": "any"}], "returns": "DateTime"} +{"name": "toDateTimeOrZero", "args": [{"type": "any"}], "returns": "DateTime"} +{"name": "toDateTimeOrNull", "args": [{"type": "any"}], "returns": "DateTime", "nullable": true} +{"name": "toUUID", "args": [{"type": "any"}], "returns": "UUID"} +{"name": "toUUIDOrZero", "args": [{"type": "any"}], "returns": "UUID"} +{"name": "toUUIDOrNull", "args": [{"type": "any"}], "returns": "UUID", "nullable": true} +{"name": "toIPv4", "args": [{"type": "any"}], "returns": "IPv4"} +{"name": "toIPv4OrZero", "args": [{"type": "any"}], "returns": "IPv4"} +{"name": "toIPv4OrNull", "args": [{"type": "any"}], "returns": "IPv4", "nullable": true} +{"name": "toIPv6", "args": [{"type": "any"}], "returns": "IPv6"} +{"name": "toIPv6OrZero", "args": [{"type": "any"}], "returns": "IPv6"} +{"name": "toIPv6OrNull", "args": [{"type": "any"}], "returns": "IPv6", "nullable": true} +{"name": "toBool", "args": [{"type": "any"}], "returns": "Bool"} +{"name": "toString", "args": [{"type": "any"}], "returns": "String"} +{"name": "toDateTime", "args": [{"type": "any"}, {"type": "any"}], "returns": "DateTime"} +{"name": "toDate", "args": [{"type": "any"}, {"type": "any"}], "returns": "Date"} +{"name": "toDateTime64", "args": [{"type": "any"}, {"type": "any"}], "returns": "DateTime64($2)"} +{"name": "toDateTime64", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "DateTime64($2, $3)"} +{"name": "toDecimal32", "args": [{"type": "any"}, {"type": "any"}], "returns": "Decimal(9, $2)"} +{"name": "toDecimal64", "args": [{"type": "any"}, {"type": "any"}], "returns": "Decimal(18, $2)"} +{"name": "toDecimal128", "args": [{"type": "any"}, {"type": "any"}], "returns": "Decimal(38, $2)"} +{"name": "toDecimal256", "args": [{"type": "any"}, {"type": "any"}], "returns": "Decimal(76, $2)"} +{"name": "toFixedString", "args": [{"type": "any"}, {"type": "any"}], "returns": "FixedString"} +{"name": "toStringCutToZero", "args": [{"type": "any"}], "returns": "String"} +{"name": "reinterpretAsString", "args": [{"type": "any"}], "returns": "String"} +{"name": "reinterpretAsUInt64", "args": [{"type": "any"}], "returns": "UInt64"} +{"name": "toUnixTimestamp", "args": [{"type": "any"}], "returns": "UInt32"} +{"name": "toUnixTimestamp", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt32"} +{"name": "fromUnixTimestamp", "args": [{"type": "any"}], "returns": "DateTime"} +{"name": "toUUIDOrNull", "args": [{"type": "any"}], "returns": "UUID", "nullable": true} +{"name": "toUUIDOrZero", "args": [{"type": "any"}], "returns": "UUID"} +{"name": "generateUUIDv4", "returns": "UUID", "never_null": true} +{"name": "generateUUIDv7", "returns": "UUID", "never_null": true} +{"name": "toIntervalSecond", "args": [{"type": "any"}], "returns": "IntervalSecond"} +{"name": "toIntervalMinute", "args": [{"type": "any"}], "returns": "IntervalMinute"} +{"name": "toIntervalHour", "args": [{"type": "any"}], "returns": "IntervalHour"} +{"name": "toIntervalDay", "args": [{"type": "any"}], "returns": "IntervalDay"} +{"name": "toIntervalWeek", "args": [{"type": "any"}], "returns": "IntervalWeek"} +{"name": "toIntervalMonth", "args": [{"type": "any"}], "returns": "IntervalMonth"} +{"name": "toIntervalYear", "args": [{"type": "any"}], "returns": "IntervalYear"} +{"name": "now", "returns": "DateTime", "never_null": true} +{"name": "now", "args": [{"type": "any"}], "returns": "DateTime", "never_null": true} +{"name": "now64", "returns": "DateTime64", "never_null": true} +{"name": "now64", "args": [{"type": "any"}], "returns": "DateTime64", "never_null": true} +{"name": "today", "returns": "Date", "never_null": true} +{"name": "yesterday", "returns": "Date", "never_null": true} +{"name": "timeZone", "returns": "String", "never_null": true} +{"name": "serverTimezone", "returns": "String", "never_null": true} +{"name": "toYear", "args": [{"type": "any"}], "returns": "UInt16"} +{"name": "toISOYear", "args": [{"type": "any"}], "returns": "UInt16"} +{"name": "toDayOfYear", "args": [{"type": "any"}], "returns": "UInt16"} +{"name": "toRelativeYearNum", "args": [{"type": "any"}], "returns": "UInt16"} +{"name": "toWeek", "args": [{"type": "any"}], "returns": "UInt8"} +{"name": "toISOWeek", "args": [{"type": "any"}], "returns": "UInt8"} +{"name": "toYearWeek", "args": [{"type": "any"}], "returns": "UInt32"} +{"name": "toQuarter", "args": [{"type": "any"}], "returns": "UInt8"} +{"name": "toMonth", "args": [{"type": "any"}], "returns": "UInt8"} +{"name": "toDayOfMonth", "args": [{"type": "any"}], "returns": "UInt8"} +{"name": "toDayOfWeek", "args": [{"type": "any"}], "returns": "UInt8"} +{"name": "toHour", "args": [{"type": "any"}], "returns": "UInt8"} +{"name": "toMinute", "args": [{"type": "any"}], "returns": "UInt8"} +{"name": "toSecond", "args": [{"type": "any"}], "returns": "UInt8"} +{"name": "toMillisecond", "args": [{"type": "any"}], "returns": "UInt8"} +{"name": "toYYYYMM", "args": [{"type": "any"}], "returns": "UInt32"} +{"name": "toYYYYMMDD", "args": [{"type": "any"}], "returns": "UInt32"} +{"name": "toYYYYMMDDhhmmss", "args": [{"type": "any"}], "returns": "UInt64"} +{"name": "toStartOfDay", "args": [{"type": "any"}], "returns": "DateTime"} +{"name": "toStartOfHour", "args": [{"type": "any"}], "returns": "DateTime"} +{"name": "toStartOfMinute", "args": [{"type": "any"}], "returns": "DateTime"} +{"name": "toStartOfFiveMinutes", "args": [{"type": "any"}], "returns": "DateTime"} +{"name": "toStartOfFifteenMinutes", "args": [{"type": "any"}], "returns": "DateTime"} +{"name": "toStartOfTenMinutes", "args": [{"type": "any"}], "returns": "DateTime"} +{"name": "toTime", "args": [{"type": "any"}], "returns": "DateTime"} +{"name": "timeSlot", "args": [{"type": "any"}], "returns": "DateTime"} +{"name": "toLastDayOfMonth", "args": [{"type": "any"}], "returns": "DateTime"} +{"name": "toLastDayOfMonth", "args": [{"type": "any"}], "returns": "Date"} +{"name": "toStartOfMonth", "args": [{"type": "any"}], "returns": "Date"} +{"name": "toStartOfQuarter", "args": [{"type": "any"}], "returns": "Date"} +{"name": "toStartOfYear", "args": [{"type": "any"}], "returns": "Date"} +{"name": "toStartOfWeek", "args": [{"type": "any"}], "returns": "Date"} +{"name": "toMonday", "args": [{"type": "any"}], "returns": "Date"} +{"name": "toStartOfISOYear", "args": [{"type": "any"}], "returns": "Date"} +{"name": "toStartOfWeek", "args": [{"type": "any"}, {"type": "any"}], "returns": "Date"} +{"name": "toStartOfInterval", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "addYears", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "addQuarters", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "addMonths", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "addWeeks", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "addDays", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "addHours", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "addMinutes", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "addSeconds", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "addMilliseconds", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "subtractYears", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "subtractQuarters", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "subtractMonths", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "subtractWeeks", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "subtractDays", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "subtractHours", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "subtractMinutes", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "subtractSeconds", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "addInterval", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "subtractInterval", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "dateDiff", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "Int64"} +{"name": "date_diff", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "Int64"} +{"name": "timestampDiff", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "Int64"} +{"name": "timestamp_diff", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "Int64"} +{"name": "age", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "Int64"} +{"name": "dateAdd", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$3"} +{"name": "date_add", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$3"} +{"name": "dateSub", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$3"} +{"name": "date_sub", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$3"} +{"name": "timestampAdd", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$3"} +{"name": "timestampSub", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$3"} +{"name": "dateTrunc", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$3"} +{"name": "date_trunc", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$3"} +{"name": "dateTrunc", "args": [{"type": "any"}, {"type": "any"}], "returns": "$2"} +{"name": "date_trunc", "args": [{"type": "any"}, {"type": "any"}], "returns": "$2"} +{"name": "toRelativeDayNum", "args": [{"type": "any"}], "returns": "UInt32"} +{"name": "toRelativeHourNum", "args": [{"type": "any"}], "returns": "UInt32"} +{"name": "toRelativeMinuteNum", "args": [{"type": "any"}], "returns": "UInt32"} +{"name": "toRelativeSecondNum", "args": [{"type": "any"}], "returns": "UInt32"} +{"name": "toRelativeMonthNum", "args": [{"type": "any"}], "returns": "UInt32"} +{"name": "toRelativeWeekNum", "args": [{"type": "any"}], "returns": "UInt32"} +{"name": "toTimeZone", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "toTimezone", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "parseDateTimeBestEffort", "args": [{"type": "any"}], "returns": "DateTime"} +{"name": "parseDateTimeBestEffortOrNull", "args": [{"type": "any"}], "returns": "DateTime", "nullable": true} +{"name": "parseDateTimeBestEffortOrZero", "args": [{"type": "any"}], "returns": "DateTime"} +{"name": "parseDateTime", "args": [{"type": "any"}, {"type": "any"}], "returns": "DateTime"} +{"name": "parseDateTime64BestEffort", "args": [{"type": "any"}], "returns": "DateTime64"} +{"name": "makeDate", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "Date"} +{"name": "makeDateTime", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}, {"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "DateTime"} +{"name": "arrayConcat", "args": [{"type": "any"}], "returns": "$1"} +{"name": "arrayConcat", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayConcat", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayDistinct", "args": [{"type": "any"}], "returns": "$1"} +{"name": "arrayDistinct", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayDistinct", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arraySort", "args": [{"type": "any"}], "returns": "$1"} +{"name": "arraySort", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arraySort", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayReverseSort", "args": [{"type": "any"}], "returns": "$1"} +{"name": "arrayReverseSort", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayReverseSort", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayReverse", "args": [{"type": "any"}], "returns": "$1"} +{"name": "arrayReverse", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayReverse", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arraySlice", "args": [{"type": "any"}], "returns": "$1"} +{"name": "arraySlice", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arraySlice", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayResize", "args": [{"type": "any"}], "returns": "$1"} +{"name": "arrayResize", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayResize", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayPushBack", "args": [{"type": "any"}], "returns": "$1"} +{"name": "arrayPushBack", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayPushBack", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayPushFront", "args": [{"type": "any"}], "returns": "$1"} +{"name": "arrayPushFront", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayPushFront", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayPopBack", "args": [{"type": "any"}], "returns": "$1"} +{"name": "arrayPopBack", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayPopBack", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayPopFront", "args": [{"type": "any"}], "returns": "$1"} +{"name": "arrayPopFront", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayPopFront", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayFlatten", "args": [{"type": "any"}], "returns": "$1"} +{"name": "arrayFlatten", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayFlatten", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayCompact", "args": [{"type": "any"}], "returns": "$1"} +{"name": "arrayCompact", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayCompact", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayIntersect", "args": [{"type": "any"}], "returns": "$1"} +{"name": "arrayIntersect", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayIntersect", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayUnion", "args": [{"type": "any"}], "returns": "$1"} +{"name": "arrayUnion", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayUnion", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayShuffle", "args": [{"type": "any"}], "returns": "$1"} +{"name": "arrayShuffle", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayShuffle", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "arrayCount", "args": [{"type": "any"}], "returns": "UInt32"} +{"name": "arrayCount", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt32"} +{"name": "arrayUniq", "args": [{"type": "any"}], "returns": "UInt32"} +{"name": "arrayExists", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "arrayAll", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "hasSubstr", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "arrayEnumerate", "args": [{"type": "any"}], "returns": "Array(UInt32)"} +{"name": "arrayEnumerateUniq", "args": [{"type": "any"}], "returns": "Array(UInt32)"} +{"name": "range", "args": [{"type": "any"}], "returns": "Array(UInt64)"} +{"name": "range", "args": [{"type": "any"}, {"type": "any"}], "returns": "Array(UInt64)"} +{"name": "range", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "Array(UInt64)"} +{"name": "mapKeys", "args": [{"type": "any"}], "returns": "$1"} +{"name": "mapValues", "args": [{"type": "any"}], "returns": "$1"} +{"name": "length", "args": [{"type": "any"}], "returns": "UInt64"} +{"name": "JSONExtractInt", "args": [{"type": "any"}, {"type": "any"}], "returns": "Int64"} +{"name": "JSONExtractInt64", "args": [{"type": "any"}, {"type": "any"}], "returns": "Int64"} +{"name": "JSONExtractUInt", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt64"} +{"name": "JSONExtractFloat", "args": [{"type": "any"}, {"type": "any"}], "returns": "Float64"} +{"name": "JSONExtractBool", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "JSONHas", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "JSONLength", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt64"} +{"name": "JSONType", "args": [{"type": "any"}, {"type": "any"}], "returns": "Enum8"} +{"name": "isValidJSON", "args": [{"type": "any"}], "returns": "UInt8"} +{"name": "JSONArrayLength", "args": [{"type": "any"}], "returns": "UInt64", "nullable": true} +{"name": "simpleJSONExtractInt", "args": [{"type": "any"}, {"type": "any"}], "returns": "Int64"} +{"name": "simpleJSONExtractUInt", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt64"} +{"name": "simpleJSONExtractFloat", "args": [{"type": "any"}, {"type": "any"}], "returns": "Float64"} +{"name": "simpleJSONExtractBool", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "simpleJSONHas", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "visitParamExtractInt", "args": [{"type": "any"}, {"type": "any"}], "returns": "Int64"} +{"name": "visitParamExtractUInt", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt64"} +{"name": "visitParamExtractFloat", "args": [{"type": "any"}, {"type": "any"}], "returns": "Float64"} +{"name": "visitParamExtractBool", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "visitParamHas", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "IPv4StringToNum", "args": [{"type": "any"}], "returns": "UInt32"} +{"name": "IPv4StringToNumOrNull", "args": [{"type": "any"}], "returns": "UInt32", "nullable": true} +{"name": "IPv6StringToNum", "args": [{"type": "any"}], "returns": "FixedString(16)"} +{"name": "isIPv4String", "args": [{"type": "any"}], "returns": "UInt8"} +{"name": "isIPv6String", "args": [{"type": "any"}], "returns": "UInt8"} +{"name": "sleep", "args": [{"type": "any"}], "returns": "UInt8"} +{"name": "blockSize", "returns": "UInt64", "never_null": true} +{"name": "rowNumberInAllBlocks", "returns": "UInt64", "never_null": true} +{"name": "materialize", "args": [{"type": "any"}], "returns": "$1"} +{"name": "ignore", "args": [{"type": "any"}], "returns": "UInt8", "never_null": true} +{"name": "ifNotFinite", "args": [{"type": "any"}, {"type": "any"}], "returns": "$1"} +{"name": "throwIf", "args": [{"type": "any"}], "returns": "UInt8"} +{"name": "transform", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$4"} +{"name": "bar", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "bar", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "dictGetString", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "String"} +{"name": "dictGetUInt64", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "UInt64"} +{"name": "dictGetInt64", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "Int64"} +{"name": "dictGetFloat64", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "Float64"} +{"name": "dictGetDate", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "Date"} +{"name": "dictGetDateTime", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "DateTime"} +{"name": "dictHas", "args": [{"type": "any"}, {"type": "any"}], "returns": "UInt8"} +{"name": "tuple", "args": [{"type": "any"}], "returns": "Tuple"} +{"name": "tupleElement", "args": [{"type": "any"}, {"type": "any"}], "returns": "any"} +{"name": "map", "args": [{"type": "any"}, {"type": "any"}], "returns": "Map"} +{"name": "multiIf", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$2"} +{"name": "multiIf", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$2"} +{"name": "multiIf", "args": [{"type": "any"}, {"type": "any"}, {"type": "any"}, {"type": "any"}, {"type": "any"}, {"type": "any"}, {"type": "any"}], "returns": "$2"} diff --git a/internal/engine/clickhouse/dialect/types.jsonl b/internal/engine/clickhouse/dialect/types.jsonl new file mode 100644 index 0000000..eb1b00e --- /dev/null +++ b/internal/engine/clickhouse/dialect/types.jsonl @@ -0,0 +1,66 @@ +{"name":"AggregateFunction","category":"U"} +{"name":"Array","category":"A"} +{"name":"BFloat16","category":"N"} +{"name":"Bool","category":"B","aliases":["boolean"]} +{"name":"Date","category":"D"} +{"name":"Date32","category":"D"} +{"name":"DateTime","category":"D","aliases":["TIMESTAMP"]} +{"name":"DateTime32","category":"D"} +{"name":"DateTime64","category":"D"} +{"name":"Decimal","category":"N","aliases":["DEC","FIXED","NUMERIC"]} +{"name":"Decimal128","category":"N"} +{"name":"Decimal256","category":"N"} +{"name":"Decimal32","category":"N"} +{"name":"Decimal64","category":"N"} +{"name":"Dynamic","category":"U"} +{"name":"Enum","category":"U"} +{"name":"Enum16","category":"U"} +{"name":"Enum8","category":"U"} +{"name":"FixedString","category":"S","aliases":["BINARY"]} +{"name":"Float32","category":"N","aliases":["FLOAT","REAL","SINGLE"]} +{"name":"Float64","category":"N","aliases":["DOUBLE","DOUBLE PRECISION"]} +{"name":"IPv4","category":"S","aliases":["INET4"]} +{"name":"IPv6","category":"S","aliases":["INET6"]} +{"name":"Int128","category":"N"} +{"name":"Int16","category":"N","aliases":["SMALLINT","SMALLINT SIGNED"]} +{"name":"Int256","category":"N"} +{"name":"Int32","category":"N","aliases":["INT","INT SIGNED","INTEGER","INTEGER SIGNED","MEDIUMINT","MEDIUMINT SIGNED"]} +{"name":"Int64","category":"N","aliases":["BIGINT","BIGINT SIGNED","SIGNED"]} +{"name":"Int8","category":"N","aliases":["BYTE","INT1","INT1 SIGNED","TINYINT","TINYINT SIGNED"]} +{"name":"IntervalDay","category":"T"} +{"name":"IntervalHour","category":"T"} +{"name":"IntervalMicrosecond","category":"T"} +{"name":"IntervalMillisecond","category":"T"} +{"name":"IntervalMinute","category":"T"} +{"name":"IntervalMonth","category":"T"} +{"name":"IntervalNanosecond","category":"T"} +{"name":"IntervalQuarter","category":"T"} +{"name":"IntervalSecond","category":"T"} +{"name":"IntervalWeek","category":"T"} +{"name":"IntervalYear","category":"T"} +{"name":"JSON","category":"U"} +{"name":"LineString","category":"U"} +{"name":"LowCardinality","category":"U"} +{"name":"Map","category":"U"} +{"name":"MultiLineString","category":"U"} +{"name":"MultiPolygon","category":"U"} +{"name":"Nested","category":"U"} +{"name":"Nothing","category":"U"} +{"name":"Nullable","category":"U"} +{"name":"Object","category":"U"} +{"name":"Point","category":"U"} +{"name":"Polygon","category":"U"} +{"name":"Ring","category":"U"} +{"name":"SimpleAggregateFunction","category":"U"} +{"name":"String","category":"S","aliases":["BINARY LARGE OBJECT","BINARY VARYING","BLOB","BYTEA","CHAR","CHAR LARGE OBJECT","CHAR VARYING","CHARACTER","CHARACTER LARGE OBJECT","CHARACTER VARYING","CLOB","GEOMETRY","LONGBLOB","LONGTEXT","MEDIUMBLOB","MEDIUMTEXT","NATIONAL CHAR","NATIONAL CHAR VARYING","NATIONAL CHARACTER","NATIONAL CHARACTER LARGE OBJECT","NATIONAL CHARACTER VARYING","NCHAR","NCHAR LARGE OBJECT","NCHAR VARYING","NVARCHAR","TEXT","TINYBLOB","TINYTEXT","VARBINARY","VARCHAR","VARCHAR2"]} +{"name":"Time","category":"D"} +{"name":"Time64","category":"D"} +{"name":"Tuple","category":"U"} +{"name":"UInt128","category":"N"} +{"name":"UInt16","category":"N","aliases":["SMALLINT UNSIGNED","YEAR"]} +{"name":"UInt256","category":"N"} +{"name":"UInt32","category":"N","aliases":["INT UNSIGNED","INTEGER UNSIGNED","MEDIUMINT UNSIGNED"]} +{"name":"UInt64","category":"N","aliases":["BIGINT UNSIGNED","BIT","SET","UNSIGNED"]} +{"name":"UInt8","category":"N","aliases":["INT1 UNSIGNED","TINYINT UNSIGNED"]} +{"name":"UUID","category":"S"} +{"name":"Variant","category":"U"} diff --git a/internal/engine/clickhouse/format.go b/internal/engine/clickhouse/format.go new file mode 100644 index 0000000..5d3cf10 --- /dev/null +++ b/internal/engine/clickhouse/format.go @@ -0,0 +1,29 @@ +package clickhouse + +// QuoteIdent returns a quoted identifier if it needs quoting. +// ClickHouse uses backticks or double quotes for quoting identifiers. +func (p *Parser) QuoteIdent(s string) string { + // For now, don't quote - can be extended to quote when necessary + return s +} + +// TypeName returns the SQL type name for the given namespace and name. +func (p *Parser) TypeName(ns, name string) string { + if ns != "" { + return ns + "." + name + } + return name +} + +// Param returns the parameter placeholder for the given number. +// ClickHouse uses {name:Type} for named parameters, but for positional +// parameters we use ? which is supported by the clickhouse-go driver. +func (p *Parser) Param(n int, numbered bool) string { + return "?" +} + +// Cast returns a type cast expression. +// ClickHouse uses CAST(expr AS type) syntax, same as MySQL. +func (p *Parser) Cast(arg, typeName string) string { + return "CAST(" + arg + " AS " + typeName + ")" +} diff --git a/internal/engine/clickhouse/parse.go b/internal/engine/clickhouse/parse.go new file mode 100644 index 0000000..fa77fd9 --- /dev/null +++ b/internal/engine/clickhouse/parse.go @@ -0,0 +1,125 @@ +package clickhouse + +import ( + "bytes" + "context" + "io" + + "github.com/sqlc-dev/doubleclick/parser" + + "github.com/sqlc-dev/sqlc/internal/source" + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +func NewParser() *Parser { + return &Parser{} +} + +type Parser struct{} + +func (p *Parser) Parse(r io.Reader) ([]ast.Statement, error) { + blob, err := io.ReadAll(r) + if err != nil { + return nil, err + } + + ctx := context.Background() + stmtNodes, err := parser.Parse(ctx, bytes.NewReader(blob)) + if err != nil { + return nil, err + } + + var stmts []ast.Statement + loc := 0 + for _, stmt := range stmtNodes { + start := stmt.Pos().Offset - 1 + if start < loc { + start = loc + } + end := statementEnd(blob, start) + + converter := &cc{} + out := converter.convert(stmt) + if _, ok := out.(*ast.TODO); ok { + loc = end + continue + } + + stmts = append(stmts, ast.Statement{ + Raw: &ast.RawStmt{ + Stmt: out, + StmtLocation: loc, + StmtLen: end - loc, + }, + }) + loc = end + } + + return stmts, nil +} + +func statementEnd(blob []byte, start int) int { + for i := start; i < len(blob); i++ { + switch blob[i] { + case '\'', '"', '`': + i = skipQuoted(blob, i) + case '-': + if i+1 < len(blob) && blob[i+1] == '-' { + i = skipLineComment(blob, i) + } + case '#': + i = skipLineComment(blob, i) + case '/': + if i+1 < len(blob) && blob[i+1] == '*' { + i = skipBlockComment(blob, i) + } + case ';': + return i + 1 + } + } + return len(blob) +} + +func skipQuoted(blob []byte, i int) int { + q := blob[i] + for j := i + 1; j < len(blob); j++ { + switch blob[j] { + case '\\': + j++ + case q: + if j+1 < len(blob) && blob[j+1] == q { + j++ + continue + } + return j + } + } + return len(blob) - 1 +} + +func skipLineComment(blob []byte, i int) int { + for j := i; j < len(blob); j++ { + if blob[j] == '\n' { + return j + } + } + return len(blob) - 1 +} + +func skipBlockComment(blob []byte, i int) int { + for j := i + 2; j < len(blob); j++ { + if blob[j] == '*' && j+1 < len(blob) && blob[j+1] == '/' { + return j + 1 + } + } + return len(blob) - 1 +} + +// https://clickhouse.com/docs/en/sql-reference/syntax#comments +func (p *Parser) CommentSyntax() source.CommentSyntax { + return source.CommentSyntax{ + Dash: true, // -- comment + SlashStar: true, // /* comment */ + Hash: true, // # comment (ClickHouse supports this) + } +} diff --git a/internal/engine/clickhouse/reserved.go b/internal/engine/clickhouse/reserved.go new file mode 100644 index 0000000..1a9ac45 --- /dev/null +++ b/internal/engine/clickhouse/reserved.go @@ -0,0 +1,150 @@ +package clickhouse + +import "strings" + +// https://clickhouse.com/docs/en/sql-reference/syntax#keywords +func (p *Parser) IsReservedKeyword(s string) bool { + switch strings.ToLower(s) { + case "add": + case "after": + case "alias": + case "all": + case "alter": + case "and": + case "anti": + case "any": + case "array": + case "as": + case "asc": + case "asof": + case "between": + case "both": + case "by": + case "case": + case "cast": + case "check": + case "cluster": + case "collate": + case "column": + case "comment": + case "constraint": + case "create": + case "cross": + case "cube": + case "database": + case "databases": + case "default": + case "delete": + case "desc": + case "describe": + case "detach": + case "distinct": + case "distributed": + case "drop": + case "else": + case "end": + case "engine": + case "exists": + case "explain": + case "expression": + case "extract": + case "false": + case "fetch": + case "final": + case "first": + case "for": + case "format": + case "from": + case "full": + case "function": + case "global": + case "grant": + case "group": + case "having": + case "if": + case "ilike": + case "in": + case "index": + case "inner": + case "insert": + case "interpolate": + case "interval": + case "into": + case "is": + case "join": + case "key": + case "kill": + case "last": + case "leading": + case "left": + case "like": + case "limit": + case "live": + case "local": + case "logs": + case "materialized": + case "modify": + case "natural": + case "not": + case "null": + case "nulls": + case "offset": + case "on": + case "optimize": + case "or": + case "order": + case "outer": + case "outfile": + case "over": + case "partition": + case "paste": + case "populate": + case "prewhere": + case "primary": + case "projection": + case "rename": + case "replace": + case "right": + case "rollup": + case "sample": + case "select": + case "semi": + case "set": + case "settings": + case "show": + case "storage": + case "substring": + case "sync": + case "system": + case "table": + case "tables": + case "temporary": + case "test": + case "then": + case "ties": + case "to": + case "top": + case "totals": + case "trailing": + case "trim": + case "true": + case "truncate": + case "ttl": + case "type": + case "union": + case "update": + case "use": + case "using": + case "uuid": + case "values": + case "view": + case "watch": + case "when": + case "where": + case "window": + case "with": + default: + return false + } + return true +} diff --git a/internal/engine/clickhouse/seed.go b/internal/engine/clickhouse/seed.go new file mode 100644 index 0000000..b87a704 --- /dev/null +++ b/internal/engine/clickhouse/seed.go @@ -0,0 +1,25 @@ +package clickhouse + +import ( + "embed" + + "github.com/sqlc-dev/sqlc/internal/core" + "github.com/sqlc-dev/sqlc/internal/core/seed" +) + +// The dialect directory describes ClickHouse's type system. types.jsonl is +// generated from system.data_type_families of the pinned ClickHouse release +// by goldeneye (internal/goldeneye), which also checks it against one; +// dialect.json and functions.jsonl are authored by hand, since ClickHouse +// publishes no function signatures. Regenerate from internal/goldeneye with: +// +// go run ./cmd/goldeneye install clickhouse +// go run ./cmd/goldeneye generate clickhouse +// +//go:embed dialect +var dialectFS embed.FS + +// Dialect returns the catalog option that seeds ClickHouse's type system. +func Dialect() core.Option { + return seed.Dialect(dialectFS, "dialect") +} diff --git a/internal/engine/clickhouse/stdlib.go b/internal/engine/clickhouse/stdlib.go new file mode 100644 index 0000000..da7b53a --- /dev/null +++ b/internal/engine/clickhouse/stdlib.go @@ -0,0 +1,9 @@ +package clickhouse + +import ( + "github.com/sqlc-dev/sqlc/internal/sql/catalog" +) + +func defaultSchema(name string) *catalog.Schema { + return &catalog.Schema{Name: name} +} diff --git a/internal/engine/clickhouse/utils.go b/internal/engine/clickhouse/utils.go new file mode 100644 index 0000000..9e52f4d --- /dev/null +++ b/internal/engine/clickhouse/utils.go @@ -0,0 +1,59 @@ +package clickhouse + +import ( + "log" + "strings" + + chast "github.com/sqlc-dev/doubleclick/ast" + + "github.com/sqlc-dev/sqlc/internal/debug" + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +func todo(n chast.Node) *ast.TODO { + if debug.Active { + log.Printf("clickhouse.convert: Unknown node type %T\n", n) + } + return &ast.TODO{} +} + +func identifier(id string) string { + return strings.ToLower(id) +} + +func NewIdentifier(t string) *ast.String { + return &ast.String{Str: identifier(t)} +} + +func parseTableName(n *chast.TableIdentifier) *ast.TableName { + return &ast.TableName{ + Schema: identifier(n.Database), + Name: identifier(n.Table), + } +} + +func parseTableIdentifierToRangeVar(n *chast.TableIdentifier) *ast.RangeVar { + schemaname := identifier(n.Database) + relname := identifier(n.Table) + return &ast.RangeVar{ + Schemaname: &schemaname, + Relname: &relname, + } +} + +func isNotNull(n *chast.ColumnDeclaration) bool { + if n.Type == nil { + return false + } + // Check if type is wrapped in Nullable() + // If it's Nullable, it can be null, so return false + // If it's not Nullable, it's NOT NULL by default in ClickHouse + if n.Type.Name != "" && strings.ToLower(n.Type.Name) == "nullable" { + return false + } + // Also check if Nullable field is explicitly set + if n.Nullable != nil && *n.Nullable { + return false + } + return true +} diff --git a/internal/engine/dolphin/CLAUDE.md b/internal/engine/dolphin/CLAUDE.md new file mode 100644 index 0000000..0a11012 --- /dev/null +++ b/internal/engine/dolphin/CLAUDE.md @@ -0,0 +1,225 @@ +# Dolphin Engine (MySQL) - Claude Code Guide + +The dolphin engine handles MySQL parsing and AST conversion using the Marino parser +(a sqlc-maintained fork of the TiDB / pingcap parser). + +## Architecture + +### Parser Flow +``` +SQL String → Marino Parser → Marino AST → sqlc AST → Analysis/Codegen +``` + +### Key Files +- `convert.go` - Converts Marino AST nodes to sqlc AST nodes +- `format.go` - MySQL-specific formatting (identifiers, types, parameters) +- `parse.go` - Entry point for parsing MySQL SQL + +## Marino Parser + +The Marino parser (`github.com/sqlc-dev/marino`) is used for MySQL parsing. It is a +hard fork of `github.com/pingcap/tidb/pkg/parser` with a flatter package layout +(no `pkg/parser/...` prefix) and the former `test_driver` types merged into the +`ast` package as `ValueExprBase` / `ParamMarkerExprBase`. + +```go +import ( + pcast "github.com/sqlc-dev/marino/ast" + "github.com/sqlc-dev/marino/mysql" + "github.com/sqlc-dev/marino/types" +) +``` + +### Common Marino Types +- `pcast.SelectStmt`, `pcast.InsertStmt`, etc. - Statement types +- `pcast.ColumnNameExpr` - Column reference +- `pcast.FuncCallExpr` - Function call +- `pcast.BinaryOperationExpr` - Binary expression +- `pcast.VariableExpr` - MySQL user variable (@var) +- `pcast.Join` - JOIN clause with Left, Right, On, Using + +## Conversion Pattern + +Each TiDB node type has a corresponding converter method: + +```go +func (c *cc) convertSelectStmt(n *pcast.SelectStmt) *ast.SelectStmt { + return &ast.SelectStmt{ + FromClause: c.convertTableRefsClause(n.From), + WhereClause: c.convert(n.Where), + // ... + } +} +``` + +The main `convert()` method dispatches to specific converters: +```go +func (c *cc) convert(node pcast.Node) ast.Node { + switch n := node.(type) { + case *pcast.SelectStmt: + return c.convertSelectStmt(n) + case *pcast.InsertStmt: + return c.convertInsertStmt(n) + // ... + } +} +``` + +## Key Conversions + +### Column References +```go +func (c *cc) convertColumnNameExpr(n *pcast.ColumnNameExpr) *ast.ColumnRef { + var items []ast.Node + if schema := n.Name.Schema.String(); schema != "" { + items = append(items, NewIdentifier(schema)) + } + if table := n.Name.Table.String(); table != "" { + items = append(items, NewIdentifier(table)) + } + items = append(items, NewIdentifier(n.Name.Name.String())) + return &ast.ColumnRef{Fields: &ast.List{Items: items}} +} +``` + +### JOINs +```go +func (c *cc) convertJoin(n *pcast.Join) *ast.List { + if n.Right != nil && n.Left != nil { + return &ast.List{ + Items: []ast.Node{&ast.JoinExpr{ + Jointype: ast.JoinType(n.Tp), + Larg: c.convert(n.Left), + Rarg: c.convert(n.Right), + Quals: c.convert(n.On), + UsingClause: convertUsing(n.Using), + }}, + } + } + // No join - just return tables + // ... +} +``` + +### MySQL User Variables +MySQL user variables (`@var`) are different from sqlc's `@param` syntax: +```go +func (c *cc) convertVariableExpr(n *pcast.VariableExpr) ast.Node { + // Use VariableExpr to preserve as-is (NOT A_Expr which would be treated as sqlc param) + return &ast.VariableExpr{ + Name: n.Name, + Location: n.OriginTextPosition(), + } +} +``` + +### Type Casts (CAST AS) +```go +func (c *cc) convertFuncCastExpr(n *pcast.FuncCastExpr) ast.Node { + typeName := types.TypeStr(n.Tp.GetType()) + // Handle UNSIGNED/SIGNED specially + if typeName == "bigint" { + if mysql.HasUnsignedFlag(n.Tp.GetFlag()) { + typeName = "bigint unsigned" + } else { + typeName = "bigint signed" + } + } + return &ast.TypeCast{ + Arg: c.convert(n.Expr), + TypeName: &ast.TypeName{Name: typeName}, + } +} +``` + +### Column Definitions +```go +func convertColumnDef(def *pcast.ColumnDef) *ast.ColumnDef { + typeName := &ast.TypeName{Name: types.TypeToStr(def.Tp.GetType(), def.Tp.GetCharset())} + + // Only add Typmods for types where length is meaningful + tp := def.Tp.GetType() + flen := def.Tp.GetFlen() + switch tp { + case mysql.TypeVarchar, mysql.TypeString, mysql.TypeVarString: + if flen >= 0 { + typeName.Typmods = &ast.List{ + Items: []ast.Node{&ast.Integer{Ival: int64(flen)}}, + } + } + // Don't add for DATETIME, TIMESTAMP - internal flen is not user-specified + } + // ... +} +``` + +### Multi-Table DELETE +MySQL supports `DELETE t1, t2 FROM t1 JOIN t2 ...`: +```go +func (c *cc) convertDeleteStmt(n *pcast.DeleteStmt) *ast.DeleteStmt { + if n.IsMultiTable && n.Tables != nil { + // Convert targets (t1.*, t2.*) + targets := &ast.List{} + for _, table := range n.Tables.Tables { + // Build ColumnRef for each target + } + stmt.Targets = targets + + // Preserve JOINs in FromClause + stmt.FromClause = c.convertTableRefsClause(n.TableRefs).Items[0] + } else { + // Single-table DELETE + stmt.Relations = c.convertTableRefsClause(n.TableRefs) + } +} +``` + +## MySQL-Specific Formatting + +### format.go +```go +func (p *Parser) TypeName(ns, name string) string { + switch name { + case "bigint unsigned": + return "UNSIGNED" + case "bigint signed": + return "SIGNED" + } + return name +} + +func (p *Parser) Param(n int) string { + return "?" // MySQL uses ? for all parameters +} +``` + +## Common Issues and Solutions + +### Issue: Panic in Walk/Apply +**Cause**: New AST node type not handled in `astutils/walk.go` or `astutils/rewrite.go` +**Solution**: Add case for the node type in both files + +### Issue: MySQL @variable being treated as parameter +**Cause**: The preprocessor's dialect said `@name` is sqlc syntax +**Solution**: MySQL sets `AtSign: false` in `internal/sql/preprocess/dialect.go`, so +`@user_id` is left alone before the parser ever sees it + +### Issue: Type length appearing incorrectly (e.g., datetime(39)) +**Cause**: Using internal `flen` for all types +**Solution**: Only populate `Typmods` for types where length is user-specified (varchar, char, etc.) + +## Testing + +### TestFormat +Tests that SQL can be: +1. Parsed +2. Formatted back to SQL +3. Re-parsed +4. Re-formatted to match + +### TestReplay +Tests the full sqlc pipeline: +1. Parse schema and queries +2. Analyze +3. Generate code +4. Compare with expected output diff --git a/internal/engine/dolphin/catalog.go b/internal/engine/dolphin/catalog.go new file mode 100644 index 0000000..e7872f7 --- /dev/null +++ b/internal/engine/dolphin/catalog.go @@ -0,0 +1,16 @@ +package dolphin + +import ( + "github.com/sqlc-dev/sqlc/internal/sql/catalog" +) + +func NewCatalog() *catalog.Catalog { + def := "public" // TODO: What is the default database for MySQL? + return &catalog.Catalog{ + DefaultSchema: def, + Schemas: []*catalog.Schema{ + defaultSchema(def), + }, + Extensions: map[string]struct{}{}, + } +} diff --git a/internal/engine/dolphin/convert.go b/internal/engine/dolphin/convert.go new file mode 100644 index 0000000..4a01a68 --- /dev/null +++ b/internal/engine/dolphin/convert.go @@ -0,0 +1,2266 @@ +package dolphin + +import ( + "log" + "strconv" + "strings" + + pcast "github.com/sqlc-dev/marino/ast" + "github.com/sqlc-dev/marino/format" + "github.com/sqlc-dev/marino/mysql" + "github.com/sqlc-dev/marino/opcode" + "github.com/sqlc-dev/marino/types" + + "github.com/sqlc-dev/sqlc/internal/debug" + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +type cc struct { + paramCount int + // preserveCase keeps identifiers exactly as written instead of + // lowercasing them for case-insensitive catalog matching; the format + // parser sets it (see NewFormatParser). + preserveCase bool +} + +func todo(n pcast.Node) *ast.TODO { + if debug.Active { + log.Printf("dolphin.convert: Unknown node type %T\n", n) + } + return &ast.TODO{} +} + +// identifier normalizes an identifier for the compiler, which matches +// case-insensitively by lowercasing everything. The format parser preserves +// the author's case instead: reprinting `Event` as `event` renames the +// table wherever table names are case-sensitive. +func (c *cc) identifier(id string) string { + if c.preserveCase { + return id + } + return strings.ToLower(id) +} + +func (c *cc) NewIdentifier(t string) *ast.String { + return &ast.String{Str: c.identifier(t)} +} + +func (c *cc) convertAlterTableStmt(n *pcast.AlterTableStmt) ast.Node { + alt := &ast.AlterTableStmt{ + Table: c.parseTableName(n.Table), + Cmds: &ast.List{}, + } + for _, spec := range n.Specs { + switch spec.Tp { + case pcast.AlterTableAddColumns: + for _, def := range spec.NewColumns { + name := def.Name.String() + alt.Cmds.Items = append(alt.Cmds.Items, &ast.AlterTableCmd{ + Name: &name, + Subtype: ast.AT_AddColumn, + Def: convertColumnDef(def), + }) + } + + case pcast.AlterTableDropColumn: + name := spec.OldColumnName.String() + alt.Cmds.Items = append(alt.Cmds.Items, &ast.AlterTableCmd{ + Name: &name, + Subtype: ast.AT_DropColumn, + MissingOk: spec.IfExists, + }) + + case pcast.AlterTableChangeColumn: + oldName := spec.OldColumnName.String() + alt.Cmds.Items = append(alt.Cmds.Items, &ast.AlterTableCmd{ + Name: &oldName, + Subtype: ast.AT_DropColumn, + }) + + for _, def := range spec.NewColumns { + name := def.Name.String() + alt.Cmds.Items = append(alt.Cmds.Items, &ast.AlterTableCmd{ + Name: &name, + Subtype: ast.AT_AddColumn, + Def: convertColumnDef(def), + }) + } + + case pcast.AlterTableModifyColumn: + for _, def := range spec.NewColumns { + name := def.Name.String() + alt.Cmds.Items = append(alt.Cmds.Items, &ast.AlterTableCmd{ + Name: &name, + Subtype: ast.AT_DropColumn, + }) + alt.Cmds.Items = append(alt.Cmds.Items, &ast.AlterTableCmd{ + Name: &name, + Subtype: ast.AT_AddColumn, + Def: convertColumnDef(def), + }) + } + + case pcast.AlterTableAlterColumn: + // spew.Dump("alter column", spec) + + case pcast.AlterTableAddConstraint: + // spew.Dump("add const", spec) + + case pcast.AlterTableRenameColumn: + // TODO: Returning here may be incorrect if there are multiple specs + oldName := spec.OldColumnName.String() + newName := spec.NewColumnName.String() + return &ast.RenameColumnStmt{ + Table: c.parseTableName(n.Table), + Col: &ast.ColumnRef{Name: oldName}, + NewName: &newName, + } + + case pcast.AlterTableRenameTable: + // TODO: Returning here may be incorrect if there are multiple specs + return &ast.RenameTableStmt{ + Table: c.parseTableName(n.Table), + NewName: &c.parseTableName(spec.NewTable).Name, + } + + default: + if debug.Active { + log.Printf("dolphin.convert: Unknown alter table cmd %v\n", spec.Tp) + } + continue + } + } + return alt +} + +func (c *cc) convertAssignment(n *pcast.Assignment) *ast.ResTarget { + name := c.identifier(n.Column.Name.String()) + target := &ast.ResTarget{ + Name: &name, + Val: c.convert(n.Expr), + } + // A multi-table UPDATE qualifies its SET columns (SET a.x = ..., b.x = + // ...); analysis matches on Name alone, but printing must keep the + // qualifier or both assignments collapse onto whichever table resolves. + if table := n.Column.Table.String(); table != "" { + table = c.identifier(table) + target.Relation = &table + } + return target +} + +// TODO: These codes should be defined in the sql/lang package +func opToName(o opcode.Op) string { + switch o { + // case opcode.And: + // case opcode.BitNeg: + // case opcode.Case: + // case opcode.Div: + case opcode.EQ: + return "=" + case opcode.GE: + return ">=" + case opcode.GT: + return ">" + // case opcode.In: + case opcode.IntDiv: + return "/" + // case opcode.IsFalsity: + // case opcode.IsNull: + // case opcode.IsTruth: + case opcode.LE: + return "<=" + case opcode.LT: + return "<" + case opcode.LeftShift: + return "<<" + // case opcode.Like: + case opcode.LogicAnd: + return "&" + case opcode.LogicOr: + return "|" + // case opcode.LogicXor: + case opcode.Minus: + return "-" + case opcode.Mod: + return "%" + case opcode.Mul: + return "*" + case opcode.NE: + return "!=" + case opcode.Not: + return "!" + // case opcode.NullEQ: + // case opcode.Or: + case opcode.Plus: + return "+" + case opcode.Regexp: + return "~" + case opcode.RightShift: + return ">>" + case opcode.Xor: + return "#" + default: + return o.String() + } +} + +func (c *cc) convertBinaryOperationExpr(n *pcast.BinaryOperationExpr) ast.Node { + if n.Op == opcode.LogicAnd || n.Op == opcode.LogicOr { + var boolop ast.BoolExprType + if n.Op == opcode.LogicAnd { + boolop = ast.BoolExprTypeAnd + } else { + boolop = ast.BoolExprTypeOr + } + return &ast.BoolExpr{ + Boolop: boolop, + Args: &ast.List{ + Items: []ast.Node{ + c.convert(n.L), + c.convert(n.R), + }, + }, + Location: n.OriginTextPosition(), + } + } else { + return &ast.A_Expr{ + // TODO: Set kind + Name: &ast.List{ + Items: []ast.Node{ + &ast.String{Str: opToName(n.Op)}, + }, + }, + Lexpr: c.convert(n.L), + Rexpr: c.convert(n.R), + Location: n.OriginTextPosition(), + } + } +} + +func (c *cc) convertCreateTableStmt(n *pcast.CreateTableStmt) ast.Node { + create := &ast.CreateTableStmt{ + Name: c.parseTableName(n.Table), + IfNotExists: n.IfNotExists, + } + if n.ReferTable != nil { + create.ReferTable = c.parseTableName(n.ReferTable) + } + for _, def := range n.Cols { + create.Cols = append(create.Cols, convertColumnDef(def)) + } + for _, opt := range n.Options { + switch opt.Tp { + case pcast.TableOptionComment: + create.Comment = opt.StrValue + } + } + return create +} + +func convertColumnDef(def *pcast.ColumnDef) *ast.ColumnDef { + var vals *ast.List + if len(def.Tp.GetElems()) > 0 { + vals = &ast.List{} + for i := range def.Tp.GetElems() { + vals.Items = append(vals.Items, &ast.String{ + Str: def.Tp.GetElems()[i], + }) + } + } + comment := "" + for _, opt := range def.Options { + switch opt.Tp { + case pcast.ColumnOptionComment: + if value, ok := opt.Expr.(*pcast.ValueExprBase); ok { + comment = value.GetString() + } + } + } + + // Build TypeName with modifiers for proper formatting + typeName := &ast.TypeName{Name: types.TypeToStr(def.Tp.GetType(), def.Tp.GetCharset())} + + // Add type modifiers (e.g., length for varchar(255), char(32)) + // Only for types where length is meaningful and user-specified + tp := def.Tp.GetType() + flen := def.Tp.GetFlen() + needsLength := false + switch tp { + case mysql.TypeVarchar, mysql.TypeString, mysql.TypeVarString: + // VARCHAR(n), CHAR(n) - always need length + needsLength = flen >= 0 + case mysql.TypeBlob, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob: + // BLOB types - only if user specified length (VARBINARY(n), BINARY(n)) + // Default blob types don't need length + needsLength = false + } + + if needsLength { + typeName.Typmods = &ast.List{ + Items: []ast.Node{ + &ast.Integer{Ival: int64(flen)}, + }, + } + } + + // DECIMAL(p,s) / NUMERIC(p,s) and FLOAT/DOUBLE with explicit precision: + // the parser leaves flen and decimal at -1 when the author wrote none, + // so their presence is the author's, and dropping them would change the + // column's type. + switch tp { + case mysql.TypeNewDecimal, mysql.TypeFloat, mysql.TypeDouble: + if flen >= 0 { + mods := []ast.Node{&ast.Integer{Ival: int64(flen)}} + if dec := def.Tp.GetDecimal(); dec > 0 { + mods = append(mods, &ast.Integer{Ival: int64(dec)}) + } + typeName.Typmods = &ast.List{Items: mods} + } + // MySQL drops an integer's display width except the one that means + // something: tinyint(1) is what drivers and codegen read as a boolean, + // and BOOLEAN itself is spelled that way. + case mysql.TypeTiny: + if flen == 1 { + typeName.Typmods = &ast.List{Items: []ast.Node{&ast.Integer{Ival: 1}}} + } + // A bit column's width is part of its type, and is 1 when left out. + case mysql.TypeBit: + if flen >= 0 { + typeName.Typmods = &ast.List{Items: []ast.Node{&ast.Integer{Ival: int64(flen)}}} + } + // A fractional-seconds precision is part of the type; zero is the + // default and is not written. + case mysql.TypeDatetime, mysql.TypeTimestamp, mysql.TypeDuration: + if fsp := def.Tp.GetDecimal(); fsp > 0 { + typeName.Typmods = &ast.List{Items: []ast.Node{&ast.Integer{Ival: int64(fsp)}}} + } + } + + columnDef := ast.ColumnDef{ + Colname: def.Name.String(), + TypeName: typeName, + IsNotNull: isNotNull(def), + IsUnsigned: isUnsigned(def), + Comment: comment, + Vals: vals, + } + if def.Tp.GetFlen() >= 0 { + length := def.Tp.GetFlen() + columnDef.Length = &length + } + + return &columnDef +} + +func (c *cc) convertColumnNameExpr(n *pcast.ColumnNameExpr) *ast.ColumnRef { + var items []ast.Node + if schema := n.Name.Schema.String(); schema != "" { + items = append(items, c.NewIdentifier(schema)) + } + if table := n.Name.Table.String(); table != "" { + items = append(items, c.NewIdentifier(table)) + } + items = append(items, c.NewIdentifier(n.Name.Name.String())) + return &ast.ColumnRef{ + Fields: &ast.List{ + Items: items, + }, + Location: n.OriginTextPosition(), + } +} + +func (c *cc) convertColumnNames(cols []*pcast.ColumnName) *ast.List { + list := &ast.List{Items: []ast.Node{}} + for i := range cols { + name := c.identifier(cols[i].Name.String()) + list.Items = append(list.Items, &ast.ResTarget{ + Name: &name, + Location: cols[i].OriginTextPosition(), + }) + } + return list +} + +func (c *cc) convertDeleteStmt(n *pcast.DeleteStmt) *ast.DeleteStmt { + stmt := &ast.DeleteStmt{ + WhereClause: c.convert(n.Where), + ReturningList: &ast.List{}, + WithClause: c.convertWithClause(n.With), + } + + if n.Limit != nil { + stmt.LimitCount = c.convert(n.Limit.Count) + } + + // Handle multi-table DELETE (DELETE t1, t2 FROM t1 JOIN t2 ...) + if n.IsMultiTable && n.Tables != nil && len(n.Tables.Tables) > 0 { + // Convert delete targets (e.g., jt.*, pt.*) + targets := &ast.List{} + for _, table := range n.Tables.Tables { + // Each table in the delete list is a ColumnRef like "jt.*" or "pt.*" + items := []ast.Node{} + if table.Schema.String() != "" { + items = append(items, c.NewIdentifier(table.Schema.String())) + } + items = append(items, c.NewIdentifier(table.Name.String())) + items = append(items, &ast.A_Star{}) + targets.Items = append(targets.Items, &ast.ColumnRef{ + Fields: &ast.List{Items: items}, + }) + } + stmt.Targets = targets + + // Convert FROM clause preserving JOINs + if n.TableRefs != nil { + fromList := c.convertTableRefsClause(n.TableRefs) + if len(fromList.Items) == 1 { + stmt.FromClause = fromList.Items[0] + } else { + stmt.FromClause = fromList + } + } + } else { + // Single-table DELETE + rels := c.convertTableRefsClause(n.TableRefs) + if len(rels.Items) != 1 { + panic("expected one range var") + } + relations := &ast.List{} + convertToRangeVarList(rels, relations) + stmt.Relations = relations + } + + return stmt +} + +func (c *cc) convertDropTableStmt(n *pcast.DropTableStmt) ast.Node { + drop := &ast.DropTableStmt{IfExists: n.IfExists} + for _, name := range n.Tables { + drop.Tables = append(drop.Tables, c.parseTableName(name)) + } + return drop +} + +func (c *cc) convertRenameTableStmt(n *pcast.RenameTableStmt) ast.Node { + list := &ast.List{Items: []ast.Node{}} + for _, table := range n.TableToTables { + list.Items = append(list.Items, &ast.RenameTableStmt{ + Table: c.parseTableName(table.OldTable), + NewName: &c.parseTableName(table.NewTable).Name, + }) + } + return list +} + +func (c *cc) convertExistsSubqueryExpr(n *pcast.ExistsSubqueryExpr) *ast.SubLink { + sublink := &ast.SubLink{ + SubLinkType: ast.EXISTS_SUBLINK, + } + if n.Sel != nil { + sublink.Subselect = c.convert(n.Sel) + } + return sublink +} + +func (c *cc) convertFieldList(n *pcast.FieldList) *ast.List { + fields := make([]ast.Node, len(n.Fields)) + for i := range n.Fields { + fields[i] = c.convertSelectField(n.Fields[i]) + } + return &ast.List{Items: fields} +} + +func (c *cc) convertFuncCallExpr(n *pcast.FuncCallExpr) ast.Node { + schema := n.Schema.String() + // Dispatch below compares against lowercase names; the emitted name + // goes through identifier so the format parser keeps the author's case. + name := strings.ToLower(n.FnName.String()) + emitted := c.identifier(n.FnName.String()) + + // TODO: Deprecate the usage of Funcname + items := []ast.Node{} + if schema != "" { + items = append(items, c.NewIdentifier(schema)) + } + items = append(items, c.NewIdentifier(emitted)) + + // Handle DATE_ADD/DATE_SUB specially to construct INTERVAL expressions + // These functions have args: [date, interval_value, TimeUnitExpr] + if (name == "date_add" || name == "date_sub") && len(n.Args) == 3 { + if timeUnit, ok := n.Args[2].(*pcast.TimeUnitExpr); ok { + args := &ast.List{ + Items: []ast.Node{ + c.convert(n.Args[0]), + &ast.IntervalExpr{ + Value: c.convert(n.Args[1]), + Unit: timeUnit.Unit.String(), + }, + }, + } + return &ast.FuncCall{ + Args: args, + Func: &ast.FuncName{ + Schema: schema, + Name: emitted, + }, + Funcname: &ast.List{ + Items: items, + }, + Location: n.OriginTextPosition(), + } + } + } + + args := &ast.List{} + for _, arg := range n.Args { + args.Items = append(args.Items, c.convert(arg)) + } + + if schema == "" && name == "coalesce" { + return &ast.CoalesceExpr{ + Args: args, + } + } else { + return &ast.FuncCall{ + Args: args, + Func: &ast.FuncName{ + Schema: schema, + Name: emitted, + }, + Funcname: &ast.List{ + Items: items, + }, + Location: n.OriginTextPosition(), + } + } +} + +func (c *cc) convertInsertStmt(n *pcast.InsertStmt) *ast.InsertStmt { + rels := c.convertTableRefsClause(n.Table) + if len(rels.Items) != 1 { + panic("expected one range var") + } + rel := rels.Items[0] + rangeVar, ok := rel.(*ast.RangeVar) + if !ok { + panic("expected range var") + } + + insert := &ast.InsertStmt{ + Relation: rangeVar, + Cols: c.convertColumnNames(n.Columns), + ReturningList: &ast.List{}, + } + if ss, ok := c.convert(n.Select).(*ast.SelectStmt); ok { + ss.ValuesLists = c.convertLists(n.Lists) + insert.SelectStmt = ss + } else { + insert.SelectStmt = &ast.SelectStmt{ + FromClause: &ast.List{}, + TargetList: &ast.List{}, + ValuesLists: c.convertLists(n.Lists), + } + } + + if n.OnDuplicate != nil { + targetList := &ast.List{} + for _, a := range n.OnDuplicate { + targetList.Items = append(targetList.Items, c.convertAssignment(a)) + } + insert.OnDuplicateKeyUpdate = &ast.OnDuplicateKeyUpdate{ + TargetList: targetList, + Location: n.OriginTextPosition(), + } + } + + return insert +} + +func (c *cc) convertLists(lists [][]pcast.ExprNode) *ast.List { + list := &ast.List{Items: []ast.Node{}} + for _, exprs := range lists { + inner := &ast.List{Items: []ast.Node{}} + for _, expr := range exprs { + inner.Items = append(inner.Items, c.convert(expr)) + } + list.Items = append(list.Items, inner) + } + return list +} + +func (c *cc) convertParamMarkerExpr(n *pcast.ParamMarkerExprBase) *ast.ParamRef { + // Parameter numbers start at one + c.paramCount += 1 + return &ast.ParamRef{ + Number: c.paramCount, + Location: n.Offset, + } +} + +func (c *cc) convertSelectField(n *pcast.SelectField) *ast.ResTarget { + var val ast.Node + if n.WildCard != nil { + val = c.convertWildCardField(n.WildCard) + } else { + val = c.convert(n.Expr) + } + var name *string + if n.AsName.O != "" { + asname := c.identifier(n.AsName.O) + name = &asname + } + return &ast.ResTarget{ + // TODO: Populate Indirection field + Name: name, + Val: val, + Location: n.Offset, + } +} + +func (c *cc) convertSelectStmt(n *pcast.SelectStmt) *ast.SelectStmt { + // The ORDER BY expressions are recorded twice: bare in WindowClause, + // where the compiler's strict_order_by validation expects them, and + // wrapped in SortBy nodes in SortClause, which carries the sort + // direction and is what formatting prints. Both share the same + // converted nodes so parameter numbering stays intact. + windowClause := &ast.List{Items: make([]ast.Node, 0)} + var sortClause *ast.List + if n.OrderBy != nil { + sortClause = &ast.List{Items: make([]ast.Node, 0)} + orderByClause := &ast.List{Items: []ast.Node{}} + for _, item := range n.OrderBy.Items { + expr := c.convert(item.Expr) + orderByClause.Items = append(orderByClause.Items, expr) + dir := ast.SortByDirDefault + if item.Desc { + dir = ast.SortByDirDesc + } + sortClause.Items = append(sortClause.Items, &ast.SortBy{ + Node: expr, + SortbyDir: dir, + }) + } + windowClause.Items = append(windowClause.Items, orderByClause) + } + + op, all := c.convertSetOprType(n.AfterSetOperator) + stmt := &ast.SelectStmt{ + TargetList: c.convertFieldList(n.Fields), + FromClause: c.convertTableRefsClause(n.From), + GroupClause: c.convertGroupByClause(n.GroupBy), + HavingClause: c.convertHavingClause(n.Having), + WhereClause: c.convert(n.Where), + WithClause: c.convertWithClause(n.With), + WindowClause: windowClause, + SortClause: sortClause, + Op: op, + All: all, + } + if n.Distinct { + // A plain DISTINCT, pg-style: a non-empty clause whose single TODO + // item means "no ON (...) expressions". + stmt.DistinctClause = &ast.List{Items: []ast.Node{&ast.TODO{}}} + } + stmt.TableHints = restoreTableHints(n.TableHints) + if n.Limit != nil { + stmt.LimitCount = c.convert(n.Limit.Count) + stmt.LimitOffset = c.convert(n.Limit.Offset) + } + return stmt +} + +// restoreTableHints renders a statement's optimizer hints back to the text +// inside their /*+ ... */ comment. The compiler has no use for hints, but +// dropping them from a query would change how the server runs it, so the +// statement carries them through to printing as text. +func restoreTableHints(hints []*pcast.TableOptimizerHint) string { + if len(hints) == 0 { + return "" + } + var sb strings.Builder + ctx := format.NewRestoreCtx(format.DefaultRestoreFlags, &sb) + for i, h := range hints { + if i != 0 { + sb.WriteString(" ") + } + if err := h.Restore(ctx); err != nil { + return "" + } + } + return sb.String() +} + +func (c *cc) convertSubqueryExpr(n *pcast.SubqueryExpr) ast.Node { + // Wrap subquery in SubLink to ensure parentheses are added + return &ast.SubLink{ + SubLinkType: ast.EXPR_SUBLINK, + Subselect: c.convert(n.Query), + } +} + +func (c *cc) convertTableRefsClause(n *pcast.TableRefsClause) *ast.List { + if n == nil { + return &ast.List{} + } + return c.convertJoin(n.TableRefs) +} + +func (c *cc) convertCommonTableExpression(n *pcast.CommonTableExpression) *ast.CommonTableExpr { + if n == nil { + return nil + } + + name := n.Name.String() + + columns := &ast.List{} + for _, col := range n.ColNameList { + columns.Items = append(columns.Items, c.NewIdentifier(col.String())) + } + + // CTE Query is wrapped in SubqueryExpr by TiDB parser. + // We need to unwrap it to get the SelectStmt directly, + // otherwise it would be double-wrapped with parentheses. + var cteQuery ast.Node + if n.Query != nil { + cteQuery = c.convert(n.Query.Query) + } + + return &ast.CommonTableExpr{ + Ctename: &name, + Ctequery: cteQuery, + Ctecolnames: columns, + } +} + +func (c *cc) convertWithClause(n *pcast.WithClause) *ast.WithClause { + if n == nil { + return nil + } + list := &ast.List{} + for _, n := range n.CTEs { + list.Items = append(list.Items, c.convertCommonTableExpression(n)) + } + + return &ast.WithClause{ + Ctes: list, + Recursive: n.IsRecursive, + Location: n.OriginTextPosition(), + } +} + +func (c *cc) convertUpdateStmt(n *pcast.UpdateStmt) *ast.UpdateStmt { + rels := c.convertTableRefsClause(n.TableRefs) + if len(rels.Items) != 1 { + panic("expected one range var") + } + + relations := &ast.List{} + convertToRangeVarList(rels, relations) + + // TargetList + list := &ast.List{} + for _, a := range n.List { + list.Items = append(list.Items, c.convertAssignment(a)) + } + stmt := &ast.UpdateStmt{ + Relations: relations, + TargetList: list, + WhereClause: c.convert(n.Where), + FromClause: &ast.List{}, + ReturningList: &ast.List{}, + WithClause: c.convertWithClause(n.With), + // The table-reference tree as written. Relations above flattens a + // multi-table UPDATE's join to bare tables for analysis, which + // would print `UPDATE a JOIN b ON ...` without its ON condition — + // an update of the whole cross product. + TableRefs: rels, + } + if n.Limit != nil { + stmt.LimitCount = c.convert(n.Limit.Count) + } + return stmt +} + +func (c *cc) convertValueExpr(n *pcast.ValueExprBase) *ast.A_Const { + // The datum's kind, not the field type, says what the literal is: a + // NULL arrives with a string field type, a decimal's value lives in + // its decimal — not float — slot, and TRUE is an int64 whose field + // type carries the boolean flag. + switch n.Datum.Kind() { + case pcast.KindNull: + return &ast.A_Const{ + Val: &ast.Null{}, + Location: n.OriginTextPosition(), + } + + case pcast.KindInt64: + if mysql.HasIsBooleanFlag(n.Type.GetFlag()) { + return &ast.A_Const{ + Val: &ast.Boolean{Boolval: n.Datum.GetInt64() > 0}, + Location: n.OriginTextPosition(), + } + } + return &ast.A_Const{ + Val: &ast.Integer{ + Ival: n.Datum.GetInt64(), + }, + Location: n.OriginTextPosition(), + } + + case pcast.KindUint64: + return &ast.A_Const{ + Val: &ast.Integer{ + Ival: int64(n.Datum.GetUint64()), + }, + Location: n.OriginTextPosition(), + } + + case pcast.KindFloat32, pcast.KindFloat64: + return &ast.A_Const{ + Val: &ast.Float{ + Str: strconv.FormatFloat(n.Datum.GetFloat64(), 'f', -1, 64), + }, + Location: n.OriginTextPosition(), + } + + case pcast.KindMysqlDecimal: + // The decimal's own rendering keeps the written scale: 1.0 stays + // 1.0. + return &ast.A_Const{ + Val: &ast.Float{ + Str: n.Datum.GetMysqlDecimal().String(), + }, + Location: n.OriginTextPosition(), + } + } + return &ast.A_Const{ + Val: &ast.String{ + Str: n.Datum.GetString(), + }, + Location: n.OriginTextPosition(), + } +} + +func (c *cc) convertWildCardField(n *pcast.WildCardField) *ast.ColumnRef { + items := []ast.Node{} + if t := n.Table.String(); t != "" { + items = append(items, c.NewIdentifier(t)) + } + items = append(items, &ast.A_Star{}) + + return &ast.ColumnRef{ + Fields: &ast.List{ + Items: items, + }, + } +} + +func (c *cc) convertAdminStmt(n *pcast.AdminStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertAggregateFuncExpr(n *pcast.AggregateFuncExpr) *ast.FuncCall { + // Comparisons below use the lowercase name; the emitted name keeps the + // author's case under the format parser. + name := strings.ToLower(n.F) + emitted := c.identifier(n.F) + fn := &ast.FuncCall{ + Func: &ast.FuncName{ + Name: emitted, + }, + Funcname: &ast.List{ + Items: []ast.Node{ + c.NewIdentifier(emitted), + }, + }, + Args: &ast.List{}, + AggOrder: &ast.List{}, + } + + // GROUP_CONCAT has special handling: + // TiDB always adds the separator as the last argument + // We need to extract it and use SEPARATOR syntax + args := n.Args + var separator string + if name == "group_concat" && len(args) >= 2 { + // The last arg is always the separator + if value, ok := args[len(args)-1].(*pcast.ValueExprBase); ok { + separator = value.GetString() + args = args[:len(args)-1] + } + } + + for _, a := range args { + if value, ok := a.(*pcast.ValueExprBase); ok { + if value.GetInt64() == int64(1) { + fn.AggStar = true + continue + } + } + fn.Args.Items = append(fn.Args.Items, c.convert(a)) + } + if n.Distinct { + fn.AggDistinct = true + } + // GROUP_CONCAT(x ORDER BY y): the ordering decides the string that + // comes back, so it must survive into the printed call. + if n.Order != nil { + fn.AggOrder = c.convertOrderByItems(n.Order.Items) + } + + // Store separator for GROUP_CONCAT (only if non-default) + if name == "group_concat" && separator != "" && separator != "," { + fn.Separator = &separator + } + + return fn +} + +func (c *cc) convertAlterDatabaseStmt(n *pcast.AlterDatabaseStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertAlterInstanceStmt(n *pcast.AlterInstanceStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertAlterTableSpec(n *pcast.AlterTableSpec) ast.Node { + return todo(n) +} + +func (c *cc) convertAlterUserStmt(n *pcast.AlterUserStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertAnalyzeTableStmt(n *pcast.AnalyzeTableStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertBRIEStmt(n *pcast.BRIEStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertBeginStmt(n *pcast.BeginStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertBetweenExpr(n *pcast.BetweenExpr) ast.Node { + return &ast.BetweenExpr{ + Expr: c.convert(n.Expr), + Left: c.convert(n.Left), + Right: c.convert(n.Right), + Location: n.OriginTextPosition(), + Not: n.Not, + } +} + +func (c *cc) convertBinlogStmt(n *pcast.BinlogStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertByItem(n *pcast.ByItem) ast.Node { + switch n.Expr.(type) { + case *pcast.PositionExpr: + return c.convertPositionExpr(n.Expr.(*pcast.PositionExpr)) + case *pcast.ColumnNameExpr: + return c.convertColumnNameExpr(n.Expr.(*pcast.ColumnNameExpr)) + default: + return todo(n) + } +} + +func (c *cc) convertCaseExpr(n *pcast.CaseExpr) ast.Node { + if n == nil { + return nil + } + list := &ast.List{Items: []ast.Node{}} + for _, n := range n.WhenClauses { + list.Items = append(list.Items, c.convertWhenClause(n)) + } + return &ast.CaseExpr{ + Arg: c.convert(n.Value), + Args: list, + Defresult: c.convert(n.ElseClause), + Location: n.OriginTextPosition(), + } +} + +func (c *cc) convertCleanupTableLockStmt(n *pcast.CleanupTableLockStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertColumnDef(n *pcast.ColumnDef) ast.Node { + return todo(n) +} + +func (c *cc) convertColumnName(n *pcast.ColumnName) ast.Node { + return todo(n) +} + +func (c *cc) convertColumnPosition(n *pcast.ColumnPosition) ast.Node { + return todo(n) +} + +func (c *cc) convertCommitStmt(n *pcast.CommitStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertCompareSubqueryExpr(n *pcast.CompareSubqueryExpr) ast.Node { + return todo(n) +} + +func (c *cc) convertConstraint(n *pcast.Constraint) ast.Node { + return todo(n) +} + +func (c *cc) convertCreateBindingStmt(n *pcast.CreateBindingStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertCreateDatabaseStmt(n *pcast.CreateDatabaseStmt) ast.Node { + return &ast.CreateSchemaStmt{ + Name: &n.Name.O, + IfNotExists: n.IfNotExists, + } +} + +func (c *cc) convertCreateIndexStmt(n *pcast.CreateIndexStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertCreateSequenceStmt(n *pcast.CreateSequenceStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertCreateStatisticsStmt(n *pcast.CreateStatisticsStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertCreateUserStmt(n *pcast.CreateUserStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertCreateViewStmt(n *pcast.CreateViewStmt) ast.Node { + return &ast.ViewStmt{ + View: c.convertTableName(n.ViewName), + Aliases: &ast.List{}, + Query: c.convert(n.Select), + Replace: n.OrReplace, + Options: &ast.List{}, + WithCheckOption: ast.ViewCheckOption(n.CheckOption), + } +} + +func (c *cc) convertDeallocateStmt(n *pcast.DeallocateStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertDefaultExpr(n *pcast.DefaultExpr) ast.Node { + return todo(n) +} + +func (c *cc) convertDeleteTableList(n *pcast.DeleteTableList) ast.Node { + return todo(n) +} + +func (c *cc) convertDoStmt(n *pcast.DoStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertDropBindingStmt(n *pcast.DropBindingStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertDropDatabaseStmt(n *pcast.DropDatabaseStmt) ast.Node { + return &ast.DropSchemaStmt{ + MissingOk: !n.IfExists, + Schemas: []*ast.String{ + c.NewIdentifier(n.Name.O), + }, + } +} + +func (c *cc) convertDropIndexStmt(n *pcast.DropIndexStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertDropSequenceStmt(n *pcast.DropSequenceStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertDropStatisticsStmt(n *pcast.DropStatisticsStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertDropStatsStmt(n *pcast.DropStatsStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertDropUserStmt(n *pcast.DropUserStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertExecuteStmt(n *pcast.ExecuteStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertExplainForStmt(n *pcast.ExplainForStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertExplainStmt(n *pcast.ExplainStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertFlashBackTableStmt(n *pcast.FlashBackTableStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertFlushStmt(n *pcast.FlushStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertFrameBound(n *pcast.FrameBound) ast.Node { + return todo(n) +} + +func (c *cc) convertFrameClause(n *pcast.FrameClause) ast.Node { + return todo(n) +} + +func (c *cc) convertFuncCastExpr(n *pcast.FuncCastExpr) ast.Node { + tp := n.Tp.GetType() + typeName := types.TypeToStr(tp, n.Tp.GetCharset()) + + // MySQL CAST AS UNSIGNED/SIGNED uses bigint internally. + // We need to preserve the signed/unsigned info for formatting. + if typeName == "bigint" { + if mysql.HasUnsignedFlag(n.Tp.GetFlag()) { + typeName = "bigint unsigned" + } else { + typeName = "bigint signed" + } + } + // CAST(x AS CHAR) and CAST(x AS BINARY) are typed by the parser as the + // wire's var_string, which is no SQL type, or as a char or binary. + // MySQL types the result as a varchar or a varbinary — its metadata + // and a view over it both say so. + switch typeName { + case "var_string", "char": + typeName = "varchar" + if n.Tp.GetCharset() == "binary" { + typeName = "varbinary" + } + case "binary": + typeName = "varbinary" + } + + out := &ast.TypeName{Name: typeName} + flen, dec := n.Tp.GetFlen(), n.Tp.GetDecimal() + switch tp { + case mysql.TypeNewDecimal: + // A decimal's precision and scale are part of its type, and a + // scale left out is 0: CAST(x AS DECIMAL(5)) is a decimal(5,0). + if flen >= 0 && flen != types.UnspecifiedLength { + mods := []ast.Node{&ast.Integer{Ival: int64(flen)}} + if dec >= 0 && dec != types.UnspecifiedLength { + mods = append(mods, &ast.Integer{Ival: int64(dec)}) + } + out.Typmods = &ast.List{Items: mods} + } + case mysql.TypeFloat, mysql.TypeDouble: + // The parser fills in a display width for a float or double, and + // a precision written as FLOAT(p) only picks between the two; the + // result is a plain float or double. + case mysql.TypeVarchar, mysql.TypeVarString, mysql.TypeString: + if flen > 0 && flen != types.UnspecifiedLength { + out.Typmods = &ast.List{Items: []ast.Node{&ast.Integer{Ival: int64(flen)}}} + } + case mysql.TypeDatetime, mysql.TypeTimestamp, mysql.TypeDuration: + if dec > 0 && dec != types.UnspecifiedLength { + out.Typmods = &ast.List{Items: []ast.Node{&ast.Integer{Ival: int64(dec)}}} + } + } + + return &ast.TypeCast{ + Arg: c.convert(n.Expr), + TypeName: out, + } +} + +func (c *cc) convertGetFormatSelectorExpr(n *pcast.GetFormatSelectorExpr) ast.Node { + return todo(n) +} + +func (c *cc) convertGrantRoleStmt(n *pcast.GrantRoleStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertGrantStmt(n *pcast.GrantStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertGroupByClause(n *pcast.GroupByClause) *ast.List { + if n == nil { + return &ast.List{} + } + + var items []ast.Node + for _, item := range n.Items { + items = append(items, c.convertByItem(item)) + } + + return &ast.List{ + Items: items, + } +} + +func (c *cc) convertHavingClause(n *pcast.HavingClause) ast.Node { + if n == nil { + return nil + } + return c.convert(n.Expr) +} + +func (c *cc) convertIndexLockAndAlgorithm(n *pcast.IndexLockAndAlgorithm) ast.Node { + return todo(n) +} + +func (c *cc) convertIndexPartSpecification(n *pcast.IndexPartSpecification) ast.Node { + return todo(n) +} + +func (c *cc) convertIsNullExpr(n *pcast.IsNullExpr) ast.Node { + op := ast.BoolExprTypeIsNull + if n.Not { + op = ast.BoolExprTypeIsNotNull + } + return &ast.BoolExpr{ + Boolop: op, + Args: &ast.List{ + Items: []ast.Node{ + c.convert(n.Expr), + }, + }, + Location: n.OriginTextPosition(), + } +} + +func (c *cc) convertIsTruthExpr(n *pcast.IsTruthExpr) ast.Node { + return todo(n) +} + +func (c *cc) convertJoin(n *pcast.Join) *ast.List { + if n == nil { + return &ast.List{} + } + if n.Right != nil && n.Left != nil { + // MySQL doesn't have a FULL join type + joinType := ast.JoinType(n.Tp) + if joinType >= ast.JoinTypeFull { + joinType++ + } + + // Convert USING clause + var usingClause *ast.List + if len(n.Using) > 0 { + items := make([]ast.Node, len(n.Using)) + for i, col := range n.Using { + items[i] = &ast.String{Str: col.Name.O} + } + usingClause = &ast.List{Items: items} + } + + return &ast.List{ + Items: []ast.Node{&ast.JoinExpr{ + Jointype: joinType, + IsNatural: n.NaturalJoin, + Larg: c.convert(n.Left), + Rarg: c.convert(n.Right), + UsingClause: usingClause, + Quals: c.convert(n.On), + }}, + } + } + var tables []ast.Node + if n.Right != nil { + tables = append(tables, c.convert(n.Right)) + } + if n.Left != nil { + tables = append(tables, c.convert(n.Left)) + } + return &ast.List{Items: tables} +} + +func (c *cc) convertKillStmt(n *pcast.KillStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertLimit(n *pcast.Limit) ast.Node { + return todo(n) +} + +func (c *cc) convertLoadDataStmt(n *pcast.LoadDataStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertLoadStatsStmt(n *pcast.LoadStatsStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertLockTablesStmt(n *pcast.LockTablesStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertMatchAgainst(n *pcast.MatchAgainst) ast.Node { + searchTerm := c.convert(n.Against) + + stringSearchTerm := &ast.TypeCast{ + Arg: searchTerm, + TypeName: &ast.TypeName{ + Name: "text", // Use 'text' type which maps to string in Go + }, + Location: n.OriginTextPosition(), + } + + matchOperation := &ast.A_Const{ + Val: &ast.String{Str: "MATCH_AGAINST"}, + } + + return &ast.A_Expr{ + Name: &ast.List{ + Items: []ast.Node{ + &ast.String{Str: "AGAINST"}, + }, + }, + Lexpr: matchOperation, + Rexpr: stringSearchTerm, + Location: n.OriginTextPosition(), + } +} + +func (c *cc) convertMaxValueExpr(n *pcast.MaxValueExpr) ast.Node { + return todo(n) +} + +func (c *cc) convertOnCondition(n *pcast.OnCondition) ast.Node { + if n == nil { + return nil + } + return c.convert(n.Expr) +} + +func (c *cc) convertOnDeleteOpt(n *pcast.OnDeleteOpt) ast.Node { + return todo(n) +} + +func (c *cc) convertOnUpdateOpt(n *pcast.OnUpdateOpt) ast.Node { + return todo(n) +} + +func (c *cc) convertOrderByClause(n *pcast.OrderByClause) ast.Node { + if n == nil { + return nil + } + list := &ast.List{Items: []ast.Node{}} + for _, item := range n.Items { + list.Items = append(list.Items, c.convert(item.Expr)) + } + return list +} + +func (c *cc) convertParenthesesExpr(n *pcast.ParenthesesExpr) ast.Node { + if n == nil { + return nil + } + inner := c.convert(n.Expr) + // Only wrap in ParenExpr for SELECT statements (needed for UNION with parenthesized subqueries) + // For other expressions, the BoolExpr already adds parentheses + if _, ok := inner.(*ast.SelectStmt); ok { + return &ast.ParenExpr{ + Expr: inner, + Location: n.OriginTextPosition(), + } + } + return inner +} + +func (c *cc) convertPartitionByClause(n *pcast.PartitionByClause) ast.Node { + return todo(n) +} + +func (c *cc) convertPatternInExpr(n *pcast.PatternInExpr) ast.Node { + var list []ast.Node + var val ast.Node + + expr := c.convert(n.Expr) + + for _, v := range n.List { + val = c.convert(v) + if val != nil { + list = append(list, val) + } + } + + sel := c.convert(n.Sel) + + in := &ast.In{ + Expr: expr, + List: list, + Not: n.Not, + Sel: sel, + Location: n.OriginTextPosition(), + } + + return in +} + +func (c *cc) convertPatternLikeExpr(n *pcast.PatternLikeOrIlikeExpr) ast.Node { + kind := ast.A_Expr_Kind_ILIKE + op := "~~*" + if n.IsLike { + kind = ast.A_Expr_Kind_LIKE + op = "~~" + } + if n.Not { + op = "!" + op + } + return &ast.A_Expr{ + Kind: kind, + Name: &ast.List{ + Items: []ast.Node{ + &ast.String{Str: op}, + }, + }, + Lexpr: c.convert(n.Expr), + Rexpr: c.convert(n.Pattern), + } +} + +func (c *cc) convertPatternRegexpExpr(n *pcast.PatternRegexpExpr) ast.Node { + return todo(n) +} + +func (c *cc) convertPositionExpr(n *pcast.PositionExpr) ast.Node { + return &ast.Integer{Ival: int64(n.N)} +} + +func (c *cc) convertPrepareStmt(n *pcast.PrepareStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertPrivElem(n *pcast.PrivElem) ast.Node { + return todo(n) +} + +func (c *cc) convertRecoverTableStmt(n *pcast.RecoverTableStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertReferenceDef(n *pcast.ReferenceDef) ast.Node { + return todo(n) +} + +func (c *cc) convertRepairTableStmt(n *pcast.RepairTableStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertRevokeRoleStmt(n *pcast.RevokeRoleStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertRevokeStmt(n *pcast.RevokeStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertRollbackStmt(n *pcast.RollbackStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertRowExpr(n *pcast.RowExpr) ast.Node { + return todo(n) +} + +func (c *cc) convertSetCollationExpr(n *pcast.SetCollationExpr) ast.Node { + return todo(n) +} + +func (c *cc) convertSetConfigStmt(n *pcast.SetConfigStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertSetDefaultRoleStmt(n *pcast.SetDefaultRoleStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertSetOprType(n *pcast.SetOprType) (op ast.SetOperation, all bool) { + if n == nil { + return + } + + switch *n { + case pcast.Union: + op = ast.Union + case pcast.UnionAll: + op = ast.Union + all = true + case pcast.Intersect: + op = ast.Intersect + case pcast.IntersectAll: + op = ast.Intersect + all = true + case pcast.Except: + op = ast.Except + case pcast.ExceptAll: + op = ast.Except + all = true + } + return +} + +// convertSetOprSelectList converts a list of SELECT from the Pingcap parser +// into a tree. It is called for UNION, INTERSECT or EXCLUDE operation. +// +// Given an union with the following nodes: +// +// [Select{1}, Select{2}, Select{3}, Select{4}] +// +// The function will return: +// +// Select{ +// Larg: Select{ +// Larg: Select{ +// Larg: Select{1}, +// Rarg: Select{2}, +// Op: Union +// }, +// Rarg: Select{3}, +// Op: Union, +// }, +// Rarg: Select{4}, +// Op: Union, +// } +func (c *cc) convertSetOprSelectList(n *pcast.SetOprSelectList) ast.Node { + selectStmts := make([]*ast.SelectStmt, len(n.Selects)) + for i, node := range n.Selects { + switch node := node.(type) { + case *pcast.SelectStmt: + selectStmts[i] = c.convertSelectStmt(node) + case *pcast.SetOprSelectList: + // If this is a single-select SetOprSelectList (e.g., from parenthesized SELECT), + // extract the inner select instead of building a UNION tree + if len(node.Selects) == 1 { + if innerSelect, ok := node.Selects[0].(*pcast.SelectStmt); ok { + selectStmts[i] = c.convertSelectStmt(innerSelect) + } else { + selectStmts[i] = c.convertSetOprSelectList(node).(*ast.SelectStmt) + } + } else { + selectStmts[i] = c.convertSetOprSelectList(node).(*ast.SelectStmt) + } + default: + // Handle other node types like ParenthesesExpr wrapping a SELECT + converted := c.convert(node) + if ss, ok := converted.(*ast.SelectStmt); ok { + selectStmts[i] = ss + } else if pe, ok := converted.(*ast.ParenExpr); ok { + // Unwrap ParenExpr to get the inner SelectStmt + if inner, ok := pe.Expr.(*ast.SelectStmt); ok { + selectStmts[i] = inner + } + } + } + } + + op, all := c.convertSetOprType(n.AfterSetOperator) + tree := &ast.SelectStmt{ + TargetList: &ast.List{}, + FromClause: &ast.List{}, + WhereClause: nil, + Op: op, + All: all, + WithClause: c.convertWithClause(n.With), + } + for _, stmt := range selectStmts { + // We move Op and All from the child to the parent. + op, all := stmt.Op, stmt.All + stmt.Op, stmt.All = ast.None, false + + switch { + case tree.Larg == nil: + tree.Larg = stmt + case tree.Rarg == nil: + tree.Rarg = stmt + tree.Op = op + tree.All = all + default: + tree = &ast.SelectStmt{ + TargetList: &ast.List{}, + FromClause: &ast.List{}, + WhereClause: nil, + Larg: tree, + Rarg: stmt, + Op: op, + All: all, + WithClause: c.convertWithClause(n.With), + } + } + } + + return tree +} + +func (c *cc) convertSetOprStmt(n *pcast.SetOprStmt) ast.Node { + if n.SelectList != nil { + sn := c.convertSetOprSelectList(n.SelectList) + if ss, ok := sn.(*ast.SelectStmt); ok { + if n.Limit != nil { + ss.LimitOffset = c.convert(n.Limit.Offset) + ss.LimitCount = c.convert(n.Limit.Count) + } + // The ORDER BY that applies to the whole compound statement + // (SELECT ... UNION SELECT ... ORDER BY x) lives on the set + // operation, not on either branch. + if n.OrderBy != nil { + ss.SortClause = c.convertOrderByItems(n.OrderBy.Items) + } + } + return sn + } + return todo(n) +} + +// convertOrderByItems converts ORDER BY items into the SortBy list a +// SelectStmt's SortClause carries. +func (c *cc) convertOrderByItems(items []*pcast.ByItem) *ast.List { + list := &ast.List{Items: make([]ast.Node, 0, len(items))} + for _, item := range items { + dir := ast.SortByDirDefault + if item.Desc { + dir = ast.SortByDirDesc + } + list.Items = append(list.Items, &ast.SortBy{ + Node: c.convert(item.Expr), + SortbyDir: dir, + }) + } + return list +} + +func (c *cc) convertSetPwdStmt(n *pcast.SetPwdStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertSetRoleStmt(n *pcast.SetRoleStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertSetStmt(n *pcast.SetStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertShowStmt(n *pcast.ShowStmt) ast.Node { + if n.Tp != pcast.ShowWarnings { + return todo(n) + } + level := "level" + code := "code" + message := "message" + stmt := &ast.SelectStmt{ + FromClause: &ast.List{}, + TargetList: &ast.List{ + Items: []ast.Node{ + &ast.ResTarget{ + Name: &level, + Val: &ast.A_Const{Val: &ast.String{}}, + }, + &ast.ResTarget{ + Name: &code, + Val: &ast.A_Const{Val: &ast.Integer{}}, + }, + &ast.ResTarget{ + Name: &message, + Val: &ast.A_Const{Val: &ast.String{}}, + }, + }, + }, + } + return stmt +} + +func (c *cc) convertShutdownStmt(n *pcast.ShutdownStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertSplitRegionStmt(n *pcast.SplitRegionStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertTableName(n *pcast.TableName) *ast.RangeVar { + schema := c.identifier(n.Schema.String()) + rel := c.identifier(n.Name.String()) + return &ast.RangeVar{ + Schemaname: &schema, + Relname: &rel, + Location: n.OriginTextPosition(), + } +} + +func (c *cc) convertTableNameExpr(n *pcast.TableNameExpr) ast.Node { + return todo(n) +} + +func (c *cc) convertTableOptimizerHint(n *pcast.TableOptimizerHint) ast.Node { + return todo(n) +} + +func (c *cc) convertTableSource(node *pcast.TableSource) ast.Node { + if node == nil { + return nil + } + alias := node.AsName.String() + switch n := node.Source.(type) { + + case *pcast.SelectStmt, *pcast.SetOprStmt: + rs := &ast.RangeSubselect{ + Subquery: c.convert(n), + } + if alias != "" { + rs.Alias = &ast.Alias{Aliasname: &alias} + } + return rs + + case *pcast.TableName: + rv := c.convertTableName(n) + if alias != "" { + rv.Alias = &ast.Alias{Aliasname: &alias} + } + return rv + + default: + return todo(n) + } +} + +func (c *cc) convertTableToTable(n *pcast.TableToTable) ast.Node { + return todo(n) +} + +func (c *cc) convertTimeUnitExpr(n *pcast.TimeUnitExpr) ast.Node { + return todo(n) +} + +func (c *cc) convertTraceStmt(n *pcast.TraceStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertTrimDirectionExpr(n *pcast.TrimDirectionExpr) ast.Node { + return todo(n) +} + +func (c *cc) convertTruncateTableStmt(n *pcast.TruncateTableStmt) *ast.TruncateStmt { + return &ast.TruncateStmt{ + Relations: c.toList(n.Table), + } +} + +func (c *cc) convertUnaryOperationExpr(n *pcast.UnaryOperationExpr) ast.Node { + return todo(n) +} + +func (c *cc) convertUnlockTablesStmt(n *pcast.UnlockTablesStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertUseStmt(n *pcast.UseStmt) ast.Node { + return todo(n) +} + +func (c *cc) convertValuesExpr(n *pcast.ValuesExpr) ast.Node { + return todo(n) +} + +func (c *cc) convertVariableAssignment(n *pcast.VariableAssignment) ast.Node { + return todo(n) +} + +func (c *cc) convertVariableExpr(n *pcast.VariableExpr) ast.Node { + // MySQL @variable references are user-defined variables, NOT sqlc named parameters. + // Use VariableExpr to preserve them as-is in the output. + return &ast.VariableExpr{ + Name: n.Name, + Location: n.OriginTextPosition(), + } +} + +func (c *cc) convertWhenClause(n *pcast.WhenClause) ast.Node { + if n == nil { + return nil + } + return &ast.CaseWhen{ + Expr: c.convert(n.Expr), + Result: c.convert(n.Result), + Location: n.OriginTextPosition(), + } +} + +func (c *cc) convertWindowFuncExpr(n *pcast.WindowFuncExpr) ast.Node { + return todo(n) +} + +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, c.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: ¶mName, + Type: &ast.TypeName{Name: types.TypeToStr(sp.ParamType.GetType(), sp.ParamType.GetCharset())}, + }) + } + return &ast.CreateFunctionStmt{ + Params: ¶ms, + 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) { + + case *pcast.ParamMarkerExprBase: + return c.convertParamMarkerExpr(n) + + case *pcast.ValueExprBase: + return c.convertValueExpr(n) + + case *pcast.AdminStmt: + return c.convertAdminStmt(n) + + case *pcast.AggregateFuncExpr: + return c.convertAggregateFuncExpr(n) + + case *pcast.AlterDatabaseStmt: + return c.convertAlterDatabaseStmt(n) + + case *pcast.AlterInstanceStmt: + return c.convertAlterInstanceStmt(n) + + case *pcast.AlterTableSpec: + return c.convertAlterTableSpec(n) + + case *pcast.AlterTableStmt: + return c.convertAlterTableStmt(n) + + case *pcast.AlterUserStmt: + return c.convertAlterUserStmt(n) + + case *pcast.AnalyzeTableStmt: + return c.convertAnalyzeTableStmt(n) + + case *pcast.Assignment: + return c.convertAssignment(n) + + case *pcast.BRIEStmt: + return c.convertBRIEStmt(n) + + case *pcast.BeginStmt: + return c.convertBeginStmt(n) + + case *pcast.BetweenExpr: + return c.convertBetweenExpr(n) + + case *pcast.BinaryOperationExpr: + return c.convertBinaryOperationExpr(n) + + case *pcast.BinlogStmt: + return c.convertBinlogStmt(n) + + case *pcast.ByItem: + return c.convertByItem(n) + + case *pcast.CallStmt: + return c.convertCallStmt(n) + + case *pcast.CaseExpr: + return c.convertCaseExpr(n) + + case *pcast.CleanupTableLockStmt: + return c.convertCleanupTableLockStmt(n) + + case *pcast.ColumnDef: + return c.convertColumnDef(n) + + case *pcast.ColumnName: + return c.convertColumnName(n) + + case *pcast.ColumnNameExpr: + return c.convertColumnNameExpr(n) + + case *pcast.ColumnPosition: + return c.convertColumnPosition(n) + + case *pcast.CommitStmt: + return c.convertCommitStmt(n) + + case *pcast.CompareSubqueryExpr: + return c.convertCompareSubqueryExpr(n) + + case *pcast.Constraint: + return c.convertConstraint(n) + + case *pcast.CreateBindingStmt: + return c.convertCreateBindingStmt(n) + + case *pcast.CreateDatabaseStmt: + return c.convertCreateDatabaseStmt(n) + + case *pcast.CreateIndexStmt: + return c.convertCreateIndexStmt(n) + + case *pcast.CreateSequenceStmt: + return c.convertCreateSequenceStmt(n) + + case *pcast.CreateStatisticsStmt: + return c.convertCreateStatisticsStmt(n) + + case *pcast.CreateTableStmt: + return c.convertCreateTableStmt(n) + + case *pcast.CreateUserStmt: + return c.convertCreateUserStmt(n) + + case *pcast.CreateViewStmt: + return c.convertCreateViewStmt(n) + + case *pcast.DeallocateStmt: + return c.convertDeallocateStmt(n) + + case *pcast.DefaultExpr: + return c.convertDefaultExpr(n) + + case *pcast.DeleteStmt: + return c.convertDeleteStmt(n) + + case *pcast.DeleteTableList: + return c.convertDeleteTableList(n) + + case *pcast.DoStmt: + return c.convertDoStmt(n) + + case *pcast.DropBindingStmt: + return c.convertDropBindingStmt(n) + + case *pcast.DropDatabaseStmt: + return c.convertDropDatabaseStmt(n) + + case *pcast.DropIndexStmt: + return c.convertDropIndexStmt(n) + + case *pcast.DropSequenceStmt: + return c.convertDropSequenceStmt(n) + + case *pcast.DropStatisticsStmt: + return c.convertDropStatisticsStmt(n) + + case *pcast.DropStatsStmt: + return c.convertDropStatsStmt(n) + + case *pcast.DropTableStmt: + return c.convertDropTableStmt(n) + + case *pcast.DropUserStmt: + return c.convertDropUserStmt(n) + + case *pcast.ExecuteStmt: + return c.convertExecuteStmt(n) + + case *pcast.ExistsSubqueryExpr: + return c.convertExistsSubqueryExpr(n) + + case *pcast.ExplainForStmt: + return c.convertExplainForStmt(n) + + case *pcast.ExplainStmt: + return c.convertExplainStmt(n) + + case *pcast.FieldList: + return c.convertFieldList(n) + + case *pcast.FlashBackTableStmt: + return c.convertFlashBackTableStmt(n) + + case *pcast.FlushStmt: + return c.convertFlushStmt(n) + + case *pcast.FrameBound: + return c.convertFrameBound(n) + + case *pcast.FrameClause: + return c.convertFrameClause(n) + + case *pcast.FuncCallExpr: + return c.convertFuncCallExpr(n) + + case *pcast.FuncCastExpr: + return c.convertFuncCastExpr(n) + + case *pcast.GetFormatSelectorExpr: + return c.convertGetFormatSelectorExpr(n) + + case *pcast.GrantRoleStmt: + return c.convertGrantRoleStmt(n) + + case *pcast.GrantStmt: + return c.convertGrantStmt(n) + + case *pcast.GroupByClause: + return c.convertGroupByClause(n) + + case *pcast.HavingClause: + return c.convertHavingClause(n) + + case *pcast.IndexLockAndAlgorithm: + return c.convertIndexLockAndAlgorithm(n) + + case *pcast.IndexPartSpecification: + return c.convertIndexPartSpecification(n) + + case *pcast.InsertStmt: + return c.convertInsertStmt(n) + + case *pcast.IsNullExpr: + return c.convertIsNullExpr(n) + + case *pcast.IsTruthExpr: + return c.convertIsTruthExpr(n) + + case *pcast.Join: + return c.convertJoin(n) + + case *pcast.KillStmt: + return c.convertKillStmt(n) + + case *pcast.Limit: + return c.convertLimit(n) + + case *pcast.LoadDataStmt: + return c.convertLoadDataStmt(n) + + case *pcast.LoadStatsStmt: + return c.convertLoadStatsStmt(n) + + case *pcast.LockTablesStmt: + return c.convertLockTablesStmt(n) + + case *pcast.MatchAgainst: + return c.convertMatchAgainst(n) + + case *pcast.MaxValueExpr: + return c.convertMaxValueExpr(n) + + case *pcast.OnCondition: + return c.convertOnCondition(n) + + case *pcast.OnDeleteOpt: + return c.convertOnDeleteOpt(n) + + case *pcast.OnUpdateOpt: + return c.convertOnUpdateOpt(n) + + case *pcast.OrderByClause: + return c.convertOrderByClause(n) + + case *pcast.ParenthesesExpr: + return c.convertParenthesesExpr(n) + + case *pcast.PartitionByClause: + return c.convertPartitionByClause(n) + + case *pcast.PatternInExpr: + return c.convertPatternInExpr(n) + + case *pcast.PatternLikeOrIlikeExpr: + return c.convertPatternLikeExpr(n) + + case *pcast.PatternRegexpExpr: + return c.convertPatternRegexpExpr(n) + + case *pcast.PositionExpr: + return c.convertPositionExpr(n) + + case *pcast.PrepareStmt: + return c.convertPrepareStmt(n) + + case *pcast.PrivElem: + return c.convertPrivElem(n) + + case *pcast.ProcedureInfo: + return c.convertProcedureInfo(n) + + case *pcast.RecoverTableStmt: + return c.convertRecoverTableStmt(n) + + case *pcast.ReferenceDef: + return c.convertReferenceDef(n) + + case *pcast.RenameTableStmt: + return c.convertRenameTableStmt(n) + + case *pcast.RepairTableStmt: + return c.convertRepairTableStmt(n) + + case *pcast.RevokeRoleStmt: + return c.convertRevokeRoleStmt(n) + + case *pcast.RevokeStmt: + return c.convertRevokeStmt(n) + + case *pcast.RollbackStmt: + return c.convertRollbackStmt(n) + + case *pcast.RowExpr: + return c.convertRowExpr(n) + + case *pcast.SelectField: + return c.convertSelectField(n) + + case *pcast.SelectStmt: + return c.convertSelectStmt(n) + + case *pcast.SetCollationExpr: + return c.convertSetCollationExpr(n) + + case *pcast.SetConfigStmt: + return c.convertSetConfigStmt(n) + + case *pcast.SetDefaultRoleStmt: + return c.convertSetDefaultRoleStmt(n) + + case *pcast.SetOprSelectList: + return c.convertSetOprSelectList(n) + + case *pcast.SetOprStmt: + return c.convertSetOprStmt(n) + + case *pcast.SetPwdStmt: + return c.convertSetPwdStmt(n) + + case *pcast.SetRoleStmt: + return c.convertSetRoleStmt(n) + + case *pcast.SetStmt: + return c.convertSetStmt(n) + + case *pcast.ShowStmt: + return c.convertShowStmt(n) + + case *pcast.ShutdownStmt: + return c.convertShutdownStmt(n) + + case *pcast.SplitRegionStmt: + return c.convertSplitRegionStmt(n) + + case *pcast.SubqueryExpr: + return c.convertSubqueryExpr(n) + + case *pcast.TableName: + return c.convertTableName(n) + + case *pcast.TableNameExpr: + return c.convertTableNameExpr(n) + + case *pcast.TableOptimizerHint: + return c.convertTableOptimizerHint(n) + + case *pcast.TableRefsClause: + return c.convertTableRefsClause(n) + + case *pcast.TableSource: + return c.convertTableSource(n) + + case *pcast.TableToTable: + return c.convertTableToTable(n) + + case *pcast.TimeUnitExpr: + return c.convertTimeUnitExpr(n) + + case *pcast.TraceStmt: + return c.convertTraceStmt(n) + + case *pcast.TrimDirectionExpr: + return c.convertTrimDirectionExpr(n) + + case *pcast.TruncateTableStmt: + return c.convertTruncateTableStmt(n) + + case *pcast.UnaryOperationExpr: + return c.convertUnaryOperationExpr(n) + + case *pcast.UnlockTablesStmt: + return c.convertUnlockTablesStmt(n) + + case *pcast.UpdateStmt: + return c.convertUpdateStmt(n) + + case *pcast.UseStmt: + return c.convertUseStmt(n) + + case *pcast.ValuesExpr: + return c.convertValuesExpr(n) + + case *pcast.VariableAssignment: + return c.convertVariableAssignment(n) + + case *pcast.VariableExpr: + return c.convertVariableExpr(n) + + case *pcast.WhenClause: + return c.convertWhenClause(n) + + case *pcast.WildCardField: + return c.convertWildCardField(n) + + case *pcast.WindowFuncExpr: + return c.convertWindowFuncExpr(n) + + case *pcast.WindowSpec: + return c.convertWindowSpec(n) + + case nil: + return nil + + default: + return todo(n) + } +} diff --git a/internal/engine/dolphin/dialect/dialect.json b/internal/engine/dolphin/dialect/dialect.json new file mode 100644 index 0000000..ce503b4 --- /dev/null +++ b/internal/engine/dolphin/dialect/dialect.json @@ -0,0 +1,50 @@ +{ + "dialect": "mysql", + "const": { + "integer": "int", + "float": "decimal", + "string": "text", + "bool": "bool" + }, + "bool": "bool", + "comparison": ["=", "<>", "!=", "<", "<=", ">", ">=", "<=>"], + "comparison_categories": "BNSDU", + "arithmetic": ["+", "-", "*", "/", "%", "DIV"], + "arithmetic_categories": "N", + "cast_categories": "NSD", + "rewrites": [ + { + "from": "boolean", + "to": "tinyint(1)" + }, + { + "from": "bool", + "to": "tinyint(1)" + }, + { + "from": "decimal", + "to": "decimal(10, 0)" + }, + { + "from": "decimal($1)", + "to": "decimal($1, 0)" + }, + { + "from": "decimal unsigned", + "to": "decimal unsigned(10, 0)" + }, + { + "from": "decimal unsigned($1)", + "to": "decimal unsigned($1, 0)" + }, + { + "from": "float($1)", + "to": "float", + "where": "$1 <= 24" + }, + { + "from": "float($1)", + "to": "double" + } + ] +} diff --git a/internal/engine/dolphin/dialect/functions.jsonl b/internal/engine/dolphin/dialect/functions.jsonl new file mode 100644 index 0000000..91fe412 --- /dev/null +++ b/internal/engine/dolphin/dialect/functions.jsonl @@ -0,0 +1,520 @@ +{"name":"ABS","args":[{"type":"tinyint"}],"returns":"tinyint"} +{"name":"ABS","args":[{"type":"smallint"}],"returns":"smallint"} +{"name":"ABS","args":[{"type":"mediumint"}],"returns":"mediumint"} +{"name":"ABS","args":[{"type":"int"}],"returns":"int"} +{"name":"ABS","args":[{"type":"bigint"}],"returns":"bigint"} +{"name":"ABS","args":[{"type":"double"}],"returns":"double"} +{"name":"ABS","args":[{"type":"double precision"}],"returns":"double precision"} +{"name":"ACOS","args":[{"type":"double precision"}],"returns":"double precision"} +{"name":"ADDDATE","args":[{"type":"date"},{"type":"int"}],"returns":"date"} +{"name":"ADDTIME","args":[{"type":"time"},{"type":"time"}],"returns":"time"} +{"name":"AES_DECRYPT","args":[{"type":"binary"},{"type":"text"}],"returns":"text"} +{"name":"AES_DECRYPT","args":[{"type":"binary"},{"type":"text"},{"type":"binary"}],"returns":"text"} +{"name":"AES_ENCRYPT","args":[{"type":"text"},{"type":"text"}],"returns":"binary"} +{"name":"AES_ENCRYPT","args":[{"type":"text"},{"type":"text"},{"type":"binary"}],"returns":"binary"} +{"name":"ANY_VALUE","args":[{"type":"any"}],"returns":"any"} +{"name":"ASCII","args":[{"type":"text"}],"returns":"int"} +{"name":"ASIN","args":[{"type":"double precision"}],"returns":"double precision"} +{"name":"ATAN","args":[{"type":"double precision"}],"returns":"double precision"} +{"name":"ATAN2","args":[{"type":"double precision"}],"returns":"double precision"} +{"name":"AVG","args":[{"type":"any"}],"returns":"any","nullable":true} +{"name":"BENCHMARK","args":[{"type":"int"},{"type":"any"}],"returns":"int"} +{"name":"BIN","args":[{"type":"int"}],"returns":"text"} +{"name":"BIN_TO_UUID","args":[{"type":"binary"}],"returns":"text"} +{"name":"BIN_TO_UUID","args":[{"type":"binary"},{"type":"tinyint"}],"returns":"text"} +{"name":"BIT_AND","args":[{"type":"any"}],"returns":"any"} +{"name":"BIT_COUNT","args":[{"type":"bigint"}],"returns":"bigint"} +{"name":"BIT_LENGTH","args":[{"type":"text"}],"returns":"int"} +{"name":"BIT_OR","args":[{"type":"any"}],"returns":"any"} +{"name":"BIT_XOR","args":[{"type":"any"}],"returns":"any"} +{"name":"CAST","args":[{"type":"any"}],"returns":"any"} +{"name":"CEIL","args":[{"type":"int"}],"returns":"int"} +{"name":"CEIL","args":[{"type":"double precision"}],"returns":"double precision"} +{"name":"CEILING","args":[{"type":"int"}],"returns":"int"} +{"name":"CEILING","args":[{"type":"double precision"}],"returns":"double precision"} +{"name":"CHAR","args":[{"type":"int"},{"type":"int","mode":"v"}],"returns":"text"} +{"name":"CHARACTER_LENGTH","args":[{"type":"text"}],"returns":"int"} +{"name":"CHARSET","args":[{"type":"text"}],"returns":"text"} +{"name":"CHAR_LENGTH","args":[{"type":"text"}],"returns":"int"} +{"name":"COERCIBILITY","args":[{"type":"text"}],"returns":"int"} +{"name":"COLLATION","args":[{"type":"text"}],"returns":"text"} +{"name":"COMPRESS","args":[{"type":"text"}],"returns":"binary"} +{"name":"CONCAT","args":[{"type":"any"},{"type":"any","mode":"v"}],"returns":"text"} +{"name":"CONCAT_WS","args":[{"type":"text"},{"type":"any"},{"type":"any","mode":"v"}],"returns":"text"} +{"name":"CONNECTION_ID","returns":"int"} +{"name":"CONV","args":[{"type":"int"},{"type":"int"},{"type":"int"}],"returns":"text"} +{"name":"CONVERT","args":[{"type":"any"},{"type":"any"}],"returns":"any"} +{"name":"CONVERT_TZ","args":[{"type":"datetime"},{"type":"text"},{"type":"text"}],"returns":"datetime"} +{"name":"COS","args":[{"type":"double precision"}],"returns":"double precision"} +{"name":"COT","args":[{"type":"double precision"}],"returns":"double precision"} +{"name":"COUNT","returns":"bigint"} +{"name":"COUNT","args":[{"type":"any"}],"returns":"bigint"} +{"name":"CRC32","args":[{"type":"text"}],"returns":"int"} +{"name":"CUME_DIST","returns":"double precision"} +{"name":"CURDATE","returns":"date"} +{"name":"CURRENT_DATE","returns":"date"} +{"name":"CURRENT_ROLE","returns":"text"} +{"name":"CURRENT_TIME","returns":"time"} +{"name":"CURRENT_TIME","args":[{"type":"int"}],"returns":"time"} +{"name":"CURRENT_TIMESTAMP","returns":"datetime"} +{"name":"CURRENT_TIMESTAMP","args":[{"type":"int"}],"returns":"datetime"} +{"name":"CURRENT_USER","returns":"text"} +{"name":"CURTIME","returns":"time"} +{"name":"CURTIME","args":[{"type":"int"}],"returns":"time"} +{"name":"DATABASE","returns":"text"} +{"name":"DATE","args":[{"type":"datetime"}],"returns":"date"} +{"name":"DATEDIFF","args":[{"type":"datetime"},{"type":"datetime"}],"returns":"int"} +{"name":"DATE_ADD","args":[{"type":"date"},{"type":"any"},{"type":"any"}],"returns":"date"} +{"name":"DATE_ADD","args":[{"type":"date"},{"type":"interval"}],"returns":"date"} +{"name":"DATE_ADD_INTERVAL","args":[{"type":"date"},{"type":"any"}],"returns":"date"} +{"name":"DATE_FORMAT","args":[{"type":"date"},{"type":"text"}],"returns":"text"} +{"name":"DATE_SUB","args":[{"type":"date"},{"type":"any"},{"type":"any"}],"returns":"date"} +{"name":"DATE_SUB","args":[{"type":"date"},{"type":"interval"}],"returns":"date"} +{"name":"DATE_SUB_INTERVAL","args":[{"type":"date"},{"type":"any"}],"returns":"date"} +{"name":"DAY","args":[{"type":"date"}],"returns":"int"} +{"name":"DAYNAME","args":[{"type":"date"}],"returns":"text"} +{"name":"DAYOFMONTH","args":[{"type":"date"}],"returns":"int"} +{"name":"DAYOFWEEK","args":[{"type":"date"}],"returns":"int"} +{"name":"DAYOFYEAR","args":[{"type":"date"}],"returns":"int"} +{"name":"DEFAULT","args":[{"type":"any"}],"returns":"any"} +{"name":"DEGREES","args":[{"type":"double precision"}],"returns":"int"} +{"name":"DENSE_RANK","returns":"int"} +{"name":"DISTINCT","args":[{"type":"any"}],"returns":"any"} +{"name":"ELT","args":[{"type":"int"},{"type":"text","mode":"v"}],"returns":"text"} +{"name":"EXP","args":[{"type":"int"}],"returns":"double precision"} +{"name":"EXPORT_SET","args":[{"type":"int"},{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"EXPORT_SET","args":[{"type":"int"},{"type":"text"},{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"EXPORT_SET","args":[{"type":"int"},{"type":"text"},{"type":"text"},{"type":"text"},{"type":"int"}],"returns":"text"} +{"name":"EXTRACT","args":[{"type":"date"},{"type":"any"}],"returns":"int"} +{"name":"EXTRACTVALUE","args":[{"type":"text"},{"type":"text"}],"returns":"any"} +{"name":"FIELD","args":[{"type":"text"},{"type":"text"},{"type":"text","mode":"v"}],"returns":"text"} +{"name":"FIND_IN_SET","args":[{"type":"text"},{"type":"text"}],"returns":"int"} +{"name":"FIRST_VALUE","args":[{"type":"any"}],"returns":"any"} +{"name":"FLOOR","args":[{"type":"double precision"}],"returns":"int"} +{"name":"FORMAT","args":[{"type":"int"},{"type":"int"}],"returns":"text"} +{"name":"FORMAT_BYTES","args":[{"type":"int"}],"returns":"text"} +{"name":"FORMAT_PICO_TIME","args":[{"type":"time"}],"returns":"text"} +{"name":"FOUND_ROWS","returns":"int"} +{"name":"FROM_BASE64","args":[{"type":"text"}],"returns":"text"} +{"name":"FROM_DAYS","args":[{"type":"int"}],"returns":"date"} +{"name":"FROM_UNIXTIME","args":[{"type":"bigint"}],"returns":"text"} +{"name":"FROM_UNIXTIME","args":[{"type":"bigint"},{"type":"text"}],"returns":"text"} +{"name":"GEOMCOLLECTION","args":[{"type":"any"},{"type":"any","mode":"v"}],"returns":"any"} +{"name":"GEOMETRYCOLLECTION","args":[{"type":"any"},{"type":"any","mode":"v"}],"returns":"any"} +{"name":"GET_FORMAT","args":[{"type":"any"},{"type":"text"}],"returns":"text"} +{"name":"GET_LOCK","args":[{"type":"text"},{"type":"int"}],"returns":"bool"} +{"name":"GREATEST","args":[{"type":"any"},{"type":"any"},{"type":"any","mode":"v"}],"returns":"any"} +{"name":"GROUPING","args":[{"type":"any"},{"type":"any","mode":"v"}],"returns":"any"} +{"name":"GROUP_CONCAT","args":[{"type":"any"},{"type":"any","mode":"v"}],"returns":"text","nullable":true} +{"name":"GTID_SUBSET","args":[{"type":"text"},{"type":"text"}],"returns":"bool"} +{"name":"GTID_SUBTRACT","args":[{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"HEX","args":[{"type":"int"}],"returns":"text"} +{"name":"HEX","args":[{"type":"text"}],"returns":"int"} +{"name":"HOUR","args":[{"type":"time"}],"returns":"int"} +{"name":"ICU_VERSION","returns":"text"} +{"name":"IF","args":[{"type":"any"},{"type":"any"},{"type":"any"}],"returns":"any"} +{"name":"IFNULL","args":[{"type":"any"},{"type":"any"}],"returns":"any"} +{"name":"INET6_ATON","args":[{"type":"text"}],"returns":"binary"} +{"name":"INET6_NTOA","args":[{"type":"binary"}],"returns":"text"} +{"name":"INET_ATON","args":[{"type":"text"}],"returns":"int"} +{"name":"INET_NTOA","args":[{"type":"int"}],"returns":"text"} +{"name":"INSERT","args":[{"type":"text"},{"type":"int"},{"type":"int"},{"type":"text"}],"returns":"text"} +{"name":"INSTR","args":[{"type":"text"},{"type":"text"}],"returns":"int"} +{"name":"INTERVAL","args":[{"type":"any"},{"type":"any"},{"type":"any","mode":"v"}],"returns":"any"} +{"name":"ISNULL","args":[{"type":"any"}],"returns":"bool"} +{"name":"IS_FREE_LOCK","args":[{"type":"text"}],"returns":"bool"} +{"name":"IS_IPV4","args":[{"type":"text"}],"returns":"bool"} +{"name":"IS_IPV4_COMPAT","args":[{"type":"binary"}],"returns":"bool"} +{"name":"IS_IPV4_MAPPED","args":[{"type":"binary"}],"returns":"bool"} +{"name":"IS_IPV6","args":[{"type":"text"}],"returns":"bool"} +{"name":"IS_USED_LOCK","args":[{"type":"text"}],"returns":"bool"} +{"name":"IS_UUID","args":[{"type":"text"}],"returns":"bool"} +{"name":"JSON_ARRAY","args":[{"type":"any","mode":"v"}],"returns":"json"} +{"name":"JSON_ARRAYAGG","args":[{"type":"any"}],"returns":"json","nullable":true} +{"name":"JSON_ARRAY_APPEND","args":[{"type":"text"},{"type":"text"},{"type":"any"},{"type":"any","mode":"v"}],"returns":"json"} +{"name":"JSON_ARRAY_INSERT","args":[{"type":"text"},{"type":"text"},{"type":"any"},{"type":"any","mode":"v"}],"returns":"json"} +{"name":"JSON_CONTAINS","args":[{"type":"text"},{"type":"text"}],"returns":"bool"} +{"name":"JSON_CONTAINS","args":[{"type":"text"},{"type":"text"},{"type":"text"}],"returns":"bool"} +{"name":"JSON_CONTAINS_PATH","args":[{"type":"text"},{"type":"text"},{"type":"text"},{"type":"text","mode":"v"}],"returns":"bool"} +{"name":"JSON_DEPTH","args":[{"type":"text"}],"returns":"int"} +{"name":"JSON_EXTRACT","args":[{"type":"text"},{"type":"text"},{"type":"text","mode":"v"}],"returns":"any"} +{"name":"JSON_INSERT","args":[{"type":"text"},{"type":"text"},{"type":"any"},{"type":"any","mode":"v"}],"returns":"json"} +{"name":"JSON_KEYS","args":[{"type":"text"}],"returns":"json"} +{"name":"JSON_KEYS","args":[{"type":"text"},{"type":"text"}],"returns":"json"} +{"name":"JSON_LENGTH","args":[{"type":"text"}],"returns":"int"} +{"name":"JSON_LENGTH","args":[{"type":"text"},{"type":"text"}],"returns":"int"} +{"name":"JSON_MERGE","args":[{"type":"text"},{"type":"text"},{"type":"text","mode":"v"}],"returns":"json"} +{"name":"JSON_MERGE_PATCH","args":[{"type":"text"},{"type":"text"},{"type":"text","mode":"v"}],"returns":"json"} +{"name":"JSON_MERGE_PRESERVE","args":[{"type":"text"},{"type":"text"},{"type":"text","mode":"v"}],"returns":"json"} +{"name":"JSON_OBJECT","args":[{"type":"any","mode":"v"}],"returns":"json"} +{"name":"JSON_OBJECTAGG","args":[{"type":"any"},{"type":"any"}],"returns":"json","nullable":true} +{"name":"JSON_OVERLAPS","args":[{"type":"text"},{"type":"text"}],"returns":"bool"} +{"name":"JSON_PRETTY","args":[{"type":"text"}],"returns":"any"} +{"name":"JSON_QUOTE","args":[{"type":"text"}],"returns":"text"} +{"name":"JSON_REMOVE","args":[{"type":"text"},{"type":"text"},{"type":"text","mode":"v"}],"returns":"json"} +{"name":"JSON_REPLACE","args":[{"type":"text"},{"type":"text"},{"type":"any"},{"type":"any","mode":"v"}],"returns":"json"} +{"name":"JSON_SCHEMA_VALID","args":[{"type":"text"},{"type":"text"}],"returns":"bool"} +{"name":"JSON_SCHEMA_VALIDATION_REPORT","args":[{"type":"text"},{"type":"text"}],"returns":"json"} +{"name":"JSON_SEARCH","args":[{"type":"text"},{"type":"text"},{"type":"text"}],"returns":"any"} +{"name":"JSON_SEARCH","args":[{"type":"text"},{"type":"text"},{"type":"text"},{"type":"text"},{"type":"text","mode":"v"}],"returns":"any"} +{"name":"JSON_SET","args":[{"type":"text"},{"type":"text"},{"type":"any"},{"type":"any","mode":"v"}],"returns":"json"} +{"name":"JSON_STORAGE_FREE","args":[{"type":"text"}],"returns":"int"} +{"name":"JSON_STORAGE_SIZE","args":[{"type":"text"}],"returns":"int"} +{"name":"JSON_TYPE","args":[{"type":"text"}],"returns":"any"} +{"name":"JSON_UNQUOTE","args":[{"type":"text"}],"returns":"json"} +{"name":"JSON_VALID","args":[{"type":"text"}],"returns":"bool"} +{"name":"JSON_VALUE","args":[{"type":"text"},{"type":"text"}],"returns":"any"} +{"name":"LAG","args":[{"type":"any"},{"type":"int","has_default":true},{"type":"any","has_default":true}],"returns":"any"} +{"name":"LAST_DAY","args":[{"type":"date"}],"returns":"date"} +{"name":"LAST_INSERT_ID","returns":"bigint"} +{"name":"LAST_INSERT_ID","args":[{"type":"any"}],"returns":"bigint"} +{"name":"LAST_VALUE","args":[{"type":"any"}],"returns":"any"} +{"name":"LCASE","args":[{"type":"text"}],"returns":"text"} +{"name":"LEAD","args":[{"type":"any"},{"type":"int","has_default":true},{"type":"any","has_default":true}],"returns":"any"} +{"name":"LEAST","args":[{"type":"any"},{"type":"any"},{"type":"any","mode":"v"}],"returns":"any"} +{"name":"LEFT","args":[{"type":"text"},{"type":"int"}],"returns":"text"} +{"name":"LENGTH","args":[{"type":"text"}],"returns":"int"} +{"name":"LINESTRING","args":[{"type":"any"},{"type":"any","mode":"v"}],"returns":"any"} +{"name":"LN","args":[{"type":"double precision"}],"returns":"double precision"} +{"name":"LOAD_FILE","args":[{"type":"text"}],"returns":"text"} +{"name":"LOCALTIME","returns":"datetime"} +{"name":"LOCALTIME","args":[{"type":"int"}],"returns":"datetime"} +{"name":"LOCALTIMESTAMP","returns":"datetime"} +{"name":"LOCALTIMESTAMP","args":[{"type":"int"}],"returns":"datetime"} +{"name":"LOCATE","args":[{"type":"text"},{"type":"text"}],"returns":"int"} +{"name":"LOCATE","args":[{"type":"text"},{"type":"text"},{"type":"int"}],"returns":"int"} +{"name":"LOG","args":[{"type":"double precision"}],"returns":"double precision"} +{"name":"LOG","args":[{"type":"double precision"},{"type":"int"}],"returns":"int"} +{"name":"LOG10","args":[{"type":"double precision"}],"returns":"int"} +{"name":"LOG2","args":[{"type":"double precision"}],"returns":"int"} +{"name":"LOWER","args":[{"type":"text"}],"returns":"text"} +{"name":"LPAD","args":[{"type":"text"},{"type":"int"},{"type":"text"}],"returns":"text"} +{"name":"LTRIM","args":[{"type":"text"}],"returns":"text"} +{"name":"MAKEDATE","args":[{"type":"int"},{"type":"int"}],"returns":"date"} +{"name":"MAKETIME","args":[{"type":"int"},{"type":"int"},{"type":"int"}],"returns":"time"} +{"name":"MAKE_SET","args":[{"type":"int"},{"type":"text"},{"type":"text","mode":"v"}],"returns":"text"} +{"name":"MASTER_POS_WAIT","args":[{"type":"text"},{"type":"int"}],"returns":"int"} +{"name":"MASTER_POS_WAIT","args":[{"type":"text"},{"type":"int"},{"type":"int"}],"returns":"int"} +{"name":"MASTER_POS_WAIT","args":[{"type":"text"},{"type":"int"},{"type":"int"},{"type":"text"}],"returns":"int"} +{"name":"MAX","args":[{"type":"any"}],"returns":"any","nullable":true} +{"name":"MBRCONTAINS","args":[{"type":"any"},{"type":"any"}],"returns":"bool"} +{"name":"MBRCOVEREDBY","args":[{"type":"any"},{"type":"any"}],"returns":"bool"} +{"name":"MBRCOVERS","args":[{"type":"any"},{"type":"any"}],"returns":"bool"} +{"name":"MBRDISJOINT","args":[{"type":"any"},{"type":"any"}],"returns":"bool"} +{"name":"MBREQUALS","args":[{"type":"any"},{"type":"any"}],"returns":"bool"} +{"name":"MBRINTERSECTS","args":[{"type":"any"},{"type":"any"}],"returns":"bool"} +{"name":"MBROVERLAPS","args":[{"type":"any"},{"type":"any"}],"returns":"bool"} +{"name":"MBRTOUCHES","args":[{"type":"any"},{"type":"any"}],"returns":"bool"} +{"name":"MBRWITHIN","args":[{"type":"any"},{"type":"any"}],"returns":"bool"} +{"name":"MD5","args":[{"type":"text"}],"returns":"text"} +{"name":"MICROSECOND","args":[{"type":"time"}],"returns":"int"} +{"name":"MID","args":[{"type":"text"},{"type":"int"},{"type":"int"}],"returns":"text"} +{"name":"MIN","args":[{"type":"any"}],"returns":"any","nullable":true} +{"name":"MINUTE","args":[{"type":"time"}],"returns":"int"} +{"name":"MOD","args":[{"type":"int"},{"type":"int"}],"returns":"int"} +{"name":"MONTH","args":[{"type":"date"}],"returns":"int"} +{"name":"MONTHNAME","args":[{"type":"date"}],"returns":"text"} +{"name":"MULTILINESTRING","args":[{"type":"any"},{"type":"any","mode":"v"}],"returns":"any"} +{"name":"MULTIPOINT","args":[{"type":"any"},{"type":"any","mode":"v"}],"returns":"any"} +{"name":"MULTIPOLYGON","args":[{"type":"any"},{"type":"any","mode":"v"}],"returns":"any"} +{"name":"NAME_CONST","args":[{"type":"any"},{"type":"any"}],"returns":"any"} +{"name":"NOW","returns":"datetime"} +{"name":"NEXTVAL","args":[{"type":"any"}],"returns":"int"} +{"name":"NOW","args":[{"type":"int"}],"returns":"datetime"} +{"name":"NTH_VALUE","args":[{"type":"any"},{"type":"int"}],"returns":"any"} +{"name":"NTILE","args":[{"type":"int"}],"returns":"int"} +{"name":"NULLIF","args":[{"type":"any"},{"type":"any"}],"returns":"any"} +{"name":"OCT","args":[{"type":"bigint"}],"returns":"text"} +{"name":"OCTET_LENGTH","args":[{"type":"text"}],"returns":"int"} +{"name":"ORD","args":[{"type":"text"}],"returns":"int"} +{"name":"PERCENT_RANK","returns":"double precision"} +{"name":"PERIOD_ADD","args":[{"type":"int"},{"type":"int"}],"returns":"int"} +{"name":"PERIOD_DIFF","args":[{"type":"int"},{"type":"int"}],"returns":"int"} +{"name":"PI","returns":"double precision"} +{"name":"POINT","args":[{"type":"double precision"},{"type":"double precision"}],"returns":"any"} +{"name":"POLYGON","args":[{"type":"any"},{"type":"any","mode":"v"}],"returns":"any"} +{"name":"POSITION","args":[{"type":"text"},{"type":"text"}],"returns":"int"} +{"name":"POW","args":[{"type":"double precision"},{"type":"double precision"}],"returns":"double precision"} +{"name":"POWER","args":[{"type":"double precision"},{"type":"double precision"}],"returns":"double precision"} +{"name":"PS_CURRENT_THREAD_ID","returns":"int"} +{"name":"PS_THREAD_ID","args":[{"type":"int"}],"returns":"int"} +{"name":"QUARTER","args":[{"type":"date"}],"returns":"int"} +{"name":"QUOTE","args":[{"type":"text"}],"returns":"text"} +{"name":"RADIANS","args":[{"type":"int"}],"returns":"double precision"} +{"name":"RAND","returns":"double precision"} +{"name":"RAND","args":[{"type":"int"}],"returns":"double precision"} +{"name":"RANDOM_BYTES","args":[{"type":"int"}],"returns":"binary"} +{"name":"RANK","returns":"int"} +{"name":"REGEXP_INSTR","args":[{"type":"text"},{"type":"text"},{"type":"int","has_default":true},{"type":"int","has_default":true},{"type":"int","has_default":true},{"type":"text","has_default":true}],"returns":"int"} +{"name":"REGEXP_LIKE","args":[{"type":"text"},{"type":"text"},{"type":"text","has_default":true}],"returns":"bool"} +{"name":"REGEXP_REPLACE","args":[{"type":"text"},{"type":"text"},{"type":"text"},{"type":"int","has_default":true},{"type":"int","has_default":true},{"type":"text","has_default":true}],"returns":"text"} +{"name":"REGEXP_SUBSTR","args":[{"type":"text"},{"type":"text"},{"type":"int","has_default":true},{"type":"int","has_default":true},{"type":"text","has_default":true}],"returns":"text"} +{"name":"RELEASE_ALL_LOCKS","returns":"int"} +{"name":"RELEASE_LOCK","args":[{"type":"text"}],"returns":"bool"} +{"name":"REPEAT","args":[{"type":"text"},{"type":"int"}],"returns":"text"} +{"name":"REPLACE","args":[{"type":"text"},{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"REVERSE","args":[{"type":"text"}],"returns":"text"} +{"name":"RIGHT","args":[{"type":"text"},{"type":"int"}],"returns":"text"} +{"name":"ROLES_GRAPHML","returns":"text"} +{"name":"ROUND","args":[{"type":"double precision"}],"returns":"double precision"} +{"name":"ROUND","args":[{"type":"double precision"},{"type":"double precision"}],"returns":"double precision"} +{"name":"ROW_COUNT","returns":"bigint"} +{"name":"ROW_NUMBER","returns":"int"} +{"name":"RPAD","args":[{"type":"text"},{"type":"int"},{"type":"text"}],"returns":"text"} +{"name":"RTRIM","args":[{"type":"text"}],"returns":"text"} +{"name":"SCHEMA","returns":"text"} +{"name":"SECOND","args":[{"type":"time"}],"returns":"int"} +{"name":"SEC_TO_TIME","args":[{"type":"int"}],"returns":"time"} +{"name":"SESSION_USER","returns":"text"} +{"name":"SHA","args":[{"type":"text"}],"returns":"text"} +{"name":"SHA1","args":[{"type":"text"}],"returns":"text"} +{"name":"SHA2","args":[{"type":"text"},{"type":"int"}],"returns":"text"} +{"name":"SIGN","args":[{"type":"double precision"}],"returns":"int"} +{"name":"SIN","args":[{"type":"double precision"}],"returns":"double precision"} +{"name":"SLEEP","args":[{"type":"int"}],"returns":"int"} +{"name":"SOUNDEX","args":[{"type":"text"}],"returns":"text"} +{"name":"SPACE","args":[{"type":"int"}],"returns":"text"} +{"name":"SQRT","args":[{"type":"double precision"}],"returns":"double precision"} +{"name":"STATEMENT_DIGEST","args":[{"type":"text"}],"returns":"text"} +{"name":"STATEMENT_DIGEST_TEXT","args":[{"type":"text"}],"returns":"text"} +{"name":"STD","args":[{"type":"any"}],"returns":"any","nullable":true} +{"name":"STDDEV","args":[{"type":"any"}],"returns":"any","nullable":true} +{"name":"STDDEV_POP","args":[{"type":"any"}],"returns":"any","nullable":true} +{"name":"STDDEV_SAMP","args":[{"type":"any"}],"returns":"any","nullable":true} +{"name":"STRCMP","args":[{"type":"text"},{"type":"text"}],"returns":"tinyint"} +{"name":"STR_TO_DATE","args":[{"type":"text"},{"type":"text"}],"returns":"datetime"} +{"name":"ST_AREA","args":[{"type":"any"}],"returns":"double precision"} +{"name":"ST_ASBINARY","args":[{"type":"any"}],"returns":"binary"} +{"name":"ST_ASBINARY","args":[{"type":"any"},{"type":"text"}],"returns":"binary"} +{"name":"ST_ASGEOJSON","args":[{"type":"any"}],"returns":"json"} +{"name":"ST_ASGEOJSON","args":[{"type":"any"},{"type":"int"}],"returns":"json"} +{"name":"ST_ASGEOJSON","args":[{"type":"any"},{"type":"int"},{"type":"tinyint"}],"returns":"json"} +{"name":"ST_ASTEXT","args":[{"type":"any"}],"returns":"text"} +{"name":"ST_ASTEXT","args":[{"type":"any"},{"type":"text"}],"returns":"text"} +{"name":"ST_ASWKB","args":[{"type":"any"}],"returns":"binary"} +{"name":"ST_ASWKB","args":[{"type":"any"},{"type":"text"}],"returns":"binary"} +{"name":"ST_ASWKT","args":[{"type":"any"}],"returns":"text"} +{"name":"ST_ASWKT","args":[{"type":"any"},{"type":"text"}],"returns":"text"} +{"name":"ST_BUFFER","args":[{"type":"any"},{"type":"double precision"}],"returns":"any"} +{"name":"ST_BUFFER","args":[{"type":"any"},{"type":"double precision"},{"type":"binary"}],"returns":"any"} +{"name":"ST_BUFFER","args":[{"type":"any"},{"type":"double precision"},{"type":"binary"},{"type":"binary"}],"returns":"any"} +{"name":"ST_BUFFER","args":[{"type":"any"},{"type":"double precision"},{"type":"binary"},{"type":"binary"},{"type":"binary"}],"returns":"any"} +{"name":"ST_BUFFER_STRATEGY","args":[{"type":"text"}],"returns":"binary"} +{"name":"ST_BUFFER_STRATEGY","args":[{"type":"text"},{"type":"int"}],"returns":"binary"} +{"name":"ST_CENTROID","args":[{"type":"any"}],"returns":"any"} +{"name":"ST_CONTAINS","args":[{"type":"any"},{"type":"any"}],"returns":"bool"} +{"name":"ST_CONVEXHULL","args":[{"type":"any"}],"returns":"any"} +{"name":"ST_CROSSES","args":[{"type":"any"},{"type":"any"}],"returns":"bool"} +{"name":"ST_DIFFERENCE","args":[{"type":"any"},{"type":"any"}],"returns":"any"} +{"name":"ST_DIMENSION","args":[{"type":"any"}],"returns":"tinyint"} +{"name":"ST_DISJOINT","args":[{"type":"any"},{"type":"any"}],"returns":"bool"} +{"name":"ST_DISTANCE","args":[{"type":"any"},{"type":"any"}],"returns":"double precision"} +{"name":"ST_DISTANCE","args":[{"type":"any"},{"type":"any"},{"type":"text"}],"returns":"double precision"} +{"name":"ST_DISTANCE_SPHERE","args":[{"type":"any"},{"type":"any"}],"returns":"double precision"} +{"name":"ST_DISTANCE_SPHERE","args":[{"type":"any"},{"type":"any"},{"type":"int"}],"returns":"double precision"} +{"name":"ST_ENDPOINT","args":[{"type":"any"}],"returns":"any"} +{"name":"ST_ENVELOPE","args":[{"type":"any"}],"returns":"any"} +{"name":"ST_EQUALS","args":[{"type":"any"},{"type":"any"}],"returns":"bool"} +{"name":"ST_EXTERIORRING","args":[{"type":"any"}],"returns":"any"} +{"name":"ST_FRECHET_DISTANCE","args":[{"type":"any"},{"type":"any"}],"returns":"double precision"} +{"name":"ST_FRECHET_DISTANCE","args":[{"type":"any"},{"type":"any"},{"type":"text"}],"returns":"double precision"} +{"name":"ST_GEOHASH","args":[{"type":"double precision"},{"type":"double precision"},{"type":"int"}],"returns":"text"} +{"name":"ST_GEOHASH","args":[{"type":"any"},{"type":"int"}],"returns":"text"} +{"name":"ST_GEOMCOLLFROMTEXT","args":[{"type":"text"}],"returns":"any"} +{"name":"ST_GEOMCOLLFROMTEXT","args":[{"type":"text"},{"type":"int"}],"returns":"any"} +{"name":"ST_GEOMCOLLFROMTEXT","args":[{"type":"text"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_GEOMCOLLFROMTXT","args":[{"type":"text"}],"returns":"any"} +{"name":"ST_GEOMCOLLFROMTXT","args":[{"type":"text"},{"type":"int"}],"returns":"any"} +{"name":"ST_GEOMCOLLFROMTXT","args":[{"type":"text"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_GEOMCOLLFROMWKB","args":[{"type":"binary"}],"returns":"any"} +{"name":"ST_GEOMCOLLFROMWKB","args":[{"type":"binary"},{"type":"int"}],"returns":"any"} +{"name":"ST_GEOMCOLLFROMWKB","args":[{"type":"binary"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_GEOMETRYCOLLECTIONFROMTEXT","args":[{"type":"text"}],"returns":"any"} +{"name":"ST_GEOMETRYCOLLECTIONFROMTEXT","args":[{"type":"text"},{"type":"int"}],"returns":"any"} +{"name":"ST_GEOMETRYCOLLECTIONFROMTEXT","args":[{"type":"text"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_GEOMETRYCOLLECTIONFROMWKB","args":[{"type":"binary"}],"returns":"any"} +{"name":"ST_GEOMETRYCOLLECTIONFROMWKB","args":[{"type":"binary"},{"type":"int"}],"returns":"any"} +{"name":"ST_GEOMETRYCOLLECTIONFROMWKB","args":[{"type":"binary"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_GEOMETRYFROMTEXT","args":[{"type":"text"}],"returns":"any"} +{"name":"ST_GEOMETRYFROMTEXT","args":[{"type":"text"},{"type":"int"}],"returns":"any"} +{"name":"ST_GEOMETRYFROMTEXT","args":[{"type":"text"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_GEOMETRYFROMWKB","args":[{"type":"binary"}],"returns":"any"} +{"name":"ST_GEOMETRYFROMWKB","args":[{"type":"binary"},{"type":"int"}],"returns":"any"} +{"name":"ST_GEOMETRYFROMWKB","args":[{"type":"binary"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_GEOMETRYN","args":[{"type":"any"},{"type":"int"}],"returns":"any"} +{"name":"ST_GEOMETRYTYPE","args":[{"type":"any"}],"returns":"text"} +{"name":"ST_GEOMFROMGEOJSON","args":[{"type":"text"}],"returns":"any"} +{"name":"ST_GEOMFROMGEOJSON","args":[{"type":"text"},{"type":"tinyint"}],"returns":"any"} +{"name":"ST_GEOMFROMGEOJSON","args":[{"type":"text"},{"type":"tinyint"},{"type":"int"}],"returns":"any"} +{"name":"ST_GEOMFROMTEXT","args":[{"type":"text"}],"returns":"any"} +{"name":"ST_GEOMFROMTEXT","args":[{"type":"text"},{"type":"int"}],"returns":"any"} +{"name":"ST_GEOMFROMTEXT","args":[{"type":"text"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_GEOMFROMWKB","args":[{"type":"binary"}],"returns":"any"} +{"name":"ST_GEOMFROMWKB","args":[{"type":"binary"},{"type":"int"}],"returns":"any"} +{"name":"ST_GEOMFROMWKB","args":[{"type":"binary"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_HAUSDORFF_DISTANCE","args":[{"type":"any"},{"type":"any"}],"returns":"double precision"} +{"name":"ST_HAUSDORFF_DISTANCE","args":[{"type":"any"},{"type":"any"},{"type":"text"}],"returns":"double precision"} +{"name":"ST_INTERIORRINGN","args":[{"type":"any"},{"type":"int"}],"returns":"any"} +{"name":"ST_INTERSECTION","args":[{"type":"any"},{"type":"any"}],"returns":"any"} +{"name":"ST_INTERSECTS","args":[{"type":"any"},{"type":"any"}],"returns":"bool"} +{"name":"ST_ISCLOSED","args":[{"type":"any"}],"returns":"bool"} +{"name":"ST_ISEMPTY","args":[{"type":"any"}],"returns":"bool"} +{"name":"ST_ISSIMPLE","args":[{"type":"any"}],"returns":"bool"} +{"name":"ST_ISVALID","args":[{"type":"any"}],"returns":"bool"} +{"name":"ST_LATFROMGEOHASH","args":[{"type":"text"}],"returns":"double precision"} +{"name":"ST_LATITUDE","args":[{"type":"any"}],"returns":"double precision"} +{"name":"ST_LATITUDE","args":[{"type":"any"},{"type":"double precision"}],"returns":"any"} +{"name":"ST_LENGTH","args":[{"type":"any"}],"returns":"double precision"} +{"name":"ST_LENGTH","args":[{"type":"any"},{"type":"text"}],"returns":"double precision"} +{"name":"ST_LINEFROMTEXT","args":[{"type":"text"}],"returns":"any"} +{"name":"ST_LINEFROMTEXT","args":[{"type":"text"},{"type":"int"}],"returns":"any"} +{"name":"ST_LINEFROMTEXT","args":[{"type":"text"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_LINEFROMWKB","args":[{"type":"binary"}],"returns":"any"} +{"name":"ST_LINEFROMWKB","args":[{"type":"binary"},{"type":"int"}],"returns":"any"} +{"name":"ST_LINEFROMWKB","args":[{"type":"binary"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_LINEINTERPOLATEPOINT","args":[{"type":"any"},{"type":"double precision"}],"returns":"any"} +{"name":"ST_LINEINTERPOLATEPOINTS","args":[{"type":"any"},{"type":"double precision"}],"returns":"any"} +{"name":"ST_LINESTRINGFROMTEXT","args":[{"type":"text"}],"returns":"any"} +{"name":"ST_LINESTRINGFROMTEXT","args":[{"type":"text"},{"type":"int"}],"returns":"any"} +{"name":"ST_LINESTRINGFROMTEXT","args":[{"type":"text"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_LINESTRINGFROMWKB","args":[{"type":"binary"}],"returns":"any"} +{"name":"ST_LINESTRINGFROMWKB","args":[{"type":"binary"},{"type":"int"}],"returns":"any"} +{"name":"ST_LINESTRINGFROMWKB","args":[{"type":"binary"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_LONGFROMGEOHASH","args":[{"type":"text"}],"returns":"double precision"} +{"name":"ST_LONGITUDE","args":[{"type":"any"}],"returns":"double precision"} +{"name":"ST_LONGITUDE","args":[{"type":"any"},{"type":"double precision"}],"returns":"any"} +{"name":"ST_MAKEENVELOPE","args":[{"type":"any"},{"type":"any"}],"returns":"any"} +{"name":"ST_MLINEFROMTEXT","args":[{"type":"text"}],"returns":"any"} +{"name":"ST_MLINEFROMTEXT","args":[{"type":"text"},{"type":"int"}],"returns":"any"} +{"name":"ST_MLINEFROMTEXT","args":[{"type":"text"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_MLINEFROMWKB","args":[{"type":"binary"}],"returns":"any"} +{"name":"ST_MLINEFROMWKB","args":[{"type":"binary"},{"type":"int"}],"returns":"any"} +{"name":"ST_MLINEFROMWKB","args":[{"type":"binary"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_MPOINTFROMTEXT","args":[{"type":"text"}],"returns":"any"} +{"name":"ST_MPOINTFROMTEXT","args":[{"type":"text"},{"type":"int"}],"returns":"any"} +{"name":"ST_MPOINTFROMTEXT","args":[{"type":"text"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_MPOINTFROMWKB","args":[{"type":"binary"}],"returns":"any"} +{"name":"ST_MPOINTFROMWKB","args":[{"type":"binary"},{"type":"int"}],"returns":"any"} +{"name":"ST_MPOINTFROMWKB","args":[{"type":"binary"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_MPOLYFROMTEXT","args":[{"type":"text"}],"returns":"any"} +{"name":"ST_MPOLYFROMTEXT","args":[{"type":"text"},{"type":"int"}],"returns":"any"} +{"name":"ST_MPOLYFROMTEXT","args":[{"type":"text"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_MPOLYFROMWKB","args":[{"type":"binary"}],"returns":"any"} +{"name":"ST_MPOLYFROMWKB","args":[{"type":"binary"},{"type":"int"}],"returns":"any"} +{"name":"ST_MPOLYFROMWKB","args":[{"type":"binary"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_MULTILINESTRINGFROMTEXT","args":[{"type":"text"}],"returns":"any"} +{"name":"ST_MULTILINESTRINGFROMTEXT","args":[{"type":"text"},{"type":"int"}],"returns":"any"} +{"name":"ST_MULTILINESTRINGFROMTEXT","args":[{"type":"text"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_MULTILINESTRINGFROMWKB","args":[{"type":"binary"}],"returns":"any"} +{"name":"ST_MULTILINESTRINGFROMWKB","args":[{"type":"binary"},{"type":"int"}],"returns":"any"} +{"name":"ST_MULTILINESTRINGFROMWKB","args":[{"type":"binary"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_MULTIPOINTFROMTEXT","args":[{"type":"text"}],"returns":"any"} +{"name":"ST_MULTIPOINTFROMTEXT","args":[{"type":"text"},{"type":"int"}],"returns":"any"} +{"name":"ST_MULTIPOINTFROMTEXT","args":[{"type":"text"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_MULTIPOINTFROMWKB","args":[{"type":"binary"}],"returns":"any"} +{"name":"ST_MULTIPOINTFROMWKB","args":[{"type":"binary"},{"type":"int"}],"returns":"any"} +{"name":"ST_MULTIPOINTFROMWKB","args":[{"type":"binary"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_MULTIPOLYGONFROMTEXT","args":[{"type":"text"}],"returns":"any"} +{"name":"ST_MULTIPOLYGONFROMTEXT","args":[{"type":"text"},{"type":"int"}],"returns":"any"} +{"name":"ST_MULTIPOLYGONFROMTEXT","args":[{"type":"text"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_MULTIPOLYGONFROMWKB","args":[{"type":"binary"}],"returns":"any"} +{"name":"ST_MULTIPOLYGONFROMWKB","args":[{"type":"binary"},{"type":"int"}],"returns":"any"} +{"name":"ST_MULTIPOLYGONFROMWKB","args":[{"type":"binary"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_NUMGEOMETRIES","args":[{"type":"any"}],"returns":"bigint"} +{"name":"ST_NUMINTERIORRING","args":[{"type":"any"}],"returns":"int"} +{"name":"ST_NUMINTERIORRINGS","args":[{"type":"any"}],"returns":"int"} +{"name":"ST_NUMPOINTS","args":[{"type":"any"}],"returns":"bigint"} +{"name":"ST_OVERLAPS","args":[{"type":"any"},{"type":"any"}],"returns":"bool"} +{"name":"ST_POINTATDISTANCE","args":[{"type":"any"},{"type":"double precision"}],"returns":"any"} +{"name":"ST_POINTFROMGEOHASH","args":[{"type":"text"},{"type":"int"}],"returns":"any"} +{"name":"ST_POINTFROMTEXT","args":[{"type":"text"}],"returns":"any"} +{"name":"ST_POINTFROMTEXT","args":[{"type":"text"},{"type":"int"}],"returns":"any"} +{"name":"ST_POINTFROMTEXT","args":[{"type":"text"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_POINTFROMWKB","args":[{"type":"binary"}],"returns":"any"} +{"name":"ST_POINTFROMWKB","args":[{"type":"binary"},{"type":"int"}],"returns":"any"} +{"name":"ST_POINTFROMWKB","args":[{"type":"binary"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_POINTN","args":[{"type":"any"},{"type":"int"}],"returns":"any"} +{"name":"ST_POLYFROMTEXT","args":[{"type":"text"}],"returns":"any"} +{"name":"ST_POLYFROMTEXT","args":[{"type":"text"},{"type":"int"}],"returns":"any"} +{"name":"ST_POLYFROMTEXT","args":[{"type":"text"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_POLYFROMWKB","args":[{"type":"binary"}],"returns":"any"} +{"name":"ST_POLYFROMWKB","args":[{"type":"binary"},{"type":"int"}],"returns":"any"} +{"name":"ST_POLYFROMWKB","args":[{"type":"binary"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_POLYGONFROMTEXT","args":[{"type":"text"}],"returns":"any"} +{"name":"ST_POLYGONFROMTEXT","args":[{"type":"text"},{"type":"int"}],"returns":"any"} +{"name":"ST_POLYGONFROMTEXT","args":[{"type":"text"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_POLYGONFROMWKB","args":[{"type":"binary"}],"returns":"any"} +{"name":"ST_POLYGONFROMWKB","args":[{"type":"binary"},{"type":"int"}],"returns":"any"} +{"name":"ST_POLYGONFROMWKB","args":[{"type":"binary"},{"type":"int"},{"type":"text"}],"returns":"any"} +{"name":"ST_SIMPLIFY","args":[{"type":"any"},{"type":"double precision"}],"returns":"any"} +{"name":"ST_SRID","args":[{"type":"any"}],"returns":"int"} +{"name":"ST_SRID","args":[{"type":"any"},{"type":"int"}],"returns":"int"} +{"name":"ST_STARTPOINT","args":[{"type":"any"}],"returns":"any"} +{"name":"ST_SWAPXY","args":[{"type":"any"}],"returns":"any"} +{"name":"ST_SYMDIFFERENCE","args":[{"type":"any"},{"type":"any"}],"returns":"any"} +{"name":"ST_TOUCHES","args":[{"type":"any"},{"type":"any"}],"returns":"bool"} +{"name":"ST_TRANSFORM","args":[{"type":"any"},{"type":"int"}],"returns":"any"} +{"name":"ST_UNION","args":[{"type":"any"},{"type":"any"}],"returns":"any"} +{"name":"ST_VALIDATE","args":[{"type":"any"}],"returns":"any"} +{"name":"ST_WITHIN","args":[{"type":"any"},{"type":"any"}],"returns":"bool"} +{"name":"ST_X","args":[{"type":"any"}],"returns":"double precision"} +{"name":"ST_X","args":[{"type":"any"},{"type":"double precision"}],"returns":"any"} +{"name":"ST_Y","args":[{"type":"any"}],"returns":"double precision"} +{"name":"ST_Y","args":[{"type":"any"},{"type":"double precision"}],"returns":"any"} +{"name":"SUBDATE","args":[{"type":"date"},{"type":"any"}],"returns":"date"} +{"name":"SUBSTR","args":[{"type":"text"},{"type":"int"}],"returns":"text"} +{"name":"SUBSTR","args":[{"type":"text"},{"type":"int"},{"type":"int"}],"returns":"text"} +{"name":"SUBSTRING","args":[{"type":"text"},{"type":"int"}],"returns":"text"} +{"name":"SUBSTRING","args":[{"type":"text"},{"type":"int"},{"type":"int"}],"returns":"text"} +{"name":"SUBSTRING_INDEX","args":[{"type":"text"},{"type":"int"},{"type":"int"}],"returns":"text"} +{"name":"SUBTIME","args":[{"type":"time"},{"type":"time"}],"returns":"time"} +{"name":"SUM","args":[{"type":"any"}],"returns":"any","nullable":true} +{"name":"SYSDATE","returns":"datetime"} +{"name":"SYSDATE","args":[{"type":"int"}],"returns":"datetime"} +{"name":"SYSTEM_USER","returns":"text"} +{"name":"TAN","args":[{"type":"double precision"}],"returns":"double precision"} +{"name":"TIME","args":[{"type":"datetime"}],"returns":"time"} +{"name":"TIMEDIFF","args":[{"type":"time"},{"type":"time"}],"returns":"time"} +{"name":"TIMESTAMP","args":[{"type":"datetime"}],"returns":"datetime"} +{"name":"TIMESTAMP","args":[{"type":"datetime"},{"type":"datetime"}],"returns":"datetime"} +{"name":"TIMESTAMPADD","args":[{"type":"any"},{"type":"int"},{"type":"datetime"}],"returns":"datetime"} +{"name":"TIMESTAMPDIFF","args":[{"type":"any"},{"type":"datetime"},{"type":"datetime"}],"returns":"int"} +{"name":"TIME_FORMAT","args":[{"type":"time"},{"type":"text"}],"returns":"text"} +{"name":"TIME_TO_SEC","args":[{"type":"time"}],"returns":"int"} +{"name":"TO_BASE64","args":[{"type":"text"}],"returns":"text"} +{"name":"TO_DAYS","args":[{"type":"date"}],"returns":"int"} +{"name":"TO_SECONDS","args":[{"type":"datetime"}],"returns":"bigint"} +{"name":"TRIM","args":[{"type":"text"}],"returns":"text"} +{"name":"TRIM","args":[{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"TRUNCATE","args":[{"type":"double precision"},{"type":"int"}],"returns":"int"} +{"name":"UCASE","args":[{"type":"text"}],"returns":"text"} +{"name":"UNCOMPRESS","args":[{"type":"binary"}],"returns":"text"} +{"name":"UNCOMPRESSED_LENGTH","args":[{"type":"binary"}],"returns":"int"} +{"name":"UNHEX","args":[{"type":"text"}],"returns":""} +{"name":"UNIX_TIMESTAMP","returns":"bigint"} +{"name":"UNIX_TIMESTAMP","args":[{"type":"datetime"}],"returns":"bigint"} +{"name":"UPDATEXML","args":[{"type":"text"},{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"UPPER","args":[{"type":"text"}],"returns":"text"} +{"name":"USER","returns":"text"} +{"name":"UTC_DATE","returns":"date"} +{"name":"UTC_TIME","returns":"time"} +{"name":"UTC_TIMESTAMP","returns":"datetime"} +{"name":"UUID","returns":"text"} +{"name":"UUID_SHORT","returns":"bigint"} +{"name":"UUID_TO_BIN","args":[{"type":"text"}],"returns":"binary"} +{"name":"UUID_TO_BIN","args":[{"type":"text"},{"type":"tinyint"}],"returns":"binary"} +{"name":"VALIDATE_PASSWORD_STRENGTH","args":[{"type":"text"}],"returns":"int"} +{"name":"VALUES","args":[{"type":"any"}],"returns":"any"} +{"name":"VARIANCE","args":[{"type":"any"}],"returns":"any","nullable":true} +{"name":"VAR_POP","args":[{"type":"any"}],"returns":"any","nullable":true} +{"name":"VAR_SAMP","args":[{"type":"any"}],"returns":"any","nullable":true} +{"name":"VERSION","returns":"text"} +{"name":"WAIT_FOR_EXECUTED_GTID_SET","args":[{"type":"text"},{"type":"int","has_default":true}],"returns":"bool"} +{"name":"WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS","args":[{"type":"text"},{"type":"int","has_default":true},{"type":"text","has_default":true}],"returns":"bool"} +{"name":"WEEK","args":[{"type":"date"}],"returns":"int"} +{"name":"WEEK","args":[{"type":"date"},{"type":"int"}],"returns":"int"} +{"name":"WEEKDAY","args":[{"type":"date"}],"returns":"int"} +{"name":"WEEKOFYEAR","args":[{"type":"date"}],"returns":"int"} +{"name":"WEIGHT_STRING","args":[{"type":"text"}],"returns":"any"} +{"name":"YEAR","args":[{"type":"date"}],"returns":"int"} +{"name":"YEARWEEK","args":[{"type":"date"}],"returns":"int"} diff --git a/internal/engine/dolphin/dialect/operators.jsonl b/internal/engine/dolphin/dialect/operators.jsonl new file mode 100644 index 0000000..9e70497 --- /dev/null +++ b/internal/engine/dolphin/dialect/operators.jsonl @@ -0,0 +1,3 @@ +{"name": "~~", "left": "text", "right": "text", "result": "bool"} +{"name": "!~~", "left": "text", "right": "text", "result": "bool"} +{"name": "REGEXP", "left": "text", "right": "text", "result": "bool"} diff --git a/internal/engine/dolphin/dialect/relations.jsonl b/internal/engine/dolphin/dialect/relations.jsonl new file mode 100644 index 0000000..0660804 --- /dev/null +++ b/internal/engine/dolphin/dialect/relations.jsonl @@ -0,0 +1,84 @@ +{"catalog":"def","schema":"information_schema","name":"administrable_role_authorizations","kind":"v","columns":[{"name":"user","type":"varchar(97)"},{"name":"host","type":"varchar(256)"},{"name":"grantee","type":"varchar(97)"},{"name":"grantee_host","type":"varchar(256)"},{"name":"role_name","type":"varchar(255)"},{"name":"role_host","type":"varchar(256)"},{"name":"is_grantable","type":"varchar(3)","not_null":true},{"name":"is_default","type":"varchar(3)"},{"name":"is_mandatory","type":"varchar(3)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"applicable_roles","kind":"v","columns":[{"name":"user","type":"varchar(97)"},{"name":"host","type":"varchar(256)"},{"name":"grantee","type":"varchar(97)"},{"name":"grantee_host","type":"varchar(256)"},{"name":"role_name","type":"varchar(255)"},{"name":"role_host","type":"varchar(256)"},{"name":"is_grantable","type":"varchar(3)","not_null":true},{"name":"is_default","type":"varchar(3)"},{"name":"is_mandatory","type":"varchar(3)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"character_sets","kind":"v","columns":[{"name":"character_set_name","type":"varchar(64)","not_null":true},{"name":"default_collate_name","type":"varchar(64)","not_null":true},{"name":"description","type":"varchar(2048)","not_null":true},{"name":"maxlen","type":"int unsigned","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"check_constraints","kind":"v","columns":[{"name":"constraint_catalog","type":"varchar(64)","not_null":true},{"name":"constraint_schema","type":"varchar(64)","not_null":true},{"name":"constraint_name","type":"varchar(64)","not_null":true},{"name":"check_clause","type":"longtext","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"collations","kind":"v","columns":[{"name":"collation_name","type":"varchar(64)","not_null":true},{"name":"character_set_name","type":"varchar(64)","not_null":true},{"name":"id","type":"bigint unsigned","not_null":true},{"name":"is_default","type":"varchar(3)","not_null":true},{"name":"is_compiled","type":"varchar(3)","not_null":true},{"name":"sortlen","type":"int unsigned","not_null":true},{"name":"pad_attribute","type":"enum('PAD SPACE','NO PAD')","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"collation_character_set_applicability","kind":"v","columns":[{"name":"collation_name","type":"varchar(64)","not_null":true},{"name":"character_set_name","type":"varchar(64)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"columns","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"column_name","type":"varchar(64)"},{"name":"ordinal_position","type":"int unsigned","not_null":true},{"name":"column_default","type":"text"},{"name":"is_nullable","type":"varchar(3)","not_null":true},{"name":"data_type","type":"longtext"},{"name":"character_maximum_length","type":"bigint"},{"name":"character_octet_length","type":"bigint"},{"name":"numeric_precision","type":"bigint unsigned"},{"name":"numeric_scale","type":"bigint unsigned"},{"name":"datetime_precision","type":"int unsigned"},{"name":"character_set_name","type":"varchar(64)"},{"name":"collation_name","type":"varchar(64)"},{"name":"column_type","type":"mediumtext","not_null":true},{"name":"column_key","type":"enum('','PRI','UNI','MUL')","not_null":true},{"name":"extra","type":"varchar(256)"},{"name":"privileges","type":"varchar(154)"},{"name":"column_comment","type":"text","not_null":true},{"name":"generation_expression","type":"longtext","not_null":true},{"name":"srs_id","type":"int unsigned"}]} +{"catalog":"def","schema":"information_schema","name":"columns_extensions","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"column_name","type":"varchar(64)"},{"name":"engine_attribute","type":"json"},{"name":"secondary_engine_attribute","type":"json"}]} +{"catalog":"def","schema":"information_schema","name":"column_privileges","kind":"v","columns":[{"name":"grantee","type":"varchar(292)","not_null":true},{"name":"table_catalog","type":"varchar(512)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"column_name","type":"varchar(64)","not_null":true},{"name":"privilege_type","type":"varchar(64)","not_null":true},{"name":"is_grantable","type":"varchar(3)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"column_statistics","kind":"v","columns":[{"name":"schema_name","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"column_name","type":"varchar(64)","not_null":true},{"name":"histogram","type":"json","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"enabled_roles","kind":"v","columns":[{"name":"role_name","type":"varchar(255)"},{"name":"role_host","type":"varchar(255)"},{"name":"is_default","type":"varchar(3)"},{"name":"is_mandatory","type":"varchar(3)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"engines","kind":"v","columns":[{"name":"engine","type":"varchar(64)","not_null":true},{"name":"support","type":"varchar(8)","not_null":true},{"name":"comment","type":"varchar(80)","not_null":true},{"name":"transactions","type":"varchar(3)"},{"name":"xa","type":"varchar(3)"},{"name":"savepoints","type":"varchar(3)"}]} +{"catalog":"def","schema":"information_schema","name":"events","kind":"v","columns":[{"name":"event_catalog","type":"varchar(64)","not_null":true},{"name":"event_schema","type":"varchar(64)","not_null":true},{"name":"event_name","type":"varchar(64)","not_null":true},{"name":"definer","type":"varchar(288)","not_null":true},{"name":"time_zone","type":"varchar(64)","not_null":true},{"name":"event_body","type":"varchar(3)","not_null":true},{"name":"event_definition","type":"longtext","not_null":true},{"name":"event_type","type":"varchar(9)","not_null":true},{"name":"execute_at","type":"datetime"},{"name":"interval_value","type":"varchar(256)"},{"name":"interval_field","type":"enum('YEAR','QUARTER','MONTH','DAY','HOUR','MINUTE','WEEK','SECOND','MICROSECOND','YEAR_MONTH','DAY_HOUR','DAY_MINUTE','DAY_SECOND','HOUR_MINUTE','HOUR_SECOND','MINUTE_SECOND','DAY_MICROSECOND','HOUR_MICROSECOND','MINUTE_MICROSECOND','SECOND_MICROSECOND')"},{"name":"sql_mode","type":"set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE','NOT_USED_9','NOT_USED_10','NOT_USED_11','NOT_USED_12','NOT_USED_13','NOT_USED_14','NOT_USED_15','NOT_USED_16','NOT_USED_17','NOT_USED_18','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','ALLOW_INVALID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NOT_USED_29','HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH','TIME_TRUNCATE_FRACTIONAL','INTERPRET_UTF8_AS_UTF8MB4')","not_null":true},{"name":"starts","type":"datetime"},{"name":"ends","type":"datetime"},{"name":"status","type":"varchar(21)","not_null":true},{"name":"on_completion","type":"varchar(12)","not_null":true},{"name":"created","type":"timestamp","not_null":true},{"name":"last_altered","type":"timestamp","not_null":true},{"name":"last_executed","type":"datetime"},{"name":"event_comment","type":"varchar(2048)","not_null":true},{"name":"originator","type":"int unsigned","not_null":true},{"name":"character_set_client","type":"varchar(64)","not_null":true},{"name":"collation_connection","type":"varchar(64)","not_null":true},{"name":"database_collation","type":"varchar(64)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"files","kind":"v","columns":[{"name":"file_id","type":"bigint"},{"name":"file_name","type":"text"},{"name":"file_type","type":"varchar(256)"},{"name":"tablespace_name","type":"varchar(268)","not_null":true},{"name":"table_catalog","type":"varchar(0)","not_null":true},{"name":"table_schema","type":"varbinary(0)"},{"name":"table_name","type":"varbinary(0)"},{"name":"logfile_group_name","type":"varchar(256)"},{"name":"logfile_group_number","type":"bigint"},{"name":"engine","type":"varchar(64)","not_null":true},{"name":"fulltext_keys","type":"varbinary(0)"},{"name":"deleted_rows","type":"varbinary(0)"},{"name":"update_count","type":"varbinary(0)"},{"name":"free_extents","type":"bigint"},{"name":"total_extents","type":"bigint"},{"name":"extent_size","type":"bigint"},{"name":"initial_size","type":"bigint"},{"name":"maximum_size","type":"bigint"},{"name":"autoextend_size","type":"bigint"},{"name":"creation_time","type":"varbinary(0)"},{"name":"last_update_time","type":"varbinary(0)"},{"name":"last_access_time","type":"varbinary(0)"},{"name":"recover_time","type":"varbinary(0)"},{"name":"transaction_counter","type":"varbinary(0)"},{"name":"version","type":"bigint"},{"name":"row_format","type":"varchar(256)"},{"name":"table_rows","type":"varbinary(0)"},{"name":"avg_row_length","type":"varbinary(0)"},{"name":"data_length","type":"varbinary(0)"},{"name":"max_data_length","type":"varbinary(0)"},{"name":"index_length","type":"varbinary(0)"},{"name":"data_free","type":"bigint"},{"name":"create_time","type":"varbinary(0)"},{"name":"update_time","type":"varbinary(0)"},{"name":"check_time","type":"varbinary(0)"},{"name":"checksum","type":"varbinary(0)"},{"name":"status","type":"varchar(256)"},{"name":"extra","type":"varchar(256)"}]} +{"catalog":"def","schema":"information_schema","name":"innodb_buffer_page","kind":"v","columns":[{"name":"pool_id","type":"bigint unsigned","not_null":true},{"name":"block_id","type":"bigint unsigned","not_null":true},{"name":"space","type":"bigint unsigned","not_null":true},{"name":"page_number","type":"bigint unsigned","not_null":true},{"name":"page_type","type":"varchar(64)"},{"name":"flush_type","type":"bigint unsigned","not_null":true},{"name":"fix_count","type":"bigint unsigned","not_null":true},{"name":"is_hashed","type":"varchar(3)"},{"name":"newest_modification","type":"bigint unsigned","not_null":true},{"name":"oldest_modification","type":"bigint unsigned","not_null":true},{"name":"access_time","type":"bigint unsigned","not_null":true},{"name":"table_name","type":"varchar(1024)"},{"name":"index_name","type":"varchar(1024)"},{"name":"number_records","type":"bigint unsigned","not_null":true},{"name":"data_size","type":"bigint unsigned","not_null":true},{"name":"compressed_size","type":"bigint unsigned","not_null":true},{"name":"page_state","type":"varchar(64)"},{"name":"io_fix","type":"varchar(64)"},{"name":"is_old","type":"varchar(3)"},{"name":"free_page_clock","type":"bigint unsigned","not_null":true},{"name":"is_stale","type":"varchar(3)"}]} +{"catalog":"def","schema":"information_schema","name":"innodb_buffer_page_lru","kind":"v","columns":[{"name":"pool_id","type":"bigint unsigned","not_null":true},{"name":"lru_position","type":"bigint unsigned","not_null":true},{"name":"space","type":"bigint unsigned","not_null":true},{"name":"page_number","type":"bigint unsigned","not_null":true},{"name":"page_type","type":"varchar(64)"},{"name":"flush_type","type":"bigint unsigned","not_null":true},{"name":"fix_count","type":"bigint unsigned","not_null":true},{"name":"is_hashed","type":"varchar(3)"},{"name":"newest_modification","type":"bigint unsigned","not_null":true},{"name":"oldest_modification","type":"bigint unsigned","not_null":true},{"name":"access_time","type":"bigint unsigned","not_null":true},{"name":"table_name","type":"varchar(1024)"},{"name":"index_name","type":"varchar(1024)"},{"name":"number_records","type":"bigint unsigned","not_null":true},{"name":"data_size","type":"bigint unsigned","not_null":true},{"name":"compressed_size","type":"bigint unsigned","not_null":true},{"name":"compressed","type":"varchar(3)"},{"name":"io_fix","type":"varchar(64)"},{"name":"is_old","type":"varchar(3)"},{"name":"free_page_clock","type":"bigint unsigned","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_buffer_pool_stats","kind":"v","columns":[{"name":"pool_id","type":"bigint unsigned","not_null":true},{"name":"pool_size","type":"bigint unsigned","not_null":true},{"name":"free_buffers","type":"bigint unsigned","not_null":true},{"name":"database_pages","type":"bigint unsigned","not_null":true},{"name":"old_database_pages","type":"bigint unsigned","not_null":true},{"name":"modified_database_pages","type":"bigint unsigned","not_null":true},{"name":"pending_decompress","type":"bigint unsigned","not_null":true},{"name":"pending_reads","type":"bigint unsigned","not_null":true},{"name":"pending_flush_lru","type":"bigint unsigned","not_null":true},{"name":"pending_flush_list","type":"bigint unsigned","not_null":true},{"name":"pages_made_young","type":"bigint unsigned","not_null":true},{"name":"pages_not_made_young","type":"bigint unsigned","not_null":true},{"name":"pages_made_young_rate","type":"float(12,0)","not_null":true},{"name":"pages_made_not_young_rate","type":"float(12,0)","not_null":true},{"name":"number_pages_read","type":"bigint unsigned","not_null":true},{"name":"number_pages_created","type":"bigint unsigned","not_null":true},{"name":"number_pages_written","type":"bigint unsigned","not_null":true},{"name":"pages_read_rate","type":"float(12,0)","not_null":true},{"name":"pages_create_rate","type":"float(12,0)","not_null":true},{"name":"pages_written_rate","type":"float(12,0)","not_null":true},{"name":"number_pages_get","type":"bigint unsigned","not_null":true},{"name":"hit_rate","type":"bigint unsigned","not_null":true},{"name":"young_make_per_thousand_gets","type":"bigint unsigned","not_null":true},{"name":"not_young_make_per_thousand_gets","type":"bigint unsigned","not_null":true},{"name":"number_pages_read_ahead","type":"bigint unsigned","not_null":true},{"name":"number_read_ahead_evicted","type":"bigint unsigned","not_null":true},{"name":"read_ahead_rate","type":"float(12,0)","not_null":true},{"name":"read_ahead_evicted_rate","type":"float(12,0)","not_null":true},{"name":"lru_io_total","type":"bigint unsigned","not_null":true},{"name":"lru_io_current","type":"bigint unsigned","not_null":true},{"name":"uncompress_total","type":"bigint unsigned","not_null":true},{"name":"uncompress_current","type":"bigint unsigned","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_cached_indexes","kind":"v","columns":[{"name":"space_id","type":"int unsigned","not_null":true},{"name":"index_id","type":"bigint unsigned","not_null":true},{"name":"n_cached_pages","type":"bigint unsigned","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_cmp","kind":"v","columns":[{"name":"page_size","type":"int","not_null":true},{"name":"compress_ops","type":"int","not_null":true},{"name":"compress_ops_ok","type":"int","not_null":true},{"name":"compress_time","type":"int","not_null":true},{"name":"uncompress_ops","type":"int","not_null":true},{"name":"uncompress_time","type":"int","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_cmpmem","kind":"v","columns":[{"name":"page_size","type":"int","not_null":true},{"name":"buffer_pool_instance","type":"int","not_null":true},{"name":"pages_used","type":"int","not_null":true},{"name":"pages_free","type":"int","not_null":true},{"name":"relocation_ops","type":"bigint","not_null":true},{"name":"relocation_time","type":"int","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_cmpmem_reset","kind":"v","columns":[{"name":"page_size","type":"int","not_null":true},{"name":"buffer_pool_instance","type":"int","not_null":true},{"name":"pages_used","type":"int","not_null":true},{"name":"pages_free","type":"int","not_null":true},{"name":"relocation_ops","type":"bigint","not_null":true},{"name":"relocation_time","type":"int","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_cmp_per_index","kind":"v","columns":[{"name":"database_name","type":"varchar(192)","not_null":true},{"name":"table_name","type":"varchar(192)","not_null":true},{"name":"index_name","type":"varchar(192)","not_null":true},{"name":"compress_ops","type":"int","not_null":true},{"name":"compress_ops_ok","type":"int","not_null":true},{"name":"compress_time","type":"int","not_null":true},{"name":"uncompress_ops","type":"int","not_null":true},{"name":"uncompress_time","type":"int","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_cmp_per_index_reset","kind":"v","columns":[{"name":"database_name","type":"varchar(192)","not_null":true},{"name":"table_name","type":"varchar(192)","not_null":true},{"name":"index_name","type":"varchar(192)","not_null":true},{"name":"compress_ops","type":"int","not_null":true},{"name":"compress_ops_ok","type":"int","not_null":true},{"name":"compress_time","type":"int","not_null":true},{"name":"uncompress_ops","type":"int","not_null":true},{"name":"uncompress_time","type":"int","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_cmp_reset","kind":"v","columns":[{"name":"page_size","type":"int","not_null":true},{"name":"compress_ops","type":"int","not_null":true},{"name":"compress_ops_ok","type":"int","not_null":true},{"name":"compress_time","type":"int","not_null":true},{"name":"uncompress_ops","type":"int","not_null":true},{"name":"uncompress_time","type":"int","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_columns","kind":"v","columns":[{"name":"table_id","type":"bigint unsigned","not_null":true},{"name":"name","type":"varchar(193)","not_null":true},{"name":"pos","type":"bigint unsigned","not_null":true},{"name":"mtype","type":"int","not_null":true},{"name":"prtype","type":"int","not_null":true},{"name":"len","type":"int","not_null":true},{"name":"has_default","type":"int","not_null":true},{"name":"default_value","type":"text"}]} +{"catalog":"def","schema":"information_schema","name":"innodb_datafiles","kind":"v","columns":[{"name":"space","type":"varbinary(256)"},{"name":"path","type":"varchar(512)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_fields","kind":"v","columns":[{"name":"index_id","type":"varbinary(256)"},{"name":"name","type":"varchar(64)","not_null":true},{"name":"pos","type":"bigint unsigned","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_foreign","kind":"v","columns":[{"name":"id","type":"varchar(129)"},{"name":"for_name","type":"varchar(129)"},{"name":"ref_name","type":"varchar(129)"},{"name":"n_cols","type":"bigint","not_null":true},{"name":"type","type":"bigint unsigned","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_foreign_cols","kind":"v","columns":[{"name":"id","type":"varchar(129)"},{"name":"for_col_name","type":"varchar(64)","not_null":true},{"name":"ref_col_name","type":"varchar(64)","not_null":true},{"name":"pos","type":"int unsigned","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_ft_being_deleted","kind":"v","columns":[{"name":"doc_id","type":"bigint unsigned","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_ft_config","kind":"v","columns":[{"name":"key","type":"varchar(193)","not_null":true},{"name":"value","type":"varchar(193)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_ft_default_stopword","kind":"v","columns":[{"name":"value","type":"varchar(18)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_ft_deleted","kind":"v","columns":[{"name":"doc_id","type":"bigint unsigned","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_ft_index_cache","kind":"v","columns":[{"name":"word","type":"varchar(337)","not_null":true},{"name":"first_doc_id","type":"bigint unsigned","not_null":true},{"name":"last_doc_id","type":"bigint unsigned","not_null":true},{"name":"doc_count","type":"bigint unsigned","not_null":true},{"name":"doc_id","type":"bigint unsigned","not_null":true},{"name":"position","type":"bigint unsigned","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_ft_index_table","kind":"v","columns":[{"name":"word","type":"varchar(337)","not_null":true},{"name":"first_doc_id","type":"bigint unsigned","not_null":true},{"name":"last_doc_id","type":"bigint unsigned","not_null":true},{"name":"doc_count","type":"bigint unsigned","not_null":true},{"name":"doc_id","type":"bigint unsigned","not_null":true},{"name":"position","type":"bigint unsigned","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_indexes","kind":"v","columns":[{"name":"index_id","type":"bigint unsigned","not_null":true},{"name":"name","type":"varchar(193)","not_null":true},{"name":"table_id","type":"bigint unsigned","not_null":true},{"name":"type","type":"int","not_null":true},{"name":"n_fields","type":"int","not_null":true},{"name":"page_no","type":"int","not_null":true},{"name":"space","type":"int","not_null":true},{"name":"merge_threshold","type":"int","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_metrics","kind":"v","columns":[{"name":"name","type":"varchar(193)","not_null":true},{"name":"subsystem","type":"varchar(193)","not_null":true},{"name":"count","type":"bigint","not_null":true},{"name":"max_count","type":"bigint"},{"name":"min_count","type":"bigint"},{"name":"avg_count","type":"float(12,0)"},{"name":"count_reset","type":"bigint","not_null":true},{"name":"max_count_reset","type":"bigint"},{"name":"min_count_reset","type":"bigint"},{"name":"avg_count_reset","type":"float(12,0)"},{"name":"time_enabled","type":"datetime"},{"name":"time_disabled","type":"datetime"},{"name":"time_elapsed","type":"bigint"},{"name":"time_reset","type":"datetime"},{"name":"status","type":"varchar(193)","not_null":true},{"name":"type","type":"varchar(193)","not_null":true},{"name":"comment","type":"varchar(193)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_session_temp_tablespaces","kind":"v","columns":[{"name":"id","type":"int unsigned","not_null":true},{"name":"space","type":"int unsigned","not_null":true},{"name":"path","type":"varchar(4001)","not_null":true},{"name":"size","type":"bigint unsigned","not_null":true},{"name":"state","type":"varchar(192)","not_null":true},{"name":"purpose","type":"varchar(192)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_tables","kind":"v","columns":[{"name":"table_id","type":"bigint unsigned","not_null":true},{"name":"name","type":"varchar(655)","not_null":true},{"name":"flag","type":"int","not_null":true},{"name":"n_cols","type":"int","not_null":true},{"name":"space","type":"bigint","not_null":true},{"name":"row_format","type":"varchar(12)"},{"name":"zip_page_size","type":"int unsigned","not_null":true},{"name":"space_type","type":"varchar(10)"},{"name":"instant_cols","type":"int","not_null":true},{"name":"total_row_versions","type":"int","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_tablespaces","kind":"v","columns":[{"name":"space","type":"int unsigned","not_null":true},{"name":"name","type":"varchar(655)","not_null":true},{"name":"flag","type":"int unsigned","not_null":true},{"name":"row_format","type":"varchar(22)"},{"name":"page_size","type":"int unsigned","not_null":true},{"name":"zip_page_size","type":"int unsigned","not_null":true},{"name":"space_type","type":"varchar(10)"},{"name":"fs_block_size","type":"int unsigned","not_null":true},{"name":"file_size","type":"bigint unsigned","not_null":true},{"name":"allocated_size","type":"bigint unsigned","not_null":true},{"name":"autoextend_size","type":"bigint unsigned","not_null":true},{"name":"server_version","type":"varchar(10)"},{"name":"space_version","type":"int unsigned","not_null":true},{"name":"encryption","type":"varchar(1)"},{"name":"state","type":"varchar(10)"}]} +{"catalog":"def","schema":"information_schema","name":"innodb_tablespaces_brief","kind":"v","columns":[{"name":"space","type":"varbinary(256)"},{"name":"name","type":"varchar(268)","not_null":true},{"name":"path","type":"varchar(512)","not_null":true},{"name":"flag","type":"varbinary(256)"},{"name":"space_type","type":"varchar(7)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_tablestats","kind":"v","columns":[{"name":"table_id","type":"bigint unsigned","not_null":true},{"name":"name","type":"varchar(193)","not_null":true},{"name":"stats_initialized","type":"varchar(193)","not_null":true},{"name":"num_rows","type":"bigint unsigned","not_null":true},{"name":"clust_index_size","type":"bigint unsigned","not_null":true},{"name":"other_index_size","type":"bigint unsigned","not_null":true},{"name":"modified_counter","type":"bigint unsigned","not_null":true},{"name":"autoinc","type":"bigint unsigned","not_null":true},{"name":"ref_count","type":"int","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_temp_table_info","kind":"v","columns":[{"name":"table_id","type":"bigint unsigned","not_null":true},{"name":"name","type":"varchar(64)"},{"name":"n_cols","type":"int unsigned","not_null":true},{"name":"space","type":"int unsigned","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"innodb_trx","kind":"v","columns":[{"name":"trx_id","type":"bigint unsigned","not_null":true},{"name":"trx_state","type":"varchar(13)","not_null":true},{"name":"trx_started","type":"datetime","not_null":true},{"name":"trx_requested_lock_id","type":"varchar(126)"},{"name":"trx_wait_started","type":"datetime"},{"name":"trx_weight","type":"bigint unsigned","not_null":true},{"name":"trx_mysql_thread_id","type":"bigint unsigned","not_null":true},{"name":"trx_query","type":"varchar(1024)"},{"name":"trx_operation_state","type":"varchar(64)"},{"name":"trx_tables_in_use","type":"bigint unsigned","not_null":true},{"name":"trx_tables_locked","type":"bigint unsigned","not_null":true},{"name":"trx_lock_structs","type":"bigint unsigned","not_null":true},{"name":"trx_lock_memory_bytes","type":"bigint unsigned","not_null":true},{"name":"trx_rows_locked","type":"bigint unsigned","not_null":true},{"name":"trx_rows_modified","type":"bigint unsigned","not_null":true},{"name":"trx_concurrency_tickets","type":"bigint unsigned","not_null":true},{"name":"trx_isolation_level","type":"varchar(16)","not_null":true},{"name":"trx_unique_checks","type":"int","not_null":true},{"name":"trx_foreign_key_checks","type":"int","not_null":true},{"name":"trx_last_foreign_key_error","type":"varchar(256)"},{"name":"trx_adaptive_hash_latched","type":"int","not_null":true},{"name":"trx_adaptive_hash_timeout","type":"bigint unsigned","not_null":true},{"name":"trx_is_read_only","type":"int","not_null":true},{"name":"trx_autocommit_non_locking","type":"int","not_null":true},{"name":"trx_schedule_weight","type":"bigint unsigned"}]} +{"catalog":"def","schema":"information_schema","name":"innodb_virtual","kind":"v","columns":[{"name":"table_id","type":"bigint unsigned","not_null":true},{"name":"pos","type":"int unsigned","not_null":true},{"name":"base_pos","type":"int unsigned","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"json_duality_views","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"definer","type":"varchar(288)"},{"name":"security_type","type":"varchar(7)"},{"name":"json_column_name","type":"varchar(64)","not_null":true},{"name":"root_table_catalog","type":"varchar(64)"},{"name":"root_table_schema","type":"varchar(64)"},{"name":"root_table_name","type":"varchar(64)"},{"name":"allow_insert","type":"varchar(4)"},{"name":"allow_update","type":"varchar(4)"},{"name":"allow_delete","type":"varchar(4)"},{"name":"read_only","type":"varchar(4)"},{"name":"status","type":"varchar(7)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"json_duality_view_columns","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"referenced_table_catalog","type":"varchar(64)"},{"name":"referenced_table_schema","type":"varchar(64)"},{"name":"referenced_table_name","type":"varchar(64)"},{"name":"is_root_table","type":"tinyint"},{"name":"referenced_table_id","type":"int"},{"name":"referenced_column_name","type":"varchar(64)"},{"name":"json_key_name","type":"varchar(64)"},{"name":"allow_insert","type":"tinyint"},{"name":"allow_update","type":"tinyint"},{"name":"allow_delete","type":"tinyint"},{"name":"read_only","type":"tinyint"}]} +{"catalog":"def","schema":"information_schema","name":"json_duality_view_links","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"parent_table_catalog","type":"varchar(64)"},{"name":"parent_table_schema","type":"varchar(64)"},{"name":"parent_table_name","type":"varchar(64)"},{"name":"child_table_catalog","type":"varchar(64)"},{"name":"child_table_schema","type":"varchar(64)"},{"name":"child_table_name","type":"varchar(64)"},{"name":"parent_column_name","type":"varchar(64)"},{"name":"child_column_name","type":"varchar(64)"},{"name":"join_type","type":"varchar(64)"},{"name":"json_key_name","type":"varchar(64)"}]} +{"catalog":"def","schema":"information_schema","name":"json_duality_view_tables","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"referenced_table_catalog","type":"varchar(64)"},{"name":"referenced_table_schema","type":"varchar(64)"},{"name":"referenced_table_name","type":"varchar(64)"},{"name":"where_clause","type":"varchar(64)"},{"name":"allow_insert","type":"tinyint"},{"name":"allow_update","type":"tinyint"},{"name":"allow_delete","type":"tinyint"},{"name":"read_only","type":"tinyint"},{"name":"is_root_table","type":"tinyint"},{"name":"referenced_table_id","type":"int"},{"name":"referenced_table_parent_id","type":"int"},{"name":"referenced_table_parent_relationship","type":"varchar(64)"}]} +{"catalog":"def","schema":"information_schema","name":"keywords","kind":"v","columns":[{"name":"word","type":"varchar(128)"},{"name":"reserved","type":"int"}]} +{"catalog":"def","schema":"information_schema","name":"key_column_usage","kind":"v","columns":[{"name":"constraint_catalog","type":"varchar(64)","not_null":true},{"name":"constraint_schema","type":"varchar(64)","not_null":true},{"name":"constraint_name","type":"varchar(64)"},{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"column_name","type":"varchar(64)"},{"name":"ordinal_position","type":"int unsigned","not_null":true},{"name":"position_in_unique_constraint","type":"int unsigned"},{"name":"referenced_table_schema","type":"varchar(64)"},{"name":"referenced_table_name","type":"varchar(64)"},{"name":"referenced_column_name","type":"varchar(64)"}]} +{"catalog":"def","schema":"information_schema","name":"libraries","kind":"v","columns":[{"name":"library_catalog","type":"varchar(64)","not_null":true},{"name":"library_schema","type":"varchar(64)","not_null":true},{"name":"library_name","type":"varchar(64)","not_null":true},{"name":"library_definition","type":"longtext"},{"name":"language","type":"varchar(64)","not_null":true},{"name":"created","type":"timestamp","not_null":true},{"name":"last_altered","type":"timestamp","not_null":true},{"name":"sql_mode","type":"set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE','NOT_USED_9','NOT_USED_10','NOT_USED_11','NOT_USED_12','NOT_USED_13','NOT_USED_14','NOT_USED_15','NOT_USED_16','NOT_USED_17','NOT_USED_18','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','ALLOW_INVALID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NOT_USED_29','HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH','TIME_TRUNCATE_FRACTIONAL','INTERPRET_UTF8_AS_UTF8MB4')","not_null":true},{"name":"library_comment","type":"text","not_null":true},{"name":"creator","type":"varchar(288)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"optimizer_trace","kind":"v","columns":[{"name":"query","type":"varchar(65535)","not_null":true},{"name":"trace","type":"varchar(65535)","not_null":true},{"name":"missing_bytes_beyond_max_mem_size","type":"int","not_null":true},{"name":"insufficient_privileges","type":"tinyint(1)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"parameters","kind":"v","columns":[{"name":"specific_catalog","type":"varchar(64)","not_null":true},{"name":"specific_schema","type":"varchar(64)","not_null":true},{"name":"specific_name","type":"varchar(64)","not_null":true},{"name":"ordinal_position","type":"bigint unsigned","not_null":true},{"name":"parameter_mode","type":"varchar(5)"},{"name":"parameter_name","type":"varchar(64)"},{"name":"data_type","type":"longtext"},{"name":"character_maximum_length","type":"bigint"},{"name":"character_octet_length","type":"bigint"},{"name":"numeric_precision","type":"int unsigned"},{"name":"numeric_scale","type":"bigint"},{"name":"datetime_precision","type":"int unsigned"},{"name":"character_set_name","type":"varchar(64)"},{"name":"collation_name","type":"varchar(64)"},{"name":"dtd_identifier","type":"mediumtext","not_null":true},{"name":"routine_type","type":"enum('FUNCTION','PROCEDURE','LIBRARY')","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"partitions","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"partition_name","type":"varchar(64)"},{"name":"subpartition_name","type":"varchar(64)"},{"name":"partition_ordinal_position","type":"int unsigned"},{"name":"subpartition_ordinal_position","type":"int unsigned"},{"name":"secondary_load","type":"varchar(1)"},{"name":"partition_method","type":"varchar(13)"},{"name":"subpartition_method","type":"varchar(13)"},{"name":"partition_expression","type":"varchar(2048)"},{"name":"subpartition_expression","type":"varchar(2048)"},{"name":"partition_description","type":"text"},{"name":"table_rows","type":"bigint unsigned"},{"name":"avg_row_length","type":"bigint unsigned"},{"name":"data_length","type":"bigint unsigned"},{"name":"max_data_length","type":"bigint unsigned"},{"name":"index_length","type":"bigint unsigned"},{"name":"data_free","type":"bigint unsigned"},{"name":"create_time","type":"timestamp","not_null":true},{"name":"update_time","type":"datetime"},{"name":"check_time","type":"datetime"},{"name":"checksum","type":"bigint"},{"name":"partition_comment","type":"text","not_null":true},{"name":"nodegroup","type":"varchar(256)"},{"name":"tablespace_name","type":"varchar(268)"}]} +{"catalog":"def","schema":"information_schema","name":"plugins","kind":"v","columns":[{"name":"plugin_name","type":"varchar(64)","not_null":true},{"name":"plugin_version","type":"varchar(20)","not_null":true},{"name":"plugin_status","type":"varchar(10)","not_null":true},{"name":"plugin_type","type":"varchar(80)","not_null":true},{"name":"plugin_type_version","type":"varchar(20)","not_null":true},{"name":"plugin_library","type":"varchar(64)"},{"name":"plugin_library_version","type":"varchar(20)"},{"name":"plugin_author","type":"varchar(64)"},{"name":"plugin_description","type":"varchar(65535)"},{"name":"plugin_license","type":"varchar(80)"},{"name":"load_option","type":"varchar(64)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"processlist","kind":"v","columns":[{"name":"id","type":"bigint unsigned","not_null":true},{"name":"user","type":"varchar(32)","not_null":true},{"name":"host","type":"varchar(261)","not_null":true},{"name":"db","type":"varchar(64)"},{"name":"command","type":"varchar(16)","not_null":true},{"name":"time","type":"int","not_null":true},{"name":"state","type":"varchar(64)"},{"name":"info","type":"varchar(65535)"}]} +{"catalog":"def","schema":"information_schema","name":"profiling","kind":"v","columns":[{"name":"query_id","type":"int","not_null":true},{"name":"seq","type":"int","not_null":true},{"name":"state","type":"varchar(30)","not_null":true},{"name":"duration","type":"decimal(905,0)","not_null":true},{"name":"cpu_user","type":"decimal(905,0)"},{"name":"cpu_system","type":"decimal(905,0)"},{"name":"context_voluntary","type":"int"},{"name":"context_involuntary","type":"int"},{"name":"block_ops_in","type":"int"},{"name":"block_ops_out","type":"int"},{"name":"messages_sent","type":"int"},{"name":"messages_received","type":"int"},{"name":"page_faults_major","type":"int"},{"name":"page_faults_minor","type":"int"},{"name":"swaps","type":"int"},{"name":"source_function","type":"varchar(30)"},{"name":"source_file","type":"varchar(20)"},{"name":"source_line","type":"int"}]} +{"catalog":"def","schema":"information_schema","name":"referential_constraints","kind":"v","columns":[{"name":"constraint_catalog","type":"varchar(64)","not_null":true},{"name":"constraint_schema","type":"varchar(64)","not_null":true},{"name":"constraint_name","type":"varchar(64)"},{"name":"unique_constraint_catalog","type":"varchar(64)","not_null":true},{"name":"unique_constraint_schema","type":"varchar(64)","not_null":true},{"name":"unique_constraint_name","type":"varchar(64)"},{"name":"match_option","type":"enum('NONE','PARTIAL','FULL')","not_null":true},{"name":"update_rule","type":"enum('NO ACTION','RESTRICT','CASCADE','SET NULL','SET DEFAULT')","not_null":true},{"name":"delete_rule","type":"enum('NO ACTION','RESTRICT','CASCADE','SET NULL','SET DEFAULT')","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"referenced_table_name","type":"varchar(64)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"resource_groups","kind":"v","columns":[{"name":"resource_group_name","type":"varchar(64)","not_null":true},{"name":"resource_group_type","type":"enum('SYSTEM','USER')","not_null":true},{"name":"resource_group_enabled","type":"tinyint(1)","not_null":true},{"name":"vcpu_ids","type":"blob"},{"name":"thread_priority","type":"int","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"role_column_grants","kind":"v","columns":[{"name":"grantor","type":"varchar(97)"},{"name":"grantor_host","type":"varchar(256)"},{"name":"grantee","type":"char(32)","not_null":true},{"name":"grantee_host","type":"char(255)","not_null":true},{"name":"table_catalog","type":"varchar(3)","not_null":true},{"name":"table_schema","type":"char(64)","not_null":true},{"name":"table_name","type":"char(64)","not_null":true},{"name":"column_name","type":"char(64)","not_null":true},{"name":"privilege_type","type":"set('Select','Insert','Update','References')","not_null":true},{"name":"is_grantable","type":"varchar(3)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"role_routine_grants","kind":"v","columns":[{"name":"grantor","type":"varchar(97)"},{"name":"grantor_host","type":"varchar(256)"},{"name":"grantee","type":"char(32)","not_null":true},{"name":"grantee_host","type":"char(255)","not_null":true},{"name":"specific_catalog","type":"varchar(3)","not_null":true},{"name":"specific_schema","type":"char(64)","not_null":true},{"name":"specific_name","type":"char(64)","not_null":true},{"name":"routine_catalog","type":"varchar(3)","not_null":true},{"name":"routine_schema","type":"char(64)","not_null":true},{"name":"routine_name","type":"char(64)","not_null":true},{"name":"privilege_type","type":"set('Execute','Alter Routine','Grant')","not_null":true},{"name":"is_grantable","type":"varchar(3)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"role_table_grants","kind":"v","columns":[{"name":"grantor","type":"varchar(97)"},{"name":"grantor_host","type":"varchar(256)"},{"name":"grantee","type":"char(32)","not_null":true},{"name":"grantee_host","type":"char(255)","not_null":true},{"name":"table_catalog","type":"varchar(3)","not_null":true},{"name":"table_schema","type":"char(64)","not_null":true},{"name":"table_name","type":"char(64)","not_null":true},{"name":"privilege_type","type":"set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger')","not_null":true},{"name":"is_grantable","type":"varchar(3)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"routines","kind":"v","columns":[{"name":"specific_name","type":"varchar(64)","not_null":true},{"name":"routine_catalog","type":"varchar(64)","not_null":true},{"name":"routine_schema","type":"varchar(64)","not_null":true},{"name":"routine_name","type":"varchar(64)","not_null":true},{"name":"routine_type","type":"enum('FUNCTION','PROCEDURE','LIBRARY')","not_null":true},{"name":"data_type","type":"longtext"},{"name":"character_maximum_length","type":"bigint"},{"name":"character_octet_length","type":"bigint"},{"name":"numeric_precision","type":"int unsigned"},{"name":"numeric_scale","type":"int unsigned"},{"name":"datetime_precision","type":"int unsigned"},{"name":"character_set_name","type":"varchar(64)"},{"name":"collation_name","type":"varchar(64)"},{"name":"dtd_identifier","type":"longtext"},{"name":"routine_body","type":"varchar(8)","not_null":true},{"name":"routine_definition","type":"longtext"},{"name":"external_name","type":"varbinary(0)"},{"name":"external_language","type":"varchar(64)","not_null":true},{"name":"parameter_style","type":"varchar(3)","not_null":true},{"name":"is_deterministic","type":"varchar(3)","not_null":true},{"name":"sql_data_access","type":"enum('CONTAINS SQL','NO SQL','READS SQL DATA','MODIFIES SQL DATA')","not_null":true},{"name":"sql_path","type":"varbinary(0)"},{"name":"security_type","type":"enum('DEFAULT','INVOKER','DEFINER')","not_null":true},{"name":"created","type":"timestamp","not_null":true},{"name":"last_altered","type":"timestamp","not_null":true},{"name":"sql_mode","type":"set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE','NOT_USED_9','NOT_USED_10','NOT_USED_11','NOT_USED_12','NOT_USED_13','NOT_USED_14','NOT_USED_15','NOT_USED_16','NOT_USED_17','NOT_USED_18','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','ALLOW_INVALID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NOT_USED_29','HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH','TIME_TRUNCATE_FRACTIONAL','INTERPRET_UTF8_AS_UTF8MB4')","not_null":true},{"name":"routine_comment","type":"text","not_null":true},{"name":"definer","type":"varchar(288)","not_null":true},{"name":"character_set_client","type":"varchar(64)","not_null":true},{"name":"collation_connection","type":"varchar(64)","not_null":true},{"name":"database_collation","type":"varchar(64)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"routine_libraries","kind":"v","columns":[{"name":"routine_catalog","type":"varchar(64)","not_null":true},{"name":"routine_schema","type":"varchar(64)","not_null":true},{"name":"routine_name","type":"varchar(64)","not_null":true},{"name":"routine_type","type":"enum('FUNCTION','PROCEDURE','LIBRARY')","not_null":true},{"name":"library_catalog","type":"varchar(64)"},{"name":"library_schema","type":"varchar(100)"},{"name":"library_name","type":"varchar(100)"},{"name":"library_version","type":"varchar(100)"}]} +{"catalog":"def","schema":"information_schema","name":"schemata","kind":"v","columns":[{"name":"catalog_name","type":"varchar(64)","not_null":true},{"name":"schema_name","type":"varchar(64)","not_null":true},{"name":"default_character_set_name","type":"varchar(64)","not_null":true},{"name":"default_collation_name","type":"varchar(64)","not_null":true},{"name":"sql_path","type":"varbinary(0)"},{"name":"default_encryption","type":"enum('NO','YES')","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"schemata_extensions","kind":"v","columns":[{"name":"catalog_name","type":"varchar(64)","not_null":true},{"name":"schema_name","type":"varchar(64)","not_null":true},{"name":"options","type":"varchar(256)"}]} +{"catalog":"def","schema":"information_schema","name":"schema_privileges","kind":"v","columns":[{"name":"grantee","type":"varchar(292)","not_null":true},{"name":"table_catalog","type":"varchar(512)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"privilege_type","type":"varchar(64)","not_null":true},{"name":"is_grantable","type":"varchar(3)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"statistics","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"non_unique","type":"int","not_null":true},{"name":"index_schema","type":"varchar(64)","not_null":true},{"name":"index_name","type":"varchar(64)"},{"name":"seq_in_index","type":"int unsigned","not_null":true},{"name":"column_name","type":"varchar(64)"},{"name":"collation","type":"varchar(1)"},{"name":"cardinality","type":"bigint"},{"name":"sub_part","type":"bigint"},{"name":"packed","type":"varbinary(0)"},{"name":"nullable","type":"varchar(3)","not_null":true},{"name":"index_type","type":"varchar(11)","not_null":true},{"name":"comment","type":"varchar(8)","not_null":true},{"name":"index_comment","type":"varchar(2048)","not_null":true},{"name":"is_visible","type":"varchar(3)","not_null":true},{"name":"expression","type":"longtext"}]} +{"catalog":"def","schema":"information_schema","name":"st_geometry_columns","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"column_name","type":"varchar(64)"},{"name":"srs_name","type":"varchar(80)"},{"name":"srs_id","type":"int unsigned"},{"name":"geometry_type_name","type":"longtext"}]} +{"catalog":"def","schema":"information_schema","name":"st_spatial_reference_systems","kind":"v","columns":[{"name":"srs_name","type":"varchar(80)","not_null":true},{"name":"srs_id","type":"int unsigned","not_null":true},{"name":"organization","type":"varchar(256)"},{"name":"organization_coordsys_id","type":"int unsigned"},{"name":"definition","type":"varchar(4096)","not_null":true},{"name":"description","type":"varchar(2048)"}]} +{"catalog":"def","schema":"information_schema","name":"st_units_of_measure","kind":"v","columns":[{"name":"unit_name","type":"varchar(255)"},{"name":"unit_type","type":"varchar(7)"},{"name":"conversion_factor","type":"double"},{"name":"description","type":"varchar(255)"}]} +{"catalog":"def","schema":"information_schema","name":"tables","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"table_type","type":"enum('BASE TABLE','VIEW','SYSTEM VIEW')","not_null":true},{"name":"engine","type":"varchar(64)"},{"name":"version","type":"int"},{"name":"row_format","type":"enum('Fixed','Dynamic','Compressed','Redundant','Compact','Paged')"},{"name":"table_rows","type":"bigint unsigned"},{"name":"avg_row_length","type":"bigint unsigned"},{"name":"data_length","type":"bigint unsigned"},{"name":"max_data_length","type":"bigint unsigned"},{"name":"index_length","type":"bigint unsigned"},{"name":"data_free","type":"bigint unsigned"},{"name":"auto_increment","type":"bigint unsigned"},{"name":"create_time","type":"timestamp","not_null":true},{"name":"update_time","type":"datetime"},{"name":"check_time","type":"datetime"},{"name":"table_collation","type":"varchar(64)"},{"name":"checksum","type":"bigint"},{"name":"create_options","type":"varchar(256)"},{"name":"table_comment","type":"text"}]} +{"catalog":"def","schema":"information_schema","name":"tablespaces_extensions","kind":"v","columns":[{"name":"tablespace_name","type":"varchar(268)","not_null":true},{"name":"engine_attribute","type":"json"}]} +{"catalog":"def","schema":"information_schema","name":"tables_extensions","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"engine_attribute","type":"json"},{"name":"secondary_engine_attribute","type":"json"}]} +{"catalog":"def","schema":"information_schema","name":"table_constraints","kind":"v","columns":[{"name":"constraint_catalog","type":"varchar(64)","not_null":true},{"name":"constraint_schema","type":"varchar(64)","not_null":true},{"name":"constraint_name","type":"varchar(64)"},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"constraint_type","type":"varchar(11)","not_null":true},{"name":"enforced","type":"varchar(3)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"table_constraints_extensions","kind":"v","columns":[{"name":"constraint_catalog","type":"varchar(64)","not_null":true},{"name":"constraint_schema","type":"varchar(64)","not_null":true},{"name":"constraint_name","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"engine_attribute","type":"json"},{"name":"secondary_engine_attribute","type":"json"}]} +{"catalog":"def","schema":"information_schema","name":"table_privileges","kind":"v","columns":[{"name":"grantee","type":"varchar(292)","not_null":true},{"name":"table_catalog","type":"varchar(512)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"privilege_type","type":"varchar(64)","not_null":true},{"name":"is_grantable","type":"varchar(3)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"triggers","kind":"v","columns":[{"name":"trigger_catalog","type":"varchar(64)","not_null":true},{"name":"trigger_schema","type":"varchar(64)","not_null":true},{"name":"trigger_name","type":"varchar(64)","not_null":true},{"name":"event_manipulation","type":"enum('INSERT','UPDATE','DELETE')","not_null":true},{"name":"event_object_catalog","type":"varchar(64)","not_null":true},{"name":"event_object_schema","type":"varchar(64)","not_null":true},{"name":"event_object_table","type":"varchar(64)","not_null":true},{"name":"action_order","type":"int unsigned","not_null":true},{"name":"action_condition","type":"varbinary(0)"},{"name":"action_statement","type":"longtext","not_null":true},{"name":"action_orientation","type":"varchar(3)","not_null":true},{"name":"action_timing","type":"enum('BEFORE','AFTER')","not_null":true},{"name":"action_reference_old_table","type":"varbinary(0)"},{"name":"action_reference_new_table","type":"varbinary(0)"},{"name":"action_reference_old_row","type":"varchar(3)","not_null":true},{"name":"action_reference_new_row","type":"varchar(3)","not_null":true},{"name":"created","type":"timestamp(2)","not_null":true},{"name":"sql_mode","type":"set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE','NOT_USED_9','NOT_USED_10','NOT_USED_11','NOT_USED_12','NOT_USED_13','NOT_USED_14','NOT_USED_15','NOT_USED_16','NOT_USED_17','NOT_USED_18','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','ALLOW_INVALID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NOT_USED_29','HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH','TIME_TRUNCATE_FRACTIONAL','INTERPRET_UTF8_AS_UTF8MB4')","not_null":true},{"name":"definer","type":"varchar(288)","not_null":true},{"name":"character_set_client","type":"varchar(64)","not_null":true},{"name":"collation_connection","type":"varchar(64)","not_null":true},{"name":"database_collation","type":"varchar(64)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"user_attributes","kind":"v","columns":[{"name":"user","type":"char(32)","not_null":true},{"name":"host","type":"char(255)","not_null":true},{"name":"attribute","type":"longtext"}]} +{"catalog":"def","schema":"information_schema","name":"user_privileges","kind":"v","columns":[{"name":"grantee","type":"varchar(292)","not_null":true},{"name":"table_catalog","type":"varchar(512)","not_null":true},{"name":"privilege_type","type":"varchar(64)","not_null":true},{"name":"is_grantable","type":"varchar(3)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"views","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"view_definition","type":"longtext"},{"name":"check_option","type":"enum('NONE','LOCAL','CASCADED')"},{"name":"is_updatable","type":"enum('NO','YES')"},{"name":"definer","type":"varchar(288)"},{"name":"security_type","type":"varchar(7)"},{"name":"character_set_client","type":"varchar(64)","not_null":true},{"name":"collation_connection","type":"varchar(64)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"view_routine_usage","kind":"v","columns":[{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true},{"name":"specific_catalog","type":"varchar(64)","not_null":true},{"name":"specific_schema","type":"varchar(64)","not_null":true},{"name":"specific_name","type":"varchar(64)","not_null":true}]} +{"catalog":"def","schema":"information_schema","name":"view_table_usage","kind":"v","columns":[{"name":"view_catalog","type":"varchar(64)","not_null":true},{"name":"view_schema","type":"varchar(64)","not_null":true},{"name":"view_name","type":"varchar(64)","not_null":true},{"name":"table_catalog","type":"varchar(64)","not_null":true},{"name":"table_schema","type":"varchar(64)","not_null":true},{"name":"table_name","type":"varchar(64)","not_null":true}]} diff --git a/internal/engine/dolphin/dialect/types.jsonl b/internal/engine/dolphin/dialect/types.jsonl new file mode 100644 index 0000000..c76d29d --- /dev/null +++ b/internal/engine/dolphin/dialect/types.jsonl @@ -0,0 +1,39 @@ +{"name": "bool", "category": "B", "aliases": ["boolean"]} +{"name": "tinyint", "category": "N"} +{"name": "tinyint unsigned", "category": "N", "base": "tinyint"} +{"name": "smallint", "category": "N"} +{"name": "smallint unsigned", "category": "N", "base": "smallint"} +{"name": "mediumint", "category": "N"} +{"name": "mediumint unsigned", "category": "N", "base": "mediumint"} +{"name": "int", "category": "N", "aliases": ["integer"]} +{"name": "int unsigned", "category": "N", "base": "int", "aliases": ["integer unsigned"]} +{"name": "bigint", "category": "N", "aliases": ["signed", "bigint signed"]} +{"name": "bigint unsigned", "category": "N", "base": "bigint", "aliases": ["unsigned"]} +{"name": "float", "category": "N"} +{"name": "float unsigned", "category": "N", "base": "float"} +{"name": "double", "category": "N", "aliases": ["double precision", "real"]} +{"name": "double unsigned", "category": "N", "base": "double", "aliases": ["double precision unsigned", "real unsigned"]} +{"name": "decimal", "category": "N", "aliases": ["numeric", "dec", "fixed"]} +{"name": "decimal unsigned", "category": "N", "base": "decimal", "aliases": ["numeric unsigned", "dec unsigned", "fixed unsigned"]} +{"name": "bit", "category": "N"} +{"name": "char", "category": "S"} +{"name": "varchar", "category": "S"} +{"name": "tinytext", "category": "S"} +{"name": "text", "category": "S"} +{"name": "mediumtext", "category": "S"} +{"name": "longtext", "category": "S"} +{"name": "enum", "category": "S"} +{"name": "set", "category": "S"} +{"name": "binary", "category": "U"} +{"name": "varbinary", "category": "U"} +{"name": "tinyblob", "category": "U"} +{"name": "blob", "category": "U"} +{"name": "mediumblob", "category": "U"} +{"name": "longblob", "category": "U"} +{"name": "json", "category": "U"} +{"name": "geometry", "category": "U"} +{"name": "date", "category": "D"} +{"name": "datetime", "category": "D"} +{"name": "timestamp", "category": "D"} +{"name": "time", "category": "D"} +{"name": "year", "category": "D"} diff --git a/internal/engine/dolphin/fingerprint.go b/internal/engine/dolphin/fingerprint.go new file mode 100644 index 0000000..1554a94 --- /dev/null +++ b/internal/engine/dolphin/fingerprint.go @@ -0,0 +1,55 @@ +package dolphin + +import ( + "fmt" + "strings" + + pcast "github.com/sqlc-dev/marino/ast" + "github.com/sqlc-dev/marino/format" + "github.com/sqlc-dev/marino/parser" +) + +// deparen unwraps parenthesized expressions so a redundant pair of +// parentheses added or dropped by formatting does not change the +// fingerprint. Everything else about the tree survives untouched. +type deparen struct{} + +func (v deparen) Enter(n pcast.Node) (pcast.Node, bool) { return n, false } +func (v deparen) Leave(n pcast.Node) (pcast.Node, bool) { + if p, ok := n.(*pcast.ParenthesesExpr); ok { + return p.Expr, true + } + return n, true +} + +// Fingerprint reduces a statement to a canonical form that survives changes +// in whitespace, keyword case, quoting style and redundant parentheses — +// and nothing else. Identifier case is preserved: MySQL table names are +// case-sensitive on most servers, so a formatting pass that changes one is +// a semantic change and must not fingerprint equal. fmt uses this as its +// proof that a formatted statement still means what the author wrote; a +// statement whose fingerprint it cannot match is left exactly as written. +func (p *Parser) Fingerprint(sql string) (string, error) { + // A fresh parser: p.pingcap carries per-parse comment state that + // ParseFile is still using. + stmts, _, err := parser.New().Parse(sql, "", "") + if err != nil { + return "", normalizeErr(err) + } + flags := format.RestoreStringSingleQuotes | + format.RestoreKeyWordUppercase | + format.RestoreNameBackQuotes + parts := make([]string, 0, len(stmts)) + for _, s := range stmts { + n, ok := s.Accept(deparen{}) + if !ok { + return "", fmt.Errorf("fingerprint: rewrite failed") + } + var sb strings.Builder + if err := n.Restore(format.NewRestoreCtx(flags, &sb)); err != nil { + return "", fmt.Errorf("fingerprint: %w", err) + } + parts = append(parts, sb.String()) + } + return strings.Join(parts, "; "), nil +} diff --git a/internal/engine/dolphin/format.go b/internal/engine/dolphin/format.go new file mode 100644 index 0000000..b9b6c40 --- /dev/null +++ b/internal/engine/dolphin/format.go @@ -0,0 +1,36 @@ +package dolphin + +// QuoteIdent returns a quoted identifier if it needs quoting. +// MySQL uses backticks for quoting identifiers. +func (p *Parser) QuoteIdent(s string) string { + // For now, don't quote - MySQL is less strict about quoting + return s +} + +// TypeName returns the SQL type name for the given namespace and name. +// Handles MySQL-specific type name mappings for formatting. +func (p *Parser) TypeName(ns, name string) string { + if ns != "" { + return ns + "." + name + } + // Map internal type names to MySQL CAST-compatible names for formatting + switch name { + case "bigint unsigned": + return "UNSIGNED" + case "bigint signed": + return "SIGNED" + } + return name +} + +// Param returns the parameter placeholder for the given number. +// MySQL uses ? for all parameters (positional). +func (p *Parser) Param(n int, numbered bool) string { + return "?" +} + +// Cast returns a type cast expression. +// MySQL uses CAST(expr AS type) syntax. +func (p *Parser) Cast(arg, typeName string) string { + return "CAST(" + arg + " AS " + typeName + ")" +} diff --git a/internal/engine/dolphin/parse.go b/internal/engine/dolphin/parse.go new file mode 100644 index 0000000..9f1f409 --- /dev/null +++ b/internal/engine/dolphin/parse.go @@ -0,0 +1,162 @@ +package dolphin + +import ( + "errors" + "fmt" + "io" + "regexp" + "strconv" + "strings" + + "github.com/sqlc-dev/marino/parser" + + "github.com/sqlc-dev/sqlc/internal/source" + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/sqlerr" +) + +func NewParser() *Parser { + return &Parser{pingcap: parser.New()} +} + +// NewFormatParser returns the parser sqlc fmt uses. It differs from the +// compiler's parser in one way: identifiers keep the case the author wrote. +// The compiler lowercases them so catalog lookups are case-insensitive, but +// a formatter that prints `Event` as `event` renames a table on the many +// servers where table names are case-sensitive. +func NewFormatParser() *Parser { + return &Parser{pingcap: parser.New(), preserveCase: true} +} + +type Parser struct { + pingcap *parser.Parser + preserveCase bool +} + +var lineColumn = regexp.MustCompile(`^line (\d+) column (\d+) (.*)`) + +func normalizeErr(err error) error { + if err == nil { + return err + } + parts := strings.Split(err.Error(), "\n") + msg := strings.TrimSpace(parts[0] + "\"") + out := lineColumn.FindStringSubmatch(msg) + if len(out) == 4 { + line, lineErr := strconv.Atoi(out[1]) + col, colErr := strconv.Atoi(out[2]) + if lineErr != nil || colErr != nil { + return errors.New(msg) + } + return &sqlerr.Error{ + Message: "syntax error", + Err: errors.New(out[3]), + Line: line, + Column: col, + } + } + return errors.New(msg) +} + +func (p *Parser) Parse(r io.Reader) ([]ast.Statement, error) { + f, err := p.ParseFile(r) + if err != nil { + return nil, err + } + // The compiler skips statements sqlc has no node for; the formatter + // must see them, so the filter lives here, not in ParseFile. + var stmts []ast.Statement + for _, stmt := range f.Stmts { + if _, ok := stmt.Raw.Stmt.(*ast.TODO); ok { + continue + } + stmts = append(stmts, stmt) + } + return stmts, nil +} + +// ParseFile parses like Parse and also carries the file's comments, which +// marino's lexer records as it scans. +func (p *Parser) ParseFile(r io.Reader) (*ast.File, error) { + blob, err := io.ReadAll(r) + if err != nil { + return nil, err + } + src := string(blob) + stmtNodes, _, err := p.pingcap.Parse(src, "", "") + if err != nil { + return nil, normalizeErr(err) + } + var stmts []ast.Statement + // A statement's text spans from the end of the previous statement + // through its terminator, so it carries the comments written above it + // (that's where the "-- name:" annotation lives). Each text is a + // contiguous slice of src laid down after the one before it, so + // searching from the previous statement's end pins every text to its + // own occurrence even when two statements read the same. + searchFrom := 0 + for i := range stmtNodes { + converter := &cc{preserveCase: p.preserveCase} + // A statement sqlc has no node for converts to a TODO and stays in + // the list: the formatter needs its extent to keep it as written, + // and Parse filters it out for the compiler. + out := converter.convert(stmtNodes[i]) + + text := stmtNodes[i].Text() + idx := strings.Index(src[searchFrom:], text) + if idx < 0 { + return nil, fmt.Errorf("could not locate statement %d in source", i) + } + loc := searchFrom + idx + searchFrom = loc + len(text) + + stmtLen := len(text) + if stmtLen > 0 && text[stmtLen-1] == ';' { + stmtLen -= 1 // Subtract one to remove semicolon + } + + stmts = append(stmts, ast.Statement{ + Raw: &ast.RawStmt{ + Stmt: out, + StmtLocation: loc, + StmtLen: stmtLen, + }, + }) + } + + var comments []ast.Comment + for _, c := range p.pingcap.Comments() { + comments = append(comments, ast.Comment{ + Text: strings.TrimRight(src[c.Begin:c.End], " \t\r\n"), + Start: c.Begin, + End: c.End, + OwnLine: ownLine(src, c.Begin), + }) + } + return &ast.File{Stmts: stmts, Comments: comments}, nil +} + +// ownLine reports that only blank space sits between the preceding line +// break and pos. +func ownLine(src string, pos int) bool { + for j := pos - 1; j >= 0; j-- { + switch src[j] { + case '\n': + return true + case ' ', '\t', '\r': + continue + default: + return false + } + } + return true +} + +// https://dev.mysql.com/doc/refman/8.0/en/comments.html +func (p *Parser) CommentSyntax() source.CommentSyntax { + return source.CommentSyntax{ + Dash: true, + SlashStar: true, + Hash: true, + } +} diff --git a/internal/engine/dolphin/reserved.go b/internal/engine/dolphin/reserved.go new file mode 100644 index 0000000..ff477c4 --- /dev/null +++ b/internal/engine/dolphin/reserved.go @@ -0,0 +1,273 @@ +package dolphin + +import "strings" + +// https://dev.mysql.com/doc/refman/8.0/en/keywords.html +func (p *Parser) IsReservedKeyword(s string) bool { + switch strings.ToLower(s) { + case "accessible": + case "add": + case "all": + case "alter": + case "analyze": + case "and": + case "as": + case "asc": + case "asensitive": + case "before": + case "between": + case "bigint": + case "binary": + case "blob": + case "both": + case "by": + case "call": + case "cascade": + case "case": + case "change": + case "char": + case "character": + case "check": + case "collate": + case "column": + case "condition": + case "constraint": + case "continue": + case "convert": + case "create": + case "cross": + case "cube": + case "cume_dist": + case "current_date": + case "current_time": + case "current_timestamp": + case "current_user": + case "cursor": + case "database": + case "databases": + case "day_hour": + case "day_microsecond": + case "day_minute": + case "day_second": + case "dec": + case "decimal": + case "declare": + case "default": + case "delayed": + case "delete": + case "dense_rank": + case "desc": + case "describe": + case "deterministic": + case "distinct": + case "distinctrow": + case "div": + case "double": + case "drop": + case "dual": + case "each": + case "else": + case "elseif": + case "empty": + case "enclosed": + case "escaped": + case "except": + case "exists": + case "exit": + case "explain": + case "false": + case "fetch": + case "first_value": + case "float": + case "float4": + case "float8": + case "for": + case "force": + case "foreign": + case "from": + case "fulltext": + case "function": + case "generated": + case "get": + case "grant": + case "group": + case "grouping": + case "groups": + case "having": + case "high_priority": + case "hour_microsecond": + case "hour_minute": + case "hour_second": + case "if": + case "ignore": + case "in": + case "index": + case "infile": + case "inner": + case "inout": + case "insensitive": + case "insert": + case "int": + case "int1": + case "int2": + case "int3": + case "int4": + case "int8": + case "integer": + case "interval": + case "into": + case "io_after_gtids": + case "io_before_gtids": + case "is": + case "iterate": + case "join": + case "json_table": + case "key": + case "keys": + case "kill": + case "lag": + case "last_value": + case "lateral": + case "lead": + case "leading": + case "leave": + case "left": + case "like": + case "limit": + case "linear": + case "lines": + case "load": + case "localtime": + case "localtimestamp": + case "lock": + case "long": + case "longblob": + case "longtext": + case "loop": + case "low_priority": + case "master_bind": + case "master_ssl_verify_server_cert": + case "match": + case "maxvalue": + case "mediumblob": + case "mediumint": + case "mediumtext": + case "middleint": + case "minute_microsecond": + case "minute_second": + case "mod": + case "modifies": + case "natural": + case "not": + case "no_write_to_binlog": + case "nth_value": + case "ntile": + case "null": + case "numeric": + case "of": + case "on": + case "optimize": + case "optimizer_costs": + case "option": + case "optionally": + case "or": + case "order": + case "out": + case "outer": + case "outfile": + case "over": + case "partition": + case "percent_rank": + case "precision": + case "primary": + case "procedure": + case "purge": + case "range": + case "rank": + case "read": + case "reads": + case "read_write": + case "real": + case "recursive": + case "references": + case "regexp": + case "release": + case "rename": + case "repeat": + case "replace": + case "require": + case "resignal": + case "restrict": + case "return": + case "revoke": + case "right": + case "rlike": + case "row": + case "rows": + case "row_number": + case "schema": + case "schemas": + case "second_microsecond": + case "select": + case "sensitive": + case "separator": + case "set": + case "show": + case "signal": + case "smallint": + case "spatial": + case "specific": + case "sql": + case "sqlexception": + case "sqlstate": + case "sqlwarning": + case "sql_big_result": + case "sql_calc_found_rows": + case "sql_small_result": + case "ssl": + case "starting": + case "stored": + case "straight_join": + case "system": + case "table": + case "terminated": + case "then": + case "tinyblob": + case "tinyint": + case "tinytext": + case "to": + case "trailing": + case "trigger": + case "true": + case "undo": + case "union": + case "unique": + case "unlock": + case "unsigned": + case "update": + case "usage": + case "use": + case "using": + case "utc_date": + case "utc_time": + case "utc_timestamp": + case "values": + case "varbinary": + case "varchar": + case "varcharacter": + case "varying": + case "virtual": + case "when": + case "where": + case "while": + case "window": + case "with": + case "write": + case "xor": + case "year_month": + case "zerofill": + default: + return false + } + return true +} diff --git a/internal/engine/dolphin/seed.go b/internal/engine/dolphin/seed.go new file mode 100644 index 0000000..ddaeffb --- /dev/null +++ b/internal/engine/dolphin/seed.go @@ -0,0 +1,34 @@ +package dolphin + +import ( + "embed" + "sync" + + "github.com/sqlc-dev/sqlc/internal/core" + "github.com/sqlc-dev/sqlc/internal/core/seed" + "github.com/sqlc-dev/sqlc/internal/sql/catalog" +) + +// The dialect directory describes MySQL's type system, and functions.jsonl is +// its standard library. Both the analysis core and the catalog the legacy +// compiler builds read them. +// +//go:embed dialect +var dialectFS embed.FS + +// Dialect returns the catalog option that seeds MySQL's type system. +func Dialect() core.Option { + return seed.Dialect(dialectFS, "dialect") +} + +// stdlib is MySQL's functions in the form the catalog uses. They are embedded +// in the binary and never change within a run, so they are read once. +var stdlib = sync.OnceValue(func() []*catalog.Function { + funcs, err := seed.Functions(dialectFS, "dialect") + if err != nil { + // A failure here means sqlc was built from a broken tree, which no + // caller can do anything about. + panic(err) + } + return funcs +}) diff --git a/internal/engine/dolphin/stdlib.go b/internal/engine/dolphin/stdlib.go new file mode 100644 index 0000000..df79c46 --- /dev/null +++ b/internal/engine/dolphin/stdlib.go @@ -0,0 +1,11 @@ +package dolphin + +import ( + "github.com/sqlc-dev/sqlc/internal/sql/catalog" +) + +// defaultSchema is MySQL's standard library, read from the dialect directory's +// functions.jsonl. +func defaultSchema(name string) *catalog.Schema { + return &catalog.Schema{Name: name, Funcs: stdlib()} +} diff --git a/internal/engine/dolphin/utils.go b/internal/engine/dolphin/utils.go new file mode 100644 index 0000000..fd443aa --- /dev/null +++ b/internal/engine/dolphin/utils.go @@ -0,0 +1,94 @@ +package dolphin + +import ( + pcast "github.com/sqlc-dev/marino/ast" + "github.com/sqlc-dev/marino/mysql" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +func (c *cc) parseTableName(n *pcast.TableName) *ast.TableName { + return &ast.TableName{ + Schema: c.identifier(n.Schema.String()), + Name: c.identifier(n.Name.String()), + } +} + +func (c *cc) toList(node pcast.Node) *ast.List { + var items []ast.Node + switch n := node.(type) { + case *pcast.TableName: + if schema := n.Schema.String(); schema != "" { + items = append(items, c.NewIdentifier(schema)) + } + items = append(items, c.NewIdentifier(n.Name.String())) + default: + return nil + } + return &ast.List{Items: items} +} + +func isNotNull(n *pcast.ColumnDef) bool { + for i := range n.Options { + if n.Options[i].Tp == pcast.ColumnOptionNotNull { + return true + } + if n.Options[i].Tp == pcast.ColumnOptionPrimaryKey { + return true + } + } + return false +} + +func convertToRangeVarList(list *ast.List, result *ast.List) { + if len(list.Items) == 0 { + return + } + switch rel := list.Items[0].(type) { + + // Special case for joins in updates + case *ast.JoinExpr: + left, ok := rel.Larg.(*ast.RangeVar) + if !ok { + if list, check := rel.Larg.(*ast.List); check { + convertToRangeVarList(list, result) + } else if subselect, check := rel.Larg.(*ast.RangeSubselect); check { + // Handle subqueries in JOIN clauses + result.Items = append(result.Items, subselect) + } else { + panic("expected range var") + } + } + if left != nil { + result.Items = append(result.Items, left) + } + + right, ok := rel.Rarg.(*ast.RangeVar) + if !ok { + if list, check := rel.Rarg.(*ast.List); check { + convertToRangeVarList(list, result) + } else if subselect, check := rel.Rarg.(*ast.RangeSubselect); check { + // Handle subqueries in JOIN clauses + result.Items = append(result.Items, subselect) + } else { + panic("expected range var") + } + } + if right != nil { + result.Items = append(result.Items, right) + } + + case *ast.RangeVar: + result.Items = append(result.Items, rel) + + case *ast.RangeSubselect: + result.Items = append(result.Items, rel) + + default: + panic("expected range var") + } +} + +func isUnsigned(n *pcast.ColumnDef) bool { + return mysql.HasUnsignedFlag(n.Tp.GetFlag()) +} diff --git a/internal/engine/duckdb/convert.go b/internal/engine/duckdb/convert.go new file mode 100644 index 0000000..29721bb --- /dev/null +++ b/internal/engine/duckdb/convert.go @@ -0,0 +1,1244 @@ +package duckdb + +import ( + "math/big" + "strconv" + "strings" + + dw "github.com/sqlc-dev/darkwing/ast" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +type cc struct{} + +// loc returns a node's start offset for the Location fields of the sqlc AST. +// darkwing marks synthesized nodes with a negative span. +func (c *cc) loc(n dw.Node) int { + if n == nil { + return 0 + } + if pos := n.Pos(); pos >= 0 { + return pos + } + return 0 +} + +func (c *cc) convert(node dw.Stmt) ast.Node { + switch n := node.(type) { + case *dw.SelectStatement: + return c.convertSelectStatement(n) + case *dw.InsertStatement: + return c.convertInsertStatement(n) + case *dw.UpdateStatement: + return c.convertUpdateStatement(n) + case *dw.DeleteStatement: + return c.convertDeleteStatement(n) + case *dw.TruncateStatement: + return c.convertTruncateStatement(n) + case *dw.CreateStatement: + return c.convertCreateStatement(n) + case *dw.DropStatement: + return c.convertDropStatement(n) + case *dw.AlterStatement: + return c.convertAlterStatement(n) + default: + return todo(n) + } +} + +func (c *cc) convertSelectStatement(n *dw.SelectStatement) ast.Node { + if n == nil { + return &ast.TODO{} + } + return c.convertQueryNode(n.Node) +} + +func (c *cc) convertQueryNode(q dw.QueryNode) ast.Node { + switch n := q.(type) { + case *dw.SelectNode: + return c.convertSelectNode(n) + case *dw.SetOperationNode: + return c.convertSetOperationNode(n) + case *dw.RecursiveCTENode: + return c.convertRecursiveCTENode(n) + default: + return todo(q) + } +} + +// applyModifiers folds a query node's result modifiers — ORDER BY, LIMIT, +// DISTINCT — into the converted statement. +func (c *cc) applyModifiers(stmt *ast.SelectStmt, mods []dw.ResultModifier) { + for _, mod := range mods { + switch m := mod.(type) { + case *dw.OrderModifier: + stmt.SortClause = c.convertOrderBys(m.Orders) + case *dw.LimitModifier: + // LIMIT n% has no row-count equivalent. + if m.LimitType == dw.LimitPercentage { + continue + } + if m.Limit != nil { + stmt.LimitCount = c.convertExpr(m.Limit) + } + if m.Offset != nil { + stmt.LimitOffset = c.convertExpr(m.Offset) + } + case *dw.DistinctModifier: + stmt.DistinctClause = &ast.List{} + for _, target := range m.DistinctOnTargets { + stmt.DistinctClause.Items = append(stmt.DistinctClause.Items, c.convertExpr(target)) + } + } + } +} + +func (c *cc) convertWithClause(ctes dw.CTEMap) *ast.WithClause { + if len(ctes.Entries) == 0 { + return nil + } + with := &ast.WithClause{Ctes: &ast.List{}} + for _, entry := range ctes.Entries { + cte := entry.CTE + name := identifier(entry.Name) + item := &ast.CommonTableExpr{ + Ctename: &name, + Ctequery: c.convertQueryNode(cte.Query), + Location: c.loc(cte), + } + // A recursive CTE parses into its own query node. + if _, ok := cte.Query.(*dw.RecursiveCTENode); ok { + with.Recursive = true + item.Cterecursive = true + } + if len(cte.Aliases) > 0 { + item.Aliascolnames = &ast.List{} + for _, alias := range cte.Aliases { + item.Aliascolnames.Items = append(item.Aliascolnames.Items, NewIdentifier(alias)) + } + } + with.Ctes.Items = append(with.Ctes.Items, item) + } + return with +} + +// isBareStar reports a plain "*" projection with no modifiers, the select +// list darkwing synthesizes when desugaring VALUES into a select. +func isBareStar(exprs []dw.Expr) bool { + if len(exprs) != 1 { + return false + } + star, ok := exprs[0].(*dw.StarExpression) + return ok && star.RelationName == "" && !star.Columns && star.Expr == nil && + len(star.ExcludeList) == 0 && len(star.QualifiedExcludeList) == 0 && + len(star.ReplaceList) == 0 && len(star.RenameList) == 0 +} + +func (c *cc) convertValuesLists(values [][]dw.Expr) *ast.List { + lists := &ast.List{} + for _, row := range values { + rowList := &ast.List{} + for _, val := range row { + rowList.Items = append(rowList.Items, c.convertExpr(val)) + } + lists.Items = append(lists.Items, rowList) + } + return lists +} + +func (c *cc) convertSelectNode(n *dw.SelectNode) ast.Node { + stmt := &ast.SelectStmt{} + + stmt.WithClause = c.convertWithClause(n.CTEs) + + // VALUES (...), (...) parses as SELECT * FROM an expression list. + if list, ok := n.FromTable.(*dw.ExpressionListRef); ok && isBareStar(n.SelectList) { + stmt.ValuesLists = c.convertValuesLists(list.Values) + c.applyModifiers(stmt, n.Modifiers) + return stmt + } + + if len(n.SelectList) > 0 { + stmt.TargetList = &ast.List{} + for _, expr := range n.SelectList { + stmt.TargetList.Items = append(stmt.TargetList.Items, c.convertResTarget(expr)) + } + } + + if from := c.convertTableRef(n.FromTable); from != nil { + stmt.FromClause = &ast.List{Items: []ast.Node{from}} + } + + if n.Where != nil { + stmt.WhereClause = c.convertExpr(n.Where) + } + + if len(n.GroupExpressions) > 0 { + stmt.GroupClause = &ast.List{} + for _, expr := range n.GroupExpressions { + stmt.GroupClause.Items = append(stmt.GroupClause.Items, c.convertExpr(expr)) + } + } + + if n.Having != nil { + stmt.HavingClause = c.convertExpr(n.Having) + } + + c.applyModifiers(stmt, n.Modifiers) + return stmt +} + +func (c *cc) convertSetOperationNode(n *dw.SetOperationNode) ast.Node { + var op ast.SetOperation + switch n.SetOpType { + case dw.SetOpUnion, dw.SetOpUnionByName: + op = ast.Union + case dw.SetOpExcept: + op = ast.Except + case dw.SetOpIntersect: + op = ast.Intersect + default: + return todo(n) + } + + // DuckDB v2 set operations are n-ary; sqlc's are binary, so a chain + // folds left-associatively. + var stmt *ast.SelectStmt + for _, input := range n.Inputs { + arg, ok := c.convertQueryNode(input).(*ast.SelectStmt) + if !ok { + return todo(n) + } + if stmt == nil { + stmt = arg + continue + } + stmt = &ast.SelectStmt{ + Op: op, + All: n.SetOpAll, + Larg: stmt, + Rarg: arg, + } + } + if stmt == nil { + return todo(n) + } + stmt.WithClause = c.convertWithClause(n.CTEs) + c.applyModifiers(stmt, n.Modifiers) + return stmt +} + +func (c *cc) convertRecursiveCTENode(n *dw.RecursiveCTENode) ast.Node { + larg, ok := c.convertQueryNode(n.Left).(*ast.SelectStmt) + if !ok { + return todo(n) + } + rarg, ok := c.convertQueryNode(n.Right).(*ast.SelectStmt) + if !ok { + return todo(n) + } + stmt := &ast.SelectStmt{ + Op: ast.Union, + All: n.UnionAll, + Larg: larg, + Rarg: rarg, + } + c.applyModifiers(stmt, n.Modifiers) + return stmt +} + +func (c *cc) convertResTarget(expr dw.Expr) *ast.ResTarget { + res := &ast.ResTarget{ + Val: c.convertExpr(expr), + Location: c.loc(expr), + } + if alias := expr.GetAlias(); alias != "" { + name := identifier(alias) + res.Name = &name + } + return res +} + +func (c *cc) convertOrderBys(orders []dw.OrderByNode) *ast.List { + list := &ast.List{} + for _, order := range orders { + sortBy := &ast.SortBy{ + Node: c.convertExpr(order.Expression), + Location: c.loc(order.Expression), + } + switch order.Type { + case dw.OrderAscending: + sortBy.SortbyDir = ast.SortByDirAsc + case dw.OrderDescending: + sortBy.SortbyDir = ast.SortByDirDesc + default: + sortBy.SortbyDir = ast.SortByDirDefault + } + switch order.NullOrder { + case dw.NullsFirst: + sortBy.SortbyNulls = ast.SortByNullsFirst + case dw.NullsLast: + sortBy.SortbyNulls = ast.SortByNullsLast + default: + sortBy.SortbyNulls = ast.SortByNullsDefault + } + list.Items = append(list.Items, sortBy) + } + return list +} + +func (c *cc) convertAlias(name string, columns []string) *ast.Alias { + if name == "" && len(columns) == 0 { + return nil + } + aliasName := identifier(name) + alias := &ast.Alias{Aliasname: &aliasName} + if len(columns) > 0 { + alias.Colnames = &ast.List{} + for _, col := range columns { + alias.Colnames.Items = append(alias.Colnames.Items, NewIdentifier(col)) + } + } + return alias +} + +func (c *cc) convertRangeVar(catalog, schema, table, alias string, loc int) *ast.RangeVar { + name := parseTableName(catalog, schema, table) + rv := &ast.RangeVar{ + Relname: &name.Name, + Location: loc, + } + if name.Schema != "" { + rv.Schemaname = &name.Schema + } + if name.Catalog != "" { + rv.Catalogname = &name.Catalog + } + if alias != "" { + rv.Alias = c.convertAlias(alias, nil) + } + return rv +} + +func (c *cc) convertTableRef(ref dw.TableRef) ast.Node { + switch t := ref.(type) { + case nil, *dw.EmptyTableRef: + return nil + case *dw.BaseTableRef: + rv := c.convertRangeVar(t.CatalogName, t.SchemaName, t.TableName, "", c.loc(t)) + if alias := c.convertAlias(t.Alias, t.ColumnNameAlias); alias != nil { + rv.Alias = alias + } + return rv + case *dw.JoinRef: + return c.convertJoinRef(t) + case *dw.SubqueryRef: + return &ast.RangeSubselect{ + Subquery: c.convertSelectStatement(t.Subquery), + Alias: c.convertAlias(t.Alias, t.ColumnNameAlias), + } + case *dw.TableFunctionRef: + return c.convertTableFunctionRef(t) + case *dw.ExpressionListRef: + // A VALUES list used as a relation becomes a values subquery. + sub := &ast.RangeSubselect{ + Subquery: &ast.SelectStmt{ValuesLists: c.convertValuesLists(t.Values)}, + Alias: c.convertAlias(t.Alias, t.ExpectedNames), + } + return sub + default: + return todo(ref) + } +} + +func (c *cc) convertJoinRef(t *dw.JoinRef) ast.Node { + join := &ast.JoinExpr{ + Larg: c.convertTableRef(t.Left), + Rarg: c.convertTableRef(t.Right), + } + switch t.JoinType { + case dw.JoinLeft: + join.Jointype = ast.JoinTypeLeft + case dw.JoinRight: + join.Jointype = ast.JoinTypeRight + case dw.JoinFull: + join.Jointype = ast.JoinTypeFull + default: + join.Jointype = ast.JoinTypeInner + } + if t.RefType == dw.JoinRefNatural { + join.IsNatural = true + } + if t.Condition != nil { + join.Quals = c.convertExpr(t.Condition) + } + if len(t.UsingColumns) > 0 { + join.UsingClause = &ast.List{} + for _, col := range t.UsingColumns { + join.UsingClause.Items = append(join.UsingClause.Items, NewIdentifier(col)) + } + } + return join +} + +func (c *cc) convertTableFunctionRef(t *dw.TableFunctionRef) ast.Node { + call, ok := c.convertExpr(t.Function).(*ast.FuncCall) + if !ok { + return todo(t) + } + return &ast.RangeFunction{ + Functions: &ast.List{Items: []ast.Node{call}}, + Alias: c.convertAlias(t.Alias, t.ColumnNameAlias), + Ordinality: t.WithOrdinality, + } +} + +func (c *cc) convertExpr(expr dw.Expr) ast.Node { + if expr == nil { + return nil + } + switch e := expr.(type) { + case *dw.ColumnRefExpression: + return c.convertColumnRef(e) + case *dw.ConstantExpression: + return c.convertConstant(e) + case *dw.ParameterExpression: + return c.convertParameter(e) + case *dw.FunctionExpression: + return c.convertFunction(e) + case *dw.OperatorExpression: + return c.convertOperator(e) + case *dw.ComparisonExpression: + return c.convertComparison(e) + case *dw.ConjunctionExpression: + return c.convertConjunction(e) + case *dw.CastExpression: + return c.convertCast(e) + case *dw.CaseExpression: + return c.convertCase(e) + case *dw.BetweenExpression: + return &ast.BetweenExpr{ + Expr: c.convertExpr(e.Input), + Left: c.convertExpr(e.Lower), + Right: c.convertExpr(e.Upper), + Location: c.loc(e), + } + case *dw.SubqueryExpression: + return c.convertSubquery(e) + case *dw.StarExpression: + return c.convertStar(e) + case *dw.CollateExpression: + return &ast.CollateExpr{ + Arg: c.convertExpr(e.Child), + Location: c.loc(e), + } + case *dw.WindowExpression: + return c.convertWindow(e) + default: + return todo(expr) + } +} + +func (c *cc) convertColumnRef(e *dw.ColumnRefExpression) *ast.ColumnRef { + fields := &ast.List{} + for _, name := range e.ColumnNames { + fields.Items = append(fields.Items, NewIdentifier(name)) + } + return &ast.ColumnRef{ + Fields: fields, + Location: c.loc(e), + } +} + +// decimalString renders a decimal's unscaled digits with the point +// re-inserted, e.g. ("15", 1) => "1.5". +func decimalString(digits string, scale int) string { + neg := strings.HasPrefix(digits, "-") + if neg { + digits = digits[1:] + } + if scale > 0 { + for len(digits) <= scale { + digits = "0" + digits + } + digits = digits[:len(digits)-scale] + "." + digits[len(digits)-scale:] + } + if neg { + digits = "-" + digits + } + return digits +} + +func hugeintString(h dw.Hugeint) string { + v := new(big.Int).SetInt64(h.Upper) + v.Lsh(v, 64) + return v.Or(v, new(big.Int).SetUint64(h.Lower)).String() +} + +func (c *cc) convertConstant(e *dw.ConstantExpression) ast.Node { + v := e.Value + konst := &ast.A_Const{Location: c.loc(e)} + switch { + case v.IsNull || v.Kind == dw.ValueNull: + konst.Val = &ast.Null{} + case v.Kind == dw.ValueBool: + konst.Val = &ast.Boolean{Boolval: v.Bool} + case v.Kind == dw.ValueInt64 && v.Type.ID == "DECIMAL": + // A decimal literal carries its unscaled value. + konst.Val = &ast.Float{Str: decimalString(strconv.FormatInt(v.Int64, 10), v.Type.Scale)} + case v.Kind == dw.ValueInt64: + konst.Val = &ast.Integer{Ival: v.Int64} + case v.Kind == dw.ValueHugeint && v.Type.ID == "DECIMAL": + konst.Val = &ast.Float{Str: decimalString(hugeintString(v.Hugeint), v.Type.Scale)} + case v.Kind == dw.ValueHugeint: + konst.Val = &ast.Float{Str: hugeintString(v.Hugeint)} + case v.Kind == dw.ValueDouble: + konst.Val = &ast.Float{Str: strconv.FormatFloat(v.Float64, 'g', -1, 64)} + case v.Kind == dw.ValueString: + konst.Val = &ast.String{Str: v.Str} + default: + return todo(e) + } + return konst +} + +// convertParameter converts a prepared-statement parameter. darkwing has +// already numbered every spelling: explicit for $3 and ?3, in order of +// appearance for ?, and in order of first use for $name. +func (c *cc) convertParameter(e *dw.ParameterExpression) ast.Node { + return &ast.ParamRef{ + Number: e.Number, + Dollar: e.Kind == dw.ParameterNumbered || e.Kind == dw.ParameterNamed, + Location: c.loc(e), + } +} + +func (c *cc) convertFunction(e *dw.FunctionExpression) ast.Node { + name := identifier(e.FunctionName) + + // Binary and prefix operators parse as operator-named functions. + if e.IsOperator { + switch len(e.Arguments) { + case 1: + return &ast.A_Expr{ + Kind: ast.A_Expr_Kind_OP, + Name: &ast.List{Items: []ast.Node{&ast.String{Str: e.FunctionName}}}, + Rexpr: c.convertExpr(e.Arguments[0].Expr), + Location: c.loc(e), + } + case 2: + return &ast.A_Expr{ + Kind: ast.A_Expr_Kind_OP, + Name: &ast.List{Items: []ast.Node{&ast.String{Str: e.FunctionName}}}, + Lexpr: c.convertExpr(e.Arguments[0].Expr), + Rexpr: c.convertExpr(e.Arguments[1].Expr), + Location: c.loc(e), + } + default: + return todo(e) + } + } + + fc := &ast.FuncCall{ + Funcname: &ast.List{}, + Location: c.loc(e), + AggDistinct: e.Distinct, + } + if schema := schemaName(e.Schema); schema != "" { + fc.Funcname.Items = append(fc.Funcname.Items, &ast.String{Str: schema}) + } + + // COUNT(*) parses as the argument-less count_star. + if name == "count_star" { + fc.Funcname.Items = append(fc.Funcname.Items, &ast.String{Str: "count"}) + fc.AggStar = true + return fc + } + fc.Funcname.Items = append(fc.Funcname.Items, &ast.String{Str: name}) + + for _, arg := range e.Arguments { + if fc.Args == nil { + fc.Args = &ast.List{} + } + fc.Args.Items = append(fc.Args.Items, c.convertExpr(arg.Expr)) + } + if e.Filter != nil { + fc.AggFilter = c.convertExpr(e.Filter) + } + if len(e.OrderBys) > 0 { + fc.AggOrder = c.convertOrderBys(e.OrderBys) + } + return fc +} + +func (c *cc) convertOperator(e *dw.OperatorExpression) ast.Node { + switch e.Type { + case dw.OperatorNot: + // NOT IN parses as NOT wrapping an IN. + if len(e.Operands) == 1 { + if in, ok := e.Operands[0].(*dw.OperatorExpression); ok && in.Type == dw.CompareIn { + node := c.convertIn(in) + node.Not = true + return node + } + } + return c.convertBoolExpr(ast.BoolExprTypeNot, e) + case dw.OperatorIsNull, dw.OperatorIsNotNull: + if len(e.Operands) != 1 { + return todo(e) + } + test := ast.NullTestTypeIsNull + if e.Type == dw.OperatorIsNotNull { + test = ast.NullTestTypeIsNotNull + } + return &ast.NullTest{ + Arg: c.convertExpr(e.Operands[0]), + Nulltesttype: test, + Location: c.loc(e), + } + case dw.CompareIn, dw.CompareNotIn: + node := c.convertIn(e) + node.Not = e.Type == dw.CompareNotIn + return node + case dw.OperatorCoalesce: + coalesce := &ast.CoalesceExpr{ + Args: &ast.List{}, + Location: c.loc(e), + } + for _, operand := range e.Operands { + coalesce.Args.Items = append(coalesce.Args.Items, c.convertExpr(operand)) + } + return coalesce + case dw.ArrayConstructor: + arr := &ast.A_ArrayExpr{ + Elements: &ast.List{}, + Location: c.loc(e), + } + for _, operand := range e.Operands { + arr.Elements.Items = append(arr.Elements.Items, c.convertExpr(operand)) + } + return arr + default: + return todo(e) + } +} + +func (c *cc) convertIn(e *dw.OperatorExpression) *ast.In { + in := &ast.In{Location: c.loc(e)} + if len(e.Operands) > 0 { + in.Expr = c.convertExpr(e.Operands[0]) + for _, item := range e.Operands[1:] { + in.List = append(in.List, c.convertExpr(item)) + } + } + return in +} + +func (c *cc) convertBoolExpr(op ast.BoolExprType, e *dw.OperatorExpression) ast.Node { + expr := &ast.BoolExpr{ + Boolop: op, + Args: &ast.List{}, + Location: c.loc(e), + } + for _, operand := range e.Operands { + expr.Args.Items = append(expr.Args.Items, c.convertExpr(operand)) + } + return expr +} + +func comparisonOperator(t dw.ExpressionType) (string, bool) { + switch t { + case dw.CompareEqual: + return "=", true + case dw.CompareNotEqual: + return "<>", true + case dw.CompareLessThan: + return "<", true + case dw.CompareGreaterThan: + return ">", true + case dw.CompareLessThanOrEqual: + return "<=", true + case dw.CompareGreaterThanOrEqual: + return ">=", true + } + return "", false +} + +func (c *cc) convertComparison(e *dw.ComparisonExpression) ast.Node { + kind := ast.A_Expr_Kind_OP + op, ok := comparisonOperator(e.Type) + if !ok { + switch e.Type { + case dw.CompareDistinctFrom: + kind, op = ast.A_Expr_Kind_DISTINCT, "=" + case dw.CompareNotDistinctFrom: + kind, op = ast.A_Expr_Kind_NOT_DISTINCT, "=" + default: + return todo(e) + } + } + return &ast.A_Expr{ + Kind: kind, + Name: &ast.List{Items: []ast.Node{&ast.String{Str: op}}}, + Lexpr: c.convertExpr(e.Left), + Rexpr: c.convertExpr(e.Right), + Location: c.loc(e), + } +} + +func (c *cc) convertConjunction(e *dw.ConjunctionExpression) ast.Node { + boolop := ast.BoolExprTypeAnd + if e.Type == dw.ConjunctionOr { + boolop = ast.BoolExprTypeOr + } + expr := &ast.BoolExpr{ + Boolop: boolop, + Args: &ast.List{}, + Location: c.loc(e), + } + for _, operand := range e.Operands { + expr.Args.Items = append(expr.Args.Items, c.convertExpr(operand)) + } + return expr +} + +func (c *cc) convertCast(e *dw.CastExpression) ast.Node { + cast := &ast.TypeCast{ + Arg: c.convertExpr(e.Child), + Location: c.loc(e), + } + switch { + case e.CastType != nil: + typeName, arrayDims := c.convertTypeExpression(e.CastType) + if arrayDims > 0 { + typeName.ArrayBounds = &ast.List{} + for i := 0; i < arrayDims; i++ { + typeName.ArrayBounds.Items = append(typeName.ArrayBounds.Items, &ast.Integer{Ival: -1}) + } + } + cast.TypeName = typeName + case e.ResolvedType != "": + cast.TypeName = &ast.TypeName{Name: identifier(e.ResolvedType)} + default: + return todo(e) + } + return cast +} + +func (c *cc) convertCase(e *dw.CaseExpression) ast.Node { + caseExpr := &ast.CaseExpr{ + Args: &ast.List{}, + Location: c.loc(e), + } + for _, check := range e.CaseChecks { + caseExpr.Args.Items = append(caseExpr.Args.Items, &ast.CaseWhen{ + Expr: c.convertExpr(check.When), + Result: c.convertExpr(check.Then), + }) + } + if e.ElseExpr != nil { + caseExpr.Defresult = c.convertExpr(e.ElseExpr) + } + return caseExpr +} + +func (c *cc) convertSubquery(e *dw.SubqueryExpression) ast.Node { + link := &ast.SubLink{ + Subselect: c.convertSelectStatement(e.Subquery), + Location: c.loc(e), + } + switch e.SubqueryType { + case dw.SubqueryExists: + link.SubLinkType = ast.EXISTS_SUBLINK + case dw.SubqueryScalar: + link.SubLinkType = ast.EXPR_SUBLINK + case dw.SubqueryAny: + // x IN (SELECT ...) and quantified comparisons desugar to ANY. + link.SubLinkType = ast.ANY_SUBLINK + link.Testexpr = c.convertExpr(e.Child) + if op, ok := comparisonOperator(e.ComparisonType); ok { + link.OperName = &ast.List{Items: []ast.Node{&ast.String{Str: op}}} + } + default: + return todo(e) + } + return link +} + +func (c *cc) convertStar(e *dw.StarExpression) ast.Node { + // COLUMNS(...) and EXCLUDE/REPLACE/RENAME modifiers have no equivalent. + if e.Columns || e.Expr != nil || len(e.ExcludeList) > 0 || + len(e.QualifiedExcludeList) > 0 || len(e.ReplaceList) > 0 || len(e.RenameList) > 0 { + return todo(e) + } + fields := &ast.List{} + if e.RelationName != "" { + fields.Items = append(fields.Items, NewIdentifier(e.RelationName)) + } + fields.Items = append(fields.Items, &ast.A_Star{}) + return &ast.ColumnRef{ + Fields: fields, + Location: c.loc(e), + } +} + +func (c *cc) convertWindow(e *dw.WindowExpression) ast.Node { + fc := &ast.FuncCall{ + Funcname: &ast.List{Items: []ast.Node{&ast.String{Str: identifier(e.FunctionName)}}}, + Location: c.loc(e), + AggDistinct: e.Distinct, + Over: &ast.WindowDef{Location: c.loc(e)}, + } + for _, arg := range e.Arguments { + if fc.Args == nil { + fc.Args = &ast.List{} + } + fc.Args.Items = append(fc.Args.Items, c.convertExpr(arg.Expr)) + } + if e.FilterExpr != nil { + fc.AggFilter = c.convertExpr(e.FilterExpr) + } + if len(e.Partitions) > 0 { + fc.Over.PartitionClause = &ast.List{} + for _, p := range e.Partitions { + fc.Over.PartitionClause.Items = append(fc.Over.PartitionClause.Items, c.convertExpr(p)) + } + } + if len(e.Orders) > 0 { + fc.Over.OrderClause = c.convertOrderBys(e.Orders) + } + return fc +} + +// convertTypeExpression maps an unbound DuckDB type to a sqlc type name and +// the number of list/array dimensions wrapped around it, which is what the +// legacy catalog reads. The whole type — its arguments, a struct's fields, +// a map's key and value, the nesting of a list of lists — goes along as +// its spelling, which is what the analysis core reads. +func (c *cc) convertTypeExpression(t *dw.TypeExpression) (*ast.TypeName, int) { + typeName, dims := c.elementTypeName(t) + typeName.Canonical = renderTypeExpression(t) + return typeName, dims +} + +func (c *cc) elementTypeName(t *dw.TypeExpression) (*ast.TypeName, int) { + name := identifier(t.TypeName) + switch name { + case "list", "array": + // int[] is LIST(INTEGER); int[3] is ARRAY(INTEGER, 3). + if len(t.Args) > 0 { + if elem, ok := t.Args[0].(*dw.TypeExpression); ok { + typeName, dims := c.elementTypeName(elem) + return typeName, dims + 1 + } + } + } + return &ast.TypeName{ + Schema: schemaName(t.Schema), + Name: name, + }, 0 +} + +// renderTypeExpression spells a type as a call expression the core reads: +// a list is array applied to its element, a fixed-size array carries its +// size, a struct's or union's fields are labelled, and a constant argument +// is written as it was. +func renderTypeExpression(t *dw.TypeExpression) string { + name := identifier(t.TypeName) + if schema := schemaName(t.Schema); schema != "" { + name = schema + "." + name + } + if name == "list" { + name = "array" + } + if len(t.Args) == 0 { + return name + } + parts := make([]string, 0, len(t.Args)) + for _, arg := range t.Args { + var part string + switch a := arg.(type) { + case *dw.TypeExpression: + part = renderTypeExpression(a) + if a.Alias != "" { + part = identifier(a.Alias) + ": " + part + } + case *dw.ConstantExpression: + switch { + case a.Value.Str != "": + part = "'" + strings.ReplaceAll(a.Value.Str, "'", "''") + "'" + default: + part = strconv.FormatInt(a.Value.Int64, 10) + } + default: + continue + } + parts = append(parts, part) + } + return name + "(" + strings.Join(parts, ", ") + ")" +} + +func (c *cc) convertReturning(returning []dw.Expr) *ast.List { + if len(returning) == 0 { + return nil + } + list := &ast.List{} + for _, expr := range returning { + list.Items = append(list.Items, c.convertResTarget(expr)) + } + return list +} + +func (c *cc) convertInsertStatement(n *dw.InsertStatement) ast.Node { + stmt := &ast.InsertStmt{ + Relation: c.convertRangeVar(n.Catalog, n.Schema, n.Table, n.TableAlias, c.loc(n)), + WithClause: c.convertWithClause(n.CTEs), + DefaultValues: n.DefaultValues, + } + + if len(n.Columns) > 0 { + stmt.Cols = &ast.List{} + for _, col := range n.Columns { + name := identifier(col) + stmt.Cols.Items = append(stmt.Cols.Items, &ast.ResTarget{Name: &name}) + } + } + + if n.Query != nil { + stmt.SelectStmt = c.convertSelectStatement(n.Query) + } + + if n.OnConflict != nil { + stmt.OnConflictClause = c.convertOnConflict(n.OnConflict) + } + + stmt.ReturningList = c.convertReturning(n.Returning) + return stmt +} + +func (c *cc) convertOnConflict(n *dw.OnConflictInfo) *ast.OnConflictClause { + clause := &ast.OnConflictClause{Location: c.loc(n)} + switch n.Action { + case dw.OnConflictUpdate: + clause.Action = ast.OnConflictActionUpdate + default: + clause.Action = ast.OnConflictActionNothing + } + if n.SetInfo != nil { + clause.TargetList = c.convertSetClause(n.SetInfo) + if n.SetInfo.Condition != nil { + clause.WhereClause = c.convertExpr(n.SetInfo.Condition) + } + } + return clause +} + +func (c *cc) convertSetClause(set *dw.UpdateSetInfo) *ast.List { + list := &ast.List{} + for i, col := range set.Columns { + if len(col) == 0 || i >= len(set.Expressions) { + continue + } + name := identifier(col[len(col)-1]) + list.Items = append(list.Items, &ast.ResTarget{ + Name: &name, + Val: c.convertExpr(set.Expressions[i]), + }) + } + return list +} + +func (c *cc) convertUpdateStatement(n *dw.UpdateStatement) ast.Node { + target := c.convertTableRef(n.Table) + if target == nil { + return todo(n) + } + stmt := &ast.UpdateStmt{ + Relations: &ast.List{Items: []ast.Node{target}}, + TargetList: &ast.List{}, + WithClause: c.convertWithClause(n.CTEs), + } + if n.SetInfo != nil { + stmt.TargetList = c.convertSetClause(n.SetInfo) + } + if from := c.convertTableRef(n.From); from != nil { + stmt.FromClause = &ast.List{Items: []ast.Node{from}} + } + if n.Where != nil { + stmt.WhereClause = c.convertExpr(n.Where) + } + stmt.ReturningList = c.convertReturning(n.Returning) + return stmt +} + +func (c *cc) convertDeleteStatement(n *dw.DeleteStatement) ast.Node { + target := c.convertTableRef(n.Table) + if target == nil { + return todo(n) + } + stmt := &ast.DeleteStmt{ + Relations: &ast.List{Items: []ast.Node{target}}, + WithClause: c.convertWithClause(n.CTEs), + } + if len(n.Using) > 0 { + stmt.UsingClause = &ast.List{} + for _, using := range n.Using { + if item := c.convertTableRef(using); item != nil { + stmt.UsingClause.Items = append(stmt.UsingClause.Items, item) + } + } + } + if n.Where != nil { + stmt.WhereClause = c.convertExpr(n.Where) + } + stmt.ReturningList = c.convertReturning(n.Returning) + return stmt +} + +func (c *cc) convertTruncateStatement(n *dw.TruncateStatement) ast.Node { + target := c.convertTableRef(n.Table) + if target == nil { + return todo(n) + } + return &ast.TruncateStmt{ + Relations: &ast.List{Items: []ast.Node{target}}, + } +} + +func (c *cc) convertCreateStatement(n *dw.CreateStatement) ast.Node { + switch info := n.Info.(type) { + case *dw.CreateTableInfo: + return c.convertCreateTableInfo(info) + case *dw.CreateViewInfo: + return c.convertCreateViewInfo(info) + case *dw.CreateTypeInfo: + return c.convertCreateTypeInfo(info) + default: + return todo(n) + } +} + +func (c *cc) convertCreateTableInfo(info *dw.CreateTableInfo) ast.Node { + name := parseTableName(info.Catalog, info.Schema, info.Name) + + // CREATE TABLE ... AS records the table as a relation defined by its + // query, like a view. + if info.Query != nil { + into := &ast.IntoClause{ + Rel: c.convertRangeVar(info.Catalog, info.Schema, info.Name, "", c.loc(info)), + } + if len(info.QueryAliases) > 0 { + into.ColNames = &ast.List{} + for _, alias := range info.QueryAliases { + into.ColNames.Items = append(into.ColNames.Items, NewIdentifier(alias)) + } + } + return &ast.CreateTableAsStmt{ + Query: c.convertSelectStatement(info.Query), + Into: into, + IfNotExists: info.OnConflict == dw.CreateIgnore, + } + } + + stmt := &ast.CreateTableStmt{ + Name: name, + IfNotExists: info.OnConflict == dw.CreateIgnore, + } + + // Column names in table-level PRIMARY KEY constraints are NOT NULL. + primaryKey := map[string]bool{} + for _, constraint := range info.Constraints { + unique, ok := constraint.(*dw.UniqueConstraint) + if !ok || !unique.IsPrimaryKey { + continue + } + for _, col := range unique.Columns { + primaryKey[identifier(col)] = true + } + } + + for i := range info.Columns { + stmt.Cols = append(stmt.Cols, c.convertColumnDef(&info.Columns[i], primaryKey)) + } + return stmt +} + +func (c *cc) convertColumnDef(col *dw.ColumnDef, tablePrimaryKey map[string]bool) *ast.ColumnDef { + name := "" + if len(col.Names) > 0 { + name = identifier(col.Names[len(col.Names)-1]) + } + def := &ast.ColumnDef{ + Colname: name, + Location: c.loc(col), + } + if col.Type != nil { + typeName, arrayDims := c.convertTypeExpression(col.Type) + def.TypeName = typeName + def.ArrayDims = arrayDims + def.IsArray = arrayDims > 0 + } else { + // A generated column may omit its type; DuckDB infers it at bind + // time. + def.TypeName = &ast.TypeName{Name: "any"} + } + for _, constraint := range col.Constraints { + switch con := constraint.(type) { + case *dw.NotNullConstraint: + def.IsNotNull = !con.Null + case *dw.UniqueConstraint: + if con.IsPrimaryKey { + def.PrimaryKey = true + def.IsNotNull = true + } + } + } + if tablePrimaryKey[name] { + def.PrimaryKey = true + def.IsNotNull = true + } + return def +} + +func (c *cc) convertCreateViewInfo(info *dw.CreateViewInfo) ast.Node { + stmt := &ast.ViewStmt{ + View: c.convertRangeVar(info.Catalog, info.Schema, info.Name, "", c.loc(info)), + Query: c.convertSelectStatement(info.Query), + Replace: info.OnConflict == dw.CreateReplace, + } + if len(info.Aliases) > 0 { + stmt.Aliases = &ast.List{} + for _, alias := range info.Aliases { + stmt.Aliases.Items = append(stmt.Aliases.Items, NewIdentifier(alias)) + } + } + return stmt +} + +func (c *cc) convertCreateTypeInfo(info *dw.CreateTypeInfo) ast.Node { + if !info.IsEnum { + return todo(info) + } + stmt := &ast.CreateEnumStmt{ + TypeName: &ast.TypeName{ + Schema: schemaName(info.Schema), + Name: identifier(info.Name), + }, + Vals: &ast.List{}, + } + for _, val := range info.EnumValues { + stmt.Vals.Items = append(stmt.Vals.Items, &ast.String{Str: val}) + } + return stmt +} + +func (c *cc) convertDropStatement(n *dw.DropStatement) ast.Node { + switch n.DropType { + case dw.DropTable, dw.DropView: + stmt := &ast.DropTableStmt{IfExists: n.IfExists} + for _, name := range n.Names { + stmt.Tables = append(stmt.Tables, parseTableName(name.Catalog, name.Schema, name.Name)) + } + return stmt + default: + return todo(n) + } +} + +func (c *cc) convertAlterStatement(n *dw.AlterStatement) ast.Node { + if n.Entity != dw.AlterEntityTable { + return todo(n) + } + table := parseTableName(n.Name.Catalog, n.Name.Schema, n.Name.Name) + + var stmts []ast.Node + alter := &ast.AlterTableStmt{ + Table: table, + Cmds: &ast.List{}, + MissingOk: n.IfExists, + } + for _, action := range n.Actions { + switch a := action.(type) { + case *dw.AddColumnInfo: + def := c.convertColumnDef(&a.Column, nil) + alter.Cmds.Items = append(alter.Cmds.Items, &ast.AlterTableCmd{ + Name: &def.Colname, + Subtype: ast.AT_AddColumn, + Def: def, + MissingOk: a.IfNotExists, + }) + case *dw.DropColumnInfo: + if len(a.Column) == 0 { + continue + } + name := identifier(a.Column[len(a.Column)-1]) + alter.Cmds.Items = append(alter.Cmds.Items, &ast.AlterTableCmd{ + Name: &name, + Subtype: ast.AT_DropColumn, + MissingOk: a.IfExists, + }) + case *dw.AlterColumnTypeInfo: + if len(a.Column) == 0 || a.Type == nil { + continue + } + name := identifier(a.Column[len(a.Column)-1]) + typeName, arrayDims := c.convertTypeExpression(a.Type) + alter.Cmds.Items = append(alter.Cmds.Items, &ast.AlterTableCmd{ + Name: &name, + Subtype: ast.AT_AlterColumnType, + Def: &ast.ColumnDef{ + Colname: name, + TypeName: typeName, + ArrayDims: arrayDims, + IsArray: arrayDims > 0, + }, + }) + case *dw.SetNotNullInfo: + if len(a.Column) == 0 { + continue + } + name := identifier(a.Column[len(a.Column)-1]) + subtype := ast.AT_SetNotNull + if a.Drop { + subtype = ast.AT_DropNotNull + } + alter.Cmds.Items = append(alter.Cmds.Items, &ast.AlterTableCmd{ + Name: &name, + Subtype: subtype, + }) + case *dw.RenameColumnInfo: + if len(a.Column) == 0 { + continue + } + newName := identifier(a.NewName) + stmts = append(stmts, &ast.RenameColumnStmt{ + Table: table, + Col: &ast.ColumnRef{ + Name: identifier(a.Column[len(a.Column)-1]), + }, + NewName: &newName, + MissingOk: n.IfExists, + }) + case *dw.RenameInfo: + newName := identifier(a.NewName) + stmts = append(stmts, &ast.RenameTableStmt{ + Table: table, + NewName: &newName, + MissingOk: n.IfExists, + }) + } + } + + if len(alter.Cmds.Items) > 0 { + stmts = append(stmts, alter) + } + switch len(stmts) { + case 0: + return todo(n) + case 1: + return stmts[0] + default: + return &ast.List{Items: stmts} + } +} diff --git a/internal/engine/duckdb/dialect/dialect.json b/internal/engine/duckdb/dialect/dialect.json new file mode 100644 index 0000000..061007b --- /dev/null +++ b/internal/engine/duckdb/dialect/dialect.json @@ -0,0 +1,26 @@ +{ + "dialect": "duckdb", + "default_schema": "main", + "const": { + "integer": "integer", + "float": "double", + "string": "varchar", + "bool": "boolean" + }, + "bool": "boolean", + "comparison": ["=", "==", "<>", "!=", "<", "<=", ">", ">=", "IS DISTINCT FROM", "IS NOT DISTINCT FROM"], + "comparison_categories": "BNSDU", + "arithmetic": ["+", "-", "*", "/", "//", "%", "**", "^"], + "arithmetic_categories": "N", + "cast_categories": "NSD", + "rewrites": [ + { + "from": "varchar($1)", + "to": "varchar" + }, + { + "from": "decimal", + "to": "decimal(18, 3)" + } + ] +} diff --git a/internal/engine/duckdb/dialect/operators.jsonl b/internal/engine/duckdb/dialect/operators.jsonl new file mode 100644 index 0000000..cb87891 --- /dev/null +++ b/internal/engine/duckdb/dialect/operators.jsonl @@ -0,0 +1,157 @@ +{"name":"!~~","left":"varchar","right":"varchar","result":"boolean"} +{"name":"!~~*","left":"varchar","right":"varchar","result":"boolean"} +{"name":"%","left":"bigint","right":"bigint","result":"bigint"} +{"name":"%","left":"decimal","right":"decimal","result":"decimal"} +{"name":"%","left":"double","right":"double","result":"double"} +{"name":"%","left":"float","right":"float","result":"float"} +{"name":"%","left":"hugeint","right":"hugeint","result":"hugeint"} +{"name":"%","left":"integer","right":"integer","result":"integer"} +{"name":"%","left":"smallint","right":"smallint","result":"smallint"} +{"name":"%","left":"tinyint","right":"tinyint","result":"tinyint"} +{"name":"%","left":"ubigint","right":"ubigint","result":"ubigint"} +{"name":"%","left":"uhugeint","right":"uhugeint","result":"uhugeint"} +{"name":"%","left":"uinteger","right":"uinteger","result":"uinteger"} +{"name":"%","left":"usmallint","right":"usmallint","result":"usmallint"} +{"name":"%","left":"utinyint","right":"utinyint","result":"utinyint"} +{"name":"\u0026","left":"bigint","right":"bigint","result":"bigint"} +{"name":"\u0026","left":"bit","right":"bit","result":"bit"} +{"name":"\u0026","left":"hugeint","right":"hugeint","result":"hugeint"} +{"name":"\u0026","left":"integer","right":"integer","result":"integer"} +{"name":"\u0026","left":"smallint","right":"smallint","result":"smallint"} +{"name":"\u0026","left":"tinyint","right":"tinyint","result":"tinyint"} +{"name":"\u0026","left":"ubigint","right":"ubigint","result":"ubigint"} +{"name":"\u0026","left":"uhugeint","right":"uhugeint","result":"uhugeint"} +{"name":"\u0026","left":"uinteger","right":"uinteger","result":"uinteger"} +{"name":"\u0026","left":"usmallint","right":"usmallint","result":"usmallint"} +{"name":"\u0026","left":"utinyint","right":"utinyint","result":"utinyint"} +{"name":"\u0026\u0026","left":"geometry","right":"geometry","result":"boolean"} +{"name":"*","left":"bigint","right":"bigint","result":"bigint"} +{"name":"*","left":"bigint","right":"interval","result":"interval"} +{"name":"*","left":"decimal","right":"decimal","result":"decimal"} +{"name":"*","left":"double","right":"double","result":"double"} +{"name":"*","left":"double","right":"interval","result":"interval"} +{"name":"*","left":"float","right":"float","result":"float"} +{"name":"*","left":"hugeint","right":"hugeint","result":"hugeint"} +{"name":"*","left":"integer","right":"integer","result":"integer"} +{"name":"*","left":"interval","right":"bigint","result":"interval"} +{"name":"*","left":"interval","right":"double","result":"interval"} +{"name":"*","left":"smallint","right":"smallint","result":"smallint"} +{"name":"*","left":"tinyint","right":"tinyint","result":"tinyint"} +{"name":"*","left":"ubigint","right":"ubigint","result":"ubigint"} +{"name":"*","left":"uhugeint","right":"uhugeint","result":"uhugeint"} +{"name":"*","left":"uinteger","right":"uinteger","result":"uinteger"} +{"name":"*","left":"usmallint","right":"usmallint","result":"usmallint"} +{"name":"*","left":"utinyint","right":"utinyint","result":"utinyint"} +{"name":"**","left":"double","right":"double","result":"double"} +{"name":"+","left":"bigint","right":"bigint","result":"bigint"} +{"name":"+","left":"bignum","right":"bignum","result":"bignum"} +{"name":"+","left":"date","right":"integer","result":"date"} +{"name":"+","left":"date","right":"interval","result":"timestamp"} +{"name":"+","left":"date","right":"time with time zone","result":"timestamp with time zone"} +{"name":"+","left":"date","right":"time","result":"timestamp"} +{"name":"+","left":"decimal","right":"decimal","result":"decimal"} +{"name":"+","left":"double","right":"double","result":"double"} +{"name":"+","left":"float","right":"float","result":"float"} +{"name":"+","left":"hugeint","right":"hugeint","result":"hugeint"} +{"name":"+","left":"integer","right":"date","result":"date"} +{"name":"+","left":"integer","right":"integer","result":"integer"} +{"name":"+","left":"interval","right":"date","result":"timestamp"} +{"name":"+","left":"interval","right":"interval","result":"interval"} +{"name":"+","left":"interval","right":"time with time zone","result":"time with time zone"} +{"name":"+","left":"interval","right":"timestamp with time zone","result":"timestamp with time zone"} +{"name":"+","left":"interval","right":"timestamp","result":"timestamp"} +{"name":"+","left":"interval","right":"time","result":"time"} +{"name":"+","left":"smallint","right":"smallint","result":"smallint"} +{"name":"+","left":"time with time zone","right":"date","result":"timestamp with time zone"} +{"name":"+","left":"time with time zone","right":"interval","result":"time with time zone"} +{"name":"+","left":"time","right":"date","result":"timestamp"} +{"name":"+","left":"time","right":"interval","result":"time"} +{"name":"+","left":"timestamp with time zone","right":"interval","result":"timestamp with time zone"} +{"name":"+","left":"timestamp","right":"interval","result":"timestamp"} +{"name":"+","left":"tinyint","right":"tinyint","result":"tinyint"} +{"name":"+","left":"ubigint","right":"ubigint","result":"ubigint"} +{"name":"+","left":"uhugeint","right":"uhugeint","result":"uhugeint"} +{"name":"+","left":"uinteger","right":"uinteger","result":"uinteger"} +{"name":"+","left":"usmallint","right":"usmallint","result":"usmallint"} +{"name":"+","left":"utinyint","right":"utinyint","result":"utinyint"} +{"name":"-","left":"bigint","right":"bigint","result":"bigint"} +{"name":"-","left":"bignum","right":"bignum","result":"bignum"} +{"name":"-","left":"date","right":"date","result":"bigint"} +{"name":"-","left":"date","right":"integer","result":"date"} +{"name":"-","left":"date","right":"interval","result":"timestamp"} +{"name":"-","left":"decimal","right":"decimal","result":"decimal"} +{"name":"-","left":"double","right":"double","result":"double"} +{"name":"-","left":"float","right":"float","result":"float"} +{"name":"-","left":"hugeint","right":"hugeint","result":"hugeint"} +{"name":"-","left":"integer","right":"integer","result":"integer"} +{"name":"-","left":"interval","right":"interval","result":"interval"} +{"name":"-","left":"smallint","right":"smallint","result":"smallint"} +{"name":"-","left":"time with time zone","right":"interval","result":"time with time zone"} +{"name":"-","left":"time","right":"interval","result":"time"} +{"name":"-","left":"timestamp with time zone","right":"interval","result":"timestamp with time zone"} +{"name":"-","left":"timestamp with time zone","right":"timestamp with time zone","result":"interval"} +{"name":"-","left":"timestamp","right":"interval","result":"timestamp"} +{"name":"-","left":"timestamp","right":"timestamp","result":"interval"} +{"name":"-","left":"tinyint","right":"tinyint","result":"tinyint"} +{"name":"-","left":"ubigint","right":"ubigint","result":"ubigint"} +{"name":"-","left":"uhugeint","right":"uhugeint","result":"uhugeint"} +{"name":"-","left":"uinteger","right":"uinteger","result":"uinteger"} +{"name":"-","left":"usmallint","right":"usmallint","result":"usmallint"} +{"name":"-","left":"utinyint","right":"utinyint","result":"utinyint"} +{"name":"-\u003e\u003e","left":"json","right":"bigint","result":"varchar"} +{"name":"-\u003e\u003e","left":"json","right":"varchar","result":"varchar"} +{"name":"-\u003e\u003e","left":"varchar","right":"bigint","result":"varchar"} +{"name":"-\u003e\u003e","left":"varchar","right":"varchar","result":"varchar"} +{"name":"/","left":"double","right":"double","result":"double"} +{"name":"/","left":"float","right":"float","result":"float"} +{"name":"/","left":"interval","right":"double","result":"interval"} +{"name":"//","left":"bigint","right":"bigint","result":"bigint"} +{"name":"//","left":"double","right":"double","result":"double"} +{"name":"//","left":"float","right":"float","result":"float"} +{"name":"//","left":"hugeint","right":"hugeint","result":"hugeint"} +{"name":"//","left":"integer","right":"integer","result":"integer"} +{"name":"//","left":"smallint","right":"smallint","result":"smallint"} +{"name":"//","left":"tinyint","right":"tinyint","result":"tinyint"} +{"name":"//","left":"ubigint","right":"ubigint","result":"ubigint"} +{"name":"//","left":"uhugeint","right":"uhugeint","result":"uhugeint"} +{"name":"//","left":"uinteger","right":"uinteger","result":"uinteger"} +{"name":"//","left":"usmallint","right":"usmallint","result":"usmallint"} +{"name":"//","left":"utinyint","right":"utinyint","result":"utinyint"} +{"name":"\u003c\u003c","left":"bigint","right":"bigint","result":"bigint"} +{"name":"\u003c\u003c","left":"bit","right":"integer","result":"bit"} +{"name":"\u003c\u003c","left":"hugeint","right":"hugeint","result":"hugeint"} +{"name":"\u003c\u003c","left":"integer","right":"integer","result":"integer"} +{"name":"\u003c\u003c","left":"smallint","right":"smallint","result":"smallint"} +{"name":"\u003c\u003c","left":"tinyint","right":"tinyint","result":"tinyint"} +{"name":"\u003c\u003c","left":"ubigint","right":"ubigint","result":"ubigint"} +{"name":"\u003c\u003c","left":"uhugeint","right":"uhugeint","result":"uhugeint"} +{"name":"\u003c\u003c","left":"uinteger","right":"uinteger","result":"uinteger"} +{"name":"\u003c\u003c","left":"usmallint","right":"usmallint","result":"usmallint"} +{"name":"\u003c\u003c","left":"utinyint","right":"utinyint","result":"utinyint"} +{"name":"\u003e\u003e","left":"bigint","right":"bigint","result":"bigint"} +{"name":"\u003e\u003e","left":"bit","right":"integer","result":"bit"} +{"name":"\u003e\u003e","left":"hugeint","right":"hugeint","result":"hugeint"} +{"name":"\u003e\u003e","left":"integer","right":"integer","result":"integer"} +{"name":"\u003e\u003e","left":"smallint","right":"smallint","result":"smallint"} +{"name":"\u003e\u003e","left":"tinyint","right":"tinyint","result":"tinyint"} +{"name":"\u003e\u003e","left":"ubigint","right":"ubigint","result":"ubigint"} +{"name":"\u003e\u003e","left":"uhugeint","right":"uhugeint","result":"uhugeint"} +{"name":"\u003e\u003e","left":"uinteger","right":"uinteger","result":"uinteger"} +{"name":"\u003e\u003e","left":"usmallint","right":"usmallint","result":"usmallint"} +{"name":"\u003e\u003e","left":"utinyint","right":"utinyint","result":"utinyint"} +{"name":"^","left":"double","right":"double","result":"double"} +{"name":"^@","left":"varchar","right":"varchar","result":"boolean"} +{"name":"|","left":"bigint","right":"bigint","result":"bigint"} +{"name":"|","left":"bit","right":"bit","result":"bit"} +{"name":"|","left":"hugeint","right":"hugeint","result":"hugeint"} +{"name":"|","left":"integer","right":"integer","result":"integer"} +{"name":"|","left":"smallint","right":"smallint","result":"smallint"} +{"name":"|","left":"tinyint","right":"tinyint","result":"tinyint"} +{"name":"|","left":"ubigint","right":"ubigint","result":"ubigint"} +{"name":"|","left":"uhugeint","right":"uhugeint","result":"uhugeint"} +{"name":"|","left":"uinteger","right":"uinteger","result":"uinteger"} +{"name":"|","left":"usmallint","right":"usmallint","result":"usmallint"} +{"name":"|","left":"utinyint","right":"utinyint","result":"utinyint"} +{"name":"~~","left":"varchar","right":"varchar","result":"boolean"} +{"name":"~~*","left":"varchar","right":"varchar","result":"boolean"} +{"name":"~~~","left":"varchar","right":"varchar","result":"boolean"} diff --git a/internal/engine/duckdb/dialect/types.jsonl b/internal/engine/duckdb/dialect/types.jsonl new file mode 100644 index 0000000..72b97de --- /dev/null +++ b/internal/engine/duckdb/dialect/types.jsonl @@ -0,0 +1,40 @@ +{"name":"any","category":"U"} +{"name":"array","category":"C"} +{"name":"bigint","category":"N","aliases":["int64","int8","long","oid"]} +{"name":"bignum","category":"U","aliases":["varint"]} +{"name":"bit","category":"U","aliases":["bitstring"]} +{"name":"blob","category":"U","aliases":["binary","bytea","varbinary"]} +{"name":"boolean","category":"B","aliases":["bool","logical"]} +{"name":"date","category":"D"} +{"name":"decimal","category":"N","aliases":["dec","numeric"]} +{"name":"double","category":"N","aliases":["float8"]} +{"name":"enum","category":"U"} +{"name":"float","category":"N","aliases":["float4","real"]} +{"name":"geometry","category":"U"} +{"name":"hugeint","category":"N","aliases":["int128"]} +{"name":"integer","category":"N","aliases":["int","int32","int4","integral","signed"]} +{"name":"interval","category":"D"} +{"name":"list","category":"C"} +{"name":"map","category":"C"} +{"name":"smallint","category":"N","aliases":["int16","int2","short"]} +{"name":"struct","category":"C","aliases":["row"]} +{"name":"time","category":"D"} +{"name":"time with time zone","category":"D","aliases":["timetz"]} +{"name":"time_ns","category":"D"} +{"name":"timestamp","category":"D","aliases":["datetime","timestamp_us"]} +{"name":"timestamp with time zone","category":"D","aliases":["timestamptz"]} +{"name":"timestamp_ms","category":"D"} +{"name":"timestamp_ns","category":"D"} +{"name":"timestamp_s","category":"D"} +{"name":"timestamptz_ns","category":"D"} +{"name":"tinyint","category":"N","aliases":["int1"]} +{"name":"tuple","category":"U"} +{"name":"ubigint","category":"N","aliases":["uint64"]} +{"name":"uhugeint","category":"N","aliases":["uint128"]} +{"name":"uinteger","category":"N","aliases":["uint32"]} +{"name":"union","category":"C"} +{"name":"usmallint","category":"N","aliases":["uint16"]} +{"name":"utinyint","category":"N","aliases":["uint8"]} +{"name":"uuid","category":"U","aliases":["guid"]} +{"name":"varchar","category":"S","aliases":["json","bpchar","char","nvarchar","string","text"]} +{"name":"variant","category":"U"} diff --git a/internal/engine/duckdb/parse.go b/internal/engine/duckdb/parse.go new file mode 100644 index 0000000..76a996e --- /dev/null +++ b/internal/engine/duckdb/parse.go @@ -0,0 +1,67 @@ +package duckdb + +import ( + "context" + "errors" + "io" + + "github.com/sqlc-dev/darkwing/parser" + + "github.com/sqlc-dev/sqlc/internal/source" + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/sqlerr" +) + +func NewParser() *Parser { + return &Parser{} +} + +type Parser struct{} + +// Parse converts DuckDB SQL into sqlc's AST. darkwing assigns every +// statement a byte span and the spans tile the input — each statement +// starts where the previous one ended — so a statement's span covers the +// comments before it, which is where the sqlc query annotation lives. +func (p *Parser) Parse(r io.Reader) ([]ast.Statement, error) { + stmts, err := parser.Parse(context.Background(), r) + if err != nil { + var perr *parser.Error + if errors.As(err, &perr) { + serr := &sqlerr.Error{ + Message: err.Error(), + Line: perr.Line, + Column: perr.Column, + } + if perr.Offset >= 0 { + serr.Location = perr.Offset + } + return nil, serr + } + return nil, err + } + + var out []ast.Statement + for _, stmt := range stmts { + converter := &cc{} + node := converter.convert(stmt) + if _, ok := node.(*ast.TODO); ok { + continue + } + out = append(out, ast.Statement{ + Raw: &ast.RawStmt{ + Stmt: node, + StmtLocation: stmt.Pos(), + StmtLen: stmt.End() - stmt.Pos(), + }, + }) + } + return out, nil +} + +// https://duckdb.org/docs/stable/sql/introduction#comments +func (p *Parser) CommentSyntax() source.CommentSyntax { + return source.CommentSyntax{ + Dash: true, // -- comment + SlashStar: true, // /* comment */ + } +} diff --git a/internal/engine/duckdb/reserved.go b/internal/engine/duckdb/reserved.go new file mode 100644 index 0000000..e80c397 --- /dev/null +++ b/internal/engine/duckdb/reserved.go @@ -0,0 +1,9 @@ +package duckdb + +import "github.com/sqlc-dev/darkwing/token" + +// IsReservedKeyword reports whether s is a reserved keyword in DuckDB's +// grammar, per the keyword lists darkwing vendors from DuckDB. +func (p *Parser) IsReservedKeyword(s string) bool { + return token.Categories(s).Has(token.KeywordReserved) +} diff --git a/internal/engine/duckdb/seed.go b/internal/engine/duckdb/seed.go new file mode 100644 index 0000000..852b5d2 --- /dev/null +++ b/internal/engine/duckdb/seed.go @@ -0,0 +1,23 @@ +package duckdb + +import ( + "embed" + + "github.com/sqlc-dev/sqlc/internal/core" + "github.com/sqlc-dev/sqlc/internal/core/seed" +) + +// The dialect directory describes DuckDB's type system. types.jsonl, +// functions.jsonl and operators.jsonl are generated from a live DuckDB 2.0 +// CLI by goldeneye (internal/goldeneye), which also checks them against one; +// dialect.json is authored by hand. Regenerate from internal/goldeneye with: +// +// DUCKDB=/path/to/duckdb go run ./cmd/goldeneye generate duckdb +// +//go:embed dialect +var dialectFS embed.FS + +// Dialect returns the catalog option that seeds DuckDB's type system. +func Dialect() core.Option { + return seed.Dialect(dialectFS, "dialect") +} diff --git a/internal/engine/duckdb/utils.go b/internal/engine/duckdb/utils.go new file mode 100644 index 0000000..490ad43 --- /dev/null +++ b/internal/engine/duckdb/utils.go @@ -0,0 +1,47 @@ +package duckdb + +import ( + "log" + "strings" + + dw "github.com/sqlc-dev/darkwing/ast" + + "github.com/sqlc-dev/sqlc/internal/debug" + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +func todo(n dw.Node) *ast.TODO { + if debug.Active { + log.Printf("duckdb.convert: Unknown node type %T\n", n) + } + return &ast.TODO{} +} + +// identifier normalizes an identifier. DuckDB identifiers are +// case-insensitive (though case-preserving); the catalog matches them +// lowercased. +func identifier(id string) string { + return strings.ToLower(id) +} + +func NewIdentifier(t string) *ast.String { + return &ast.String{Str: identifier(t)} +} + +// schemaName normalizes a schema qualifier. DuckDB's default "main" schema +// maps to the catalog's default namespace, so it is treated as unqualified. +func schemaName(s string) string { + s = identifier(s) + if s == "main" { + return "" + } + return s +} + +func parseTableName(catalog, schema, name string) *ast.TableName { + return &ast.TableName{ + Catalog: identifier(catalog), + Schema: schemaName(schema), + Name: identifier(name), + } +} diff --git a/internal/engine/googlesql/catalog.go b/internal/engine/googlesql/catalog.go new file mode 100644 index 0000000..33dd939 --- /dev/null +++ b/internal/engine/googlesql/catalog.go @@ -0,0 +1,16 @@ +package googlesql + +import ( + "github.com/sqlc-dev/sqlc/internal/sql/catalog" +) + +func NewCatalog() *catalog.Catalog { + def := "main" // GoogleSQL has no implicit schema; use "main" as the default + return &catalog.Catalog{ + DefaultSchema: def, + Schemas: []*catalog.Schema{ + defaultSchema(def), + }, + Extensions: map[string]struct{}{}, + } +} diff --git a/internal/engine/googlesql/convert.go b/internal/engine/googlesql/convert.go new file mode 100644 index 0000000..cedfe7f --- /dev/null +++ b/internal/engine/googlesql/convert.go @@ -0,0 +1,977 @@ +package googlesql + +import ( + "strconv" + "strings" + + zjast "github.com/sqlc-dev/zetajones/ast" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +type cc struct { + paramCount int + // namedParams tracks the number assigned to each "@name" so repeated uses + // share a single parameter. + namedParams map[string]int +} + +func (c *cc) convert(node zjast.Node) ast.Node { + switch n := node.(type) { + case *zjast.QueryStatement: + return c.convertQuery(n.Query) + case *zjast.InsertStatement: + return c.convertInsertStatement(n) + case *zjast.UpdateStatement: + return c.convertUpdateStatement(n) + case *zjast.DeleteStatement: + return c.convertDeleteStatement(n) + case *zjast.CreateTableStatement: + return c.convertCreateTableStatement(n) + case *zjast.DropStatement: + return c.convertDropStatement(n) + case *zjast.TruncateStatement: + return c.convertTruncateStatement(n) + case *zjast.HintedStatement: + if n.Statement == nil { + return todo(n) + } + return c.convert(n.Statement) + default: + return todo(n) + } +} + +func (c *cc) convertQuery(n *zjast.Query) ast.Node { + if n == nil { + return todo(n) + } + // Pipe operators (|>) have no sqlc AST equivalent. + if len(n.PipeOperators) > 0 { + return todo(n) + } + node := c.convertQueryExpr(n.QueryExpr) + stmt, ok := node.(*ast.SelectStmt) + if !ok { + return node + } + if n.WithClause != nil { + stmt.WithClause = c.convertWithClause(n.WithClause) + } + if n.OrderBy != nil { + stmt.SortClause = c.convertOrderBy(n.OrderBy) + } + if n.Limit != nil { + if n.Limit.Limit != nil { + if _, all := n.Limit.Limit.Expr.(*zjast.LimitAll); !all { + stmt.LimitCount = c.convertExpr(n.Limit.Limit.Expr) + } + } + if n.Limit.Offset != nil { + stmt.LimitOffset = c.convertExpr(n.Limit.Offset) + } + } + return stmt +} + +func (c *cc) convertQueryExpr(node zjast.Node) ast.Node { + switch n := node.(type) { + case *zjast.Select: + return c.convertSelect(n) + case *zjast.SetOperation: + return c.convertSetOperation(n) + case *zjast.Query: + // Parenthesized query. + return c.convertQuery(n) + case *zjast.AliasedQueryExpression: + return c.convertQuery(n.Query) + default: + return todo(n) + } +} + +func (c *cc) convertSetOperation(n *zjast.SetOperation) ast.Node { + if len(n.Inputs) == 0 { + return todo(n) + } + var entries []*zjast.SetOperationMetadata + if n.Metadata != nil { + entries = n.Metadata.Entries + } + result, ok := c.convertQueryExpr(n.Inputs[0]).(*ast.SelectStmt) + if !ok { + return todo(n) + } + for i, input := range n.Inputs[1:] { + rarg, ok := c.convertQueryExpr(input).(*ast.SelectStmt) + if !ok { + return todo(n) + } + op := ast.Union + all := false + if i < len(entries) && entries[i] != nil { + meta := entries[i] + if meta.OpType != nil { + switch strings.ToUpper(meta.OpType.Op) { + case "UNION": + op = ast.Union + case "INTERSECT": + op = ast.Intersect + case "EXCEPT": + op = ast.Except + } + } + if meta.AllOrDistinct != nil { + all = strings.ToUpper(meta.AllOrDistinct.Value) == "ALL" + } + } + result = &ast.SelectStmt{ + Op: op, + All: all, + Larg: result, + Rarg: rarg, + } + } + return result +} + +func (c *cc) convertSelect(n *zjast.Select) *ast.SelectStmt { + stmt := &ast.SelectStmt{} + + if n.SelectList != nil { + stmt.TargetList = &ast.List{} + for _, col := range n.SelectList.Columns { + if col == nil { + continue + } + stmt.TargetList.Items = append(stmt.TargetList.Items, c.convertSelectColumn(col)) + } + } + + if n.From != nil { + stmt.FromClause = &ast.List{ + Items: []ast.Node{c.convertTableExpr(n.From.TableExpression)}, + } + } + + if n.Where != nil { + stmt.WhereClause = c.convertExpr(n.Where.Expr) + } + + if n.GroupBy != nil { + stmt.GroupClause = &ast.List{} + for _, item := range n.GroupBy.Items { + if item == nil { + continue + } + if item.Expr != nil { + stmt.GroupClause.Items = append(stmt.GroupClause.Items, c.convertExpr(item.Expr)) + } else { + // ROLLUP, CUBE, GROUPING SETS, or the empty grouping item. + stmt.GroupClause.Items = append(stmt.GroupClause.Items, todo(item)) + } + } + } + + if n.Having != nil { + stmt.HavingClause = c.convertExpr(n.Having.Expr) + } + + if n.Distinct { + stmt.DistinctClause = &ast.List{} + } + + return stmt +} + +func (c *cc) convertSelectColumn(n *zjast.SelectColumn) *ast.ResTarget { + res := &ast.ResTarget{ + Location: n.Pos(), + } + if n.Alias != nil && n.Alias.Identifier != nil { + name := identifier(n.Alias.Identifier.Name) + res.Name = &name + } + res.Val = c.convertExpr(n.Expr) + return res +} + +func (c *cc) convertTableExpr(node zjast.Node) ast.Node { + switch n := node.(type) { + case *zjast.TablePathExpression: + return c.convertTablePathExpression(n) + case *zjast.TableSubquery: + if len(n.PostfixOperators) > 0 { + return todo(n) + } + return &ast.RangeSubselect{ + Lateral: n.IsLateral, + Subquery: c.convertQuery(n.Query), + Alias: convertAlias(n.Alias), + } + case *zjast.Join: + return c.convertJoin(n) + case *zjast.ParenthesizedJoin: + if len(n.PostfixOperators) > 0 { + return todo(n) + } + return c.convertTableExpr(n.Join) + case *zjast.TVF: + return c.convertTVF(n) + default: + return todo(n) + } +} + +func (c *cc) convertTablePathExpression(n *zjast.TablePathExpression) ast.Node { + if len(n.PostfixOperators) > 0 { + return todo(n) + } + if n.UnnestExpr != nil { + return &ast.RangeFunction{ + Functions: &ast.List{ + Items: []ast.Node{c.convertUnnestExpression(n.UnnestExpr)}, + }, + Alias: convertAlias(n.Alias), + } + } + rv := parseRangeVar(n.Path) + rv.Alias = convertAlias(n.Alias) + return rv +} + +func (c *cc) convertUnnestExpression(n *zjast.UnnestExpression) *ast.FuncCall { + fc := &ast.FuncCall{ + Func: &ast.FuncName{Name: "unnest"}, + Funcname: &ast.List{Items: []ast.Node{&ast.String{Str: "unnest"}}}, + Args: &ast.List{}, + Location: n.Pos(), + } + for _, e := range n.Expressions { + if e == nil { + continue + } + fc.Args.Items = append(fc.Args.Items, c.convertExpr(e.Expr)) + } + return fc +} + +func (c *cc) convertTVF(n *zjast.TVF) ast.Node { + if len(n.PostfixOperators) > 0 { + return todo(n) + } + parts := pathParts(n.Name) + if len(parts) == 0 { + return todo(n) + } + fc := c.newFuncCall(parts, n.Pos()) + for _, arg := range n.Args { + if arg == nil || arg.Expr == nil { + continue + } + fc.Args.Items = append(fc.Args.Items, c.convertExpr(arg.Expr)) + } + return &ast.RangeFunction{ + Functions: &ast.List{Items: []ast.Node{fc}}, + Alias: convertAlias(n.Alias), + } +} + +func (c *cc) convertJoin(n *zjast.Join) ast.Node { + join := &ast.JoinExpr{ + Larg: c.convertTableExpr(n.Lhs), + Rarg: c.convertTableExpr(n.Rhs), + IsNatural: n.Natural, + } + + switch strings.ToUpper(n.JoinType) { + case "", "INNER", "CROSS", "COMMA": + join.Jointype = ast.JoinTypeInner + case "LEFT": + join.Jointype = ast.JoinTypeLeft + case "RIGHT": + join.Jointype = ast.JoinTypeRight + case "FULL": + join.Jointype = ast.JoinTypeFull + default: + join.Jointype = ast.JoinTypeInner + } + + switch clause := n.OnOrUsingClause.(type) { + case *zjast.OnClause: + join.Quals = c.convertExpr(clause.Expr) + case *zjast.UsingClause: + join.UsingClause = &ast.List{} + for _, key := range clause.Keys { + if key == nil { + continue + } + join.UsingClause.Items = append(join.UsingClause.Items, NewIdentifier(key.Name)) + } + } + + return join +} + +func (c *cc) convertWithClause(n *zjast.WithClause) *ast.WithClause { + wc := &ast.WithClause{ + Recursive: n.Recursive, + Ctes: &ast.List{}, + Location: n.Pos(), + } + for _, entry := range n.Entries { + if entry == nil || entry.AliasedQuery == nil { + // "name() AS GROUP ROWS" entries are not supported. + continue + } + aq := entry.AliasedQuery + cte := &ast.CommonTableExpr{ + Location: aq.Pos(), + Ctequery: c.convertQuery(aq.Query), + } + if aq.Identifier != nil { + name := identifier(aq.Identifier.Name) + cte.Ctename = &name + } + wc.Ctes.Items = append(wc.Ctes.Items, cte) + } + return wc +} + +func (c *cc) convertOrderBy(n *zjast.OrderBy) *ast.List { + list := &ast.List{} + for _, item := range n.Items { + if item == nil { + continue + } + sortBy := &ast.SortBy{ + Node: c.convertExpr(item.Expr), + Location: item.Pos(), + } + switch { + case item.Descending: + sortBy.SortbyDir = ast.SortByDirDesc + case item.HasAsc: + sortBy.SortbyDir = ast.SortByDirAsc + default: + sortBy.SortbyDir = ast.SortByDirDefault + } + if item.NullOrder != nil { + if item.NullOrder.NullsFirst { + sortBy.SortbyNulls = ast.SortByNullsFirst + } else { + sortBy.SortbyNulls = ast.SortByNullsLast + } + } + list.Items = append(list.Items, sortBy) + } + return list +} + +func (c *cc) convertExpr(node zjast.Node) ast.Node { + if node == nil { + return nil + } + switch n := node.(type) { + case *zjast.Identifier: + return &ast.ColumnRef{ + Fields: &ast.List{Items: []ast.Node{NewIdentifier(n.Name)}}, + Location: n.Pos(), + } + case *zjast.PathExpression: + return c.convertPathExpression(n) + case *zjast.DotIdentifier: + if fields, ok := columnRefFields(n); ok { + return &ast.ColumnRef{ + Fields: &ast.List{Items: fields}, + Location: n.Pos(), + } + } + return todo(n) + case *zjast.IntLiteral: + return c.convertIntLiteral(n) + case *zjast.FloatLiteral: + return &ast.A_Const{ + Val: &ast.Float{Str: n.Image}, + Location: n.Pos(), + } + case *zjast.StringLiteral: + return &ast.A_Const{ + Val: &ast.String{Str: stringLiteralValue(n)}, + Location: n.Pos(), + } + case *zjast.BooleanLiteral: + return &ast.A_Const{ + Val: &ast.Boolean{Boolval: n.Value}, + Location: n.Pos(), + } + case *zjast.NullLiteral: + return &ast.A_Const{ + Val: &ast.Null{}, + Location: n.Pos(), + } + case *zjast.ParameterExpr: + return c.convertParameterExpr(n) + case *zjast.UnaryExpression: + return c.convertUnaryExpression(n) + case *zjast.BinaryExpression: + return c.convertBinaryExpression(n) + case *zjast.BitwiseShiftExpression: + op := ">>" + if n.IsLeftShift { + op = "<<" + } + return &ast.A_Expr{ + Kind: ast.A_Expr_Kind_OP, + Name: &ast.List{Items: []ast.Node{&ast.String{Str: op}}}, + Lexpr: c.convertExpr(n.Lhs), + Rexpr: c.convertExpr(n.Rhs), + Location: n.Pos(), + } + case *zjast.AndExpr: + return c.convertBoolExpr(ast.BoolExprTypeAnd, n.Conjuncts, n.Pos()) + case *zjast.OrExpr: + return c.convertBoolExpr(ast.BoolExprTypeOr, n.Disjuncts, n.Pos()) + case *zjast.BetweenExpression: + return &ast.BetweenExpr{ + Expr: c.convertExpr(n.Lhs), + Left: c.convertExpr(n.Low), + Right: c.convertExpr(n.High), + Not: n.IsNot, + Location: n.Pos(), + } + case *zjast.InExpression: + return c.convertInExpression(n) + case *zjast.CaseValueExpression: + if len(n.Arguments) == 0 { + return todo(n) + } + return c.buildCaseExpr(c.convertExpr(n.Arguments[0]), n.Arguments[1:], n.Pos()) + case *zjast.CaseNoValueExpression: + return c.buildCaseExpr(nil, n.Arguments, n.Pos()) + case *zjast.CastExpression: + return &ast.TypeCast{ + Arg: c.convertExpr(n.Expr), + TypeName: spelledTypeName(typeName(n.Type)), + Location: n.Pos(), + } + case *zjast.ExpressionSubquery: + return c.convertExpressionSubquery(n) + case *zjast.FunctionCall: + return c.convertFunctionCall(n) + case *zjast.AnalyticFunctionCall: + return c.convertAnalyticFunctionCall(n) + case *zjast.Star: + return &ast.ColumnRef{ + Fields: &ast.List{Items: []ast.Node{&ast.A_Star{}}}, + Location: n.Pos(), + } + case *zjast.DotStar: + return c.convertDotStar(n) + case *zjast.ArrayElement: + return &ast.A_Indirection{ + Arg: c.convertExpr(n.Array), + Indirection: &ast.List{ + Items: []ast.Node{ + &ast.A_Indices{Uidx: c.convertExpr(n.Position)}, + }, + }, + } + case *zjast.NamedArgument: + return c.convertExpr(n.Value) + case *zjast.ExpressionWithAlias: + return c.convertExpr(n.Expression) + default: + return todo(n) + } +} + +func (c *cc) convertPathExpression(n *zjast.PathExpression) ast.Node { + fields, ok := columnRefFields(n) + if !ok { + return todo(n) + } + return &ast.ColumnRef{ + Fields: &ast.List{Items: fields}, + Location: n.Pos(), + } +} + +func (c *cc) convertIntLiteral(n *zjast.IntLiteral) ast.Node { + // Base 0 also accepts hexadecimal literals (0x1a). + ival, err := strconv.ParseInt(n.Image, 0, 64) + if err != nil { + return &ast.A_Const{ + Val: &ast.Float{Str: n.Image}, + Location: n.Pos(), + } + } + return &ast.A_Const{ + Val: &ast.Integer{Ival: ival}, + Location: n.Pos(), + } +} + +// convertParameterExpr converts "@name" and "?" query parameters. +// +// Both become ParamRef nodes. "@name" is native GoogleSQL syntax rather than +// sqlc syntax, so nothing rewrites it before the parser runs and the numbering +// here is what the rest of the pipeline sees: repeated uses of a name share a +// number, and positional parameters are numbered by their 1-based position in +// the statement. +func (c *cc) convertParameterExpr(n *zjast.ParameterExpr) ast.Node { + if n.Name != nil { + number, ok := c.namedParams[n.Name.Name] + if !ok { + c.paramCount++ + number = c.paramCount + if c.namedParams == nil { + c.namedParams = map[string]int{} + } + c.namedParams[n.Name.Name] = number + } + return &ast.ParamRef{ + Number: number, + Location: n.Pos(), + } + } + c.paramCount++ + number := n.Position + if number == 0 { + number = c.paramCount + } + return &ast.ParamRef{ + Number: number, + Location: n.Pos(), + } +} + +func (c *cc) convertUnaryExpression(n *zjast.UnaryExpression) ast.Node { + if strings.ToUpper(n.Op) == "NOT" { + return &ast.BoolExpr{ + Boolop: ast.BoolExprTypeNot, + Args: &ast.List{ + Items: []ast.Node{c.convertExpr(n.Operand)}, + }, + Location: n.Pos(), + } + } + return &ast.A_Expr{ + Kind: ast.A_Expr_Kind_OP, + Name: &ast.List{Items: []ast.Node{&ast.String{Str: n.Op}}}, + Rexpr: c.convertExpr(n.Operand), + Location: n.Pos(), + } +} + +func (c *cc) convertBinaryExpression(n *zjast.BinaryExpression) ast.Node { + // "x IS NULL" and "x IS NOT NULL" become NullTest nodes. + if strings.ToUpper(n.Op) == "IS" { + if _, isNull := n.Right.(*zjast.NullLiteral); isNull { + nullTest := &ast.NullTest{ + Arg: c.convertExpr(n.Left), + Location: n.Pos(), + } + if n.IsNot { + nullTest.Nulltesttype = ast.NullTestTypeIsNotNull + } else { + nullTest.Nulltesttype = ast.NullTestTypeIsNull + } + return nullTest + } + } + + var expr ast.Node = &ast.A_Expr{ + Kind: ast.A_Expr_Kind_OP, + Name: &ast.List{Items: []ast.Node{&ast.String{Str: n.Op}}}, + Lexpr: c.convertExpr(n.Left), + Rexpr: c.convertExpr(n.Right), + Location: n.Pos(), + } + if n.IsNot { + // "a NOT LIKE b", "a IS NOT b", etc: wrap the comparison in a NOT. + expr = &ast.BoolExpr{ + Boolop: ast.BoolExprTypeNot, + Args: &ast.List{Items: []ast.Node{expr}}, + Location: n.Pos(), + } + } + return expr +} + +func (c *cc) convertBoolExpr(op ast.BoolExprType, operands []zjast.Node, loc int) *ast.BoolExpr { + expr := &ast.BoolExpr{ + Boolop: op, + Args: &ast.List{}, + Location: loc, + } + for _, operand := range operands { + expr.Args.Items = append(expr.Args.Items, c.convertExpr(operand)) + } + return expr +} + +func (c *cc) convertInExpression(n *zjast.InExpression) ast.Node { + in := &ast.In{ + Expr: c.convertExpr(n.Lhs), + Not: n.IsNot, + Location: n.Pos(), + } + if n.List != nil { + for _, expr := range n.List.Exprs { + in.List = append(in.List, c.convertExpr(expr)) + } + } + if n.UnnestExpr != nil { + in.List = append(in.List, c.convertUnnestExpression(n.UnnestExpr)) + } + if n.Query != nil { + in.Sel = c.convertQuery(n.Query) + } + return in +} + +// buildCaseExpr builds a CaseExpr from the alternating WHEN/THEN expression +// pairs (and optional trailing ELSE expression) of a zetajones CASE node. +func (c *cc) buildCaseExpr(arg ast.Node, rest []zjast.Node, loc int) *ast.CaseExpr { + caseExpr := &ast.CaseExpr{ + Arg: arg, + Args: &ast.List{}, + Location: loc, + } + i := 0 + for ; i+1 < len(rest); i += 2 { + caseExpr.Args.Items = append(caseExpr.Args.Items, &ast.CaseWhen{ + Expr: c.convertExpr(rest[i]), + Result: c.convertExpr(rest[i+1]), + }) + } + if i < len(rest) { + caseExpr.Defresult = c.convertExpr(rest[i]) + } + return caseExpr +} + +func (c *cc) convertExpressionSubquery(n *zjast.ExpressionSubquery) *ast.SubLink { + subLink := &ast.SubLink{ + Subselect: c.convertQuery(n.Query), + Location: n.Pos(), + } + switch strings.ToUpper(n.Modifier) { + case "EXISTS": + subLink.SubLinkType = ast.EXISTS_SUBLINK + case "ARRAY": + subLink.SubLinkType = ast.ARRAY_SUBLINK + default: + subLink.SubLinkType = ast.EXPR_SUBLINK + } + return subLink +} + +// newFuncCall builds a FuncCall from a dotted function path. GoogleSQL +// function names are case-insensitive, so they are lowercased. +func (c *cc) newFuncCall(parts []string, loc int) *ast.FuncCall { + name := strings.ToLower(parts[len(parts)-1]) + var schema string + if len(parts) > 1 { + schema = strings.ToLower(strings.Join(parts[:len(parts)-1], ".")) + } + items := []ast.Node{} + if schema != "" { + items = append(items, &ast.String{Str: schema}) + } + items = append(items, &ast.String{Str: name}) + return &ast.FuncCall{ + Func: &ast.FuncName{Schema: schema, Name: name}, + Funcname: &ast.List{Items: items}, + Args: &ast.List{}, + Location: loc, + } +} + +func (c *cc) convertFunctionCall(n *zjast.FunctionCall) ast.Node { + // Chained calls ("expr.method(...)") have no sqlc AST equivalent. + if n.IsChained { + return todo(n) + } + parts := pathParts(n.Function) + if len(parts) == 0 { + return todo(n) + } + fc := c.newFuncCall(parts, n.Pos()) + fc.AggDistinct = n.Distinct + for _, arg := range n.Args { + if _, ok := arg.(*zjast.Star); ok { + fc.AggStar = true + continue + } + fc.Args.Items = append(fc.Args.Items, c.convertExpr(arg)) + } + if n.OrderBy != nil { + fc.AggOrder = c.convertOrderBy(n.OrderBy) + } + return fc +} + +func (c *cc) convertAnalyticFunctionCall(n *zjast.AnalyticFunctionCall) ast.Node { + base := c.convertExpr(n.Expr) + fc, ok := base.(*ast.FuncCall) + if !ok { + return base + } + over := &ast.WindowDef{Location: n.Pos()} + if spec := n.WindowSpec; spec != nil { + if spec.Name != nil { + name := identifier(spec.Name.Name) + over.Name = &name + } + if spec.PartitionBy != nil { + over.PartitionClause = &ast.List{} + for _, expr := range spec.PartitionBy.Expressions { + over.PartitionClause.Items = append(over.PartitionClause.Items, c.convertExpr(expr)) + } + } + if spec.OrderBy != nil { + over.OrderClause = c.convertOrderBy(spec.OrderBy) + } + } + fc.Over = over + return fc +} + +func (c *cc) convertDotStar(n *zjast.DotStar) ast.Node { + fields, ok := columnRefFields(n.Expr) + if !ok { + return todo(n) + } + fields = append(fields, &ast.A_Star{}) + return &ast.ColumnRef{ + Fields: &ast.List{Items: fields}, + Location: n.Pos(), + } +} + +// targetPath extracts the table path of an INSERT/UPDATE/DELETE target. +func targetPath(node zjast.Node) (*zjast.PathExpression, bool) { + path, ok := node.(*zjast.PathExpression) + return path, ok && path != nil +} + +func (c *cc) convertInsertStatement(n *zjast.InsertStatement) ast.Node { + path, ok := targetPath(n.Target) + if !ok { + return todo(n) + } + stmt := &ast.InsertStmt{ + Relation: parseRangeVar(path), + } + + if n.Columns != nil { + stmt.Cols = &ast.List{} + for _, col := range n.Columns.Identifiers { + if col == nil { + continue + } + name := identifier(col.Name) + stmt.Cols.Items = append(stmt.Cols.Items, &ast.ResTarget{ + Name: &name, + Location: col.Pos(), + }) + } + } + + switch { + case n.Rows != nil: + selectStmt := &ast.SelectStmt{ + ValuesLists: &ast.List{}, + } + for _, row := range n.Rows.Rows { + if row == nil { + continue + } + rowList := &ast.List{} + for _, val := range row.Values { + rowList.Items = append(rowList.Items, c.convertExpr(val)) + } + selectStmt.ValuesLists.Items = append(selectStmt.ValuesLists.Items, rowList) + } + stmt.SelectStmt = selectStmt + case n.Query != nil: + stmt.SelectStmt = c.convertQuery(n.Query) + } + + if n.Returning != nil { + stmt.ReturningList = c.convertReturningClause(n.Returning) + } + + return stmt +} + +// convertReturningClause converts a "THEN RETURN" clause to a returning list. +func (c *cc) convertReturningClause(n *zjast.ReturningClause) *ast.List { + list := &ast.List{} + if n.SelectList != nil { + for _, col := range n.SelectList.Columns { + if col == nil { + continue + } + list.Items = append(list.Items, c.convertSelectColumn(col)) + } + } + return list +} + +func (c *cc) convertUpdateStatement(n *zjast.UpdateStatement) ast.Node { + path, ok := targetPath(n.Target) + if !ok { + return todo(n) + } + rv := parseRangeVar(path) + rv.Alias = convertAlias(n.Alias) + stmt := &ast.UpdateStmt{ + Relations: &ast.List{Items: []ast.Node{rv}}, + TargetList: &ast.List{}, + } + + if n.UpdateItemList != nil { + for _, item := range n.UpdateItemList.Items { + if item == nil || item.SetValue == nil { + // Nested INSERT/UPDATE/DELETE update items are unsupported. + continue + } + stmt.TargetList.Items = append(stmt.TargetList.Items, c.convertUpdateSetValue(item.SetValue)) + } + } + + if n.From != nil { + stmt.FromClause = &ast.List{ + Items: []ast.Node{c.convertTableExpr(n.From.TableExpression)}, + } + } + + if n.Where != nil { + stmt.WhereClause = c.convertExpr(whereExpr(n.Where)) + } + + if n.Returning != nil { + stmt.ReturningList = c.convertReturningClause(n.Returning) + } + + return stmt +} + +func (c *cc) convertUpdateSetValue(n *zjast.UpdateSetValue) *ast.ResTarget { + res := &ast.ResTarget{ + Val: c.convertExpr(n.Value), + Location: n.Pos(), + } + if path, ok := n.Path.(*zjast.PathExpression); ok { + if parts := pathParts(path); len(parts) > 0 { + name := identifier(parts[len(parts)-1]) + res.Name = &name + } + } + return res +} + +func (c *cc) convertDeleteStatement(n *zjast.DeleteStatement) ast.Node { + path, ok := targetPath(n.Target) + if !ok { + return todo(n) + } + rv := parseRangeVar(path) + rv.Alias = convertAlias(n.Alias) + stmt := &ast.DeleteStmt{ + Relations: &ast.List{Items: []ast.Node{rv}}, + } + + if n.Where != nil { + stmt.WhereClause = c.convertExpr(whereExpr(n.Where)) + } + + if n.Returning != nil { + stmt.ReturningList = c.convertReturningClause(n.Returning) + } + + return stmt +} + +func (c *cc) convertCreateTableStatement(n *zjast.CreateTableStatement) ast.Node { + stmt := &ast.CreateTableStmt{ + Name: parseTableName(n.Name), + IfNotExists: n.IsIfNotExists, + } + if n.TableElementList != nil { + for _, elem := range n.TableElementList.Elements { + col, ok := elem.(*zjast.ColumnDefinition) + if !ok { + // Table-level PRIMARY KEY, FOREIGN KEY, and CHECK + // constraints are skipped. + continue + } + stmt.Cols = append(stmt.Cols, c.convertColumnDefinition(col)) + } + } + return stmt +} + +func (c *cc) convertColumnDefinition(n *zjast.ColumnDefinition) *ast.ColumnDef { + col := &ast.ColumnDef{ + Location: n.Pos(), + TypeName: spelledTypeName(columnSchemaTypeName(n.Schema)), + } + if n.Name != nil { + col.Colname = identifier(n.Name.Name) + } + + if attrs := columnAttributes(n.Schema); attrs != nil { + for _, attr := range attrs.Attributes { + switch attr.(type) { + case *zjast.NotNullColumnAttribute: + col.IsNotNull = true + case *zjast.PrimaryKeyColumnAttribute: + col.PrimaryKey = true + } + } + } + + if simple, ok := n.Schema.(*zjast.SimpleColumnSchema); ok { + if simple.DefaultExpression != nil { + col.RawDefault = c.convertExpr(simple.DefaultExpression) + } + } + + return col +} + +func (c *cc) convertDropStatement(n *zjast.DropStatement) ast.Node { + // Only DROP TABLE maps onto the sqlc AST; other object kinds (views, + // functions, schemas, ...) fall through to TODO. + if strings.EqualFold(n.ObjectKind, "TABLE") && n.Path != nil { + return &ast.DropTableStmt{ + IfExists: n.IsIfExists, + Tables: []*ast.TableName{parseTableName(n.Path)}, + } + } + return todo(n) +} + +func (c *cc) convertTruncateStatement(n *zjast.TruncateStatement) ast.Node { + if n.Target == nil { + return todo(n) + } + return &ast.TruncateStmt{ + Relations: &ast.List{Items: []ast.Node{parseRangeVar(n.Target)}}, + } +} + +// spelledTypeName is a type name the core reads from its spelling, whose +// name is the family the spelling applies: string for string(10), array +// for array(int64). +func spelledTypeName(spelling string) *ast.TypeName { + name := spelling + if i := strings.IndexByte(name, '('); i >= 0 { + name = name[:i] + } + return &ast.TypeName{Name: name, Canonical: spelling} +} diff --git a/internal/engine/googlesql/dialect/dialect.json b/internal/engine/googlesql/dialect/dialect.json new file mode 100644 index 0000000..728546d --- /dev/null +++ b/internal/engine/googlesql/dialect/dialect.json @@ -0,0 +1,15 @@ +{ + "dialect": "googlesql", + "const": { + "integer": "int64", + "float": "float64", + "string": "string", + "bool": "bool" + }, + "bool": "bool", + "comparison": ["=", "<>", "!=", "<", "<=", ">", ">="], + "comparison_categories": "BNSDTU", + "arithmetic": ["+", "-", "*", "/"], + "arithmetic_categories": "N", + "idents": ["max"] +} diff --git a/internal/engine/googlesql/dialect/functions.jsonl b/internal/engine/googlesql/dialect/functions.jsonl new file mode 100644 index 0000000..42bf289 --- /dev/null +++ b/internal/engine/googlesql/dialect/functions.jsonl @@ -0,0 +1 @@ +{"name": "count", "kind": "a", "returns": "int64"} diff --git a/internal/engine/googlesql/dialect/operators.jsonl b/internal/engine/googlesql/dialect/operators.jsonl new file mode 100644 index 0000000..5967f9f --- /dev/null +++ b/internal/engine/googlesql/dialect/operators.jsonl @@ -0,0 +1 @@ +{"name": "||", "left": "string", "right": "string", "result": "string"} diff --git a/internal/engine/googlesql/dialect/relations.jsonl b/internal/engine/googlesql/dialect/relations.jsonl new file mode 100644 index 0000000..03e4e78 --- /dev/null +++ b/internal/engine/googlesql/dialect/relations.jsonl @@ -0,0 +1,98 @@ +{"schema":"INFORMATION_SCHEMA","name":"CHANGE_STREAMS","kind":"v","columns":[{"name":"CHANGE_STREAM_CATALOG","type":"string(max)","not_null":true},{"name":"CHANGE_STREAM_SCHEMA","type":"string(max)","not_null":true},{"name":"CHANGE_STREAM_NAME","type":"string(max)","not_null":true},{"name":"ALL","type":"bool","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"CHANGE_STREAM_COLUMNS","kind":"v","columns":[{"name":"CHANGE_STREAM_CATALOG","type":"string(max)","not_null":true},{"name":"CHANGE_STREAM_SCHEMA","type":"string(max)","not_null":true},{"name":"CHANGE_STREAM_NAME","type":"string(max)","not_null":true},{"name":"TABLE_CATALOG","type":"string(max)","not_null":true},{"name":"TABLE_SCHEMA","type":"string(max)","not_null":true},{"name":"TABLE_NAME","type":"string(max)","not_null":true},{"name":"COLUMN_NAME","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"CHANGE_STREAM_OPTIONS","kind":"v","columns":[{"name":"CHANGE_STREAM_CATALOG","type":"string(max)","not_null":true},{"name":"CHANGE_STREAM_SCHEMA","type":"string(max)","not_null":true},{"name":"CHANGE_STREAM_NAME","type":"string(max)","not_null":true},{"name":"OPTION_NAME","type":"string(max)","not_null":true},{"name":"OPTION_TYPE","type":"string(max)","not_null":true},{"name":"OPTION_VALUE","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"CHANGE_STREAM_PRIVILEGES","kind":"v","columns":[{"name":"CHANGE_STREAM_CATALOG","type":"string(max)","not_null":true},{"name":"CHANGE_STREAM_SCHEMA","type":"string(max)","not_null":true},{"name":"CHANGE_STREAM_NAME","type":"string(max)","not_null":true},{"name":"PRIVILEGE_TYPE","type":"string(max)","not_null":true},{"name":"GRANTEE","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"CHANGE_STREAM_TABLES","kind":"v","columns":[{"name":"CHANGE_STREAM_CATALOG","type":"string(max)","not_null":true},{"name":"CHANGE_STREAM_SCHEMA","type":"string(max)","not_null":true},{"name":"CHANGE_STREAM_NAME","type":"string(max)","not_null":true},{"name":"TABLE_CATALOG","type":"string(max)","not_null":true},{"name":"TABLE_SCHEMA","type":"string(max)","not_null":true},{"name":"TABLE_NAME","type":"string(max)","not_null":true},{"name":"ALL_COLUMNS","type":"bool","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"CHECK_CONSTRAINTS","kind":"v","columns":[{"name":"CONSTRAINT_CATALOG","type":"string(max)","not_null":true},{"name":"CONSTRAINT_SCHEMA","type":"string(max)","not_null":true},{"name":"CONSTRAINT_NAME","type":"string(max)","not_null":true},{"name":"CHECK_CLAUSE","type":"string(max)","not_null":true},{"name":"SPANNER_STATE","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"COLUMNS","kind":"v","columns":[{"name":"TABLE_CATALOG","type":"string(max)","not_null":true},{"name":"TABLE_SCHEMA","type":"string(max)","not_null":true},{"name":"TABLE_NAME","type":"string(max)","not_null":true},{"name":"COLUMN_NAME","type":"string(max)","not_null":true},{"name":"ORDINAL_POSITION","type":"int64","not_null":true},{"name":"COLUMN_DEFAULT","type":"string(max)"},{"name":"DATA_TYPE","type":"string(max)"},{"name":"IS_NULLABLE","type":"string(max)"},{"name":"SPANNER_TYPE","type":"string(max)"},{"name":"IS_GENERATED","type":"string(max)","not_null":true},{"name":"GENERATION_EXPRESSION","type":"string(max)"},{"name":"IS_STORED","type":"string(max)"},{"name":"IS_HIDDEN","type":"bool","not_null":true},{"name":"SPANNER_STATE","type":"string(max)"},{"name":"IS_IDENTITY","type":"string(max)"},{"name":"IDENTITY_GENERATION","type":"string(max)"},{"name":"IDENTITY_KIND","type":"string(max)"},{"name":"IDENTITY_START_WITH_COUNTER","type":"string(max)"},{"name":"IDENTITY_SKIP_RANGE_MIN","type":"string(max)"},{"name":"IDENTITY_SKIP_RANGE_MAX","type":"string(max)"},{"name":"ON_UPDATE_EXPRESSION","type":"string(max)"}]} +{"schema":"INFORMATION_SCHEMA","name":"COLUMN_COLUMN_USAGE","kind":"v","columns":[{"name":"TABLE_CATALOG","type":"string(max)","not_null":true},{"name":"TABLE_SCHEMA","type":"string(max)","not_null":true},{"name":"TABLE_NAME","type":"string(max)","not_null":true},{"name":"COLUMN_NAME","type":"string(max)","not_null":true},{"name":"DEPENDENT_COLUMN","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"COLUMN_OPTIONS","kind":"v","columns":[{"name":"TABLE_CATALOG","type":"string(max)","not_null":true},{"name":"TABLE_SCHEMA","type":"string(max)","not_null":true},{"name":"TABLE_NAME","type":"string(max)","not_null":true},{"name":"COLUMN_NAME","type":"string(max)","not_null":true},{"name":"OPTION_NAME","type":"string(max)","not_null":true},{"name":"OPTION_TYPE","type":"string(max)","not_null":true},{"name":"OPTION_VALUE","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"COLUMN_PRIVILEGES","kind":"v","columns":[{"name":"TABLE_CATALOG","type":"string(max)","not_null":true},{"name":"TABLE_SCHEMA","type":"string(max)","not_null":true},{"name":"TABLE_NAME","type":"string(max)","not_null":true},{"name":"COLUMN_NAME","type":"string(max)","not_null":true},{"name":"PRIVILEGE_TYPE","type":"string(max)","not_null":true},{"name":"GRANTEE","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"CONSTRAINT_COLUMN_USAGE","kind":"v","columns":[{"name":"TABLE_CATALOG","type":"string(max)","not_null":true},{"name":"TABLE_SCHEMA","type":"string(max)","not_null":true},{"name":"TABLE_NAME","type":"string(max)","not_null":true},{"name":"COLUMN_NAME","type":"string(max)","not_null":true},{"name":"CONSTRAINT_CATALOG","type":"string(max)","not_null":true},{"name":"CONSTRAINT_SCHEMA","type":"string(max)","not_null":true},{"name":"CONSTRAINT_NAME","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"CONSTRAINT_TABLE_USAGE","kind":"v","columns":[{"name":"TABLE_CATALOG","type":"string(max)","not_null":true},{"name":"TABLE_SCHEMA","type":"string(max)","not_null":true},{"name":"TABLE_NAME","type":"string(max)","not_null":true},{"name":"CONSTRAINT_CATALOG","type":"string(max)","not_null":true},{"name":"CONSTRAINT_SCHEMA","type":"string(max)","not_null":true},{"name":"CONSTRAINT_NAME","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"DATABASE_OPTIONS","kind":"v","columns":[{"name":"CATALOG_NAME","type":"string(max)","not_null":true},{"name":"SCHEMA_NAME","type":"string(max)","not_null":true},{"name":"OPTION_NAME","type":"string(max)","not_null":true},{"name":"OPTION_TYPE","type":"string(max)","not_null":true},{"name":"OPTION_VALUE","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"INDEXES","kind":"v","columns":[{"name":"TABLE_CATALOG","type":"string(max)","not_null":true},{"name":"TABLE_SCHEMA","type":"string(max)","not_null":true},{"name":"TABLE_NAME","type":"string(max)","not_null":true},{"name":"INDEX_NAME","type":"string(max)","not_null":true},{"name":"INDEX_TYPE","type":"string(max)","not_null":true},{"name":"PARENT_TABLE_NAME","type":"string(max)","not_null":true},{"name":"IS_UNIQUE","type":"bool","not_null":true},{"name":"IS_NULL_FILTERED","type":"bool","not_null":true},{"name":"INDEX_STATE","type":"string(100)","not_null":true},{"name":"FILTER","type":"string(max)"},{"name":"SPANNER_IS_MANAGED","type":"bool","not_null":true},{"name":"SEARCH_PARTITION_BY","type":"string(max)","array":true},{"name":"SEARCH_ORDER_BY","type":"string(max)","array":true},{"name":"SEARCH_UNNEST","type":"string(max)","array":true}]} +{"schema":"INFORMATION_SCHEMA","name":"INDEX_COLUMNS","kind":"v","columns":[{"name":"TABLE_CATALOG","type":"string(max)","not_null":true},{"name":"TABLE_SCHEMA","type":"string(max)","not_null":true},{"name":"TABLE_NAME","type":"string(max)","not_null":true},{"name":"INDEX_NAME","type":"string(max)","not_null":true},{"name":"INDEX_TYPE","type":"string(max)","not_null":true},{"name":"COLUMN_NAME","type":"string(max)","not_null":true},{"name":"ORDINAL_POSITION","type":"int64"},{"name":"COLUMN_ORDERING","type":"string(max)"},{"name":"IS_NULLABLE","type":"string(max)"},{"name":"SPANNER_TYPE","type":"string(max)"},{"name":"EXPRESSION","type":"string(max)"}]} +{"schema":"INFORMATION_SCHEMA","name":"INDEX_OPTIONS","kind":"v","columns":[{"name":"TABLE_CATALOG","type":"string(max)","not_null":true},{"name":"TABLE_SCHEMA","type":"string(max)","not_null":true},{"name":"TABLE_NAME","type":"string(max)","not_null":true},{"name":"INDEX_NAME","type":"string(max)","not_null":true},{"name":"INDEX_TYPE","type":"string(max)","not_null":true},{"name":"OPTION_NAME","type":"string(max)","not_null":true},{"name":"OPTION_TYPE","type":"string(max)","not_null":true},{"name":"OPTION_VALUE","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"KEY_COLUMN_USAGE","kind":"v","columns":[{"name":"CONSTRAINT_CATALOG","type":"string(max)","not_null":true},{"name":"CONSTRAINT_SCHEMA","type":"string(max)","not_null":true},{"name":"CONSTRAINT_NAME","type":"string(max)","not_null":true},{"name":"TABLE_CATALOG","type":"string(max)","not_null":true},{"name":"TABLE_SCHEMA","type":"string(max)","not_null":true},{"name":"TABLE_NAME","type":"string(max)","not_null":true},{"name":"COLUMN_NAME","type":"string(max)","not_null":true},{"name":"ORDINAL_POSITION","type":"int64","not_null":true},{"name":"POSITION_IN_UNIQUE_CONSTRAINT","type":"int64"}]} +{"schema":"INFORMATION_SCHEMA","name":"LOCALITY_GROUP_OPTIONS","kind":"v","columns":[{"name":"LOCALITY_GROUP_NAME","type":"string(max)","not_null":true},{"name":"OPTION_NAME","type":"string(max)","not_null":true},{"name":"OPTION_VALUE","type":"string(max)"}]} +{"schema":"INFORMATION_SCHEMA","name":"MODELS","kind":"v","columns":[{"name":"MODEL_CATALOG","type":"string(max)","not_null":true},{"name":"MODEL_SCHEMA","type":"string(max)","not_null":true},{"name":"MODEL_NAME","type":"string(max)","not_null":true},{"name":"IS_REMOTE","type":"bool","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"MODEL_COLUMNS","kind":"v","columns":[{"name":"MODEL_CATALOG","type":"string(max)","not_null":true},{"name":"MODEL_SCHEMA","type":"string(max)","not_null":true},{"name":"MODEL_NAME","type":"string(max)","not_null":true},{"name":"COLUMN_KIND","type":"string(max)","not_null":true},{"name":"COLUMN_NAME","type":"string(max)","not_null":true},{"name":"ORDINAL_POSITION","type":"int64","not_null":true},{"name":"DATA_TYPE","type":"string(max)","not_null":true},{"name":"IS_EXPLICIT","type":"bool","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"MODEL_COLUMN_OPTIONS","kind":"v","columns":[{"name":"MODEL_CATALOG","type":"string(max)","not_null":true},{"name":"MODEL_SCHEMA","type":"string(max)","not_null":true},{"name":"MODEL_NAME","type":"string(max)","not_null":true},{"name":"COLUMN_KIND","type":"string(max)","not_null":true},{"name":"COLUMN_NAME","type":"string(max)","not_null":true},{"name":"OPTION_NAME","type":"string(max)","not_null":true},{"name":"OPTION_TYPE","type":"string(max)","not_null":true},{"name":"OPTION_VALUE","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"MODEL_OPTIONS","kind":"v","columns":[{"name":"MODEL_CATALOG","type":"string(max)","not_null":true},{"name":"MODEL_SCHEMA","type":"string(max)","not_null":true},{"name":"MODEL_NAME","type":"string(max)","not_null":true},{"name":"OPTION_NAME","type":"string(max)","not_null":true},{"name":"OPTION_TYPE","type":"string(max)","not_null":true},{"name":"OPTION_VALUE","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"MODEL_PRIVILEGES","kind":"v","columns":[{"name":"MODEL_CATALOG","type":"string(max)","not_null":true},{"name":"MODEL_SCHEMA","type":"string(max)","not_null":true},{"name":"MODEL_NAME","type":"string(max)","not_null":true},{"name":"PRIVILEGE_TYPE","type":"string(max)","not_null":true},{"name":"GRANTEE","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"PARAMETERS","kind":"v","columns":[{"name":"SPECIFIC_CATALOG","type":"string(max)","not_null":true},{"name":"SPECIFIC_SCHEMA","type":"string(max)","not_null":true},{"name":"SPECIFIC_NAME","type":"string(max)","not_null":true},{"name":"ORDINAL_POSITION","type":"int64","not_null":true},{"name":"PARAMETER_NAME","type":"string(max)","not_null":true},{"name":"DATA_TYPE","type":"string(max)","not_null":true},{"name":"PARAMETER_DEFAULT","type":"string(max)"},{"name":"SPANNER_TYPE","type":"string(max)"}]} +{"schema":"INFORMATION_SCHEMA","name":"PLACEMENTS","kind":"v","columns":[{"name":"PLACEMENT_NAME","type":"string(max)","not_null":true},{"name":"IS_DEFAULT","type":"bool","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"PLACEMENT_OPTIONS","kind":"v","columns":[{"name":"PLACEMENT_NAME","type":"string(max)","not_null":true},{"name":"OPTION_NAME","type":"string(max)","not_null":true},{"name":"OPTION_TYPE","type":"string(max)","not_null":true},{"name":"OPTION_VALUE","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"PROPERTY_GRAPHS","kind":"v","columns":[{"name":"PROPERTY_GRAPH_CATALOG","type":"string(max)","not_null":true},{"name":"PROPERTY_GRAPH_SCHEMA","type":"string(max)","not_null":true},{"name":"PROPERTY_GRAPH_NAME","type":"string(max)","not_null":true},{"name":"PROPERTY_GRAPH_METADATA_JSON","type":"json"}]} +{"schema":"INFORMATION_SCHEMA","name":"REFERENTIAL_CONSTRAINTS","kind":"v","columns":[{"name":"CONSTRAINT_CATALOG","type":"string(max)","not_null":true},{"name":"CONSTRAINT_SCHEMA","type":"string(max)","not_null":true},{"name":"CONSTRAINT_NAME","type":"string(max)","not_null":true},{"name":"UNIQUE_CONSTRAINT_CATALOG","type":"string(max)"},{"name":"UNIQUE_CONSTRAINT_SCHEMA","type":"string(max)"},{"name":"UNIQUE_CONSTRAINT_NAME","type":"string(max)"},{"name":"MATCH_OPTION","type":"string(max)","not_null":true},{"name":"UPDATE_RULE","type":"string(max)","not_null":true},{"name":"DELETE_RULE","type":"string(max)","not_null":true},{"name":"SPANNER_STATE","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"ROLES","kind":"v","columns":[{"name":"ROLE_NAME","type":"string(max)","not_null":true},{"name":"IS_SYSTEM","type":"bool","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"ROLE_CHANGE_STREAM_GRANTS","kind":"v","columns":[{"name":"CHANGE_STREAM_CATALOG","type":"string(max)","not_null":true},{"name":"CHANGE_STREAM_SCHEMA","type":"string(max)","not_null":true},{"name":"CHANGE_STREAM_NAME","type":"string(max)","not_null":true},{"name":"PRIVILEGE_TYPE","type":"string(max)","not_null":true},{"name":"GRANTEE","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"ROLE_COLUMN_GRANTS","kind":"v","columns":[{"name":"TABLE_CATALOG","type":"string(max)","not_null":true},{"name":"TABLE_SCHEMA","type":"string(max)","not_null":true},{"name":"TABLE_NAME","type":"string(max)","not_null":true},{"name":"COLUMN_NAME","type":"string(max)","not_null":true},{"name":"PRIVILEGE_TYPE","type":"string(max)","not_null":true},{"name":"GRANTEE","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"ROLE_GRANTEES","kind":"v","columns":[{"name":"ROLE_NAME","type":"string(max)","not_null":true},{"name":"GRANTEE","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"ROLE_MODEL_GRANTS","kind":"v","columns":[{"name":"MODEL_CATALOG","type":"string(max)","not_null":true},{"name":"MODEL_SCHEMA","type":"string(max)","not_null":true},{"name":"MODEL_NAME","type":"string(max)","not_null":true},{"name":"PRIVILEGE_TYPE","type":"string(max)","not_null":true},{"name":"GRANTEE","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"ROLE_ROUTINE_GRANTS","kind":"v","columns":[{"name":"SPECIFIC_CATALOG","type":"string(max)","not_null":true},{"name":"SPECIFIC_SCHEMA","type":"string(max)","not_null":true},{"name":"SPECIFIC_NAME","type":"string(max)","not_null":true},{"name":"PRIVILEGE_TYPE","type":"string(max)","not_null":true},{"name":"GRANTEE","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"ROLE_TABLE_GRANTS","kind":"v","columns":[{"name":"TABLE_CATALOG","type":"string(max)","not_null":true},{"name":"TABLE_SCHEMA","type":"string(max)","not_null":true},{"name":"TABLE_NAME","type":"string(max)","not_null":true},{"name":"PRIVILEGE_TYPE","type":"string(max)","not_null":true},{"name":"GRANTEE","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"ROUTINES","kind":"v","columns":[{"name":"SPECIFIC_CATALOG","type":"string(max)","not_null":true},{"name":"SPECIFIC_SCHEMA","type":"string(max)","not_null":true},{"name":"SPECIFIC_NAME","type":"string(max)","not_null":true},{"name":"ROUTINE_CATALOG","type":"string(max)","not_null":true},{"name":"ROUTINE_SCHEMA","type":"string(max)","not_null":true},{"name":"ROUTINE_NAME","type":"string(max)","not_null":true},{"name":"ROUTINE_TYPE","type":"string(max)","not_null":true},{"name":"DATA_TYPE","type":"string(max)","not_null":true},{"name":"ROUTINE_BODY","type":"string(max)","not_null":true},{"name":"ROUTINE_DEFINITION","type":"string(max)","not_null":true},{"name":"SECURITY_TYPE","type":"string(max)","not_null":true},{"name":"SPANNER_TYPE","type":"string(max)"}]} +{"schema":"INFORMATION_SCHEMA","name":"ROUTINE_OPTIONS","kind":"v","columns":[{"name":"SPECIFIC_CATALOG","type":"string(max)","not_null":true},{"name":"SPECIFIC_SCHEMA","type":"string(max)","not_null":true},{"name":"SPECIFIC_NAME","type":"string(max)","not_null":true},{"name":"OPTION_NAME","type":"string(max)","not_null":true},{"name":"OPTION_TYPE","type":"string(max)","not_null":true},{"name":"OPTION_VALUE","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"ROUTINE_PRIVILEGES","kind":"v","columns":[{"name":"SPECIFIC_CATALOG","type":"string(max)","not_null":true},{"name":"SPECIFIC_SCHEMA","type":"string(max)","not_null":true},{"name":"SPECIFIC_NAME","type":"string(max)","not_null":true},{"name":"PRIVILEGE_TYPE","type":"string(max)","not_null":true},{"name":"GRANTEE","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"SCHEMATA","kind":"v","columns":[{"name":"CATALOG_NAME","type":"string(max)","not_null":true},{"name":"SCHEMA_NAME","type":"string(max)","not_null":true},{"name":"EFFECTIVE_TIMESTAMP","type":"int64"},{"name":"PROTO_BUNDLE","type":"proto('proto2.FileDescriptorSet')"},{"name":"SCHEMA_OWNER","type":"string(max)"}]} +{"schema":"INFORMATION_SCHEMA","name":"SEQUENCES","kind":"v","columns":[{"name":"CATALOG","type":"string(max)","not_null":true},{"name":"SCHEMA","type":"string(max)","not_null":true},{"name":"NAME","type":"string(max)","not_null":true},{"name":"DATA_TYPE","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"SEQUENCE_OPTIONS","kind":"v","columns":[{"name":"CATALOG","type":"string(max)","not_null":true},{"name":"SCHEMA","type":"string(max)","not_null":true},{"name":"NAME","type":"string(max)","not_null":true},{"name":"OPTION_NAME","type":"string(max)","not_null":true},{"name":"OPTION_TYPE","type":"string(max)","not_null":true},{"name":"OPTION_VALUE","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"SPANNER_STATISTICS","kind":"v","columns":[{"name":"CATALOG_NAME","type":"string(max)","not_null":true},{"name":"SCHEMA_NAME","type":"string(max)","not_null":true},{"name":"PACKAGE_NAME","type":"string(max)","not_null":true},{"name":"ALLOW_GC","type":"bool","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"TABLES","kind":"v","columns":[{"name":"TABLE_CATALOG","type":"string(max)","not_null":true},{"name":"TABLE_SCHEMA","type":"string(max)","not_null":true},{"name":"TABLE_NAME","type":"string(max)","not_null":true},{"name":"PARENT_TABLE_NAME","type":"string(max)"},{"name":"ON_DELETE_ACTION","type":"string(max)"},{"name":"TABLE_TYPE","type":"string(32)","not_null":true},{"name":"SPANNER_STATE","type":"string(max)"},{"name":"INTERLEAVE_TYPE","type":"string(max)"},{"name":"ROW_DELETION_POLICY_EXPRESSION","type":"string(max)"}]} +{"schema":"INFORMATION_SCHEMA","name":"TABLE_CONSTRAINTS","kind":"v","columns":[{"name":"CONSTRAINT_CATALOG","type":"string(max)","not_null":true},{"name":"CONSTRAINT_SCHEMA","type":"string(max)","not_null":true},{"name":"CONSTRAINT_NAME","type":"string(max)","not_null":true},{"name":"TABLE_CATALOG","type":"string(max)","not_null":true},{"name":"TABLE_SCHEMA","type":"string(max)","not_null":true},{"name":"TABLE_NAME","type":"string(max)","not_null":true},{"name":"CONSTRAINT_TYPE","type":"string(max)","not_null":true},{"name":"IS_DEFERRABLE","type":"string(max)","not_null":true},{"name":"INITIALLY_DEFERRED","type":"string(max)","not_null":true},{"name":"ENFORCED","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"TABLE_OPTIONS","kind":"v","columns":[{"name":"TABLE_CATALOG","type":"string(max)","not_null":true},{"name":"TABLE_SCHEMA","type":"string(max)","not_null":true},{"name":"TABLE_NAME","type":"string(max)","not_null":true},{"name":"OPTION_NAME","type":"string(max)","not_null":true},{"name":"OPTION_TYPE","type":"string(max)","not_null":true},{"name":"OPTION_VALUE","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"TABLE_PRIVILEGES","kind":"v","columns":[{"name":"TABLE_CATALOG","type":"string(max)","not_null":true},{"name":"TABLE_SCHEMA","type":"string(max)","not_null":true},{"name":"TABLE_NAME","type":"string(max)","not_null":true},{"name":"PRIVILEGE_TYPE","type":"string(max)","not_null":true},{"name":"GRANTEE","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"TABLE_SYNONYMS","kind":"v","columns":[{"name":"SYNONYM_CATALOG","type":"string(max)","not_null":true},{"name":"SYNONYM_SCHEMA","type":"string(max)","not_null":true},{"name":"SYNONYM_NAME","type":"string(max)","not_null":true},{"name":"TABLE_CATALOG","type":"string(max)","not_null":true},{"name":"TABLE_SCHEMA","type":"string(max)","not_null":true},{"name":"TABLE_NAME","type":"string(max)","not_null":true}]} +{"schema":"INFORMATION_SCHEMA","name":"VIEWS","kind":"v","columns":[{"name":"TABLE_CATALOG","type":"string(max)","not_null":true},{"name":"TABLE_SCHEMA","type":"string(max)","not_null":true},{"name":"TABLE_NAME","type":"string(max)","not_null":true},{"name":"VIEW_DEFINITION","type":"string(max)"},{"name":"SECURITY_TYPE","type":"string(max)","not_null":true}]} +{"schema":"SPANNER_SYS","name":"ACTIVE_PARTITIONED_DMLS","kind":"v","columns":[{"name":"TEXT","type":"string(max)"},{"name":"TEXT_FINGERPRINT","type":"string(max)"},{"name":"SESSION_ID","type":"string(max)"},{"name":"NUM_PARTITIONS_TOTAL","type":"int64"},{"name":"NUM_PARTITIONS_COMPLETE","type":"int64"},{"name":"NUM_TRIVIAL_PARTITIONS_COMPLETE","type":"int64"},{"name":"PROGRESS","type":"string(max)"},{"name":"ROWS_PROCESSED","type":"int64"},{"name":"START_TIMESTAMP","type":"timestamp"},{"name":"LAST_UPDATE_TIMESTAMP","type":"timestamp"}]} +{"schema":"SPANNER_SYS","name":"ACTIVE_QUERIES_SUMMARY","kind":"v","columns":[{"name":"ACTIVE_COUNT","type":"int64"},{"name":"OLDEST_START_TIME","type":"timestamp"},{"name":"COUNT_OLDER_THAN_1S","type":"int64"},{"name":"COUNT_OLDER_THAN_10S","type":"int64"},{"name":"COUNT_OLDER_THAN_100S","type":"int64"}]} +{"schema":"SPANNER_SYS","name":"COLUMN_OPERATIONS_STATS_10MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"TABLE_NAME","type":"string(max)"},{"name":"COLUMN_NAME","type":"string(max)"},{"name":"QUERY_COUNT","type":"int64"},{"name":"READ_COUNT","type":"int64"},{"name":"WRITE_COUNT","type":"int64"},{"name":"IS_QUERY_CACHE_MEMORY_CAPPED","type":"bool"}]} +{"schema":"SPANNER_SYS","name":"COLUMN_OPERATIONS_STATS_HOUR","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"TABLE_NAME","type":"string(max)"},{"name":"COLUMN_NAME","type":"string(max)"},{"name":"QUERY_COUNT","type":"int64"},{"name":"READ_COUNT","type":"int64"},{"name":"WRITE_COUNT","type":"int64"},{"name":"IS_QUERY_CACHE_MEMORY_CAPPED","type":"bool"}]} +{"schema":"SPANNER_SYS","name":"COLUMN_OPERATIONS_STATS_MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"TABLE_NAME","type":"string(max)"},{"name":"COLUMN_NAME","type":"string(max)"},{"name":"QUERY_COUNT","type":"int64"},{"name":"READ_COUNT","type":"int64"},{"name":"WRITE_COUNT","type":"int64"},{"name":"IS_QUERY_CACHE_MEMORY_CAPPED","type":"bool"}]} +{"schema":"SPANNER_SYS","name":"GRAPH_OPERATION_EXECUTION_STATUS","kind":"v","columns":[{"name":"QUERY_ID","type":"string(max)"},{"name":"QUERY_TEXT","type":"string(max)"},{"name":"START_TIMESTAMP","type":"timestamp"},{"name":"LAST_UPDATE_TIMESTAMP","type":"timestamp"},{"name":"PROGRESS","type":"float64"},{"name":"STATUS","type":"string(max)"},{"name":"ERROR_MESSAGE","type":"string(max)"}]} +{"schema":"SPANNER_SYS","name":"LOCK_STATS_TOP_10MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"ROW_RANGE_START_KEY","type":"bytes(max)"},{"name":"LOCK_WAIT_SECONDS","type":"float64"},{"name":"SAMPLE_LOCK_REQUESTS","type":"struct(COLUMN: string(max), LOCK_MODE: string(max), TRANSACTION_TAG: string(max))","array":true},{"name":"SAMPLE_LOCK_REQUESTS_JSON_STRING","type":"string(max)"}]} +{"schema":"SPANNER_SYS","name":"LOCK_STATS_TOP_HOUR","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"ROW_RANGE_START_KEY","type":"bytes(max)"},{"name":"LOCK_WAIT_SECONDS","type":"float64"},{"name":"SAMPLE_LOCK_REQUESTS","type":"struct(COLUMN: string(max), LOCK_MODE: string(max), TRANSACTION_TAG: string(max))","array":true},{"name":"SAMPLE_LOCK_REQUESTS_JSON_STRING","type":"string(max)"}]} +{"schema":"SPANNER_SYS","name":"LOCK_STATS_TOP_MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"ROW_RANGE_START_KEY","type":"bytes(max)"},{"name":"LOCK_WAIT_SECONDS","type":"float64"},{"name":"SAMPLE_LOCK_REQUESTS","type":"struct(COLUMN: string(max), LOCK_MODE: string(max), TRANSACTION_TAG: string(max))","array":true},{"name":"SAMPLE_LOCK_REQUESTS_JSON_STRING","type":"string(max)"}]} +{"schema":"SPANNER_SYS","name":"LOCK_STATS_TOTAL_10MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"TOTAL_LOCK_WAIT_SECONDS","type":"float64"}]} +{"schema":"SPANNER_SYS","name":"LOCK_STATS_TOTAL_HOUR","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"TOTAL_LOCK_WAIT_SECONDS","type":"float64"}]} +{"schema":"SPANNER_SYS","name":"LOCK_STATS_TOTAL_MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"TOTAL_LOCK_WAIT_SECONDS","type":"float64"}]} +{"schema":"SPANNER_SYS","name":"OLDEST_ACTIVE_QUERIES","kind":"v","columns":[{"name":"START_TIME","type":"timestamp"},{"name":"TEXT_FINGERPRINT","type":"int64"},{"name":"TEXT","type":"string(max)"},{"name":"TEXT_TRUNCATED","type":"bool"},{"name":"SESSION_ID","type":"string(max)"},{"name":"QUERY_ID","type":"string(max)"},{"name":"CLIENT_IP_ADDRESS","type":"string(max)"},{"name":"API_CLIENT_HEADER","type":"string(max)"},{"name":"USER_AGENT_HEADER","type":"string(max)"},{"name":"SERVER_REGION","type":"string(max)"},{"name":"PRIORITY","type":"string(max)"},{"name":"TRANSACTION_TYPE","type":"string(max)"}]} +{"schema":"SPANNER_SYS","name":"QUERY_PROFILES_TOP_10MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"TEXT_FINGERPRINT","type":"int64"},{"name":"LATENCY_SECONDS","type":"float64"},{"name":"QUERY_PROFILE","type":"string(max)"}]} +{"schema":"SPANNER_SYS","name":"QUERY_PROFILES_TOP_HOUR","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"TEXT_FINGERPRINT","type":"int64"},{"name":"LATENCY_SECONDS","type":"float64"},{"name":"QUERY_PROFILE","type":"string(max)"}]} +{"schema":"SPANNER_SYS","name":"QUERY_PROFILES_TOP_MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"TEXT_FINGERPRINT","type":"int64"},{"name":"LATENCY_SECONDS","type":"float64"},{"name":"QUERY_PROFILE","type":"string(max)"}]} +{"schema":"SPANNER_SYS","name":"QUERY_RECOMMENDATIONS","kind":"v","columns":[{"name":"GENERATION_TIME","type":"timestamp"},{"name":"TEXT_FINGERPRINT","type":"int64"},{"name":"QUERY_RECOMMENDATIONS","type":"string(max)"}]} +{"schema":"SPANNER_SYS","name":"QUERY_STATS_TOP_10MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"TEXT","type":"string(max)"},{"name":"TEXT_TRUNCATED","type":"bool"},{"name":"TEXT_FINGERPRINT","type":"int64"},{"name":"EXECUTION_COUNT","type":"int64"},{"name":"AVG_LATENCY_SECONDS","type":"float64"},{"name":"AVG_ROWS","type":"float64"},{"name":"AVG_BYTES","type":"float64"},{"name":"AVG_ROWS_SCANNED","type":"float64"},{"name":"AVG_CPU_SECONDS","type":"float64"},{"name":"CANCELLED_OR_DISCONNECTED_EXECUTION_COUNT","type":"int64"},{"name":"TIMED_OUT_EXECUTION_COUNT","type":"int64"},{"name":"ALL_FAILED_EXECUTION_COUNT","type":"int64"},{"name":"ALL_FAILED_AVG_LATENCY_SECONDS","type":"float64"},{"name":"REQUEST_TAG","type":"string(max)"},{"name":"AVG_BYTES_WRITTEN","type":"float64"},{"name":"AVG_ROWS_WRITTEN","type":"float64"},{"name":"STATEMENT_COUNT","type":"int64"},{"name":"LATENCY_DISTRIBUTION","type":"struct(COUNT: int64, MEAN: float64, SUM_OF_SQUARED_DEVIATION: float64, NUM_FINITE_BUCKETS: int64, GROWTH_FACTOR: float64, SCALE: float64, BUCKET_COUNTS: int64[])","array":true},{"name":"RUN_IN_RW_TRANSACTION_EXECUTION_COUNT","type":"int64"},{"name":"QUERY_TYPE","type":"string(max)"},{"name":"AVG_MEMORY_PEAK_USAGE_BYTES","type":"float64"},{"name":"AVG_MEMORY_USAGE_PERCENTAGE","type":"float64"},{"name":"AVG_QUERY_PLAN_CREATION_TIME_SECS","type":"float64"},{"name":"AVG_FILESYSTEM_DELAY_SECS","type":"float64"},{"name":"AVG_REMOTE_SERVER_CALLS","type":"float64"},{"name":"AVG_ROWS_SPOOLED","type":"float64"},{"name":"AVG_DISK_IO_COST","type":"float64"},{"name":"LATENCY_DISTRIBUTION_JSON_STRING","type":"string(max)"},{"name":"AVG_COLUMNAR_READ_SHARE","type":"float64"},{"name":"QUERY_OPTIMIZER_VERSIONS","type":"int64","array":true},{"name":"STATISTICS_PACKAGE_NAMES","type":"string(max)","array":true}]} +{"schema":"SPANNER_SYS","name":"QUERY_STATS_TOP_HOUR","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"TEXT","type":"string(max)"},{"name":"TEXT_TRUNCATED","type":"bool"},{"name":"TEXT_FINGERPRINT","type":"int64"},{"name":"EXECUTION_COUNT","type":"int64"},{"name":"AVG_LATENCY_SECONDS","type":"float64"},{"name":"AVG_ROWS","type":"float64"},{"name":"AVG_BYTES","type":"float64"},{"name":"AVG_ROWS_SCANNED","type":"float64"},{"name":"AVG_CPU_SECONDS","type":"float64"},{"name":"CANCELLED_OR_DISCONNECTED_EXECUTION_COUNT","type":"int64"},{"name":"TIMED_OUT_EXECUTION_COUNT","type":"int64"},{"name":"ALL_FAILED_EXECUTION_COUNT","type":"int64"},{"name":"ALL_FAILED_AVG_LATENCY_SECONDS","type":"float64"},{"name":"REQUEST_TAG","type":"string(max)"},{"name":"AVG_BYTES_WRITTEN","type":"float64"},{"name":"AVG_ROWS_WRITTEN","type":"float64"},{"name":"STATEMENT_COUNT","type":"int64"},{"name":"LATENCY_DISTRIBUTION","type":"struct(COUNT: int64, MEAN: float64, SUM_OF_SQUARED_DEVIATION: float64, NUM_FINITE_BUCKETS: int64, GROWTH_FACTOR: float64, SCALE: float64, BUCKET_COUNTS: int64[])","array":true},{"name":"RUN_IN_RW_TRANSACTION_EXECUTION_COUNT","type":"int64"},{"name":"QUERY_TYPE","type":"string(max)"},{"name":"AVG_MEMORY_PEAK_USAGE_BYTES","type":"float64"},{"name":"AVG_MEMORY_USAGE_PERCENTAGE","type":"float64"},{"name":"AVG_QUERY_PLAN_CREATION_TIME_SECS","type":"float64"},{"name":"AVG_FILESYSTEM_DELAY_SECS","type":"float64"},{"name":"AVG_REMOTE_SERVER_CALLS","type":"float64"},{"name":"AVG_ROWS_SPOOLED","type":"float64"},{"name":"AVG_DISK_IO_COST","type":"float64"},{"name":"LATENCY_DISTRIBUTION_JSON_STRING","type":"string(max)"},{"name":"AVG_COLUMNAR_READ_SHARE","type":"float64"},{"name":"QUERY_OPTIMIZER_VERSIONS","type":"int64","array":true},{"name":"STATISTICS_PACKAGE_NAMES","type":"string(max)","array":true}]} +{"schema":"SPANNER_SYS","name":"QUERY_STATS_TOP_MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"TEXT","type":"string(max)"},{"name":"TEXT_TRUNCATED","type":"bool"},{"name":"TEXT_FINGERPRINT","type":"int64"},{"name":"EXECUTION_COUNT","type":"int64"},{"name":"AVG_LATENCY_SECONDS","type":"float64"},{"name":"AVG_ROWS","type":"float64"},{"name":"AVG_BYTES","type":"float64"},{"name":"AVG_ROWS_SCANNED","type":"float64"},{"name":"AVG_CPU_SECONDS","type":"float64"},{"name":"CANCELLED_OR_DISCONNECTED_EXECUTION_COUNT","type":"int64"},{"name":"TIMED_OUT_EXECUTION_COUNT","type":"int64"},{"name":"ALL_FAILED_EXECUTION_COUNT","type":"int64"},{"name":"ALL_FAILED_AVG_LATENCY_SECONDS","type":"float64"},{"name":"REQUEST_TAG","type":"string(max)"},{"name":"AVG_BYTES_WRITTEN","type":"float64"},{"name":"AVG_ROWS_WRITTEN","type":"float64"},{"name":"STATEMENT_COUNT","type":"int64"},{"name":"LATENCY_DISTRIBUTION","type":"struct(COUNT: int64, MEAN: float64, SUM_OF_SQUARED_DEVIATION: float64, NUM_FINITE_BUCKETS: int64, GROWTH_FACTOR: float64, SCALE: float64, BUCKET_COUNTS: int64[])","array":true},{"name":"RUN_IN_RW_TRANSACTION_EXECUTION_COUNT","type":"int64"},{"name":"QUERY_TYPE","type":"string(max)"},{"name":"AVG_MEMORY_PEAK_USAGE_BYTES","type":"float64"},{"name":"AVG_MEMORY_USAGE_PERCENTAGE","type":"float64"},{"name":"AVG_QUERY_PLAN_CREATION_TIME_SECS","type":"float64"},{"name":"AVG_FILESYSTEM_DELAY_SECS","type":"float64"},{"name":"AVG_REMOTE_SERVER_CALLS","type":"float64"},{"name":"AVG_ROWS_SPOOLED","type":"float64"},{"name":"AVG_DISK_IO_COST","type":"float64"},{"name":"LATENCY_DISTRIBUTION_JSON_STRING","type":"string(max)"},{"name":"AVG_COLUMNAR_READ_SHARE","type":"float64"},{"name":"QUERY_OPTIMIZER_VERSIONS","type":"int64","array":true},{"name":"STATISTICS_PACKAGE_NAMES","type":"string(max)","array":true}]} +{"schema":"SPANNER_SYS","name":"QUERY_STATS_TOTAL_10MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"EXECUTION_COUNT","type":"int64"},{"name":"AVG_LATENCY_SECONDS","type":"float64"},{"name":"AVG_ROWS","type":"float64"},{"name":"AVG_BYTES","type":"float64"},{"name":"AVG_ROWS_SCANNED","type":"float64"},{"name":"AVG_CPU_SECONDS","type":"float64"},{"name":"CANCELLED_OR_DISCONNECTED_EXECUTION_COUNT","type":"int64"},{"name":"TIMED_OUT_EXECUTION_COUNT","type":"int64"},{"name":"ALL_FAILED_EXECUTION_COUNT","type":"int64"},{"name":"ALL_FAILED_AVG_LATENCY_SECONDS","type":"float64"},{"name":"AVG_BYTES_WRITTEN","type":"float64"},{"name":"AVG_ROWS_WRITTEN","type":"float64"},{"name":"LATENCY_DISTRIBUTION","type":"struct(COUNT: int64, MEAN: float64, SUM_OF_SQUARED_DEVIATION: float64, NUM_FINITE_BUCKETS: int64, GROWTH_FACTOR: float64, SCALE: float64, BUCKET_COUNTS: int64[])","array":true},{"name":"RUN_IN_RW_TRANSACTION_EXECUTION_COUNT","type":"int64"},{"name":"AVG_MEMORY_PEAK_USAGE_BYTES","type":"float64"},{"name":"AVG_MEMORY_USAGE_PERCENTAGE","type":"float64"},{"name":"AVG_QUERY_PLAN_CREATION_TIME_SECS","type":"float64"},{"name":"AVG_FILESYSTEM_DELAY_SECS","type":"float64"},{"name":"AVG_REMOTE_SERVER_CALLS","type":"float64"},{"name":"AVG_ROWS_SPOOLED","type":"float64"},{"name":"AVG_DISK_IO_COST","type":"float64"},{"name":"LATENCY_DISTRIBUTION_JSON_STRING","type":"string(max)"},{"name":"AVG_COLUMNAR_READ_SHARE","type":"float64"}]} +{"schema":"SPANNER_SYS","name":"QUERY_STATS_TOTAL_HOUR","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"EXECUTION_COUNT","type":"int64"},{"name":"AVG_LATENCY_SECONDS","type":"float64"},{"name":"AVG_ROWS","type":"float64"},{"name":"AVG_BYTES","type":"float64"},{"name":"AVG_ROWS_SCANNED","type":"float64"},{"name":"AVG_CPU_SECONDS","type":"float64"},{"name":"CANCELLED_OR_DISCONNECTED_EXECUTION_COUNT","type":"int64"},{"name":"TIMED_OUT_EXECUTION_COUNT","type":"int64"},{"name":"ALL_FAILED_EXECUTION_COUNT","type":"int64"},{"name":"ALL_FAILED_AVG_LATENCY_SECONDS","type":"float64"},{"name":"AVG_BYTES_WRITTEN","type":"float64"},{"name":"AVG_ROWS_WRITTEN","type":"float64"},{"name":"LATENCY_DISTRIBUTION","type":"struct(COUNT: int64, MEAN: float64, SUM_OF_SQUARED_DEVIATION: float64, NUM_FINITE_BUCKETS: int64, GROWTH_FACTOR: float64, SCALE: float64, BUCKET_COUNTS: int64[])","array":true},{"name":"RUN_IN_RW_TRANSACTION_EXECUTION_COUNT","type":"int64"},{"name":"AVG_MEMORY_PEAK_USAGE_BYTES","type":"float64"},{"name":"AVG_MEMORY_USAGE_PERCENTAGE","type":"float64"},{"name":"AVG_QUERY_PLAN_CREATION_TIME_SECS","type":"float64"},{"name":"AVG_FILESYSTEM_DELAY_SECS","type":"float64"},{"name":"AVG_REMOTE_SERVER_CALLS","type":"float64"},{"name":"AVG_ROWS_SPOOLED","type":"float64"},{"name":"AVG_DISK_IO_COST","type":"float64"},{"name":"LATENCY_DISTRIBUTION_JSON_STRING","type":"string(max)"},{"name":"AVG_COLUMNAR_READ_SHARE","type":"float64"}]} +{"schema":"SPANNER_SYS","name":"QUERY_STATS_TOTAL_MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"EXECUTION_COUNT","type":"int64"},{"name":"AVG_LATENCY_SECONDS","type":"float64"},{"name":"AVG_ROWS","type":"float64"},{"name":"AVG_BYTES","type":"float64"},{"name":"AVG_ROWS_SCANNED","type":"float64"},{"name":"AVG_CPU_SECONDS","type":"float64"},{"name":"CANCELLED_OR_DISCONNECTED_EXECUTION_COUNT","type":"int64"},{"name":"TIMED_OUT_EXECUTION_COUNT","type":"int64"},{"name":"ALL_FAILED_EXECUTION_COUNT","type":"int64"},{"name":"ALL_FAILED_AVG_LATENCY_SECONDS","type":"float64"},{"name":"AVG_BYTES_WRITTEN","type":"float64"},{"name":"AVG_ROWS_WRITTEN","type":"float64"},{"name":"LATENCY_DISTRIBUTION","type":"struct(COUNT: int64, MEAN: float64, SUM_OF_SQUARED_DEVIATION: float64, NUM_FINITE_BUCKETS: int64, GROWTH_FACTOR: float64, SCALE: float64, BUCKET_COUNTS: int64[])","array":true},{"name":"RUN_IN_RW_TRANSACTION_EXECUTION_COUNT","type":"int64"},{"name":"AVG_MEMORY_PEAK_USAGE_BYTES","type":"float64"},{"name":"AVG_MEMORY_USAGE_PERCENTAGE","type":"float64"},{"name":"AVG_QUERY_PLAN_CREATION_TIME_SECS","type":"float64"},{"name":"AVG_FILESYSTEM_DELAY_SECS","type":"float64"},{"name":"AVG_REMOTE_SERVER_CALLS","type":"float64"},{"name":"AVG_ROWS_SPOOLED","type":"float64"},{"name":"AVG_DISK_IO_COST","type":"float64"},{"name":"LATENCY_DISTRIBUTION_JSON_STRING","type":"string(max)"},{"name":"AVG_COLUMNAR_READ_SHARE","type":"float64"}]} +{"schema":"SPANNER_SYS","name":"READ_STATS_TOP_10MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"READ_COLUMNS","type":"string(max)","array":true},{"name":"FPRINT","type":"int64"},{"name":"EXECUTION_COUNT","type":"int64"},{"name":"AVG_ROWS","type":"float64"},{"name":"AVG_BYTES","type":"float64"},{"name":"AVG_CPU_SECONDS","type":"float64"},{"name":"AVG_LOCKING_DELAY_SECONDS","type":"float64"},{"name":"AVG_CLIENT_WAIT_SECONDS","type":"float64"},{"name":"AVG_LEADER_REFRESH_DELAY_SECONDS","type":"float64"},{"name":"REQUEST_TAG","type":"string(max)"},{"name":"RUN_IN_RW_TRANSACTION_EXECUTION_COUNT","type":"int64"},{"name":"READ_TYPE","type":"string(max)"},{"name":"AVG_DISK_IO_COST","type":"float64"}]} +{"schema":"SPANNER_SYS","name":"READ_STATS_TOP_HOUR","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"READ_COLUMNS","type":"string(max)","array":true},{"name":"FPRINT","type":"int64"},{"name":"EXECUTION_COUNT","type":"int64"},{"name":"AVG_ROWS","type":"float64"},{"name":"AVG_BYTES","type":"float64"},{"name":"AVG_CPU_SECONDS","type":"float64"},{"name":"AVG_LOCKING_DELAY_SECONDS","type":"float64"},{"name":"AVG_CLIENT_WAIT_SECONDS","type":"float64"},{"name":"AVG_LEADER_REFRESH_DELAY_SECONDS","type":"float64"},{"name":"REQUEST_TAG","type":"string(max)"},{"name":"RUN_IN_RW_TRANSACTION_EXECUTION_COUNT","type":"int64"},{"name":"READ_TYPE","type":"string(max)"},{"name":"AVG_DISK_IO_COST","type":"float64"}]} +{"schema":"SPANNER_SYS","name":"READ_STATS_TOP_MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"READ_COLUMNS","type":"string(max)","array":true},{"name":"FPRINT","type":"int64"},{"name":"EXECUTION_COUNT","type":"int64"},{"name":"AVG_ROWS","type":"float64"},{"name":"AVG_BYTES","type":"float64"},{"name":"AVG_CPU_SECONDS","type":"float64"},{"name":"AVG_LOCKING_DELAY_SECONDS","type":"float64"},{"name":"AVG_CLIENT_WAIT_SECONDS","type":"float64"},{"name":"AVG_LEADER_REFRESH_DELAY_SECONDS","type":"float64"},{"name":"REQUEST_TAG","type":"string(max)"},{"name":"RUN_IN_RW_TRANSACTION_EXECUTION_COUNT","type":"int64"},{"name":"READ_TYPE","type":"string(max)"},{"name":"AVG_DISK_IO_COST","type":"float64"}]} +{"schema":"SPANNER_SYS","name":"READ_STATS_TOTAL_10MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"EXECUTION_COUNT","type":"int64"},{"name":"AVG_ROWS","type":"float64"},{"name":"AVG_BYTES","type":"float64"},{"name":"AVG_CPU_SECONDS","type":"float64"},{"name":"AVG_LOCKING_DELAY_SECONDS","type":"float64"},{"name":"AVG_CLIENT_WAIT_SECONDS","type":"float64"},{"name":"AVG_LEADER_REFRESH_DELAY_SECONDS","type":"float64"},{"name":"RUN_IN_RW_TRANSACTION_EXECUTION_COUNT","type":"int64"},{"name":"AVG_DISK_IO_COST","type":"float64"}]} +{"schema":"SPANNER_SYS","name":"READ_STATS_TOTAL_HOUR","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"EXECUTION_COUNT","type":"int64"},{"name":"AVG_ROWS","type":"float64"},{"name":"AVG_BYTES","type":"float64"},{"name":"AVG_CPU_SECONDS","type":"float64"},{"name":"AVG_LOCKING_DELAY_SECONDS","type":"float64"},{"name":"AVG_CLIENT_WAIT_SECONDS","type":"float64"},{"name":"AVG_LEADER_REFRESH_DELAY_SECONDS","type":"float64"},{"name":"RUN_IN_RW_TRANSACTION_EXECUTION_COUNT","type":"int64"},{"name":"AVG_DISK_IO_COST","type":"float64"}]} +{"schema":"SPANNER_SYS","name":"READ_STATS_TOTAL_MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"EXECUTION_COUNT","type":"int64"},{"name":"AVG_ROWS","type":"float64"},{"name":"AVG_BYTES","type":"float64"},{"name":"AVG_CPU_SECONDS","type":"float64"},{"name":"AVG_LOCKING_DELAY_SECONDS","type":"float64"},{"name":"AVG_CLIENT_WAIT_SECONDS","type":"float64"},{"name":"AVG_LEADER_REFRESH_DELAY_SECONDS","type":"float64"},{"name":"RUN_IN_RW_TRANSACTION_EXECUTION_COUNT","type":"int64"},{"name":"AVG_DISK_IO_COST","type":"float64"}]} +{"schema":"SPANNER_SYS","name":"ROW_DELETION_POLICIES","kind":"v","columns":[{"name":"TABLE_NAME","type":"string(max)","not_null":true},{"name":"PROCESSED_WATERMARK","type":"timestamp"},{"name":"UNDELETABLE_ROWS","type":"int64","not_null":true},{"name":"MIN_UNDELETABLE_TIMESTAMP","type":"timestamp"}]} +{"schema":"SPANNER_SYS","name":"SCHEMA_RECOMMENDATIONS","kind":"v","columns":[{"name":"GENERATION_TIME","type":"timestamp"},{"name":"FINGERPRINT","type":"string(max)"},{"name":"SCHEMA_RECOMMENDATIONS","type":"string(max)"}]} +{"schema":"SPANNER_SYS","name":"SPLIT_HOTNESS_STATS_TOP_MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"SPLIT_START","type":"string(max)"},{"name":"SPLIT_LIMIT","type":"string(max)"},{"name":"AFFECTED_TABLES","type":"string(max)","array":true},{"name":"HOTNESS","type":"int64"}]} +{"schema":"SPANNER_SYS","name":"SPLIT_STATS_TOP_10MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"SPLIT_START","type":"string(max)"},{"name":"SPLIT_LIMIT","type":"string(max)"},{"name":"AFFECTED_TABLES","type":"string(max)","array":true},{"name":"CPU_USAGE_SCORE","type":"int64"},{"name":"UNSPLITTABLE_REASONS","type":"string(max)","array":true}]} +{"schema":"SPANNER_SYS","name":"SPLIT_STATS_TOP_HOUR","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"SPLIT_START","type":"string(max)"},{"name":"SPLIT_LIMIT","type":"string(max)"},{"name":"AFFECTED_TABLES","type":"string(max)","array":true},{"name":"CPU_USAGE_SCORE","type":"int64"},{"name":"UNSPLITTABLE_REASONS","type":"string(max)","array":true}]} +{"schema":"SPANNER_SYS","name":"SPLIT_STATS_TOP_MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"SPLIT_START","type":"string(max)"},{"name":"SPLIT_LIMIT","type":"string(max)"},{"name":"AFFECTED_TABLES","type":"string(max)","array":true},{"name":"CPU_USAGE_SCORE","type":"int64"},{"name":"UNSPLITTABLE_REASONS","type":"string(max)","array":true}]} +{"schema":"SPANNER_SYS","name":"SUPPORTED_OPTIMIZER_VERSIONS","kind":"v","columns":[{"name":"VERSION","type":"int64","not_null":true},{"name":"RELEASE_DATE","type":"date","not_null":true},{"name":"IS_DEFAULT","type":"bool","not_null":true}]} +{"schema":"SPANNER_SYS","name":"TABLE_OPERATIONS_STATS_10MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"TABLE_NAME","type":"string(max)"},{"name":"READ_QUERY_COUNT","type":"int64"},{"name":"WRITE_COUNT","type":"int64"},{"name":"DELETE_COUNT","type":"int64"}]} +{"schema":"SPANNER_SYS","name":"TABLE_OPERATIONS_STATS_HOUR","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"TABLE_NAME","type":"string(max)"},{"name":"READ_QUERY_COUNT","type":"int64"},{"name":"WRITE_COUNT","type":"int64"},{"name":"DELETE_COUNT","type":"int64"}]} +{"schema":"SPANNER_SYS","name":"TABLE_OPERATIONS_STATS_MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"TABLE_NAME","type":"string(max)"},{"name":"READ_QUERY_COUNT","type":"int64"},{"name":"WRITE_COUNT","type":"int64"},{"name":"DELETE_COUNT","type":"int64"}]} +{"schema":"SPANNER_SYS","name":"TABLE_SIZES_STATS_1HOUR","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"TABLE_NAME","type":"string(max)"},{"name":"USED_BYTES","type":"float64"},{"name":"USED_SSD_BYTES","type":"float64"},{"name":"USED_HDD_BYTES","type":"float64"},{"name":"COLUMNAR_USED_BYTES","type":"float64"},{"name":"COLUMNAR_USED_SSD_BYTES","type":"float64"},{"name":"COLUMNAR_USED_HDD_BYTES","type":"float64"},{"name":"COLUMNAR_COVERAGE_RATIO","type":"float64"},{"name":"COLUMNAR_SSD_COVERAGE_RATIO","type":"float64"},{"name":"COLUMNAR_HDD_COVERAGE_RATIO","type":"float64"}]} +{"schema":"SPANNER_SYS","name":"TABLE_SIZES_STATS_PER_LOCALITY_GROUP_1HOUR","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"TABLE_NAME","type":"string(max)"},{"name":"LOCALITY_GROUP","type":"string(max)"},{"name":"USED_SSD_BYTES","type":"float64"},{"name":"USED_HDD_BYTES","type":"float64"}]} +{"schema":"SPANNER_SYS","name":"TASKS","kind":"v","columns":[{"name":"TASK_NAME","type":"string(max)","not_null":true},{"name":"PROCESSED_WATERMARK","type":"timestamp"},{"name":"LAST_RUN_STATUS","type":"string(max)"},{"name":"UNDELETABLE_ROWS","type":"int64","not_null":true}]} +{"schema":"SPANNER_SYS","name":"TXN_STATS_TOP_10MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"FPRINT","type":"int64"},{"name":"READ_COLUMNS","type":"string(max)","array":true},{"name":"WRITE_CONSTRUCTIVE_COLUMNS","type":"string(max)","array":true},{"name":"WRITE_DELETE_TABLES","type":"string(max)","array":true},{"name":"COMMIT_ATTEMPT_COUNT","type":"int64"},{"name":"COMMIT_FAILED_PRECONDITION_COUNT","type":"int64"},{"name":"COMMIT_ABORT_COUNT","type":"int64"},{"name":"AVG_PARTICIPANTS","type":"float64"},{"name":"AVG_TOTAL_LATENCY_SECONDS","type":"float64"},{"name":"AVG_COMMIT_LATENCY_SECONDS","type":"float64"},{"name":"AVG_BYTES","type":"float64"},{"name":"COMMIT_RETRY_COUNT","type":"int64"},{"name":"TRANSACTION_TAG","type":"string(max)"},{"name":"OPERATIONS_BY_TABLE","type":"struct(TABLE_NAME: string(max), INSERT_OR_UPDATE_COUNT: int64, INSERT_OR_UPDATE_BYTES: int64)","array":true},{"name":"TOTAL_LATENCY_DISTRIBUTION","type":"struct(COUNT: int64, MEAN: float64, SUM_OF_SQUARED_DEVIATION: float64, NUM_FINITE_BUCKETS: int64, GROWTH_FACTOR: float64, SCALE: float64, BUCKET_COUNTS: int64[])","array":true},{"name":"ATTEMPT_COUNT","type":"int64"},{"name":"SERIALIZABLE_PESSIMISTIC_TXN_COUNT","type":"int64"},{"name":"REPEATABLE_READ_OPTIMISTIC_TXN_COUNT","type":"int64"},{"name":"OPERATIONS_BY_TABLE_JSON_STRING","type":"string(max)"},{"name":"TOTAL_LATENCY_DISTRIBUTION_JSON_STRING","type":"string(max)"},{"name":"SERIALIZABLE_OPTIMISTIC_TXN_COUNT","type":"int64"},{"name":"REPEATABLE_READ_PESSIMISTIC_TXN_COUNT","type":"int64"}]} +{"schema":"SPANNER_SYS","name":"TXN_STATS_TOP_HOUR","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"FPRINT","type":"int64"},{"name":"READ_COLUMNS","type":"string(max)","array":true},{"name":"WRITE_CONSTRUCTIVE_COLUMNS","type":"string(max)","array":true},{"name":"WRITE_DELETE_TABLES","type":"string(max)","array":true},{"name":"COMMIT_ATTEMPT_COUNT","type":"int64"},{"name":"COMMIT_FAILED_PRECONDITION_COUNT","type":"int64"},{"name":"COMMIT_ABORT_COUNT","type":"int64"},{"name":"AVG_PARTICIPANTS","type":"float64"},{"name":"AVG_TOTAL_LATENCY_SECONDS","type":"float64"},{"name":"AVG_COMMIT_LATENCY_SECONDS","type":"float64"},{"name":"AVG_BYTES","type":"float64"},{"name":"COMMIT_RETRY_COUNT","type":"int64"},{"name":"TRANSACTION_TAG","type":"string(max)"},{"name":"OPERATIONS_BY_TABLE","type":"struct(TABLE_NAME: string(max), INSERT_OR_UPDATE_COUNT: int64, INSERT_OR_UPDATE_BYTES: int64)","array":true},{"name":"TOTAL_LATENCY_DISTRIBUTION","type":"struct(COUNT: int64, MEAN: float64, SUM_OF_SQUARED_DEVIATION: float64, NUM_FINITE_BUCKETS: int64, GROWTH_FACTOR: float64, SCALE: float64, BUCKET_COUNTS: int64[])","array":true},{"name":"ATTEMPT_COUNT","type":"int64"},{"name":"SERIALIZABLE_PESSIMISTIC_TXN_COUNT","type":"int64"},{"name":"REPEATABLE_READ_OPTIMISTIC_TXN_COUNT","type":"int64"},{"name":"OPERATIONS_BY_TABLE_JSON_STRING","type":"string(max)"},{"name":"TOTAL_LATENCY_DISTRIBUTION_JSON_STRING","type":"string(max)"},{"name":"SERIALIZABLE_OPTIMISTIC_TXN_COUNT","type":"int64"},{"name":"REPEATABLE_READ_PESSIMISTIC_TXN_COUNT","type":"int64"}]} +{"schema":"SPANNER_SYS","name":"TXN_STATS_TOP_MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"FPRINT","type":"int64"},{"name":"READ_COLUMNS","type":"string(max)","array":true},{"name":"WRITE_CONSTRUCTIVE_COLUMNS","type":"string(max)","array":true},{"name":"WRITE_DELETE_TABLES","type":"string(max)","array":true},{"name":"COMMIT_ATTEMPT_COUNT","type":"int64"},{"name":"COMMIT_FAILED_PRECONDITION_COUNT","type":"int64"},{"name":"COMMIT_ABORT_COUNT","type":"int64"},{"name":"AVG_PARTICIPANTS","type":"float64"},{"name":"AVG_TOTAL_LATENCY_SECONDS","type":"float64"},{"name":"AVG_COMMIT_LATENCY_SECONDS","type":"float64"},{"name":"AVG_BYTES","type":"float64"},{"name":"COMMIT_RETRY_COUNT","type":"int64"},{"name":"TRANSACTION_TAG","type":"string(max)"},{"name":"OPERATIONS_BY_TABLE","type":"struct(TABLE_NAME: string(max), INSERT_OR_UPDATE_COUNT: int64, INSERT_OR_UPDATE_BYTES: int64)","array":true},{"name":"TOTAL_LATENCY_DISTRIBUTION","type":"struct(COUNT: int64, MEAN: float64, SUM_OF_SQUARED_DEVIATION: float64, NUM_FINITE_BUCKETS: int64, GROWTH_FACTOR: float64, SCALE: float64, BUCKET_COUNTS: int64[])","array":true},{"name":"ATTEMPT_COUNT","type":"int64"},{"name":"SERIALIZABLE_PESSIMISTIC_TXN_COUNT","type":"int64"},{"name":"REPEATABLE_READ_OPTIMISTIC_TXN_COUNT","type":"int64"},{"name":"OPERATIONS_BY_TABLE_JSON_STRING","type":"string(max)"},{"name":"TOTAL_LATENCY_DISTRIBUTION_JSON_STRING","type":"string(max)"},{"name":"SERIALIZABLE_OPTIMISTIC_TXN_COUNT","type":"int64"},{"name":"REPEATABLE_READ_PESSIMISTIC_TXN_COUNT","type":"int64"}]} +{"schema":"SPANNER_SYS","name":"TXN_STATS_TOTAL_10MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"COMMIT_ATTEMPT_COUNT","type":"int64"},{"name":"COMMIT_FAILED_PRECONDITION_COUNT","type":"int64"},{"name":"COMMIT_ABORT_COUNT","type":"int64"},{"name":"AVG_PARTICIPANTS","type":"float64"},{"name":"AVG_TOTAL_LATENCY_SECONDS","type":"float64"},{"name":"AVG_COMMIT_LATENCY_SECONDS","type":"float64"},{"name":"AVG_BYTES","type":"float64"},{"name":"COMMIT_RETRY_COUNT","type":"int64"},{"name":"OPERATIONS_BY_TABLE","type":"struct(TABLE_NAME: string(max), INSERT_OR_UPDATE_COUNT: int64, INSERT_OR_UPDATE_BYTES: int64)","array":true},{"name":"TOTAL_LATENCY_DISTRIBUTION","type":"struct(COUNT: int64, MEAN: float64, SUM_OF_SQUARED_DEVIATION: float64, NUM_FINITE_BUCKETS: int64, GROWTH_FACTOR: float64, SCALE: float64, BUCKET_COUNTS: int64[])","array":true},{"name":"ATTEMPT_COUNT","type":"int64"},{"name":"SERIALIZABLE_PESSIMISTIC_TXN_COUNT","type":"int64"},{"name":"REPEATABLE_READ_OPTIMISTIC_TXN_COUNT","type":"int64"},{"name":"OPERATIONS_BY_TABLE_JSON_STRING","type":"string(max)"},{"name":"TOTAL_LATENCY_DISTRIBUTION_JSON_STRING","type":"string(max)"},{"name":"SERIALIZABLE_OPTIMISTIC_TXN_COUNT","type":"int64"},{"name":"REPEATABLE_READ_PESSIMISTIC_TXN_COUNT","type":"int64"}]} +{"schema":"SPANNER_SYS","name":"TXN_STATS_TOTAL_HOUR","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"COMMIT_ATTEMPT_COUNT","type":"int64"},{"name":"COMMIT_FAILED_PRECONDITION_COUNT","type":"int64"},{"name":"COMMIT_ABORT_COUNT","type":"int64"},{"name":"AVG_PARTICIPANTS","type":"float64"},{"name":"AVG_TOTAL_LATENCY_SECONDS","type":"float64"},{"name":"AVG_COMMIT_LATENCY_SECONDS","type":"float64"},{"name":"AVG_BYTES","type":"float64"},{"name":"COMMIT_RETRY_COUNT","type":"int64"},{"name":"OPERATIONS_BY_TABLE","type":"struct(TABLE_NAME: string(max), INSERT_OR_UPDATE_COUNT: int64, INSERT_OR_UPDATE_BYTES: int64)","array":true},{"name":"TOTAL_LATENCY_DISTRIBUTION","type":"struct(COUNT: int64, MEAN: float64, SUM_OF_SQUARED_DEVIATION: float64, NUM_FINITE_BUCKETS: int64, GROWTH_FACTOR: float64, SCALE: float64, BUCKET_COUNTS: int64[])","array":true},{"name":"ATTEMPT_COUNT","type":"int64"},{"name":"SERIALIZABLE_PESSIMISTIC_TXN_COUNT","type":"int64"},{"name":"REPEATABLE_READ_OPTIMISTIC_TXN_COUNT","type":"int64"},{"name":"OPERATIONS_BY_TABLE_JSON_STRING","type":"string(max)"},{"name":"TOTAL_LATENCY_DISTRIBUTION_JSON_STRING","type":"string(max)"},{"name":"SERIALIZABLE_OPTIMISTIC_TXN_COUNT","type":"int64"},{"name":"REPEATABLE_READ_PESSIMISTIC_TXN_COUNT","type":"int64"}]} +{"schema":"SPANNER_SYS","name":"TXN_STATS_TOTAL_MINUTE","kind":"v","columns":[{"name":"INTERVAL_END","type":"timestamp"},{"name":"COMMIT_ATTEMPT_COUNT","type":"int64"},{"name":"COMMIT_FAILED_PRECONDITION_COUNT","type":"int64"},{"name":"COMMIT_ABORT_COUNT","type":"int64"},{"name":"AVG_PARTICIPANTS","type":"float64"},{"name":"AVG_TOTAL_LATENCY_SECONDS","type":"float64"},{"name":"AVG_COMMIT_LATENCY_SECONDS","type":"float64"},{"name":"AVG_BYTES","type":"float64"},{"name":"COMMIT_RETRY_COUNT","type":"int64"},{"name":"OPERATIONS_BY_TABLE","type":"struct(TABLE_NAME: string(max), INSERT_OR_UPDATE_COUNT: int64, INSERT_OR_UPDATE_BYTES: int64)","array":true},{"name":"TOTAL_LATENCY_DISTRIBUTION","type":"struct(COUNT: int64, MEAN: float64, SUM_OF_SQUARED_DEVIATION: float64, NUM_FINITE_BUCKETS: int64, GROWTH_FACTOR: float64, SCALE: float64, BUCKET_COUNTS: int64[])","array":true},{"name":"ATTEMPT_COUNT","type":"int64"},{"name":"SERIALIZABLE_PESSIMISTIC_TXN_COUNT","type":"int64"},{"name":"REPEATABLE_READ_OPTIMISTIC_TXN_COUNT","type":"int64"},{"name":"OPERATIONS_BY_TABLE_JSON_STRING","type":"string(max)"},{"name":"TOTAL_LATENCY_DISTRIBUTION_JSON_STRING","type":"string(max)"},{"name":"SERIALIZABLE_OPTIMISTIC_TXN_COUNT","type":"int64"},{"name":"REPEATABLE_READ_PESSIMISTIC_TXN_COUNT","type":"int64"}]} +{"schema":"SPANNER_SYS","name":"USER_SPLIT_POINTS","kind":"v","columns":[{"name":"TABLE_NAME","type":"string(max)"},{"name":"INDEX_NAME","type":"string(max)"},{"name":"INITIATOR","type":"string(max)"},{"name":"SPLIT_KEY","type":"string(max)"},{"name":"EXPIRE_TIME","type":"timestamp"}]} +{"schema":"SPANNER_SYS","name":"VECTOR_INDEX_METRICS_HISTORY","kind":"v","columns":[{"name":"VECTOR_INDEX_NAME","type":"string(max)"},{"name":"START_TIME","type":"timestamp"},{"name":"COMPLETION_TIME","type":"timestamp"},{"name":"ROWS_SCANNED","type":"int64"},{"name":"CLUSTERS_SAMPLED","type":"int64"},{"name":"ZERO_SIZE_CLUSTERS_SAMPLED","type":"int64"},{"name":"MIN_CLUSTER_SIZE","type":"int64"},{"name":"MAX_CLUSTER_SIZE","type":"int64"},{"name":"CLUSTER_SIZE_PERCENTILES","type":"struct(percentile: int64, value_at_percentile: int64)","array":true},{"name":"CLUSTER_AVERAGE_DISTANCE_TO_CENTROID_PERCENTILES","type":"struct(percentile: int64, value_at_percentile: float64)","array":true},{"name":"NUM_LEAVES","type":"int64"},{"name":"NUM_BRANCHES","type":"int64"}]} diff --git a/internal/engine/googlesql/dialect/types.jsonl b/internal/engine/googlesql/dialect/types.jsonl new file mode 100644 index 0000000..8c6dac4 --- /dev/null +++ b/internal/engine/googlesql/dialect/types.jsonl @@ -0,0 +1,23 @@ +{"name": "bool", "category": "B"} +{"name": "int64", "category": "N"} +{"name": "float32", "category": "N"} +{"name": "float64", "category": "N"} +{"name": "numeric", "category": "N"} +{"name": "bignumeric", "category": "N"} +{"name": "string", "category": "S"} +{"name": "bytes", "category": "S"} +{"name": "uuid", "category": "S"} +{"name": "date", "category": "D"} +{"name": "datetime", "category": "D"} +{"name": "time", "category": "D"} +{"name": "timestamp", "category": "D"} +{"name": "interval", "category": "T"} +{"name": "json", "category": "U"} +{"name": "geography", "category": "U"} +{"name": "struct", "category": "U"} +{"name": "enum", "category": "U"} +{"name": "proto", "category": "U"} +{"name": "tokenlist", "category": "U"} +{"name": "array", "category": "A"} +{"name": "range", "category": "U"} +{"name": "map", "category": "U"} diff --git a/internal/engine/googlesql/parse.go b/internal/engine/googlesql/parse.go new file mode 100644 index 0000000..87967c0 --- /dev/null +++ b/internal/engine/googlesql/parse.go @@ -0,0 +1,70 @@ +package googlesql + +import ( + "bytes" + "context" + "io" + + "github.com/sqlc-dev/zetajones/parser" + + "github.com/sqlc-dev/sqlc/internal/source" + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +func NewParser() *Parser { + return &Parser{} +} + +type Parser struct{} + +func (p *Parser) Parse(r io.Reader) ([]ast.Statement, error) { + blob, err := io.ReadAll(r) + if err != nil { + return nil, err + } + + ctx := context.Background() + stmtNodes, err := parser.Parse(ctx, bytes.NewReader(blob)) + if err != nil { + return nil, err + } + + // zetajones node locations are byte offsets into the input. Following the + // convention used by the other engines, a statement's location starts at the + // end of the previous statement (or the start of the input) so that any + // leading comment — in particular the "-- name:" annotation sqlc relies on — + // is captured as part of the statement. + var stmts []ast.Statement + loc := 0 + for _, stmt := range stmtNodes { + converter := &cc{} + out := converter.convert(stmt) + if _, ok := out.(*ast.TODO); ok { + // Skip over the unsupported statement (and its trailing semicolon) + // so the next statement's leading comment is measured from here. + loc = stmt.End() + 1 + continue + } + + end := stmt.End() + stmts = append(stmts, ast.Statement{ + Raw: &ast.RawStmt{ + Stmt: out, + StmtLocation: loc, + StmtLen: end - loc, + }, + }) + loc = end + 1 + } + + return stmts, nil +} + +// https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#comments +func (p *Parser) CommentSyntax() source.CommentSyntax { + return source.CommentSyntax{ + Dash: true, // -- comment + SlashStar: true, // /* comment */ + Hash: true, // # comment + } +} diff --git a/internal/engine/googlesql/reserved.go b/internal/engine/googlesql/reserved.go new file mode 100644 index 0000000..14db130 --- /dev/null +++ b/internal/engine/googlesql/reserved.go @@ -0,0 +1,11 @@ +package googlesql + +import ( + "github.com/sqlc-dev/zetajones/token" +) + +// IsReservedKeyword reports whether s is a reserved keyword in GoogleSQL; see +// https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#reserved_keywords +func (p *Parser) IsReservedKeyword(s string) bool { + return token.IsReservedKeyword(s) +} diff --git a/internal/engine/googlesql/seed.go b/internal/engine/googlesql/seed.go new file mode 100644 index 0000000..11c85dd --- /dev/null +++ b/internal/engine/googlesql/seed.go @@ -0,0 +1,16 @@ +package googlesql + +import ( + "embed" + + "github.com/sqlc-dev/sqlc/internal/core" + "github.com/sqlc-dev/sqlc/internal/core/seed" +) + +//go:embed dialect +var dialectFS embed.FS + +// Dialect returns the catalog option that seeds GoogleSQL's type system. +func Dialect() core.Option { + return seed.Dialect(dialectFS, "dialect") +} diff --git a/internal/engine/googlesql/stdlib.go b/internal/engine/googlesql/stdlib.go new file mode 100644 index 0000000..e43d9c0 --- /dev/null +++ b/internal/engine/googlesql/stdlib.go @@ -0,0 +1,9 @@ +package googlesql + +import ( + "github.com/sqlc-dev/sqlc/internal/sql/catalog" +) + +func defaultSchema(name string) *catalog.Schema { + return &catalog.Schema{Name: name} +} diff --git a/internal/engine/googlesql/utils.go b/internal/engine/googlesql/utils.go new file mode 100644 index 0000000..0ee4c58 --- /dev/null +++ b/internal/engine/googlesql/utils.go @@ -0,0 +1,298 @@ +package googlesql + +import ( + "log" + "strings" + + zjast "github.com/sqlc-dev/zetajones/ast" + + "github.com/sqlc-dev/sqlc/internal/debug" + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +func todo(n zjast.Node) *ast.TODO { + if debug.Active { + log.Printf("googlesql.convert: Unknown node type %T\n", n) + } + return &ast.TODO{} +} + +// identifier passes table and column identifiers through unchanged. GoogleSQL +// keywords are case-insensitive, but table names (on BigQuery) are +// case-sensitive, so unlike the MySQL and ClickHouse engines we do not +// lowercase identifiers here. Function and type names, which are +// case-insensitive, are lowercased at their call sites instead. +func identifier(id string) string { + return id +} + +func NewIdentifier(t string) *ast.String { + return &ast.String{Str: identifier(t)} +} + +// pathParts returns the identifier names of a dotted path expression. +func pathParts(n *zjast.PathExpression) []string { + if n == nil { + return nil + } + parts := make([]string, 0, len(n.Names)) + for _, id := range n.Names { + if id == nil { + continue + } + parts = append(parts, id.Name) + } + return parts +} + +func parseTableName(n *zjast.PathExpression) *ast.TableName { + name := &ast.TableName{} + parts := pathParts(n) + switch len(parts) { + case 0: + case 1: + name.Name = identifier(parts[0]) + case 2: + name.Schema = identifier(parts[0]) + name.Name = identifier(parts[1]) + default: + name.Catalog = identifier(parts[0]) + name.Schema = identifier(parts[len(parts)-2]) + name.Name = identifier(parts[len(parts)-1]) + } + return name +} + +func parseRangeVar(n *zjast.PathExpression) *ast.RangeVar { + tn := parseTableName(n) + rv := &ast.RangeVar{} + if n != nil { + rv.Location = n.Pos() + } + if tn.Catalog != "" { + catalog := tn.Catalog + rv.Catalogname = &catalog + } + if tn.Schema != "" { + schema := tn.Schema + rv.Schemaname = &schema + } + if tn.Name != "" { + relname := tn.Name + rv.Relname = &relname + } + return rv +} + +func convertAlias(a *zjast.Alias) *ast.Alias { + if a == nil || a.Identifier == nil { + return nil + } + name := identifier(a.Identifier.Name) + return &ast.Alias{Aliasname: &name} +} + +// whereExpr unwraps a WHERE clause node to its expression. The DELETE and +// UPDATE statement nodes hold either a *WhereClause or a bare expression. +func whereExpr(node zjast.Node) zjast.Node { + if wc, ok := node.(*zjast.WhereClause); ok { + return wc.Expr + } + return node +} + +// stringLiteralValue concatenates and unquotes the components of a string +// literal. +func stringLiteralValue(n *zjast.StringLiteral) string { + var sb strings.Builder + for _, comp := range n.Components { + if comp == nil { + continue + } + sb.WriteString(unquote(comp.Image)) + } + return sb.String() +} + +// unquote strips the optional r/b prefix and the surrounding quotes from a +// string literal component and decodes escape sequences for non-raw strings. +// It is best-effort: malformed input is returned unchanged. +func unquote(image string) string { + raw := false + i := 0 +prefix: + for i < len(image) { + switch image[i] { + case 'r', 'R': + raw = true + i++ + case 'b', 'B': + i++ + default: + break prefix + } + } + s := image[i:] + for _, q := range []string{`'''`, `"""`, `'`, `"`} { + if len(s) >= 2*len(q) && strings.HasPrefix(s, q) && strings.HasSuffix(s, q) { + s = s[len(q) : len(s)-len(q)] + if raw || !strings.ContainsRune(s, '\\') { + return s + } + return decodeEscapes(s) + } + } + return image +} + +func decodeEscapes(s string) string { + var sb strings.Builder + for i := 0; i < len(s); i++ { + ch := s[i] + if ch != '\\' || i+1 >= len(s) { + sb.WriteByte(ch) + continue + } + i++ + switch s[i] { + case 'n': + sb.WriteByte('\n') + case 't': + sb.WriteByte('\t') + case 'r': + sb.WriteByte('\r') + case 'a': + sb.WriteByte('\a') + case 'b': + sb.WriteByte('\b') + case 'f': + sb.WriteByte('\f') + case 'v': + sb.WriteByte('\v') + case '\\', '\'', '"', '?', '`': + sb.WriteByte(s[i]) + default: + // Unknown escape (\x, \u, ...): keep it verbatim. + sb.WriteByte('\\') + sb.WriteByte(s[i]) + } + } + return sb.String() +} + +// typeName renders a zetajones type node (used by CAST) as a lowercased type +// name. Nested types degrade to a readable representation. +// typeName spells a type the way the analysis core reads one: a family +// applied to its arguments, with an array's element, a struct's labelled +// fields, a range's subtype and a map's key and value nested, and a +// parameter list's integers and MAX written as they were. +func typeName(node zjast.Node) string { + switch t := node.(type) { + case *zjast.SimpleType: + return strings.ToLower(strings.Join(pathParts(t.Name), ".")) + typeParameters(t.TypeParameters) + case *zjast.ArrayType: + return "array(" + typeName(t.ElementType) + ")" + case *zjast.StructType: + fields := make([]string, 0, len(t.Fields)) + for _, f := range t.Fields { + field := typeName(f.Type) + if f.Name != nil { + field = identifier(f.Name.Name) + ": " + field + } + fields = append(fields, field) + } + return "struct(" + strings.Join(fields, ", ") + ")" + case *zjast.RangeType: + return "range(" + typeName(t.ElementType) + ")" + case *zjast.MapType: + return "map(" + typeName(t.KeyType) + ", " + typeName(t.ValueType) + ")" + default: + return "" + } +} + +// typeParameters spells a parameter list, STRING(10) or BYTES(MAX), as the +// arguments of a call. +func typeParameters(params *zjast.TypeParameterList) string { + if params == nil || len(params.Parameters) == 0 { + return "" + } + parts := make([]string, 0, len(params.Parameters)) + for _, p := range params.Parameters { + switch v := p.(type) { + case *zjast.IntLiteral: + parts = append(parts, v.Image) + case *zjast.MaxLiteral: + parts = append(parts, "max") + default: + continue + } + } + if len(parts) == 0 { + return "" + } + return "(" + strings.Join(parts, ", ") + ")" +} + +// columnSchemaTypeName renders a CREATE TABLE column schema as a lowercased +// type name. Nested types degrade to a readable representation. +// columnSchemaTypeName spells a column's type the way typeName spells a +// type. +func columnSchemaTypeName(node zjast.Node) string { + switch t := node.(type) { + case *zjast.SimpleColumnSchema: + return strings.ToLower(strings.Join(pathParts(t.Type), ".")) + typeParameters(t.TypeParameters) + case *zjast.ArrayColumnSchema: + return "array(" + columnSchemaTypeName(t.ElementSchema) + ")" + case *zjast.StructColumnSchema: + fields := make([]string, 0, len(t.Fields)) + for _, f := range t.Fields { + field := columnSchemaTypeName(f.Schema) + if f.Name != nil { + field = identifier(f.Name.Name) + ": " + field + } + fields = append(fields, field) + } + return "struct(" + strings.Join(fields, ", ") + ")" + default: + return "" + } +} + +// columnAttributes returns the attribute list (NOT NULL, PRIMARY KEY, ...) of +// a column schema, if any. +func columnAttributes(node zjast.Node) *zjast.ColumnAttributeList { + switch t := node.(type) { + case *zjast.SimpleColumnSchema: + return t.Attributes + case *zjast.ArrayColumnSchema: + return t.Attributes + case *zjast.StructColumnSchema: + return t.Attributes + default: + return nil + } +} + +// columnRefFields flattens an identifier, path expression, or dotted +// identifier chain into ColumnRef fields. +func columnRefFields(node zjast.Node) ([]ast.Node, bool) { + switch n := node.(type) { + case *zjast.Identifier: + return []ast.Node{NewIdentifier(n.Name)}, true + case *zjast.PathExpression: + var fields []ast.Node + for _, part := range pathParts(n) { + fields = append(fields, NewIdentifier(part)) + } + return fields, len(fields) > 0 + case *zjast.DotIdentifier: + base, ok := columnRefFields(n.Expr) + if !ok || n.Name == nil { + return nil, false + } + return append(base, NewIdentifier(n.Name.Name)), true + default: + return nil, false + } +} diff --git a/internal/engine/mssql/convert.go b/internal/engine/mssql/convert.go new file mode 100644 index 0000000..dc0ac71 --- /dev/null +++ b/internal/engine/mssql/convert.go @@ -0,0 +1,1199 @@ +package mssql + +import ( + "strconv" + "strings" + + tsql "github.com/sqlc-dev/teesql/ast" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +type cc struct { + paramCount int + // namedParams tracks the number assigned to each "@name" so repeated + // uses share a single parameter. + namedParams map[string]int + // toByte maps a teesql UTF-16 code-unit offset to a byte offset in the + // source, so Location fields agree with StmtLocation/StmtLen. + toByte func(int) int +} + +// loc returns a node's start offset in bytes, for the Location fields of the +// sqlc AST. +func (c *cc) loc(n any) int { + f, ok := n.(fragmented) + if !ok { + return 0 + } + off := f.Frag().StartOffset + if c.toByte != nil { + return c.toByte(off) + } + return off +} + +func (c *cc) parseRangeVar(n *tsql.SchemaObjectName) *ast.RangeVar { + name := parseTableName(n) + rv := &ast.RangeVar{ + Relname: &name.Name, + Location: c.loc(n), + } + if name.Schema != "" { + rv.Schemaname = &name.Schema + } + return rv +} + +func (c *cc) convert(node tsql.Node) ast.Node { + switch n := node.(type) { + case *tsql.SelectStatement: + return c.convertSelectStatement(n) + case *tsql.InsertStatement: + return c.convertInsertStatement(n) + case *tsql.UpdateStatement: + return c.convertUpdateStatement(n) + case *tsql.DeleteStatement: + return c.convertDeleteStatement(n) + case *tsql.CreateTableStatement: + return c.convertCreateTableStatement(n) + case *tsql.DropTableStatement: + return c.convertDropTableStatement(n) + case *tsql.AlterTableAddTableElementStatement: + return c.convertAlterTableAddTableElementStatement(n) + case *tsql.AlterTableDropTableElementStatement: + return c.convertAlterTableDropTableElementStatement(n) + case *tsql.CreateTypeUddtStatement: + return c.convertCreateTypeUddtStatement(n) + default: + return todo(n) + } +} + +// convertCreateTypeUddtStatement reports CREATE TYPE name FROM base [NOT +// NULL] as the domain it is: a type standing on its base that may forbid +// NULL. +func (c *cc) convertCreateTypeUddtStatement(n *tsql.CreateTypeUddtStatement) ast.Node { + if n.Name == nil || n.Name.BaseIdentifier == nil || n.DataType == nil { + return todo(n) + } + stmt := &ast.CreateDomainStmt{ + Domainname: &ast.List{}, + TypeName: dataTypeName(n.DataType), + } + if n.Name.SchemaIdentifier != nil { + stmt.Domainname.Items = append(stmt.Domainname.Items, NewIdentifier(identifierValue(n.Name.SchemaIdentifier))) + } + stmt.Domainname.Items = append(stmt.Domainname.Items, NewIdentifier(identifierValue(n.Name.BaseIdentifier))) + if n.NullableConstraint != nil && !n.NullableConstraint.Nullable { + stmt.Constraints = &ast.List{Items: []ast.Node{&ast.Constraint{Contype: ast.ConstrTypeNotNull}}} + } + return stmt +} + +func (c *cc) convertSelectStatement(n *tsql.SelectStatement) ast.Node { + stmt := c.convertQueryExpression(n.QueryExpression) + sel, ok := stmt.(*ast.SelectStmt) + if !ok { + return stmt + } + if with := c.convertWithClause(n.WithCtesAndXmlNamespaces); with != nil { + sel.WithClause = with + } + return sel +} + +func (c *cc) convertWithClause(n *tsql.WithCtesAndXmlNamespaces) *ast.WithClause { + if n == nil || len(n.CommonTableExpressions) == 0 { + return nil + } + with := &ast.WithClause{ + Ctes: &ast.List{}, + Location: c.loc(n), + } + for _, cte := range n.CommonTableExpressions { + name := identifierValue(cte.ExpressionName) + item := &ast.CommonTableExpr{ + Ctename: &name, + Ctequery: c.convertQueryExpression(cte.QueryExpression), + Location: c.loc(cte), + } + if len(cte.Columns) > 0 { + item.Aliascolnames = &ast.List{} + for _, col := range cte.Columns { + item.Aliascolnames.Items = append(item.Aliascolnames.Items, NewIdentifier(col.Value)) + } + } + with.Ctes.Items = append(with.Ctes.Items, item) + } + return with +} + +func (c *cc) convertQueryExpression(q tsql.QueryExpression) ast.Node { + switch n := q.(type) { + case *tsql.QuerySpecification: + return c.convertQuerySpecification(n) + case *tsql.BinaryQueryExpression: + return c.convertBinaryQueryExpression(n) + case *tsql.QueryParenthesisExpression: + return c.convertQueryExpression(n.QueryExpression) + default: + return todo(q) + } +} + +func (c *cc) convertBinaryQueryExpression(n *tsql.BinaryQueryExpression) ast.Node { + var op ast.SetOperation + switch n.BinaryQueryExpressionType { + case "Union": + op = ast.Union + case "Except": + op = ast.Except + case "Intersect": + op = ast.Intersect + default: + return todo(n) + } + larg, ok := c.convertQueryExpression(n.FirstQueryExpression).(*ast.SelectStmt) + if !ok { + return todo(n) + } + rarg, ok := c.convertQueryExpression(n.SecondQueryExpression).(*ast.SelectStmt) + if !ok { + return todo(n) + } + stmt := &ast.SelectStmt{ + Op: op, + All: n.All, + Larg: larg, + Rarg: rarg, + } + if n.OrderByClause != nil { + stmt.SortClause = c.convertOrderByClause(n.OrderByClause) + } + return stmt +} + +func (c *cc) convertQuerySpecification(n *tsql.QuerySpecification) *ast.SelectStmt { + stmt := &ast.SelectStmt{} + + if len(n.SelectElements) > 0 { + stmt.TargetList = &ast.List{} + for _, elem := range n.SelectElements { + if target := c.convertSelectElement(elem); target != nil { + stmt.TargetList.Items = append(stmt.TargetList.Items, target) + } + } + } + + if n.FromClause != nil { + stmt.FromClause = &ast.List{} + for _, ref := range n.FromClause.TableReferences { + stmt.FromClause.Items = append(stmt.FromClause.Items, c.convertTableReference(ref)) + } + } + + if n.WhereClause != nil { + stmt.WhereClause = c.convertBooleanExpression(n.WhereClause.SearchCondition) + } + + if n.GroupByClause != nil { + stmt.GroupClause = &ast.List{} + for _, spec := range n.GroupByClause.GroupingSpecifications { + if g, ok := spec.(*tsql.ExpressionGroupingSpecification); ok { + stmt.GroupClause.Items = append(stmt.GroupClause.Items, c.convertScalarExpression(g.Expression)) + } + } + } + + if n.HavingClause != nil { + stmt.HavingClause = c.convertBooleanExpression(n.HavingClause.SearchCondition) + } + + if n.OrderByClause != nil { + stmt.SortClause = c.convertOrderByClause(n.OrderByClause) + } + + // OFFSET n ROWS FETCH NEXT m ROWS ONLY + if n.OffsetClause != nil { + if n.OffsetClause.OffsetExpression != nil { + stmt.LimitOffset = c.convertScalarExpression(n.OffsetClause.OffsetExpression) + } + if n.OffsetClause.FetchExpression != nil { + stmt.LimitCount = c.convertScalarExpression(n.OffsetClause.FetchExpression) + } + } + + // TOP n; TOP n PERCENT does not translate to a row count. + if n.TopRowFilter != nil && !n.TopRowFilter.Percent { + stmt.LimitCount = c.convertScalarExpression(n.TopRowFilter.Expression) + } + + if n.UniqueRowFilter == "Distinct" { + stmt.DistinctClause = &ast.List{} + } + + return stmt +} + +func (c *cc) convertSelectElement(elem tsql.SelectElement) ast.Node { + switch e := elem.(type) { + case *tsql.SelectScalarExpression: + res := &ast.ResTarget{ + Val: c.convertScalarExpression(e.Expression), + Location: c.loc(e), + } + if name := columnAlias(e.ColumnName); name != "" { + res.Name = &name + } + return res + case *tsql.SelectStarExpression: + fields := &ast.List{} + if e.Qualifier != nil { + for _, id := range e.Qualifier.Identifiers { + fields.Items = append(fields.Items, NewIdentifier(id.Value)) + } + } + fields.Items = append(fields.Items, &ast.A_Star{}) + return &ast.ResTarget{ + Val: &ast.ColumnRef{ + Fields: fields, + Location: c.loc(e), + }, + Location: c.loc(e), + } + default: + return &ast.ResTarget{ + Val: todo(elem), + Location: c.loc(elem), + } + } +} + +func columnAlias(n *tsql.IdentifierOrValueExpression) string { + if n == nil { + return "" + } + if n.Identifier != nil { + return identifierValue(n.Identifier) + } + if n.Value != "" { + return identifier(n.Value) + } + return "" +} + +func (c *cc) convertOrderByClause(n *tsql.OrderByClause) *ast.List { + list := &ast.List{} + for _, elem := range n.OrderByElements { + sortBy := &ast.SortBy{ + Node: c.convertScalarExpression(elem.Expression), + Location: c.loc(elem), + } + switch elem.SortOrder { + case "Descending": + sortBy.SortbyDir = ast.SortByDirDesc + case "Ascending": + sortBy.SortbyDir = ast.SortByDirAsc + default: + sortBy.SortbyDir = ast.SortByDirDefault + } + list.Items = append(list.Items, sortBy) + } + return list +} + +func (c *cc) convertTableReference(ref tsql.TableReference) ast.Node { + switch t := ref.(type) { + case *tsql.NamedTableReference: + rv := c.parseRangeVar(t.SchemaObject) + if t.Alias != nil { + alias := identifierValue(t.Alias) + rv.Alias = &ast.Alias{Aliasname: &alias} + } + return rv + case *tsql.QueryDerivedTable: + sub := &ast.RangeSubselect{ + Subquery: c.convertQueryExpression(t.QueryExpression), + } + if t.Alias != nil { + alias := identifierValue(t.Alias) + sub.Alias = &ast.Alias{Aliasname: &alias} + } + return sub + case *tsql.QualifiedJoin: + join := &ast.JoinExpr{ + Larg: c.convertTableReference(t.FirstTableReference), + Rarg: c.convertTableReference(t.SecondTableReference), + } + switch t.QualifiedJoinType { + case "LeftOuter": + join.Jointype = ast.JoinTypeLeft + case "RightOuter": + join.Jointype = ast.JoinTypeRight + case "FullOuter": + join.Jointype = ast.JoinTypeFull + default: + join.Jointype = ast.JoinTypeInner + } + if t.SearchCondition != nil { + join.Quals = c.convertBooleanExpression(t.SearchCondition) + } + return join + case *tsql.UnqualifiedJoin: + if t.UnqualifiedJoinType != "CrossJoin" { + return todo(ref) + } + return &ast.JoinExpr{ + Jointype: ast.JoinTypeInner, + Larg: c.convertTableReference(t.FirstTableReference), + Rarg: c.convertTableReference(t.SecondTableReference), + } + default: + return todo(ref) + } +} + +func (c *cc) convertBooleanExpression(expr tsql.BooleanExpression) ast.Node { + if expr == nil { + return nil + } + switch e := expr.(type) { + case *tsql.BooleanComparisonExpression: + return &ast.A_Expr{ + Kind: ast.A_Expr_Kind_OP, + Name: &ast.List{ + Items: []ast.Node{&ast.String{Str: comparisonOperator(e.ComparisonType)}}, + }, + Lexpr: c.convertScalarExpression(e.FirstExpression), + Rexpr: c.convertScalarExpression(e.SecondExpression), + Location: c.loc(e), + } + case *tsql.BooleanBinaryExpression: + boolop := ast.BoolExprTypeAnd + if e.BinaryExpressionType == "Or" { + boolop = ast.BoolExprTypeOr + } + return &ast.BoolExpr{ + Boolop: boolop, + Args: &ast.List{ + Items: []ast.Node{ + c.convertBooleanExpression(e.FirstExpression), + c.convertBooleanExpression(e.SecondExpression), + }, + }, + Location: c.loc(e), + } + case *tsql.BooleanNotExpression: + return &ast.BoolExpr{ + Boolop: ast.BoolExprTypeNot, + Args: &ast.List{ + Items: []ast.Node{c.convertBooleanExpression(e.Expression)}, + }, + Location: c.loc(e), + } + case *tsql.BooleanParenthesisExpression: + return c.convertBooleanExpression(e.Expression) + case *tsql.BooleanIsNullExpression: + test := ast.NullTestTypeIsNull + if e.IsNot { + test = ast.NullTestTypeIsNotNull + } + return &ast.NullTest{ + Arg: c.convertScalarExpression(e.Expression), + Nulltesttype: test, + Location: c.loc(e), + } + case *tsql.BooleanTernaryExpression: + return &ast.BetweenExpr{ + Expr: c.convertScalarExpression(e.FirstExpression), + Left: c.convertScalarExpression(e.SecondExpression), + Right: c.convertScalarExpression(e.ThirdExpression), + Not: e.TernaryExpressionType == "NotBetween", + Location: c.loc(e), + } + case *tsql.BooleanInExpression: + in := &ast.In{ + Expr: c.convertScalarExpression(e.Expression), + Not: e.NotDefined, + Location: c.loc(e), + } + for _, item := range e.Values { + in.List = append(in.List, c.convertScalarExpression(item)) + } + if e.Subquery != nil { + in.Sel = c.convertQueryExpression(e.Subquery) + } + return in + case *tsql.BooleanLikeExpression: + op := "~~" + if e.NotDefined { + op = "!~~" + } + return &ast.A_Expr{ + Kind: ast.A_Expr_Kind_OP, + Name: &ast.List{ + Items: []ast.Node{&ast.String{Str: op}}, + }, + Lexpr: c.convertScalarExpression(e.FirstExpression), + Rexpr: c.convertScalarExpression(e.SecondExpression), + Location: c.loc(e), + } + case *tsql.ExistsPredicate: + return &ast.SubLink{ + SubLinkType: ast.EXISTS_SUBLINK, + Subselect: c.convertQueryExpression(e.Subquery), + Location: c.loc(e), + } + case *tsql.BooleanScalarPlaceholder: + return c.convertScalarExpression(e.Scalar) + default: + return todo(expr) + } +} + +func comparisonOperator(comparisonType string) string { + switch comparisonType { + case "Equals": + return "=" + case "NotEqualToBrackets", "NotEqualToExclamation": + return "<>" + case "GreaterThan": + return ">" + case "LessThan": + return "<" + case "GreaterThanOrEqualTo", "NotLessThan": + return ">=" + case "LessThanOrEqualTo", "NotGreaterThan": + return "<=" + default: + return "=" + } +} + +func (c *cc) convertScalarExpression(expr tsql.ScalarExpression) ast.Node { + if expr == nil { + return nil + } + switch e := expr.(type) { + case *tsql.ColumnReferenceExpression: + return c.convertColumnReference(e) + case *tsql.VariableReference: + return c.convertVariableReference(e) + case *tsql.IntegerLiteral: + ival, _ := strconv.ParseInt(e.Value, 10, 64) + return &ast.A_Const{ + Val: &ast.Integer{Ival: ival}, + Location: c.loc(e), + } + case *tsql.NumericLiteral: + return &ast.A_Const{ + Val: &ast.Float{Str: e.Value}, + Location: c.loc(e), + } + case *tsql.RealLiteral: + return &ast.A_Const{ + Val: &ast.Float{Str: e.Value}, + Location: c.loc(e), + } + case *tsql.MoneyLiteral: + return &ast.A_Const{ + Val: &ast.Float{Str: e.Value}, + Location: c.loc(e), + } + case *tsql.StringLiteral: + return &ast.A_Const{ + Val: &ast.String{Str: e.Value}, + Location: c.loc(e), + } + case *tsql.NullLiteral: + return &ast.A_Const{ + Val: &ast.Null{}, + Location: c.loc(e), + } + case *tsql.BinaryExpression: + return &ast.A_Expr{ + Kind: ast.A_Expr_Kind_OP, + Name: &ast.List{ + Items: []ast.Node{&ast.String{Str: binaryOperator(e.BinaryExpressionType)}}, + }, + Lexpr: c.convertScalarExpression(e.FirstExpression), + Rexpr: c.convertScalarExpression(e.SecondExpression), + Location: c.loc(e), + } + case *tsql.UnaryExpression: + switch e.UnaryExpressionType { + case "Positive": + return c.convertScalarExpression(e.Expression) + case "BitwiseNot": + return &ast.A_Expr{ + Kind: ast.A_Expr_Kind_OP, + Name: &ast.List{ + Items: []ast.Node{&ast.String{Str: "~"}}, + }, + Rexpr: c.convertScalarExpression(e.Expression), + Location: c.loc(e), + } + default: // Negative + return &ast.A_Expr{ + Kind: ast.A_Expr_Kind_OP, + Name: &ast.List{ + Items: []ast.Node{&ast.String{Str: "-"}}, + }, + Rexpr: c.convertScalarExpression(e.Expression), + Location: c.loc(e), + } + } + case *tsql.ParenthesisExpression: + return c.convertScalarExpression(e.Expression) + case *tsql.FunctionCall: + return c.convertFunctionCall(e) + case *tsql.CastCall: + return &ast.TypeCast{ + Arg: c.convertScalarExpression(e.Parameter), + TypeName: dataTypeName(e.DataType), + Location: c.loc(e), + } + case *tsql.TryCastCall: + return &ast.TypeCast{ + Arg: c.convertScalarExpression(e.Parameter), + TypeName: dataTypeName(e.DataType), + Location: c.loc(e), + } + case *tsql.ConvertCall: + return &ast.TypeCast{ + Arg: c.convertScalarExpression(e.Parameter), + TypeName: dataTypeName(e.DataType), + Location: c.loc(e), + } + case *tsql.TryConvertCall: + return &ast.TypeCast{ + Arg: c.convertScalarExpression(e.Parameter), + TypeName: dataTypeName(e.DataType), + Location: c.loc(e), + } + case *tsql.CoalesceExpression: + coalesce := &ast.CoalesceExpr{ + Args: &ast.List{}, + Location: c.loc(e), + } + for _, arg := range e.Expressions { + coalesce.Args.Items = append(coalesce.Args.Items, c.convertScalarExpression(arg)) + } + return coalesce + case *tsql.NullIfExpression: + return &ast.FuncCall{ + Funcname: &ast.List{ + Items: []ast.Node{&ast.String{Str: "nullif"}}, + }, + Args: &ast.List{ + Items: []ast.Node{ + c.convertScalarExpression(e.FirstExpression), + c.convertScalarExpression(e.SecondExpression), + }, + }, + Location: c.loc(e), + } + case *tsql.IIfCall: + return &ast.CaseExpr{ + Args: &ast.List{ + Items: []ast.Node{ + &ast.CaseWhen{ + Expr: c.convertBooleanExpression(e.Predicate), + Result: c.convertScalarExpression(e.ThenExpression), + }, + }, + }, + Defresult: c.convertScalarExpression(e.ElseExpression), + Location: c.loc(e), + } + case *tsql.SearchedCaseExpression: + caseExpr := &ast.CaseExpr{ + Args: &ast.List{}, + Location: c.loc(e), + } + for _, when := range e.WhenClauses { + caseExpr.Args.Items = append(caseExpr.Args.Items, &ast.CaseWhen{ + Expr: c.convertBooleanExpression(when.WhenExpression), + Result: c.convertScalarExpression(when.ThenExpression), + }) + } + if e.ElseExpression != nil { + caseExpr.Defresult = c.convertScalarExpression(e.ElseExpression) + } + return caseExpr + case *tsql.SimpleCaseExpression: + caseExpr := &ast.CaseExpr{ + Arg: c.convertScalarExpression(e.InputExpression), + Args: &ast.List{}, + Location: c.loc(e), + } + for _, when := range e.WhenClauses { + caseExpr.Args.Items = append(caseExpr.Args.Items, &ast.CaseWhen{ + Expr: c.convertScalarExpression(when.WhenExpression), + Result: c.convertScalarExpression(when.ThenExpression), + }) + } + if e.ElseExpression != nil { + caseExpr.Defresult = c.convertScalarExpression(e.ElseExpression) + } + return caseExpr + case *tsql.ScalarSubquery: + return &ast.SubLink{ + SubLinkType: ast.EXPR_SUBLINK, + Subselect: c.convertQueryExpression(e.QueryExpression), + Location: c.loc(e), + } + case *tsql.ParameterlessCall: + return &ast.FuncCall{ + Funcname: &ast.List{ + Items: []ast.Node{&ast.String{Str: identifier(e.ParameterlessCallType)}}, + }, + Location: c.loc(e), + } + default: + return todo(expr) + } +} + +func binaryOperator(binaryExpressionType string) string { + switch binaryExpressionType { + case "Add": + return "+" + case "Subtract": + return "-" + case "Multiply": + return "*" + case "Divide": + return "/" + case "Modulo": + return "%" + case "BitwiseAnd": + return "&" + case "BitwiseOr": + return "|" + case "BitwiseXor": + return "^" + default: + return "+" + } +} + +func (c *cc) convertColumnReference(n *tsql.ColumnReferenceExpression) *ast.ColumnRef { + fields := &ast.List{} + if n.MultiPartIdentifier != nil { + for _, id := range n.MultiPartIdentifier.Identifiers { + fields.Items = append(fields.Items, NewIdentifier(id.Value)) + } + } + if n.ColumnType == "Wildcard" { + fields.Items = append(fields.Items, &ast.A_Star{}) + } + return &ast.ColumnRef{ + Fields: fields, + Location: c.loc(n), + } +} + +// convertVariableReference converts an "@name" query parameter. Repeated uses +// of a name share a single parameter number. +func (c *cc) convertVariableReference(n *tsql.VariableReference) ast.Node { + name := strings.TrimPrefix(n.Name, "@") + number, ok := c.namedParams[name] + if !ok { + c.paramCount++ + number = c.paramCount + if c.namedParams == nil { + c.namedParams = map[string]int{} + } + c.namedParams[name] = number + } + return &ast.ParamRef{ + Number: number, + Location: c.loc(n), + } +} + +func (c *cc) convertFunctionCall(n *tsql.FunctionCall) *ast.FuncCall { + fc := &ast.FuncCall{ + Funcname: &ast.List{ + Items: []ast.Node{&ast.String{Str: identifierValue(n.FunctionName)}}, + }, + Location: c.loc(n), + AggDistinct: n.UniqueRowFilter == "Distinct", + } + + for _, param := range n.Parameters { + // COUNT(*) and friends carry the star as a wildcard column reference. + if col, ok := param.(*tsql.ColumnReferenceExpression); ok && col.ColumnType == "Wildcard" && col.MultiPartIdentifier == nil { + fc.AggStar = true + continue + } + if fc.Args == nil { + fc.Args = &ast.List{} + } + fc.Args.Items = append(fc.Args.Items, c.convertScalarExpression(param)) + } + + if n.OverClause != nil { + fc.Over = &ast.WindowDef{Location: c.loc(n.OverClause)} + if len(n.OverClause.Partitions) > 0 { + fc.Over.PartitionClause = &ast.List{} + for _, p := range n.OverClause.Partitions { + fc.Over.PartitionClause.Items = append(fc.Over.PartitionClause.Items, c.convertScalarExpression(p)) + } + } + if n.OverClause.OrderByClause != nil { + fc.Over.OrderClause = c.convertOrderByClause(n.OverClause.OrderByClause) + } + } + + return fc +} + +// convertOutputClause converts an OUTPUT clause to a returning list. The +// INSERTED and DELETED pseudo-table qualifiers are stripped so the columns +// resolve against the statement's target table. +func (c *cc) convertOutputClause(n *tsql.OutputClause) *ast.List { + if n == nil || len(n.SelectColumns) == 0 { + return nil + } + list := &ast.List{} + for _, elem := range n.SelectColumns { + target := c.convertSelectElement(elem) + if res, ok := target.(*ast.ResTarget); ok { + stripOutputQualifier(res.Val) + } + list.Items = append(list.Items, target) + } + return list +} + +func stripOutputQualifier(node ast.Node) { + ref, ok := node.(*ast.ColumnRef) + if !ok || ref.Fields == nil || len(ref.Fields.Items) < 2 { + return + } + if first, ok := ref.Fields.Items[0].(*ast.String); ok { + switch first.Str { + case "inserted", "deleted": + ref.Fields.Items = ref.Fields.Items[1:] + } + } +} + +func (c *cc) convertInsertStatement(n *tsql.InsertStatement) ast.Node { + if n.InsertSpecification == nil { + return todo(n) + } + spec := n.InsertSpecification + + target, ok := spec.Target.(*tsql.NamedTableReference) + if !ok { + return todo(n) + } + + stmt := &ast.InsertStmt{ + Relation: c.parseRangeVar(target.SchemaObject), + } + + if len(spec.Columns) > 0 { + stmt.Cols = &ast.List{} + for _, col := range spec.Columns { + if col.MultiPartIdentifier == nil || len(col.MultiPartIdentifier.Identifiers) == 0 { + continue + } + ids := col.MultiPartIdentifier.Identifiers + name := identifierValue(ids[len(ids)-1]) + stmt.Cols.Items = append(stmt.Cols.Items, &ast.ResTarget{ + Name: &name, + Location: c.loc(col), + }) + } + } + + switch src := spec.InsertSource.(type) { + case *tsql.ValuesInsertSource: + if !src.IsDefaultValues { + sel := &ast.SelectStmt{ + ValuesLists: &ast.List{}, + } + for _, row := range src.RowValues { + rowList := &ast.List{} + for _, val := range row.ColumnValues { + rowList.Items = append(rowList.Items, c.convertScalarExpression(val)) + } + sel.ValuesLists.Items = append(sel.ValuesLists.Items, rowList) + } + stmt.SelectStmt = sel + } + case *tsql.SelectInsertSource: + stmt.SelectStmt = c.convertQueryExpression(src.Select) + } + + if returning := c.convertOutputClause(spec.OutputClause); returning != nil { + stmt.ReturningList = returning + } + + return stmt +} + +func (c *cc) convertUpdateStatement(n *tsql.UpdateStatement) ast.Node { + if n.UpdateSpecification == nil { + return todo(n) + } + spec := n.UpdateSpecification + + target, ok := spec.Target.(*tsql.NamedTableReference) + if !ok { + return todo(n) + } + + rv, fromItems, quals := c.dmlTargetAndFrom(target, spec.FromClause) + stmt := &ast.UpdateStmt{ + Relations: &ast.List{ + Items: []ast.Node{rv}, + }, + TargetList: &ast.List{}, + FromClause: &ast.List{Items: fromItems}, + ReturningList: &ast.List{}, + WithClause: c.convertWithClause(n.WithCtesAndXmlNamespaces), + } + + for _, sc := range spec.SetClauses { + assign, ok := sc.(*tsql.AssignmentSetClause) + if !ok || assign.Column == nil { + continue + } + ids := assign.Column.MultiPartIdentifier + if ids == nil || len(ids.Identifiers) == 0 { + continue + } + name := identifierValue(ids.Identifiers[len(ids.Identifiers)-1]) + stmt.TargetList.Items = append(stmt.TargetList.Items, &ast.ResTarget{ + Name: &name, + Val: c.convertScalarExpression(assign.NewValue), + Location: c.loc(assign), + }) + } + + if spec.WhereClause != nil { + stmt.WhereClause = c.convertBooleanExpression(spec.WhereClause.SearchCondition) + } + stmt.WhereClause = andQuals(stmt.WhereClause, quals) + + if returning := c.convertOutputClause(spec.OutputClause); returning != nil { + stmt.ReturningList = returning + } + + return stmt +} + +func (c *cc) convertDeleteStatement(n *tsql.DeleteStatement) ast.Node { + if n.DeleteSpecification == nil { + return todo(n) + } + spec := n.DeleteSpecification + + target, ok := spec.Target.(*tsql.NamedTableReference) + if !ok { + return todo(n) + } + + rv, fromItems, quals := c.dmlTargetAndFrom(target, spec.FromClause) + stmt := &ast.DeleteStmt{ + Relations: &ast.List{ + Items: []ast.Node{rv}, + }, + ReturningList: &ast.List{}, + WithClause: c.convertWithClause(n.WithCtesAndXmlNamespaces), + } + if len(fromItems) > 0 { + stmt.FromClause = &ast.List{Items: fromItems} + } + + if spec.WhereClause != nil { + stmt.WhereClause = c.convertBooleanExpression(spec.WhereClause.SearchCondition) + } + stmt.WhereClause = andQuals(stmt.WhereClause, quals) + + if returning := c.convertOutputClause(spec.OutputClause); returning != nil { + stmt.ReturningList = returning + } + + return stmt +} + +// dmlTargetAndFrom resolves an UPDATE or DELETE statement's target against +// its FROM clause. T-SQL names the target by the alias the FROM clause gives +// it — "UPDATE a SET ... FROM authors a" — so a target matching a FROM +// relation becomes that relation, removed from the returned FROM items. The +// ON conditions of inner joins dissolved by the removal are returned as +// extra WHERE conditions. +func (c *cc) dmlTargetAndFrom(target *tsql.NamedTableReference, from *tsql.FromClause) (*ast.RangeVar, []ast.Node, []ast.Node) { + rv := c.parseRangeVar(target.SchemaObject) + if target.Alias != nil { + alias := identifierValue(target.Alias) + rv.Alias = &ast.Alias{Aliasname: &alias} + } + var items []ast.Node + if from != nil { + for _, ref := range from.TableReferences { + items = append(items, c.convertTableReference(ref)) + } + } + if rv.Schemaname == nil && rv.Alias == nil && rv.Relname != nil { + for i, item := range items { + found, remaining, quals := extractTarget(item, *rv.Relname) + if found == nil { + continue + } + if remaining == nil { + items = append(items[:i], items[i+1:]...) + } else { + items[i] = remaining + } + return found, items, quals + } + } + return rv, items, nil +} + +// extractTarget removes the relation named name — by alias, or by table name +// when unaliased — from a FROM item. It returns the extracted relation, what +// remains of the item (nil when the relation was the whole item), and the ON +// conditions of any inner join dissolved by the removal. Relations under an +// outer join are left alone: pulling one out would change the join's meaning. +func extractTarget(item ast.Node, name string) (*ast.RangeVar, ast.Node, []ast.Node) { + switch v := item.(type) { + case *ast.RangeVar: + if rangeVarNamed(v, name) { + return v, nil, nil + } + case *ast.JoinExpr: + if v.Jointype != ast.JoinTypeInner { + return nil, item, nil + } + if found, remaining, quals := extractTarget(v.Larg, name); found != nil { + if remaining == nil { + if v.Quals != nil { + quals = append(quals, v.Quals) + } + return found, v.Rarg, quals + } + v.Larg = remaining + return found, v, quals + } + if found, remaining, quals := extractTarget(v.Rarg, name); found != nil { + if remaining == nil { + if v.Quals != nil { + quals = append(quals, v.Quals) + } + return found, v.Larg, quals + } + v.Rarg = remaining + return found, v, quals + } + } + return nil, item, nil +} + +func rangeVarNamed(rv *ast.RangeVar, name string) bool { + if rv.Alias != nil && rv.Alias.Aliasname != nil { + return *rv.Alias.Aliasname == name + } + return rv.Schemaname == nil && rv.Relname != nil && *rv.Relname == name +} + +// andQuals conjoins the ON conditions of dissolved inner joins onto a WHERE +// clause; for inner joins the two forms are equivalent. +func andQuals(where ast.Node, quals []ast.Node) ast.Node { + for _, q := range quals { + if where == nil { + where = q + continue + } + where = &ast.BoolExpr{ + Boolop: ast.BoolExprTypeAnd, + Args: &ast.List{Items: []ast.Node{where, q}}, + } + } + return where +} + +func (c *cc) convertCreateTableStatement(n *tsql.CreateTableStatement) ast.Node { + if n.SchemaObjectName == nil || n.Definition == nil { + return todo(n) + } + + stmt := &ast.CreateTableStmt{ + Name: parseTableName(n.SchemaObjectName), + } + + // Column names in table-level PRIMARY KEY constraints are NOT NULL. + primaryKey := map[string]bool{} + for _, constraint := range n.Definition.TableConstraints { + unique, ok := constraint.(*tsql.UniqueConstraintDefinition) + if !ok || !unique.IsPrimaryKey { + continue + } + for _, col := range unique.Columns { + if col.Column == nil || col.Column.MultiPartIdentifier == nil { + continue + } + ids := col.Column.MultiPartIdentifier.Identifiers + if len(ids) == 0 { + continue + } + primaryKey[identifierValue(ids[len(ids)-1])] = true + } + } + + for _, col := range n.Definition.ColumnDefinitions { + stmt.Cols = append(stmt.Cols, c.convertColumnDefinition(col, primaryKey)) + } + + return stmt +} + +func (c *cc) convertColumnDefinition(n *tsql.ColumnDefinition, tablePrimaryKey map[string]bool) *ast.ColumnDef { + name := identifierValue(n.ColumnIdentifier) + colDef := &ast.ColumnDef{ + Colname: name, + TypeName: dataTypeName(n.DataType), + Location: c.loc(n), + } + + // T-SQL columns are nullable unless declared otherwise, except that a + // rowversion column is NOT NULL unless declared nullable, and sysname + // is defined as nvarchar(128) NOT NULL. + if n.Nullable != nil && !n.Nullable.Nullable { + colDef.IsNotNull = true + } + if n.Nullable == nil { + switch strings.TrimPrefix(colDef.TypeName.Name, "sys.") { + case "rowversion", "timestamp", "sysname": + colDef.IsNotNull = true + } + } + // IDENTITY columns are always NOT NULL. + if n.IdentityOptions != nil { + colDef.IsNotNull = true + } + for _, constraint := range n.Constraints { + switch cons := constraint.(type) { + case *tsql.NullableConstraintDefinition: + colDef.IsNotNull = !cons.Nullable + case *tsql.UniqueConstraintDefinition: + if cons.IsPrimaryKey { + colDef.PrimaryKey = true + colDef.IsNotNull = true + } + } + } + if tablePrimaryKey[name] { + colDef.PrimaryKey = true + colDef.IsNotNull = true + } + + return colDef +} + +// dataTypeName returns the lowercased base name of a column's declared type, +// e.g. "nvarchar" for NVARCHAR(100). Length and precision arguments do not +// name distinct types. +// dataTypeName is a type as the core reads it: its name, qualified by its +// schema for a user-defined type, with its parameters as type modifiers, +// MAX among them as the word it is. +func dataTypeName(ref tsql.DataTypeReference) *ast.TypeName { + switch t := ref.(type) { + case *tsql.SqlDataTypeReference: + out := &ast.TypeName{Name: identifier(t.SqlDataTypeOption)} + if t.Name != nil && t.Name.BaseIdentifier != nil { + out.Name = identifierValue(t.Name.BaseIdentifier) + } + for _, p := range t.Parameters { + switch v := p.(type) { + case *tsql.IntegerLiteral: + n, _ := strconv.ParseInt(v.Value, 10, 64) + out.Typmods = appendTypmod(out.Typmods, &ast.A_Const{Val: &ast.Integer{Ival: n}}) + case *tsql.MaxLiteral: + out.Typmods = appendTypmod(out.Typmods, &ast.String{Str: "max"}) + } + } + return out + case *tsql.XmlDataTypeReference: + return &ast.TypeName{Name: "xml"} + case *tsql.UserDataTypeReference: + if t.Name != nil && t.Name.BaseIdentifier != nil { + name := identifierValue(t.Name.BaseIdentifier) + if t.Name.SchemaIdentifier != nil { + name = identifierValue(t.Name.SchemaIdentifier) + "." + name + } + return &ast.TypeName{Name: name} + } + } + return &ast.TypeName{} +} + +func appendTypmod(l *ast.List, n ast.Node) *ast.List { + if l == nil { + l = &ast.List{} + } + l.Items = append(l.Items, n) + return l +} + +func (c *cc) convertDropTableStatement(n *tsql.DropTableStatement) ast.Node { + stmt := &ast.DropTableStmt{ + IfExists: n.IsIfExists, + } + for _, obj := range n.Objects { + stmt.Tables = append(stmt.Tables, parseTableName(obj)) + } + return stmt +} + +func (c *cc) convertAlterTableAddTableElementStatement(n *tsql.AlterTableAddTableElementStatement) ast.Node { + if n.SchemaObjectName == nil || n.Definition == nil { + return todo(n) + } + stmt := &ast.AlterTableStmt{ + Table: parseTableName(n.SchemaObjectName), + Cmds: &ast.List{}, + } + for _, col := range n.Definition.ColumnDefinitions { + def := c.convertColumnDefinition(col, nil) + stmt.Cmds.Items = append(stmt.Cmds.Items, &ast.AlterTableCmd{ + Name: &def.Colname, + Subtype: ast.AT_AddColumn, + Def: def, + }) + } + return stmt +} + +func (c *cc) convertAlterTableDropTableElementStatement(n *tsql.AlterTableDropTableElementStatement) ast.Node { + if n.SchemaObjectName == nil { + return todo(n) + } + stmt := &ast.AlterTableStmt{ + Table: parseTableName(n.SchemaObjectName), + Cmds: &ast.List{}, + } + for _, elem := range n.AlterTableDropTableElements { + if elem.TableElementType != "Column" || elem.Name == nil { + continue + } + name := identifierValue(elem.Name) + stmt.Cmds.Items = append(stmt.Cmds.Items, &ast.AlterTableCmd{ + Name: &name, + Subtype: ast.AT_DropColumn, + MissingOk: elem.IsIfExists, + }) + } + if len(stmt.Cmds.Items) == 0 { + return todo(n) + } + return stmt +} diff --git a/internal/engine/mssql/dialect/dialect.json b/internal/engine/mssql/dialect/dialect.json new file mode 100644 index 0000000..30ea408 --- /dev/null +++ b/internal/engine/mssql/dialect/dialect.json @@ -0,0 +1,84 @@ +{ + "dialect": "mssql", + "default_schema": "dbo", + "const": { + "integer": "int", + "float": "float", + "string": "varchar", + "bool": "bit" + }, + "bool": "bit", + "comparison": ["=", "<>", "!=", "<", "<=", ">", ">="], + "comparison_categories": "NBSD", + "arithmetic": ["+", "-", "*", "/", "%"], + "arithmetic_categories": "N", + "cast_categories": "NSD", + "idents": ["max"], + "rewrites": [ + { + "from": "sysname", + "to": "nvarchar(128)" + }, + { + "from": "float($1)", + "to": "real", + "where": "$1 <= 24" + }, + { + "from": "float($1)", + "to": "float" + }, + { + "from": "char", + "to": "char(1)" + }, + { + "from": "varchar", + "to": "varchar(1)" + }, + { + "from": "nchar", + "to": "nchar(1)" + }, + { + "from": "nvarchar", + "to": "nvarchar(1)" + }, + { + "from": "binary", + "to": "binary(1)" + }, + { + "from": "varbinary", + "to": "varbinary(1)" + }, + { + "from": "decimal", + "to": "decimal(18, 0)" + }, + { + "from": "decimal($1)", + "to": "decimal($1, 0)" + }, + { + "from": "numeric", + "to": "numeric(18, 0)" + }, + { + "from": "numeric($1)", + "to": "numeric($1, 0)" + }, + { + "from": "datetime2", + "to": "datetime2(7)" + }, + { + "from": "time", + "to": "time(7)" + }, + { + "from": "datetimeoffset", + "to": "datetimeoffset(7)" + } + ] +} diff --git a/internal/engine/mssql/dialect/functions.jsonl b/internal/engine/mssql/dialect/functions.jsonl new file mode 100644 index 0000000..e0cd454 --- /dev/null +++ b/internal/engine/mssql/dialect/functions.jsonl @@ -0,0 +1,76 @@ +{"name": "count", "kind": "a", "returns": "int"} +{"name": "count_big", "kind": "a", "returns": "bigint"} +{"name": "sum", "kind": "a", "args": [{"type": "bigint"}], "returns": "bigint", "nullable": true} +{"name": "sum", "kind": "a", "args": [{"type": "int"}], "returns": "int", "nullable": true} +{"name": "sum", "kind": "a", "args": [{"type": "smallint"}], "returns": "int", "nullable": true} +{"name": "sum", "kind": "a", "args": [{"type": "tinyint"}], "returns": "int", "nullable": true} +{"name": "sum", "kind": "a", "args": [{"type": "decimal"}], "returns": "decimal", "nullable": true} +{"name": "sum", "kind": "a", "args": [{"type": "money"}], "returns": "money", "nullable": true} +{"name": "sum", "kind": "a", "args": [{"type": "float"}], "returns": "float", "nullable": true} +{"name": "sum", "kind": "a", "args": [{"type": "real"}], "returns": "float", "nullable": true} +{"name": "avg", "kind": "a", "args": [{"type": "bigint"}], "returns": "bigint", "nullable": true} +{"name": "avg", "kind": "a", "args": [{"type": "int"}], "returns": "int", "nullable": true} +{"name": "avg", "kind": "a", "args": [{"type": "smallint"}], "returns": "int", "nullable": true} +{"name": "avg", "kind": "a", "args": [{"type": "tinyint"}], "returns": "int", "nullable": true} +{"name": "avg", "kind": "a", "args": [{"type": "decimal"}], "returns": "decimal", "nullable": true} +{"name": "avg", "kind": "a", "args": [{"type": "money"}], "returns": "money", "nullable": true} +{"name": "avg", "kind": "a", "args": [{"type": "float"}], "returns": "float", "nullable": true} +{"name": "avg", "kind": "a", "args": [{"type": "real"}], "returns": "float", "nullable": true} +{"name": "min", "kind": "a", "args": [{"type": "bigint"}], "returns": "bigint", "nullable": true} +{"name": "min", "kind": "a", "args": [{"type": "int"}], "returns": "int", "nullable": true} +{"name": "min", "kind": "a", "args": [{"type": "smallint"}], "returns": "smallint", "nullable": true} +{"name": "min", "kind": "a", "args": [{"type": "tinyint"}], "returns": "tinyint", "nullable": true} +{"name": "min", "kind": "a", "args": [{"type": "decimal"}], "returns": "decimal", "nullable": true} +{"name": "min", "kind": "a", "args": [{"type": "money"}], "returns": "money", "nullable": true} +{"name": "min", "kind": "a", "args": [{"type": "float"}], "returns": "float", "nullable": true} +{"name": "min", "kind": "a", "args": [{"type": "real"}], "returns": "real", "nullable": true} +{"name": "min", "kind": "a", "args": [{"type": "date"}], "returns": "date", "nullable": true} +{"name": "min", "kind": "a", "args": [{"type": "datetime"}], "returns": "datetime", "nullable": true} +{"name": "min", "kind": "a", "args": [{"type": "datetime2"}], "returns": "datetime2", "nullable": true} +{"name": "min", "kind": "a", "args": [{"type": "datetimeoffset"}], "returns": "datetimeoffset", "nullable": true} +{"name": "min", "kind": "a", "args": [{"type": "time"}], "returns": "time", "nullable": true} +{"name": "min", "kind": "a", "args": [{"type": "varchar"}], "returns": "varchar", "nullable": true} +{"name": "min", "kind": "a", "args": [{"type": "nvarchar"}], "returns": "nvarchar", "nullable": true} +{"name": "min", "kind": "a", "args": [{"type": "char"}], "returns": "char", "nullable": true} +{"name": "min", "kind": "a", "args": [{"type": "nchar"}], "returns": "nchar", "nullable": true} +{"name": "max", "kind": "a", "args": [{"type": "bigint"}], "returns": "bigint", "nullable": true} +{"name": "max", "kind": "a", "args": [{"type": "int"}], "returns": "int", "nullable": true} +{"name": "max", "kind": "a", "args": [{"type": "smallint"}], "returns": "smallint", "nullable": true} +{"name": "max", "kind": "a", "args": [{"type": "tinyint"}], "returns": "tinyint", "nullable": true} +{"name": "max", "kind": "a", "args": [{"type": "decimal"}], "returns": "decimal", "nullable": true} +{"name": "max", "kind": "a", "args": [{"type": "money"}], "returns": "money", "nullable": true} +{"name": "max", "kind": "a", "args": [{"type": "float"}], "returns": "float", "nullable": true} +{"name": "max", "kind": "a", "args": [{"type": "real"}], "returns": "real", "nullable": true} +{"name": "max", "kind": "a", "args": [{"type": "date"}], "returns": "date", "nullable": true} +{"name": "max", "kind": "a", "args": [{"type": "datetime"}], "returns": "datetime", "nullable": true} +{"name": "max", "kind": "a", "args": [{"type": "datetime2"}], "returns": "datetime2", "nullable": true} +{"name": "max", "kind": "a", "args": [{"type": "datetimeoffset"}], "returns": "datetimeoffset", "nullable": true} +{"name": "max", "kind": "a", "args": [{"type": "time"}], "returns": "time", "nullable": true} +{"name": "max", "kind": "a", "args": [{"type": "varchar"}], "returns": "varchar", "nullable": true} +{"name": "max", "kind": "a", "args": [{"type": "nvarchar"}], "returns": "nvarchar", "nullable": true} +{"name": "max", "kind": "a", "args": [{"type": "char"}], "returns": "char", "nullable": true} +{"name": "max", "kind": "a", "args": [{"type": "nchar"}], "returns": "nchar", "nullable": true} +{"name": "getdate", "returns": "datetime"} +{"name": "getutcdate", "returns": "datetime"} +{"name": "sysdatetime", "returns": "datetime2"} +{"name": "sysutcdatetime", "returns": "datetime2"} +{"name": "sysdatetimeoffset", "returns": "datetimeoffset"} +{"name": "current_timestamp", "returns": "datetime"} +{"name": "newid", "returns": "uniqueidentifier"} +{"name": "newsequentialid", "returns": "uniqueidentifier"} +{"name": "scope_identity", "returns": "decimal"} +{"name": "len", "args": [{"type": "varchar"}], "returns": "int"} +{"name": "len", "args": [{"type": "nvarchar"}], "returns": "int"} +{"name": "datalength", "args": [{"type": "varchar"}], "returns": "int"} +{"name": "datalength", "args": [{"type": "nvarchar"}], "returns": "int"} +{"name": "datalength", "args": [{"type": "varbinary"}], "returns": "int"} +{"name": "lower", "args": [{"type": "varchar"}], "returns": "varchar"} +{"name": "lower", "args": [{"type": "nvarchar"}], "returns": "nvarchar"} +{"name": "upper", "args": [{"type": "varchar"}], "returns": "varchar"} +{"name": "upper", "args": [{"type": "nvarchar"}], "returns": "nvarchar"} +{"name": "ltrim", "args": [{"type": "varchar"}], "returns": "varchar"} +{"name": "ltrim", "args": [{"type": "nvarchar"}], "returns": "nvarchar"} +{"name": "rtrim", "args": [{"type": "varchar"}], "returns": "varchar"} +{"name": "rtrim", "args": [{"type": "nvarchar"}], "returns": "nvarchar"} +{"name": "trim", "args": [{"type": "varchar"}], "returns": "varchar"} +{"name": "trim", "args": [{"type": "nvarchar"}], "returns": "nvarchar"} diff --git a/internal/engine/mssql/dialect/types.jsonl b/internal/engine/mssql/dialect/types.jsonl new file mode 100644 index 0000000..e730686 --- /dev/null +++ b/internal/engine/mssql/dialect/types.jsonl @@ -0,0 +1,34 @@ +{"name": "bigint", "category": "N"} +{"name": "int", "category": "N", "aliases": ["integer"]} +{"name": "smallint", "category": "N"} +{"name": "tinyint", "category": "N"} +{"name": "bit", "category": "B"} +{"name": "decimal", "category": "N", "aliases": ["dec", "numeric"]} +{"name": "money", "category": "N"} +{"name": "smallmoney", "category": "N"} +{"name": "float", "category": "N", "aliases": ["double precision"]} +{"name": "real", "category": "N"} +{"name": "date", "category": "D"} +{"name": "datetime", "category": "D"} +{"name": "datetime2", "category": "D"} +{"name": "smalldatetime", "category": "D"} +{"name": "datetimeoffset", "category": "D"} +{"name": "time", "category": "D"} +{"name": "char", "category": "S", "aliases": ["character"]} +{"name": "varchar", "category": "S"} +{"name": "text", "category": "S"} +{"name": "nchar", "category": "S"} +{"name": "nvarchar", "category": "S"} +{"name": "ntext", "category": "S"} +{"name": "binary", "category": "S"} +{"name": "varbinary", "category": "S"} +{"name": "image", "category": "S"} +{"name": "uniqueidentifier", "category": "S"} +{"name": "xml", "category": "U"} +{"name": "json", "category": "U"} +{"name": "sql_variant", "category": "U"} +{"name": "rowversion", "category": "U", "aliases": ["timestamp"]} +{"name": "hierarchyid", "category": "U"} +{"name": "geography", "category": "U"} +{"name": "geometry", "category": "U"} +{"name": "vector", "category": "U"} diff --git a/internal/engine/mssql/parse.go b/internal/engine/mssql/parse.go new file mode 100644 index 0000000..e222708 --- /dev/null +++ b/internal/engine/mssql/parse.go @@ -0,0 +1,187 @@ +package mssql + +import ( + "bytes" + "context" + "io" + "unicode/utf8" + + "github.com/sqlc-dev/teesql/parser" + + "github.com/sqlc-dev/sqlc/internal/source" + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +func NewParser() *Parser { + return &Parser{} +} + +type Parser struct{} + +func (p *Parser) Parse(r io.Reader) ([]ast.Statement, error) { + blob, err := io.ReadAll(r) + if err != nil { + return nil, err + } + + ctx := context.Background() + script, err := parser.Parse(ctx, bytes.NewReader(blob)) + if err != nil { + return nil, err + } + + toByte := byteOffsets(blob) + + var stmts []ast.Statement + loc := 0 + for _, batch := range script.Batches { + for _, stmt := range batch.Statements { + start := loc + if frag, ok := stmt.(fragmented); ok && frag.Frag().HasSpan() { + if s := toByte(frag.Frag().StartOffset); s > start { + start = s + } + } + end := statementEnd(blob, start) + + converter := &cc{toByte: toByte} + out := converter.convert(stmt) + if _, ok := out.(*ast.TODO); ok { + loc = end + continue + } + + stmts = append(stmts, ast.Statement{ + Raw: &ast.RawStmt{ + Stmt: out, + StmtLocation: loc, + StmtLen: end - loc, + }, + }) + loc = end + } + } + + return stmts, nil +} + +// byteOffsets returns a function mapping a UTF-16 code-unit offset — how +// teesql records source spans, mirroring ScriptDom — to a byte offset in +// blob. For ASCII input the two are identical and the identity is returned. +func byteOffsets(blob []byte) func(int) int { + ascii := true + for _, b := range blob { + if b >= utf8.RuneSelf { + ascii = false + break + } + } + if ascii { + return func(off int) int { return off } + } + // Walk the blob once, recording the byte index at which each UTF-16 + // offset begins. + byteAt := make([]int, 0, len(blob)+1) + for i := 0; i < len(blob); { + r, size := utf8.DecodeRune(blob[i:]) + units := 1 + if r > 0xFFFF { + units = 2 + } + for u := 0; u < units; u++ { + byteAt = append(byteAt, i) + } + i += size + } + byteAt = append(byteAt, len(blob)) + return func(off int) int { + if off < 0 { + return 0 + } + if off >= len(byteAt) { + return len(blob) + } + return byteAt[off] + } +} + +// statementEnd scans from start for the semicolon ending the statement, +// skipping string literals, quoted and bracketed identifiers, and comments. +func statementEnd(blob []byte, start int) int { + for i := start; i < len(blob); i++ { + switch blob[i] { + case '\'', '"': + i = skipQuoted(blob, i) + case '[': + i = skipBracketed(blob, i) + case '-': + if i+1 < len(blob) && blob[i+1] == '-' { + i = skipLineComment(blob, i) + } + case '/': + if i+1 < len(blob) && blob[i+1] == '*' { + i = skipBlockComment(blob, i) + } + case ';': + return i + 1 + } + } + return len(blob) +} + +// skipQuoted skips a string literal or quoted identifier; T-SQL escapes the +// quote character by doubling it. +func skipQuoted(blob []byte, i int) int { + q := blob[i] + for j := i + 1; j < len(blob); j++ { + if blob[j] == q { + if j+1 < len(blob) && blob[j+1] == q { + j++ + continue + } + return j + } + } + return len(blob) - 1 +} + +// skipBracketed skips a [bracketed identifier]; a closing bracket is escaped +// by doubling it. +func skipBracketed(blob []byte, i int) int { + for j := i + 1; j < len(blob); j++ { + if blob[j] == ']' { + if j+1 < len(blob) && blob[j+1] == ']' { + j++ + continue + } + return j + } + } + return len(blob) - 1 +} + +func skipLineComment(blob []byte, i int) int { + for j := i; j < len(blob); j++ { + if blob[j] == '\n' { + return j + } + } + return len(blob) - 1 +} + +func skipBlockComment(blob []byte, i int) int { + for j := i + 2; j < len(blob); j++ { + if blob[j] == '*' && j+1 < len(blob) && blob[j+1] == '/' { + return j + 1 + } + } + return len(blob) - 1 +} + +// https://learn.microsoft.com/en-us/sql/t-sql/language-elements/comment-transact-sql +func (p *Parser) CommentSyntax() source.CommentSyntax { + return source.CommentSyntax{ + Dash: true, // -- comment + SlashStar: true, // /* comment */ + } +} diff --git a/internal/engine/mssql/reserved.go b/internal/engine/mssql/reserved.go new file mode 100644 index 0000000..e1a697a --- /dev/null +++ b/internal/engine/mssql/reserved.go @@ -0,0 +1,196 @@ +package mssql + +import "strings" + +// https://learn.microsoft.com/en-us/sql/t-sql/language-elements/reserved-keywords-transact-sql +func (p *Parser) IsReservedKeyword(s string) bool { + switch strings.ToLower(s) { + case "add": + case "all": + case "alter": + case "and": + case "any": + case "as": + case "asc": + case "authorization": + case "backup": + case "begin": + case "between": + case "break": + case "browse": + case "bulk": + case "by": + case "cascade": + case "case": + case "check": + case "checkpoint": + case "close": + case "clustered": + case "coalesce": + case "collate": + case "column": + case "commit": + case "compute": + case "constraint": + case "contains": + case "containstable": + case "continue": + case "convert": + case "create": + case "cross": + case "current": + case "current_date": + case "current_time": + case "current_timestamp": + case "current_user": + case "cursor": + case "database": + case "dbcc": + case "deallocate": + case "declare": + case "default": + case "delete": + case "deny": + case "desc": + case "disk": + case "distinct": + case "distributed": + case "double": + case "drop": + case "dump": + case "else": + case "end": + case "errlvl": + case "escape": + case "except": + case "exec": + case "execute": + case "exists": + case "exit": + case "external": + case "fetch": + case "file": + case "fillfactor": + case "for": + case "foreign": + case "freetext": + case "freetexttable": + case "from": + case "full": + case "function": + case "goto": + case "grant": + case "group": + case "having": + case "holdlock": + case "identity": + case "identity_insert": + case "identitycol": + case "if": + case "in": + case "index": + case "inner": + case "insert": + case "intersect": + case "into": + case "is": + case "join": + case "key": + case "kill": + case "left": + case "like": + case "lineno": + case "load": + case "merge": + case "national": + case "nocheck": + case "nonclustered": + case "not": + case "null": + case "nullif": + case "of": + case "off": + case "offsets": + case "on": + case "open": + case "opendatasource": + case "openquery": + case "openrowset": + case "openxml": + case "option": + case "or": + case "order": + case "outer": + case "over": + case "percent": + case "pivot": + case "plan": + case "precision": + case "primary": + case "print": + case "proc": + case "procedure": + case "public": + case "raiserror": + case "read": + case "readtext": + case "reconfigure": + case "references": + case "replication": + case "restore": + case "restrict": + case "return": + case "revert": + case "revoke": + case "right": + case "rollback": + case "rowcount": + case "rowguidcol": + case "rule": + case "save": + case "schema": + case "securityaudit": + case "select": + case "semantickeyphrasetable": + case "semanticsimilaritydetailstable": + case "semanticsimilaritytable": + case "session_user": + case "set": + case "setuser": + case "shutdown": + case "some": + case "statistics": + case "system_user": + case "table": + case "tablesample": + case "textsize": + case "then": + case "to": + case "top": + case "tran": + case "transaction": + case "trigger": + case "truncate": + case "try_convert": + case "tsequal": + case "union": + case "unique": + case "unpivot": + case "update": + case "updatetext": + case "use": + case "user": + case "values": + case "varying": + case "view": + case "waitfor": + case "when": + case "where": + case "while": + case "with": + case "writetext": + default: + return false + } + return true +} diff --git a/internal/engine/mssql/seed.go b/internal/engine/mssql/seed.go new file mode 100644 index 0000000..7ce732b --- /dev/null +++ b/internal/engine/mssql/seed.go @@ -0,0 +1,16 @@ +package mssql + +import ( + "embed" + + "github.com/sqlc-dev/sqlc/internal/core" + "github.com/sqlc-dev/sqlc/internal/core/seed" +) + +//go:embed dialect +var dialectFS embed.FS + +// Dialect returns the catalog option that seeds SQL Server's type system. +func Dialect() core.Option { + return seed.Dialect(dialectFS, "dialect") +} diff --git a/internal/engine/mssql/utils.go b/internal/engine/mssql/utils.go new file mode 100644 index 0000000..0675669 --- /dev/null +++ b/internal/engine/mssql/utils.go @@ -0,0 +1,65 @@ +package mssql + +import ( + "log" + "strings" + + tsql "github.com/sqlc-dev/teesql/ast" + + "github.com/sqlc-dev/sqlc/internal/debug" + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +// fragmented is satisfied by every teesql node via its embedded Fragment. +type fragmented interface { + Frag() *tsql.Fragment +} + +func todo(n tsql.Node) *ast.TODO { + if debug.Active { + log.Printf("mssql.convert: Unknown node type %T\n", n) + } + return &ast.TODO{} +} + +// identifier normalizes an identifier. T-SQL identifiers are +// case-insensitive under the default collations. +func identifier(id string) string { + return strings.ToLower(id) +} + +func NewIdentifier(t string) *ast.String { + return &ast.String{Str: identifier(t)} +} + +func identifierValue(id *tsql.Identifier) string { + if id == nil { + return "" + } + return identifier(id.Value) +} + +// schemaName returns the schema an object name qualifies it with. The "dbo" +// default schema maps to the catalog's default namespace, so it is treated +// as unqualified. +func schemaName(n *tsql.SchemaObjectName) string { + if n == nil || n.SchemaIdentifier == nil { + return "" + } + s := identifier(n.SchemaIdentifier.Value) + if s == "dbo" { + return "" + } + return s +} + +func parseTableName(n *tsql.SchemaObjectName) *ast.TableName { + if n == nil { + return &ast.TableName{} + } + return &ast.TableName{ + Schema: schemaName(n), + Name: identifierValue(n.BaseIdentifier), + } +} + diff --git a/internal/engine/postgresql/analyzer/analyze.go b/internal/engine/postgresql/analyzer/analyze.go new file mode 100644 index 0000000..c25dd81 --- /dev/null +++ b/internal/engine/postgresql/analyzer/analyze.go @@ -0,0 +1,322 @@ +package analyzer + +import ( + "context" + "errors" + "fmt" + "strings" + "sync" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" + "github.com/jackc/pgx/v5/pgxpool" + + core "github.com/sqlc-dev/sqlc/internal/analysis" + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/dbmanager" + "github.com/sqlc-dev/sqlc/internal/shfmt" + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/named" + "github.com/sqlc-dev/sqlc/internal/sql/sqlerr" + "github.com/sqlc-dev/sqlc/internal/sqlcdebug" +) + +var debugDatabases = sqlcdebug.New("databases") + +type Analyzer struct { + db config.Database + client dbmanager.Client + pool *pgxpool.Pool + replacer *shfmt.Replacer + formats sync.Map + columns sync.Map + tables sync.Map +} + +func New(client dbmanager.Client, db config.Database) *Analyzer { + return &Analyzer{ + db: db, + client: client, + replacer: shfmt.NewReplacer(nil), + } +} + +const columnQuery = ` +SELECT + pg_catalog.format_type(pg_attribute.atttypid, pg_attribute.atttypmod) AS data_type, + pg_attribute.attnotnull as not_null, + pg_attribute.attndims as array_dims +FROM + pg_catalog.pg_attribute +WHERE + attrelid = $1 + AND attnum = $2; +` + +const tableQuery = ` +SELECT + pg_class.relname as table_name, + pg_namespace.nspname as schema_name +FROM + pg_catalog.pg_class +JOIN + pg_catalog.pg_namespace ON pg_namespace.oid = pg_class.relnamespace +WHERE + pg_class.oid = $1; +` + +type pgTable struct { + TableName string `db:"table_name"` + SchemaName string `db:"schema_name"` +} + +// Cache these types in memory +func (a *Analyzer) tableInfo(ctx context.Context, oid uint32) (*pgTable, error) { + ctbl, ok := a.tables.Load(oid) + if ok { + return ctbl.(*pgTable), nil + } + rows, err := a.pool.Query(ctx, tableQuery, oid) + if err != nil { + return nil, err + } + tbl, err := pgx.CollectOneRow(rows, pgx.RowToStructByName[pgTable]) + if err != nil { + return nil, err + } + a.tables.Store(oid, &tbl) + return &tbl, nil +} + +type pgColumn struct { + DataType string `db:"data_type"` + NotNull bool `db:"not_null"` + ArrayDims int `db:"array_dims"` +} + +type columnKey struct { + OID uint32 + Attr uint16 +} + +// Cache these types in memory +func (a *Analyzer) columnInfo(ctx context.Context, field pgconn.FieldDescription) (*pgColumn, error) { + key := columnKey{field.TableOID, field.TableAttributeNumber} + cinfo, ok := a.columns.Load(key) + if ok { + return cinfo.(*pgColumn), nil + } + rows, err := a.pool.Query(ctx, columnQuery, field.TableOID, int16(field.TableAttributeNumber)) + if err != nil { + return nil, err + } + col, err := pgx.CollectOneRow(rows, pgx.RowToStructByName[pgColumn]) + if err != nil { + return nil, err + } + a.columns.Store(key, &col) + return &col, nil +} + +type formatKey struct { + OID uint32 + Modified int32 +} + +// TODO: Use PGX to do the lookup for basic OID types +func (a *Analyzer) formatType(ctx context.Context, oid uint32, modifier int32) (string, error) { + key := formatKey{oid, modifier} + ftyp, ok := a.formats.Load(key) + if ok { + return ftyp.(string), nil + } + rows, err := a.pool.Query(ctx, `SELECT format_type($1, $2)`, oid, modifier) + if err != nil { + return "", err + } + dt, err := pgx.CollectOneRow(rows, pgx.RowTo[string]) + if err != nil { + return "", err + } + a.formats.Store(key, dt) + return dt, err +} + +// TODO: This is bad +func rewriteType(dt string) string { + switch { + case strings.HasPrefix(dt, "character("): + return "pg_catalog.bpchar" + case strings.HasPrefix(dt, "character varying"): + return "pg_catalog.varchar" + case strings.HasPrefix(dt, "bit varying"): + return "pg_catalog.varbit" + case strings.HasPrefix(dt, "bit("): + return "pg_catalog.bit" + } + switch dt { + case "bpchar": + return "pg_catalog.bpchar" + case "timestamp without time zone": + return "pg_catalog.timestamp" + case "timestamp with time zone": + return "pg_catalog.timestamptz" + case "time without time zone": + return "pg_catalog.time" + case "time with time zone": + return "pg_catalog.timetz" + } + return dt +} + +func parseType(dt string) (string, bool, int) { + size := 0 + for { + trimmed := strings.TrimSuffix(dt, "[]") + if trimmed == dt { + return rewriteType(dt), size > 0, size + } + size += 1 + dt = trimmed + } +} + +// Don't create a database per query +func (a *Analyzer) Analyze(ctx context.Context, n ast.Node, query string, migrations []string, ps *named.ParamSet) (*core.Analysis, error) { + extractSqlErr := func(e error) error { + var pgErr *pgconn.PgError + if errors.As(e, &pgErr) { + return &sqlerr.Error{ + Code: pgErr.Code, + Message: pgErr.Message, + Location: max(n.Pos()+int(pgErr.Position)-1, 0), + } + } + return e + } + + if a.pool == nil { + var uri string + if a.db.Managed { + if a.client == nil { + return nil, fmt.Errorf("client is nil") + } + edb, err := a.client.CreateDatabase(ctx, &dbmanager.CreateDatabaseRequest{ + Engine: "postgresql", + Migrations: migrations, + }) + if err != nil { + return nil, err + } + uri = edb.Uri + } else if debugDatabases.Value() == "managed" { + return nil, fmt.Errorf("database: connections disabled via SQLCDEBUG=databases=managed") + } else { + uri = a.replacer.Replace(a.db.URI) + } + conf, err := pgxpool.ParseConfig(uri) + if err != nil { + return nil, err + } + pool, err := pgxpool.NewWithConfig(ctx, conf) + if err != nil { + return nil, err + } + a.pool = pool + } + + c, err := a.pool.Acquire(ctx) + if err != nil { + return nil, err + } + defer c.Release() + + // TODO: Pick a random name + desc, err := c.Conn().Prepare(ctx, "foo", query) + if err != nil { + return nil, extractSqlErr(err) + } + + if err := c.Conn().Deallocate(ctx, "foo"); err != nil { + return nil, err + } + + var result core.Analysis + for _, field := range desc.Fields { + if field.TableOID > 0 { + col, err := a.columnInfo(ctx, field) + if err != nil { + return nil, err + } + // debug.Dump(i, field, col) + tbl, err := a.tableInfo(ctx, field.TableOID) + if err != nil { + return nil, err + } + dt, isArray, dims := parseType(col.DataType) + notNull := col.NotNull + name := field.Name + result.Columns = append(result.Columns, &core.Column{ + Name: name, + OriginalName: field.Name, + DataType: dt, + NotNull: notNull, + IsArray: isArray, + ArrayDims: int32(max(col.ArrayDims, dims)), + Table: &core.Identifier{ + Schema: tbl.SchemaName, + Name: tbl.TableName, + }, + }) + } else { + dataType, err := a.formatType(ctx, field.DataTypeOID, field.TypeModifier) + if err != nil { + return nil, err + } + // debug.Dump(i, field, dataType) + notNull := false + name := field.Name + dt, isArray, dims := parseType(dataType) + result.Columns = append(result.Columns, &core.Column{ + Name: name, + OriginalName: field.Name, + DataType: dt, + NotNull: notNull, + IsArray: isArray, + ArrayDims: int32(dims), + }) + } + } + + for i, oid := range desc.ParamOIDs { + dataType, err := a.formatType(ctx, oid, -1) + if err != nil { + return nil, err + } + notNull := false + dt, isArray, dims := parseType(dataType) + name := "" + if ps != nil { + name, _ = ps.NameFor(i + 1) + } + result.Params = append(result.Params, &core.Parameter{ + Number: int32(i + 1), + Column: &core.Column{ + Name: name, + DataType: dt, + IsArray: isArray, + ArrayDims: int32(dims), + NotNull: notNull, + }, + }) + } + + return &result, nil +} + +func (a *Analyzer) Close(_ context.Context) error { + if a.pool != nil { + a.pool.Close() + } + return nil +} diff --git a/internal/engine/postgresql/catalog.go b/internal/engine/postgresql/catalog.go new file mode 100644 index 0000000..08049b7 --- /dev/null +++ b/internal/engine/postgresql/catalog.go @@ -0,0 +1,40 @@ +package postgresql + +import ( + "github.com/sqlc-dev/sqlc/internal/core/seed" + "github.com/sqlc-dev/sqlc/internal/sql/catalog" +) + +func NewCatalog() *catalog.Catalog { + c := catalog.New("public") + c.Schemas = append(c.Schemas, pgTemp()) + c.Schemas = append(c.Schemas, genPGCatalog()) + c.Schemas = append(c.Schemas, genInformationSchema()) + c.SearchPath = []string{"pg_catalog"} + c.LoadExtension = loadExtension + return c +} + +// genPGCatalog and genInformationSchema build the schemas sqlc knows +// PostgreSQL by. Both read the dialect directory, which goldeneye writes, +// and which the analysis core seeds its catalog from as well. +func genPGCatalog() *catalog.Schema { + return systemSchema("pg_catalog", pgCatalogFuncs()) +} + +func genInformationSchema() *catalog.Schema { + return systemSchema("information_schema", nil) +} + +// systemSchema builds a schema from the relations recorded for it. The tables +// are read fresh each time, because a catalog is free to change the schemas it +// was built with. +func systemSchema(name string, funcs []*catalog.Function) *catalog.Schema { + tables, err := seed.Relations(dialectFS, "dialect", name) + if err != nil { + // The relations are embedded in the binary: a failure here means sqlc + // was built from a broken tree, which no caller can do anything about. + panic(err) + } + return &catalog.Schema{Name: name, Funcs: funcs, Tables: tables} +} diff --git a/internal/engine/postgresql/catalog_test.go b/internal/engine/postgresql/catalog_test.go new file mode 100644 index 0000000..875ea7e --- /dev/null +++ b/internal/engine/postgresql/catalog_test.go @@ -0,0 +1,170 @@ +package postgresql + +import ( + "errors" + "strconv" + "strings" + "testing" + + "github.com/sqlc-dev/sqlc/internal/sql/sqlerr" + + "github.com/google/go-cmp/cmp" +) + +func TestUpdateErrors(t *testing.T) { + p := NewParser() + for i, tc := range []struct { + stmt string + err *sqlerr.Error + }{ + { + ` + CREATE TABLE foo (); + CREATE TABLE foo (); + `, + sqlerr.RelationExists("foo"), + }, + { + ` + CREATE TYPE foo AS ENUM ('bar'); + CREATE TYPE foo AS ENUM ('bar'); + `, + sqlerr.TypeExists("foo"), + }, + { + ` + DROP TABLE foo; + `, + sqlerr.RelationNotFound("foo"), + }, + { + ` + DROP TYPE foo; + `, + sqlerr.TypeNotFound("foo"), + }, + { + ` + CREATE TABLE foo (); + CREATE TABLE bar (); + ALTER TABLE foo RENAME TO bar; + `, + sqlerr.RelationExists("bar"), + }, + { + ` + ALTER TABLE foo RENAME TO bar; + `, + sqlerr.RelationNotFound("foo"), + }, + { + ` + CREATE TABLE foo (); + ALTER TABLE foo ADD COLUMN bar text; + ALTER TABLE foo ADD COLUMN bar text; + `, + sqlerr.ColumnExists("foo", "bar"), + }, + { + ` + CREATE TABLE foo (); + ALTER TABLE foo DROP COLUMN bar; + `, + sqlerr.ColumnNotFound("foo", "bar"), + }, + { + ` + CREATE TABLE foo (); + ALTER TABLE foo ALTER COLUMN bar SET NOT NULL; + `, + sqlerr.ColumnNotFound("foo", "bar"), + }, + { + ` + CREATE TABLE foo (); + ALTER TABLE foo ALTER COLUMN bar DROP NOT NULL; + `, + sqlerr.ColumnNotFound("foo", "bar"), + }, + { + ` + CREATE SCHEMA foo; + CREATE SCHEMA foo; + `, + sqlerr.SchemaExists("foo"), + }, + { + ` + ALTER TABLE foo.baz SET SCHEMA bar; + `, + sqlerr.SchemaNotFound("foo"), + }, + { + ` + CREATE SCHEMA foo; + ALTER TABLE foo.baz SET SCHEMA bar; + `, + sqlerr.RelationNotFound("baz"), + }, + { + ` + CREATE SCHEMA foo; + CREATE TABLE foo.baz (); + ALTER TABLE foo.baz SET SCHEMA bar; + `, + sqlerr.SchemaNotFound("bar"), + }, + { + ` + DROP SCHEMA bar; + `, + sqlerr.SchemaNotFound("bar"), + }, + { + ` + ALTER TABLE foo RENAME bar TO baz; + `, + sqlerr.RelationNotFound("foo"), + }, + { + ` + CREATE TABLE foo (); + ALTER TABLE foo RENAME bar TO baz; + `, + sqlerr.ColumnNotFound("foo", "bar"), + }, + { + ` + CREATE TABLE foo (bar text, baz text); + ALTER TABLE foo RENAME bar TO baz; + `, + sqlerr.ColumnExists("foo", "baz"), + }, + } { + test := tc + t.Run(strconv.Itoa(i), func(t *testing.T) { + stmts, err := p.Parse(strings.NewReader(test.stmt)) + if err != nil { + t.Log(test.stmt) + t.Fatal(err) + } + + c := NewCatalog() + err = c.Build(stmts) + if err == nil { + t.Log(test.stmt) + t.Fatal("err was nil") + } + + var actual *sqlerr.Error + if !errors.As(err, &actual) { + t.Fatalf("err is not *sqlerr.Error: %#v", err) + } + + if diff := cmp.Diff(test.err.Error(), actual.Error()); diff != "" { + t.Log(test.stmt) + t.Errorf("error mismatch: \n%s", diff) + } + }) + } +} diff --git a/internal/engine/postgresql/convert.go b/internal/engine/postgresql/convert.go new file mode 100644 index 0000000..586ebd7 --- /dev/null +++ b/internal/engine/postgresql/convert.go @@ -0,0 +1,3728 @@ +package postgresql + +import ( + "fmt" + + pg "github.com/sqlc-dev/oliphant" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +func convertFuncParamMode(m pg.FunctionParameterMode) (ast.FuncParamMode, error) { + switch m { + case pg.FunctionParameterMode_FUNC_PARAM_IN: + return ast.FuncParamIn, nil + case pg.FunctionParameterMode_FUNC_PARAM_OUT: + return ast.FuncParamOut, nil + case pg.FunctionParameterMode_FUNC_PARAM_INOUT: + return ast.FuncParamInOut, nil + case pg.FunctionParameterMode_FUNC_PARAM_VARIADIC: + return ast.FuncParamVariadic, nil + case pg.FunctionParameterMode_FUNC_PARAM_TABLE: + return ast.FuncParamTable, nil + case pg.FunctionParameterMode_FUNC_PARAM_DEFAULT: + return ast.FuncParamDefault, nil + default: + return -1, fmt.Errorf("parse func param: invalid mode %v", m) + } +} + +func convertSubLinkType(t pg.SubLinkType) (ast.SubLinkType, error) { + switch t { + case pg.SubLinkType_EXISTS_SUBLINK: + return ast.EXISTS_SUBLINK, nil + case pg.SubLinkType_ALL_SUBLINK: + return ast.ALL_SUBLINK, nil + case pg.SubLinkType_ANY_SUBLINK: + return ast.ANY_SUBLINK, nil + case pg.SubLinkType_ROWCOMPARE_SUBLINK: + return ast.ROWCOMPARE_SUBLINK, nil + case pg.SubLinkType_EXPR_SUBLINK: + return ast.EXPR_SUBLINK, nil + case pg.SubLinkType_MULTIEXPR_SUBLINK: + return ast.MULTIEXPR_SUBLINK, nil + case pg.SubLinkType_ARRAY_SUBLINK: + return ast.ARRAY_SUBLINK, nil + case pg.SubLinkType_CTE_SUBLINK: + return ast.CTE_SUBLINK, nil + default: + return 0, fmt.Errorf("parse sublink type: unknown type %s", t) + } +} + +func convertSetOperation(t pg.SetOperation) (ast.SetOperation, error) { + switch t { + case pg.SetOperation_SETOP_NONE: + return ast.None, nil + case pg.SetOperation_SETOP_UNION: + return ast.Union, nil + case pg.SetOperation_SETOP_INTERSECT: + return ast.Intersect, nil + case pg.SetOperation_SETOP_EXCEPT: + return ast.Except, nil + default: + return 0, fmt.Errorf("parse set operation: unknown type %s", t) + } +} + +func convertList(l *pg.List) *ast.List { + out := &ast.List{} + for _, item := range l.Items { + out.Items = append(out.Items, convertNode(item)) + } + return out +} + +func convertSlice(nodes []*pg.Node) *ast.List { + out := &ast.List{} + for _, n := range nodes { + out.Items = append(out.Items, convertNode(n)) + } + return out +} + +func convert(node *pg.Node) (ast.Node, error) { + return convertNode(node), nil +} + +func convertA_ArrayExpr(n *pg.A_ArrayExpr) *ast.A_ArrayExpr { + if n == nil { + return nil + } + return &ast.A_ArrayExpr{ + Elements: convertSlice(n.Elements), + Location: int(n.Location), + } +} + +func convertA_Const(n *pg.A_Const) *ast.A_Const { + if n == nil { + return nil + } + var val ast.Node + if n.Isnull { + val = &ast.Null{} + } else { + switch v := n.Val.(type) { + case *pg.A_Const_Boolval: + val = convertBoolean(v.Boolval) + case *pg.A_Const_Bsval: + val = convertBitString(v.Bsval) + case *pg.A_Const_Fval: + val = convertFloat(v.Fval) + case *pg.A_Const_Ival: + val = convertInteger(v.Ival) + case *pg.A_Const_Sval: + val = convertString(v.Sval) + } + } + return &ast.A_Const{ + Val: val, + Location: int(n.Location), + } +} + +func convertA_Expr(n *pg.A_Expr) *ast.A_Expr { + if n == nil { + return nil + } + return &ast.A_Expr{ + Kind: ast.A_Expr_Kind(n.Kind), + Name: convertSlice(n.Name), + Lexpr: convertNode(n.Lexpr), + Rexpr: convertNode(n.Rexpr), + Location: int(n.Location), + } +} + +func convertA_Indices(n *pg.A_Indices) *ast.A_Indices { + if n == nil { + return nil + } + return &ast.A_Indices{ + IsSlice: n.IsSlice, + Lidx: convertNode(n.Lidx), + Uidx: convertNode(n.Uidx), + } +} + +func convertA_Indirection(n *pg.A_Indirection) *ast.A_Indirection { + if n == nil { + return nil + } + return &ast.A_Indirection{ + Arg: convertNode(n.Arg), + Indirection: convertSlice(n.Indirection), + } +} + +func convertA_Star(n *pg.A_Star) *ast.A_Star { + if n == nil { + return nil + } + return &ast.A_Star{} +} + +func convertAccessPriv(n *pg.AccessPriv) *ast.AccessPriv { + if n == nil { + return nil + } + return &ast.AccessPriv{ + PrivName: makeString(n.PrivName), + Cols: convertSlice(n.Cols), + } +} + +func convertAggref(n *pg.Aggref) *ast.Aggref { + if n == nil { + return nil + } + return &ast.Aggref{ + Xpr: convertNode(n.Xpr), + Aggfnoid: ast.Oid(n.Aggfnoid), + Aggtype: ast.Oid(n.Aggtype), + Aggcollid: ast.Oid(n.Aggcollid), + Inputcollid: ast.Oid(n.Inputcollid), + Aggargtypes: convertSlice(n.Aggargtypes), + Aggdirectargs: convertSlice(n.Aggdirectargs), + Args: convertSlice(n.Args), + Aggorder: convertSlice(n.Aggorder), + Aggdistinct: convertSlice(n.Aggdistinct), + Aggfilter: convertNode(n.Aggfilter), + Aggstar: n.Aggstar, + Aggvariadic: n.Aggvariadic, + Aggkind: makeByte(n.Aggkind), + Agglevelsup: ast.Index(n.Agglevelsup), + Aggsplit: ast.AggSplit(n.Aggsplit), + Location: int(n.Location), + } +} + +func convertAlias(n *pg.Alias) *ast.Alias { + if n == nil { + return nil + } + return &ast.Alias{ + Aliasname: makeString(n.Aliasname), + Colnames: convertSlice(n.Colnames), + } +} + +func convertAlterCollationStmt(n *pg.AlterCollationStmt) *ast.AlterCollationStmt { + if n == nil { + return nil + } + return &ast.AlterCollationStmt{ + Collname: convertSlice(n.Collname), + } +} + +func convertAlterDatabaseSetStmt(n *pg.AlterDatabaseSetStmt) *ast.AlterDatabaseSetStmt { + if n == nil { + return nil + } + return &ast.AlterDatabaseSetStmt{ + Dbname: makeString(n.Dbname), + Setstmt: convertVariableSetStmt(n.Setstmt), + } +} + +func convertAlterDatabaseStmt(n *pg.AlterDatabaseStmt) *ast.AlterDatabaseStmt { + if n == nil { + return nil + } + return &ast.AlterDatabaseStmt{ + Dbname: makeString(n.Dbname), + Options: convertSlice(n.Options), + } +} + +func convertAlterDefaultPrivilegesStmt(n *pg.AlterDefaultPrivilegesStmt) *ast.AlterDefaultPrivilegesStmt { + if n == nil { + return nil + } + return &ast.AlterDefaultPrivilegesStmt{ + Options: convertSlice(n.Options), + Action: convertGrantStmt(n.Action), + } +} + +func convertAlterDomainStmt(n *pg.AlterDomainStmt) *ast.AlterDomainStmt { + if n == nil { + return nil + } + return &ast.AlterDomainStmt{ + Subtype: makeByte(n.Subtype), + TypeName: convertSlice(n.TypeName), + Name: makeString(n.Name), + Def: convertNode(n.Def), + Behavior: ast.DropBehavior(n.Behavior), + MissingOk: n.MissingOk, + } +} + +func convertAlterEnumStmt(n *pg.AlterEnumStmt) *ast.AlterEnumStmt { + if n == nil { + return nil + } + return &ast.AlterEnumStmt{ + TypeName: convertSlice(n.TypeName), + OldVal: makeString(n.OldVal), + NewVal: makeString(n.NewVal), + NewValNeighbor: makeString(n.NewValNeighbor), + NewValIsAfter: n.NewValIsAfter, + SkipIfNewValExists: n.SkipIfNewValExists, + } +} + +func convertAlterEventTrigStmt(n *pg.AlterEventTrigStmt) *ast.AlterEventTrigStmt { + if n == nil { + return nil + } + return &ast.AlterEventTrigStmt{ + Trigname: makeString(n.Trigname), + Tgenabled: makeByte(n.Tgenabled), + } +} + +func convertAlterExtensionContentsStmt(n *pg.AlterExtensionContentsStmt) *ast.AlterExtensionContentsStmt { + if n == nil { + return nil + } + return &ast.AlterExtensionContentsStmt{ + Extname: makeString(n.Extname), + Action: int(n.Action), + Objtype: ast.ObjectType(n.Objtype), + Object: convertNode(n.Object), + } +} + +func convertAlterExtensionStmt(n *pg.AlterExtensionStmt) *ast.AlterExtensionStmt { + if n == nil { + return nil + } + return &ast.AlterExtensionStmt{ + Extname: makeString(n.Extname), + Options: convertSlice(n.Options), + } +} + +func convertAlterFdwStmt(n *pg.AlterFdwStmt) *ast.AlterFdwStmt { + if n == nil { + return nil + } + return &ast.AlterFdwStmt{ + Fdwname: makeString(n.Fdwname), + FuncOptions: convertSlice(n.FuncOptions), + Options: convertSlice(n.Options), + } +} + +func convertAlterForeignServerStmt(n *pg.AlterForeignServerStmt) *ast.AlterForeignServerStmt { + if n == nil { + return nil + } + return &ast.AlterForeignServerStmt{ + Servername: makeString(n.Servername), + Version: makeString(n.Version), + Options: convertSlice(n.Options), + HasVersion: n.HasVersion, + } +} + +func convertAlterFunctionStmt(n *pg.AlterFunctionStmt) *ast.AlterFunctionStmt { + if n == nil { + return nil + } + return &ast.AlterFunctionStmt{ + Func: convertObjectWithArgs(n.Func), + Actions: convertSlice(n.Actions), + } +} + +func convertAlterObjectDependsStmt(n *pg.AlterObjectDependsStmt) *ast.AlterObjectDependsStmt { + if n == nil { + return nil + } + return &ast.AlterObjectDependsStmt{ + ObjectType: ast.ObjectType(n.ObjectType), + Relation: convertRangeVar(n.Relation), + Object: convertNode(n.Object), + Extname: convertString(n.Extname), + } +} + +func convertAlterObjectSchemaStmt(n *pg.AlterObjectSchemaStmt) *ast.AlterObjectSchemaStmt { + if n == nil { + return nil + } + return &ast.AlterObjectSchemaStmt{ + ObjectType: ast.ObjectType(n.ObjectType), + Relation: convertRangeVar(n.Relation), + Object: convertNode(n.Object), + Newschema: makeString(n.Newschema), + MissingOk: n.MissingOk, + } +} + +func convertAlterOpFamilyStmt(n *pg.AlterOpFamilyStmt) *ast.AlterOpFamilyStmt { + if n == nil { + return nil + } + return &ast.AlterOpFamilyStmt{ + Opfamilyname: convertSlice(n.Opfamilyname), + Amname: makeString(n.Amname), + IsDrop: n.IsDrop, + Items: convertSlice(n.Items), + } +} + +func convertAlterOperatorStmt(n *pg.AlterOperatorStmt) *ast.AlterOperatorStmt { + if n == nil { + return nil + } + return &ast.AlterOperatorStmt{ + Opername: convertObjectWithArgs(n.Opername), + Options: convertSlice(n.Options), + } +} + +func convertAlterOwnerStmt(n *pg.AlterOwnerStmt) *ast.AlterOwnerStmt { + if n == nil { + return nil + } + return &ast.AlterOwnerStmt{ + ObjectType: ast.ObjectType(n.ObjectType), + Relation: convertRangeVar(n.Relation), + Object: convertNode(n.Object), + Newowner: convertRoleSpec(n.Newowner), + } +} + +func convertAlterPolicyStmt(n *pg.AlterPolicyStmt) *ast.AlterPolicyStmt { + if n == nil { + return nil + } + return &ast.AlterPolicyStmt{ + PolicyName: makeString(n.PolicyName), + Table: convertRangeVar(n.Table), + Roles: convertSlice(n.Roles), + Qual: convertNode(n.Qual), + WithCheck: convertNode(n.WithCheck), + } +} + +func convertAlterPublicationStmt(n *pg.AlterPublicationStmt) *ast.AlterPublicationStmt { + if n == nil { + return nil + } + return &ast.AlterPublicationStmt{ + Pubname: makeString(n.Pubname), + Options: convertSlice(n.Options), + Tables: convertSlice(n.Pubobjects), + ForAllTables: n.ForAllTables, + TableAction: ast.DefElemAction(n.Action), + } +} + +func convertAlterRoleSetStmt(n *pg.AlterRoleSetStmt) *ast.AlterRoleSetStmt { + if n == nil { + return nil + } + return &ast.AlterRoleSetStmt{ + Role: convertRoleSpec(n.Role), + Database: makeString(n.Database), + Setstmt: convertVariableSetStmt(n.Setstmt), + } +} + +func convertAlterRoleStmt(n *pg.AlterRoleStmt) *ast.AlterRoleStmt { + if n == nil { + return nil + } + return &ast.AlterRoleStmt{ + Role: convertRoleSpec(n.Role), + Options: convertSlice(n.Options), + Action: int(n.Action), + } +} + +func convertAlterSeqStmt(n *pg.AlterSeqStmt) *ast.AlterSeqStmt { + if n == nil { + return nil + } + return &ast.AlterSeqStmt{ + Sequence: convertRangeVar(n.Sequence), + Options: convertSlice(n.Options), + ForIdentity: n.ForIdentity, + MissingOk: n.MissingOk, + } +} + +func convertAlterSubscriptionStmt(n *pg.AlterSubscriptionStmt) *ast.AlterSubscriptionStmt { + if n == nil { + return nil + } + return &ast.AlterSubscriptionStmt{ + Kind: ast.AlterSubscriptionType(n.Kind), + Subname: makeString(n.Subname), + Conninfo: makeString(n.Conninfo), + Publication: convertSlice(n.Publication), + Options: convertSlice(n.Options), + } +} + +func convertAlterSystemStmt(n *pg.AlterSystemStmt) *ast.AlterSystemStmt { + if n == nil { + return nil + } + return &ast.AlterSystemStmt{ + Setstmt: convertVariableSetStmt(n.Setstmt), + } +} + +func convertAlterTSConfigurationStmt(n *pg.AlterTSConfigurationStmt) *ast.AlterTSConfigurationStmt { + if n == nil { + return nil + } + return &ast.AlterTSConfigurationStmt{ + Kind: ast.AlterTSConfigType(n.Kind), + Cfgname: convertSlice(n.Cfgname), + Tokentype: convertSlice(n.Tokentype), + Dicts: convertSlice(n.Dicts), + Override: n.Override, + Replace: n.Replace, + MissingOk: n.MissingOk, + } +} + +func convertAlterTSDictionaryStmt(n *pg.AlterTSDictionaryStmt) *ast.AlterTSDictionaryStmt { + if n == nil { + return nil + } + return &ast.AlterTSDictionaryStmt{ + Dictname: convertSlice(n.Dictname), + Options: convertSlice(n.Options), + } +} + +func convertAlterTableCmd(n *pg.AlterTableCmd) *ast.AlterTableCmd { + if n == nil { + return nil + } + def := convertNode(n.Def) + columnDef := def.(*ast.ColumnDef) + return &ast.AlterTableCmd{ + Subtype: ast.AlterTableType(n.Subtype), + Name: makeString(n.Name), + Newowner: convertRoleSpec(n.Newowner), + Def: columnDef, + Behavior: ast.DropBehavior(n.Behavior), + MissingOk: n.MissingOk, + } +} + +func convertAlterTableMoveAllStmt(n *pg.AlterTableMoveAllStmt) *ast.AlterTableMoveAllStmt { + if n == nil { + return nil + } + return &ast.AlterTableMoveAllStmt{ + OrigTablespacename: makeString(n.OrigTablespacename), + Objtype: ast.ObjectType(n.Objtype), + Roles: convertSlice(n.Roles), + NewTablespacename: makeString(n.NewTablespacename), + Nowait: n.Nowait, + } +} + +func convertAlterTableSpaceOptionsStmt(n *pg.AlterTableSpaceOptionsStmt) *ast.AlterTableSpaceOptionsStmt { + if n == nil { + return nil + } + return &ast.AlterTableSpaceOptionsStmt{ + Tablespacename: makeString(n.Tablespacename), + Options: convertSlice(n.Options), + IsReset: n.IsReset, + } +} + +func convertAlterTableStmt(n *pg.AlterTableStmt) *ast.AlterTableStmt { + if n == nil { + return nil + } + return &ast.AlterTableStmt{ + Relation: convertRangeVar(n.Relation), + Cmds: convertSlice(n.Cmds), + Relkind: ast.ObjectType(n.Objtype), + MissingOk: n.MissingOk, + } +} + +func convertAlterUserMappingStmt(n *pg.AlterUserMappingStmt) *ast.AlterUserMappingStmt { + if n == nil { + return nil + } + return &ast.AlterUserMappingStmt{ + User: convertRoleSpec(n.User), + Servername: makeString(n.Servername), + Options: convertSlice(n.Options), + } +} + +func convertAlternativeSubPlan(n *pg.AlternativeSubPlan) *ast.AlternativeSubPlan { + if n == nil { + return nil + } + return &ast.AlternativeSubPlan{ + Xpr: convertNode(n.Xpr), + Subplans: convertSlice(n.Subplans), + } +} + +func convertArrayCoerceExpr(n *pg.ArrayCoerceExpr) *ast.ArrayCoerceExpr { + if n == nil { + return nil + } + return &ast.ArrayCoerceExpr{ + Xpr: convertNode(n.Xpr), + Arg: convertNode(n.Arg), + Resulttype: ast.Oid(n.Resulttype), + Resulttypmod: n.Resulttypmod, + Resultcollid: ast.Oid(n.Resultcollid), + Coerceformat: ast.CoercionForm(n.Coerceformat), + Location: int(n.Location), + } +} + +func convertArrayExpr(n *pg.ArrayExpr) *ast.ArrayExpr { + if n == nil { + return nil + } + return &ast.ArrayExpr{ + Xpr: convertNode(n.Xpr), + ArrayTypeid: ast.Oid(n.ArrayTypeid), + ArrayCollid: ast.Oid(n.ArrayCollid), + ElementTypeid: ast.Oid(n.ElementTypeid), + Elements: convertSlice(n.Elements), + Multidims: n.Multidims, + Location: int(n.Location), + } +} + +func convertBitString(n *pg.BitString) *ast.BitString { + if n == nil { + return nil + } + return &ast.BitString{ + Str: n.Bsval, + } +} + +func convertBoolExpr(n *pg.BoolExpr) *ast.BoolExpr { + if n == nil { + return nil + } + return &ast.BoolExpr{ + Xpr: convertNode(n.Xpr), + Boolop: ast.BoolExprType(n.Boolop), + Args: convertSlice(n.Args), + Location: int(n.Location), + } +} + +func convertBoolean(n *pg.Boolean) *ast.Boolean { + if n == nil { + return nil + } + return &ast.Boolean{ + Boolval: n.Boolval, + } +} + +func convertBooleanTest(n *pg.BooleanTest) *ast.BooleanTest { + if n == nil { + return nil + } + return &ast.BooleanTest{ + Xpr: convertNode(n.Xpr), + Arg: convertNode(n.Arg), + Booltesttype: ast.BoolTestType(n.Booltesttype), + Location: int(n.Location), + } +} + +func convertCallStmt(n *pg.CallStmt) *ast.CallStmt { + if n == nil { + return nil + } + rel, err := parseRelationFromNodes(n.Funccall.Funcname) + if err != nil { + // TODO: How should we handle errors? + panic(err) + } + + return &ast.CallStmt{ + FuncCall: &ast.FuncCall{ + Func: rel.FuncName(), + Funcname: convertSlice(n.Funccall.Funcname), + Args: convertSlice(n.Funccall.Args), + AggOrder: convertSlice(n.Funccall.AggOrder), + AggFilter: convertNode(n.Funccall.AggFilter), + AggWithinGroup: n.Funccall.AggWithinGroup, + AggStar: n.Funccall.AggStar, + AggDistinct: n.Funccall.AggDistinct, + FuncVariadic: n.Funccall.FuncVariadic, + Over: convertWindowDef(n.Funccall.Over), + Location: int(n.Funccall.Location), + }, + } +} + +func convertCaseExpr(n *pg.CaseExpr) *ast.CaseExpr { + if n == nil { + return nil + } + return &ast.CaseExpr{ + Xpr: convertNode(n.Xpr), + Casetype: ast.Oid(n.Casetype), + Casecollid: ast.Oid(n.Casecollid), + Arg: convertNode(n.Arg), + Args: convertSlice(n.Args), + Defresult: convertNode(n.Defresult), + Location: int(n.Location), + } +} + +func convertCaseTestExpr(n *pg.CaseTestExpr) *ast.CaseTestExpr { + if n == nil { + return nil + } + return &ast.CaseTestExpr{ + Xpr: convertNode(n.Xpr), + TypeId: ast.Oid(n.TypeId), + TypeMod: n.TypeMod, + Collation: ast.Oid(n.Collation), + } +} + +func convertCaseWhen(n *pg.CaseWhen) *ast.CaseWhen { + if n == nil { + return nil + } + return &ast.CaseWhen{ + Xpr: convertNode(n.Xpr), + Expr: convertNode(n.Expr), + Result: convertNode(n.Result), + Location: int(n.Location), + } +} + +func convertCheckPointStmt(n *pg.CheckPointStmt) *ast.CheckPointStmt { + if n == nil { + return nil + } + return &ast.CheckPointStmt{} +} + +func convertClosePortalStmt(n *pg.ClosePortalStmt) *ast.ClosePortalStmt { + if n == nil { + return nil + } + return &ast.ClosePortalStmt{ + Portalname: makeString(n.Portalname), + } +} + +func convertClusterStmt(n *pg.ClusterStmt) *ast.ClusterStmt { + if n == nil { + return nil + } + return &ast.ClusterStmt{ + Relation: convertRangeVar(n.Relation), + Indexname: makeString(n.Indexname), + } +} + +func convertCoalesceExpr(n *pg.CoalesceExpr) *ast.CoalesceExpr { + if n == nil { + return nil + } + return &ast.CoalesceExpr{ + Xpr: convertNode(n.Xpr), + Coalescetype: ast.Oid(n.Coalescetype), + Coalescecollid: ast.Oid(n.Coalescecollid), + Args: convertSlice(n.Args), + Location: int(n.Location), + } +} + +func convertCoerceToDomain(n *pg.CoerceToDomain) *ast.CoerceToDomain { + if n == nil { + return nil + } + return &ast.CoerceToDomain{ + Xpr: convertNode(n.Xpr), + Arg: convertNode(n.Arg), + Resulttype: ast.Oid(n.Resulttype), + Resulttypmod: n.Resulttypmod, + Resultcollid: ast.Oid(n.Resultcollid), + Coercionformat: ast.CoercionForm(n.Coercionformat), + Location: int(n.Location), + } +} + +func convertCoerceToDomainValue(n *pg.CoerceToDomainValue) *ast.CoerceToDomainValue { + if n == nil { + return nil + } + return &ast.CoerceToDomainValue{ + Xpr: convertNode(n.Xpr), + TypeId: ast.Oid(n.TypeId), + TypeMod: n.TypeMod, + Collation: ast.Oid(n.Collation), + Location: int(n.Location), + } +} + +func convertCoerceViaIO(n *pg.CoerceViaIO) *ast.CoerceViaIO { + if n == nil { + return nil + } + return &ast.CoerceViaIO{ + Xpr: convertNode(n.Xpr), + Arg: convertNode(n.Arg), + Resulttype: ast.Oid(n.Resulttype), + Resultcollid: ast.Oid(n.Resultcollid), + Coerceformat: ast.CoercionForm(n.Coerceformat), + Location: int(n.Location), + } +} + +func convertCollateClause(n *pg.CollateClause) *ast.CollateClause { + if n == nil { + return nil + } + return &ast.CollateClause{ + Arg: convertNode(n.Arg), + Collname: convertSlice(n.Collname), + Location: int(n.Location), + } +} + +func convertCollateExpr(n *pg.CollateExpr) *ast.CollateExpr { + if n == nil { + return nil + } + return &ast.CollateExpr{ + Xpr: convertNode(n.Xpr), + Arg: convertNode(n.Arg), + CollOid: ast.Oid(n.CollOid), + Location: int(n.Location), + } +} + +func convertColumnDef(n *pg.ColumnDef) *ast.ColumnDef { + if n == nil { + return nil + } + return &ast.ColumnDef{ + Colname: n.Colname, + TypeName: convertTypeName(n.TypeName), + Inhcount: int(n.Inhcount), + IsLocal: n.IsLocal, + IsNotNull: n.IsNotNull, + IsFromType: n.IsFromType, + Storage: makeByte(n.Storage), + RawDefault: convertNode(n.RawDefault), + CookedDefault: convertNode(n.CookedDefault), + Identity: makeByte(n.Identity), + CollClause: convertCollateClause(n.CollClause), + CollOid: ast.Oid(n.CollOid), + Constraints: convertSlice(n.Constraints), + Fdwoptions: convertSlice(n.Fdwoptions), + Location: int(n.Location), + } +} + +func convertColumnRef(n *pg.ColumnRef) *ast.ColumnRef { + if n == nil { + return nil + } + return &ast.ColumnRef{ + Fields: convertSlice(n.Fields), + Location: int(n.Location), + } +} + +func convertCommentStmt(n *pg.CommentStmt) *ast.CommentStmt { + if n == nil { + return nil + } + return &ast.CommentStmt{ + Objtype: ast.ObjectType(n.Objtype), + Object: convertNode(n.Object), + Comment: makeString(n.Comment), + } +} + +func convertCommonTableExpr(n *pg.CommonTableExpr) *ast.CommonTableExpr { + if n == nil { + return nil + } + return &ast.CommonTableExpr{ + Ctename: makeString(n.Ctename), + Aliascolnames: convertSlice(n.Aliascolnames), + Ctequery: convertNode(n.Ctequery), + Location: int(n.Location), + Cterecursive: n.Cterecursive, + Cterefcount: int(n.Cterefcount), + Ctecolnames: convertSlice(n.Ctecolnames), + Ctecoltypes: convertSlice(n.Ctecoltypes), + Ctecoltypmods: convertSlice(n.Ctecoltypmods), + Ctecolcollations: convertSlice(n.Ctecolcollations), + } +} + +func convertCompositeTypeStmt(n *pg.CompositeTypeStmt) *ast.CompositeTypeStmt { + if n == nil { + return nil + } + rel := parseRelationFromRangeVar(n.Typevar) + return &ast.CompositeTypeStmt{ + TypeName: rel.TypeName(), + } +} + +func convertConstraint(n *pg.Constraint) *ast.Constraint { + if n == nil { + return nil + } + return &ast.Constraint{ + Contype: ast.ConstrType(n.Contype), + Conname: makeString(n.Conname), + Deferrable: n.Deferrable, + Initdeferred: n.Initdeferred, + Location: int(n.Location), + IsNoInherit: n.IsNoInherit, + RawExpr: convertNode(n.RawExpr), + CookedExpr: makeString(n.CookedExpr), + GeneratedWhen: makeByte(n.GeneratedWhen), + Keys: convertSlice(n.Keys), + Exclusions: convertSlice(n.Exclusions), + Options: convertSlice(n.Options), + Indexname: makeString(n.Indexname), + Indexspace: makeString(n.Indexspace), + AccessMethod: makeString(n.AccessMethod), + WhereClause: convertNode(n.WhereClause), + Pktable: convertRangeVar(n.Pktable), + FkAttrs: convertSlice(n.FkAttrs), + PkAttrs: convertSlice(n.PkAttrs), + FkMatchtype: makeByte(n.FkMatchtype), + FkUpdAction: makeByte(n.FkUpdAction), + FkDelAction: makeByte(n.FkDelAction), + OldConpfeqop: convertSlice(n.OldConpfeqop), + OldPktableOid: ast.Oid(n.OldPktableOid), + SkipValidation: n.SkipValidation, + InitiallyValid: n.InitiallyValid, + } +} + +func convertConstraintsSetStmt(n *pg.ConstraintsSetStmt) *ast.ConstraintsSetStmt { + if n == nil { + return nil + } + return &ast.ConstraintsSetStmt{ + Constraints: convertSlice(n.Constraints), + Deferred: n.Deferred, + } +} + +func convertConvertRowtypeExpr(n *pg.ConvertRowtypeExpr) *ast.ConvertRowtypeExpr { + if n == nil { + return nil + } + return &ast.ConvertRowtypeExpr{ + Xpr: convertNode(n.Xpr), + Arg: convertNode(n.Arg), + Resulttype: ast.Oid(n.Resulttype), + Convertformat: ast.CoercionForm(n.Convertformat), + Location: int(n.Location), + } +} + +func convertCopyStmt(n *pg.CopyStmt) *ast.CopyStmt { + if n == nil { + return nil + } + return &ast.CopyStmt{ + Relation: convertRangeVar(n.Relation), + Query: convertNode(n.Query), + Attlist: convertSlice(n.Attlist), + IsFrom: n.IsFrom, + IsProgram: n.IsProgram, + Filename: makeString(n.Filename), + Options: convertSlice(n.Options), + } +} + +func convertCreateAmStmt(n *pg.CreateAmStmt) *ast.CreateAmStmt { + if n == nil { + return nil + } + return &ast.CreateAmStmt{ + Amname: makeString(n.Amname), + HandlerName: convertSlice(n.HandlerName), + Amtype: makeByte(n.Amtype), + } +} + +func convertCreateCastStmt(n *pg.CreateCastStmt) *ast.CreateCastStmt { + if n == nil { + return nil + } + return &ast.CreateCastStmt{ + Sourcetype: convertTypeName(n.Sourcetype), + Targettype: convertTypeName(n.Targettype), + Func: convertObjectWithArgs(n.Func), + Context: ast.CoercionContext(n.Context), + Inout: n.Inout, + } +} + +func convertCreateConversionStmt(n *pg.CreateConversionStmt) *ast.CreateConversionStmt { + if n == nil { + return nil + } + return &ast.CreateConversionStmt{ + ConversionName: convertSlice(n.ConversionName), + ForEncodingName: makeString(n.ForEncodingName), + ToEncodingName: makeString(n.ToEncodingName), + FuncName: convertSlice(n.FuncName), + Def: n.Def, + } +} + +func convertCreateDomainStmt(n *pg.CreateDomainStmt) *ast.CreateDomainStmt { + if n == nil { + return nil + } + return &ast.CreateDomainStmt{ + Domainname: convertSlice(n.Domainname), + TypeName: convertTypeName(n.TypeName), + CollClause: convertCollateClause(n.CollClause), + Constraints: convertSlice(n.Constraints), + } +} + +func convertCreateEnumStmt(n *pg.CreateEnumStmt) *ast.CreateEnumStmt { + if n == nil { + return nil + } + rel, err := parseRelationFromNodes(n.TypeName) + if err != nil { + panic(err) + } + return &ast.CreateEnumStmt{ + TypeName: rel.TypeName(), + Vals: convertSlice(n.Vals), + } +} + +func convertCreateEventTrigStmt(n *pg.CreateEventTrigStmt) *ast.CreateEventTrigStmt { + if n == nil { + return nil + } + return &ast.CreateEventTrigStmt{ + Trigname: makeString(n.Trigname), + Eventname: makeString(n.Eventname), + Whenclause: convertSlice(n.Whenclause), + Funcname: convertSlice(n.Funcname), + } +} + +func convertCreateExtensionStmt(n *pg.CreateExtensionStmt) *ast.CreateExtensionStmt { + if n == nil { + return nil + } + return &ast.CreateExtensionStmt{ + Extname: makeString(n.Extname), + IfNotExists: n.IfNotExists, + Options: convertSlice(n.Options), + } +} + +func convertCreateFdwStmt(n *pg.CreateFdwStmt) *ast.CreateFdwStmt { + if n == nil { + return nil + } + return &ast.CreateFdwStmt{ + Fdwname: makeString(n.Fdwname), + FuncOptions: convertSlice(n.FuncOptions), + Options: convertSlice(n.Options), + } +} + +func convertCreateForeignServerStmt(n *pg.CreateForeignServerStmt) *ast.CreateForeignServerStmt { + if n == nil { + return nil + } + return &ast.CreateForeignServerStmt{ + Servername: makeString(n.Servername), + Servertype: makeString(n.Servertype), + Version: makeString(n.Version), + Fdwname: makeString(n.Fdwname), + IfNotExists: n.IfNotExists, + Options: convertSlice(n.Options), + } +} + +func convertCreateForeignTableStmt(n *pg.CreateForeignTableStmt) *ast.CreateForeignTableStmt { + if n == nil { + return nil + } + return &ast.CreateForeignTableStmt{ + Servername: makeString(n.Servername), + Options: convertSlice(n.Options), + } +} + +func convertCreateFunctionStmt(n *pg.CreateFunctionStmt) *ast.CreateFunctionStmt { + if n == nil { + return nil + } + rel, err := parseRelationFromNodes(n.Funcname) + if err != nil { + panic(err) + } + return &ast.CreateFunctionStmt{ + Replace: n.Replace, + Func: rel.FuncName(), + Params: convertSlice(n.Parameters), + ReturnType: convertTypeName(n.ReturnType), + Options: convertSlice(n.Options), + } +} + +func convertCreateOpClassItem(n *pg.CreateOpClassItem) *ast.CreateOpClassItem { + if n == nil { + return nil + } + return &ast.CreateOpClassItem{ + Itemtype: int(n.Itemtype), + Name: convertObjectWithArgs(n.Name), + Number: int(n.Number), + OrderFamily: convertSlice(n.OrderFamily), + ClassArgs: convertSlice(n.ClassArgs), + Storedtype: convertTypeName(n.Storedtype), + } +} + +func convertCreateOpClassStmt(n *pg.CreateOpClassStmt) *ast.CreateOpClassStmt { + if n == nil { + return nil + } + return &ast.CreateOpClassStmt{ + Opclassname: convertSlice(n.Opclassname), + Opfamilyname: convertSlice(n.Opfamilyname), + Amname: makeString(n.Amname), + Datatype: convertTypeName(n.Datatype), + Items: convertSlice(n.Items), + IsDefault: n.IsDefault, + } +} + +func convertCreateOpFamilyStmt(n *pg.CreateOpFamilyStmt) *ast.CreateOpFamilyStmt { + if n == nil { + return nil + } + return &ast.CreateOpFamilyStmt{ + Opfamilyname: convertSlice(n.Opfamilyname), + Amname: makeString(n.Amname), + } +} + +func convertCreatePLangStmt(n *pg.CreatePLangStmt) *ast.CreatePLangStmt { + if n == nil { + return nil + } + return &ast.CreatePLangStmt{ + Replace: n.Replace, + Plname: makeString(n.Plname), + Plhandler: convertSlice(n.Plhandler), + Plinline: convertSlice(n.Plinline), + Plvalidator: convertSlice(n.Plvalidator), + Pltrusted: n.Pltrusted, + } +} + +func convertCreatePolicyStmt(n *pg.CreatePolicyStmt) *ast.CreatePolicyStmt { + if n == nil { + return nil + } + return &ast.CreatePolicyStmt{ + PolicyName: makeString(n.PolicyName), + Table: convertRangeVar(n.Table), + CmdName: makeString(n.CmdName), + Permissive: n.Permissive, + Roles: convertSlice(n.Roles), + Qual: convertNode(n.Qual), + WithCheck: convertNode(n.WithCheck), + } +} + +func convertCreatePublicationStmt(n *pg.CreatePublicationStmt) *ast.CreatePublicationStmt { + if n == nil { + return nil + } + return &ast.CreatePublicationStmt{ + Pubname: makeString(n.Pubname), + Options: convertSlice(n.Options), + Tables: convertSlice(n.Pubobjects), + ForAllTables: n.ForAllTables, + } +} + +func convertCreateRangeStmt(n *pg.CreateRangeStmt) *ast.CreateRangeStmt { + if n == nil { + return nil + } + return &ast.CreateRangeStmt{ + TypeName: convertSlice(n.TypeName), + Params: convertSlice(n.Params), + } +} + +func convertCreateRoleStmt(n *pg.CreateRoleStmt) *ast.CreateRoleStmt { + if n == nil { + return nil + } + return &ast.CreateRoleStmt{ + StmtType: ast.RoleStmtType(n.StmtType), + Role: makeString(n.Role), + Options: convertSlice(n.Options), + } +} + +func convertCreateSchemaStmt(n *pg.CreateSchemaStmt) *ast.CreateSchemaStmt { + if n == nil { + return nil + } + return &ast.CreateSchemaStmt{ + Name: makeString(n.Schemaname), + Authrole: convertRoleSpec(n.Authrole), + SchemaElts: convertSlice(n.SchemaElts), + IfNotExists: n.IfNotExists, + } +} + +func convertCreateSeqStmt(n *pg.CreateSeqStmt) *ast.CreateSeqStmt { + if n == nil { + return nil + } + return &ast.CreateSeqStmt{ + Sequence: convertRangeVar(n.Sequence), + Options: convertSlice(n.Options), + OwnerId: ast.Oid(n.OwnerId), + ForIdentity: n.ForIdentity, + IfNotExists: n.IfNotExists, + } +} + +func convertCreateStatsStmt(n *pg.CreateStatsStmt) *ast.CreateStatsStmt { + if n == nil { + return nil + } + return &ast.CreateStatsStmt{ + Defnames: convertSlice(n.Defnames), + StatTypes: convertSlice(n.StatTypes), + Exprs: convertSlice(n.Exprs), + Relations: convertSlice(n.Relations), + IfNotExists: n.IfNotExists, + } +} + +func convertCreateStmt(n *pg.CreateStmt) *ast.CreateStmt { + if n == nil { + return nil + } + return &ast.CreateStmt{ + Relation: convertRangeVar(n.Relation), + TableElts: convertSlice(n.TableElts), + InhRelations: convertSlice(n.InhRelations), + Partbound: convertPartitionBoundSpec(n.Partbound), + Partspec: convertPartitionSpec(n.Partspec), + OfTypename: convertTypeName(n.OfTypename), + Constraints: convertSlice(n.Constraints), + Options: convertSlice(n.Options), + Oncommit: ast.OnCommitAction(n.Oncommit), + Tablespacename: makeString(n.Tablespacename), + IfNotExists: n.IfNotExists, + } +} + +func convertCreateSubscriptionStmt(n *pg.CreateSubscriptionStmt) *ast.CreateSubscriptionStmt { + if n == nil { + return nil + } + return &ast.CreateSubscriptionStmt{ + Subname: makeString(n.Subname), + Conninfo: makeString(n.Conninfo), + Publication: convertSlice(n.Publication), + Options: convertSlice(n.Options), + } +} + +func convertCreateTableAsStmt(n *pg.CreateTableAsStmt) *ast.CreateTableAsStmt { + if n == nil { + return nil + } + res := &ast.CreateTableAsStmt{ + Query: convertNode(n.Query), + Into: convertIntoClause(n.Into), + Relkind: ast.ObjectType(n.Objtype), + IsSelectInto: n.IsSelectInto, + IfNotExists: n.IfNotExists, + } + return res +} + +func convertCreateTableSpaceStmt(n *pg.CreateTableSpaceStmt) *ast.CreateTableSpaceStmt { + if n == nil { + return nil + } + return &ast.CreateTableSpaceStmt{ + Tablespacename: makeString(n.Tablespacename), + Owner: convertRoleSpec(n.Owner), + Location: makeString(n.Location), + Options: convertSlice(n.Options), + } +} + +func convertCreateTransformStmt(n *pg.CreateTransformStmt) *ast.CreateTransformStmt { + if n == nil { + return nil + } + return &ast.CreateTransformStmt{ + Replace: n.Replace, + TypeName: convertTypeName(n.TypeName), + Lang: makeString(n.Lang), + Fromsql: convertObjectWithArgs(n.Fromsql), + Tosql: convertObjectWithArgs(n.Tosql), + } +} + +func convertCreateTrigStmt(n *pg.CreateTrigStmt) *ast.CreateTrigStmt { + if n == nil { + return nil + } + return &ast.CreateTrigStmt{ + Trigname: makeString(n.Trigname), + Relation: convertRangeVar(n.Relation), + Funcname: convertSlice(n.Funcname), + Args: convertSlice(n.Args), + Row: n.Row, + Timing: int16(n.Timing), + Events: int16(n.Events), + Columns: convertSlice(n.Columns), + WhenClause: convertNode(n.WhenClause), + Isconstraint: n.Isconstraint, + TransitionRels: convertSlice(n.TransitionRels), + Deferrable: n.Deferrable, + Initdeferred: n.Initdeferred, + Constrrel: convertRangeVar(n.Constrrel), + } +} + +func convertCreateUserMappingStmt(n *pg.CreateUserMappingStmt) *ast.CreateUserMappingStmt { + if n == nil { + return nil + } + return &ast.CreateUserMappingStmt{ + User: convertRoleSpec(n.User), + Servername: makeString(n.Servername), + IfNotExists: n.IfNotExists, + Options: convertSlice(n.Options), + } +} + +func convertCreatedbStmt(n *pg.CreatedbStmt) *ast.CreatedbStmt { + if n == nil { + return nil + } + return &ast.CreatedbStmt{ + Dbname: makeString(n.Dbname), + Options: convertSlice(n.Options), + } +} + +func convertCurrentOfExpr(n *pg.CurrentOfExpr) *ast.CurrentOfExpr { + if n == nil { + return nil + } + return &ast.CurrentOfExpr{ + Xpr: convertNode(n.Xpr), + Cvarno: ast.Index(n.Cvarno), + CursorName: makeString(n.CursorName), + CursorParam: int(n.CursorParam), + } +} + +func convertDeallocateStmt(n *pg.DeallocateStmt) *ast.DeallocateStmt { + if n == nil { + return nil + } + return &ast.DeallocateStmt{ + Name: makeString(n.Name), + } +} + +func convertDeclareCursorStmt(n *pg.DeclareCursorStmt) *ast.DeclareCursorStmt { + if n == nil { + return nil + } + return &ast.DeclareCursorStmt{ + Portalname: makeString(n.Portalname), + Options: int(n.Options), + Query: convertNode(n.Query), + } +} + +func convertDefElem(n *pg.DefElem) *ast.DefElem { + if n == nil { + return nil + } + return &ast.DefElem{ + Defnamespace: makeString(n.Defnamespace), + Defname: makeString(n.Defname), + Arg: convertNode(n.Arg), + Defaction: ast.DefElemAction(n.Defaction), + Location: int(n.Location), + } +} + +func convertDefineStmt(n *pg.DefineStmt) *ast.DefineStmt { + if n == nil { + return nil + } + return &ast.DefineStmt{ + Kind: ast.ObjectType(n.Kind), + Oldstyle: n.Oldstyle, + Defnames: convertSlice(n.Defnames), + Args: convertSlice(n.Args), + Definition: convertSlice(n.Definition), + IfNotExists: n.IfNotExists, + } +} + +func convertDeleteStmt(n *pg.DeleteStmt) *ast.DeleteStmt { + if n == nil { + return nil + } + oldAlias, newAlias := convertReturningOptions(n.ReturningClause) + return &ast.DeleteStmt{ + Relations: &ast.List{ + Items: []ast.Node{convertRangeVar(n.Relation)}, + }, + UsingClause: convertSlice(n.UsingClause), + WhereClause: convertNode(n.WhereClause), + ReturningList: convertSlice(n.ReturningClause.GetExprs()), + ReturningOldAlias: oldAlias, + ReturningNewAlias: newAlias, + WithClause: convertWithClause(n.WithClause), + } +} + +// convertReturningOptions extracts the aliases assigned to the OLD and NEW +// rows by a PostgreSQL 18 RETURNING WITH (...) option list. +func convertReturningOptions(n *pg.ReturningClause) (oldAlias, newAlias string) { + for _, option := range n.GetOptions() { + ro := option.GetReturningOption() + if ro == nil { + continue + } + switch ro.Option { + case pg.ReturningOptionKind_RETURNING_OPTION_OLD: + oldAlias = ro.Value + case pg.ReturningOptionKind_RETURNING_OPTION_NEW: + newAlias = ro.Value + } + } + return oldAlias, newAlias +} + +func convertDiscardStmt(n *pg.DiscardStmt) *ast.DiscardStmt { + if n == nil { + return nil + } + return &ast.DiscardStmt{ + Target: ast.DiscardMode(n.Target), + } +} + +func convertDoStmt(n *pg.DoStmt) *ast.DoStmt { + if n == nil { + return nil + } + return &ast.DoStmt{ + Args: convertSlice(n.Args), + } +} + +func convertDropOwnedStmt(n *pg.DropOwnedStmt) *ast.DropOwnedStmt { + if n == nil { + return nil + } + return &ast.DropOwnedStmt{ + Roles: convertSlice(n.Roles), + Behavior: ast.DropBehavior(n.Behavior), + } +} + +func convertDropRoleStmt(n *pg.DropRoleStmt) *ast.DropRoleStmt { + if n == nil { + return nil + } + return &ast.DropRoleStmt{ + Roles: convertSlice(n.Roles), + MissingOk: n.MissingOk, + } +} + +func convertDropStmt(n *pg.DropStmt) *ast.DropStmt { + if n == nil { + return nil + } + return &ast.DropStmt{ + Objects: convertSlice(n.Objects), + RemoveType: ast.ObjectType(n.RemoveType), + Behavior: ast.DropBehavior(n.Behavior), + MissingOk: n.MissingOk, + Concurrent: n.Concurrent, + } +} + +func convertDropSubscriptionStmt(n *pg.DropSubscriptionStmt) *ast.DropSubscriptionStmt { + if n == nil { + return nil + } + return &ast.DropSubscriptionStmt{ + Subname: makeString(n.Subname), + MissingOk: n.MissingOk, + Behavior: ast.DropBehavior(n.Behavior), + } +} + +func convertDropTableSpaceStmt(n *pg.DropTableSpaceStmt) *ast.DropTableSpaceStmt { + if n == nil { + return nil + } + return &ast.DropTableSpaceStmt{ + Tablespacename: makeString(n.Tablespacename), + MissingOk: n.MissingOk, + } +} + +func convertDropUserMappingStmt(n *pg.DropUserMappingStmt) *ast.DropUserMappingStmt { + if n == nil { + return nil + } + return &ast.DropUserMappingStmt{ + User: convertRoleSpec(n.User), + Servername: makeString(n.Servername), + MissingOk: n.MissingOk, + } +} + +func convertDropdbStmt(n *pg.DropdbStmt) *ast.DropdbStmt { + if n == nil { + return nil + } + return &ast.DropdbStmt{ + Dbname: makeString(n.Dbname), + MissingOk: n.MissingOk, + } +} + +func convertExecuteStmt(n *pg.ExecuteStmt) *ast.ExecuteStmt { + if n == nil { + return nil + } + return &ast.ExecuteStmt{ + Name: makeString(n.Name), + Params: convertSlice(n.Params), + } +} + +func convertExplainStmt(n *pg.ExplainStmt) *ast.ExplainStmt { + if n == nil { + return nil + } + return &ast.ExplainStmt{ + Query: convertNode(n.Query), + Options: convertSlice(n.Options), + } +} + +func convertFetchStmt(n *pg.FetchStmt) *ast.FetchStmt { + if n == nil { + return nil + } + return &ast.FetchStmt{ + Direction: ast.FetchDirection(n.Direction), + HowMany: n.HowMany, + Portalname: makeString(n.Portalname), + Ismove: n.Ismove, + } +} + +func convertFieldSelect(n *pg.FieldSelect) *ast.FieldSelect { + if n == nil { + return nil + } + return &ast.FieldSelect{ + Xpr: convertNode(n.Xpr), + Arg: convertNode(n.Arg), + Fieldnum: ast.AttrNumber(n.Fieldnum), + Resulttype: ast.Oid(n.Resulttype), + Resulttypmod: n.Resulttypmod, + Resultcollid: ast.Oid(n.Resultcollid), + } +} + +func convertFieldStore(n *pg.FieldStore) *ast.FieldStore { + if n == nil { + return nil + } + return &ast.FieldStore{ + Xpr: convertNode(n.Xpr), + Arg: convertNode(n.Arg), + Newvals: convertSlice(n.Newvals), + Fieldnums: convertSlice(n.Fieldnums), + Resulttype: ast.Oid(n.Resulttype), + } +} + +func convertFloat(n *pg.Float) *ast.Float { + if n == nil { + return nil + } + return &ast.Float{ + Str: n.Fval, + } +} + +func convertFromExpr(n *pg.FromExpr) *ast.FromExpr { + if n == nil { + return nil + } + return &ast.FromExpr{ + Fromlist: convertSlice(n.Fromlist), + Quals: convertNode(n.Quals), + } +} + +func convertFuncCall(n *pg.FuncCall) *ast.FuncCall { + if n == nil { + return nil + } + rel, err := parseRelationFromNodes(n.Funcname) + if err != nil { + // TODO: How should we handle errors? + panic(err) + } + return &ast.FuncCall{ + Func: rel.FuncName(), + Funcname: convertSlice(n.Funcname), + Args: convertSlice(n.Args), + AggOrder: convertSlice(n.AggOrder), + AggFilter: convertNode(n.AggFilter), + AggWithinGroup: n.AggWithinGroup, + AggStar: n.AggStar, + AggDistinct: n.AggDistinct, + FuncVariadic: n.FuncVariadic, + Over: convertWindowDef(n.Over), + Location: int(n.Location), + } +} + +func convertFuncExpr(n *pg.FuncExpr) *ast.FuncExpr { + if n == nil { + return nil + } + return &ast.FuncExpr{ + Xpr: convertNode(n.Xpr), + Funcid: ast.Oid(n.Funcid), + Funcresulttype: ast.Oid(n.Funcresulttype), + Funcretset: n.Funcretset, + Funcvariadic: n.Funcvariadic, + Funcformat: ast.CoercionForm(n.Funcformat), + Funccollid: ast.Oid(n.Funccollid), + Inputcollid: ast.Oid(n.Inputcollid), + Args: convertSlice(n.Args), + Location: int(n.Location), + } +} + +func convertFunctionParameter(n *pg.FunctionParameter) *ast.FunctionParameter { + if n == nil { + return nil + } + return &ast.FunctionParameter{ + Name: makeString(n.Name), + ArgType: convertTypeName(n.ArgType), + Mode: ast.FunctionParameterMode(n.Mode), + Defexpr: convertNode(n.Defexpr), + } +} + +func convertGrantRoleStmt(n *pg.GrantRoleStmt) *ast.GrantRoleStmt { + if n == nil { + return nil + } + return &ast.GrantRoleStmt{ + GrantedRoles: convertSlice(n.GrantedRoles), + GranteeRoles: convertSlice(n.GranteeRoles), + IsGrant: n.IsGrant, + Grantor: convertRoleSpec(n.Grantor), + Behavior: ast.DropBehavior(n.Behavior), + } +} + +func convertGrantStmt(n *pg.GrantStmt) *ast.GrantStmt { + if n == nil { + return nil + } + return &ast.GrantStmt{ + IsGrant: n.IsGrant, + Targtype: ast.GrantTargetType(n.Targtype), + Objtype: ast.GrantObjectType(n.Objtype), + Objects: convertSlice(n.Objects), + Privileges: convertSlice(n.Privileges), + Grantees: convertSlice(n.Grantees), + GrantOption: n.GrantOption, + Behavior: ast.DropBehavior(n.Behavior), + } +} + +func convertGroupingFunc(n *pg.GroupingFunc) *ast.GroupingFunc { + if n == nil { + return nil + } + return &ast.GroupingFunc{ + Xpr: convertNode(n.Xpr), + Args: convertSlice(n.Args), + Refs: convertSlice(n.Refs), + Agglevelsup: ast.Index(n.Agglevelsup), + Location: int(n.Location), + } +} + +func convertGroupingSet(n *pg.GroupingSet) *ast.GroupingSet { + if n == nil { + return nil + } + return &ast.GroupingSet{ + Kind: ast.GroupingSetKind(n.Kind), + Content: convertSlice(n.Content), + Location: int(n.Location), + } +} + +func convertImportForeignSchemaStmt(n *pg.ImportForeignSchemaStmt) *ast.ImportForeignSchemaStmt { + if n == nil { + return nil + } + return &ast.ImportForeignSchemaStmt{ + ServerName: makeString(n.ServerName), + RemoteSchema: makeString(n.RemoteSchema), + LocalSchema: makeString(n.LocalSchema), + ListType: ast.ImportForeignSchemaType(n.ListType), + TableList: convertSlice(n.TableList), + Options: convertSlice(n.Options), + } +} + +func convertIndexElem(n *pg.IndexElem) *ast.IndexElem { + if n == nil { + return nil + } + return &ast.IndexElem{ + Name: makeString(n.Name), + Expr: convertNode(n.Expr), + Indexcolname: makeString(n.Indexcolname), + Collation: convertSlice(n.Collation), + Opclass: convertSlice(n.Opclass), + Ordering: ast.SortByDir(n.Ordering), + NullsOrdering: ast.SortByNulls(n.NullsOrdering), + } +} + +func convertIndexStmt(n *pg.IndexStmt) *ast.IndexStmt { + if n == nil { + return nil + } + return &ast.IndexStmt{ + Idxname: makeString(n.Idxname), + Relation: convertRangeVar(n.Relation), + AccessMethod: makeString(n.AccessMethod), + TableSpace: makeString(n.TableSpace), + IndexParams: convertSlice(n.IndexParams), + Options: convertSlice(n.Options), + WhereClause: convertNode(n.WhereClause), + ExcludeOpNames: convertSlice(n.ExcludeOpNames), + Idxcomment: makeString(n.Idxcomment), + IndexOid: ast.Oid(n.IndexOid), + Unique: n.Unique, + Primary: n.Primary, + Isconstraint: n.Isconstraint, + Deferrable: n.Deferrable, + Initdeferred: n.Initdeferred, + Transformed: n.Transformed, + Concurrent: n.Concurrent, + IfNotExists: n.IfNotExists, + } +} + +func convertInferClause(n *pg.InferClause) *ast.InferClause { + if n == nil { + return nil + } + return &ast.InferClause{ + IndexElems: convertSlice(n.IndexElems), + WhereClause: convertNode(n.WhereClause), + Conname: makeString(n.Conname), + Location: int(n.Location), + } +} + +func convertInferenceElem(n *pg.InferenceElem) *ast.InferenceElem { + if n == nil { + return nil + } + return &ast.InferenceElem{ + Xpr: convertNode(n.Xpr), + Expr: convertNode(n.Expr), + Infercollid: ast.Oid(n.Infercollid), + Inferopclass: ast.Oid(n.Inferopclass), + } +} + +func convertInlineCodeBlock(n *pg.InlineCodeBlock) *ast.InlineCodeBlock { + if n == nil { + return nil + } + return &ast.InlineCodeBlock{ + SourceText: makeString(n.SourceText), + LangOid: ast.Oid(n.LangOid), + LangIsTrusted: n.LangIsTrusted, + } +} + +func convertInsertStmt(n *pg.InsertStmt) *ast.InsertStmt { + if n == nil { + return nil + } + oldAlias, newAlias := convertReturningOptions(n.ReturningClause) + return &ast.InsertStmt{ + Relation: convertRangeVar(n.Relation), + Cols: convertSlice(n.Cols), + SelectStmt: convertNode(n.SelectStmt), + OnConflictClause: convertOnConflictClause(n.OnConflictClause), + ReturningList: convertSlice(n.ReturningClause.GetExprs()), + ReturningOldAlias: oldAlias, + ReturningNewAlias: newAlias, + WithClause: convertWithClause(n.WithClause), + Override: ast.OverridingKind(n.Override), + } +} + +func convertInteger(n *pg.Integer) *ast.Integer { + if n == nil { + return nil + } + return &ast.Integer{ + Ival: int64(n.Ival), + } +} + +func convertIntoClause(n *pg.IntoClause) *ast.IntoClause { + if n == nil { + return nil + } + var viewQuery ast.Node = &ast.TODO{} + if n.ViewQuery != nil { + viewQuery = convertQuery(n.ViewQuery) + } + return &ast.IntoClause{ + Rel: convertRangeVar(n.Rel), + ColNames: convertSlice(n.ColNames), + Options: convertSlice(n.Options), + OnCommit: ast.OnCommitAction(n.OnCommit), + TableSpaceName: makeString(n.TableSpaceName), + ViewQuery: viewQuery, + SkipData: n.SkipData, + } +} + +func convertJoinExpr(n *pg.JoinExpr) *ast.JoinExpr { + if n == nil { + return nil + } + jointype := ast.JoinType(n.Jointype) + // PostgreSQL parses CROSS JOIN as an inner join with no condition — + // the only inner join its grammar allows without one — so that shape + // is CROSS JOIN, and must print as it: a bare JOIN with no ON or + // USING is a syntax error in PostgreSQL. + if jointype == ast.JoinTypeInner && !n.IsNatural && n.Quals == nil && len(n.UsingClause) == 0 { + jointype = ast.JoinTypeCross + } + return &ast.JoinExpr{ + Jointype: jointype, + IsNatural: n.IsNatural, + Larg: convertNode(n.Larg), + Rarg: convertNode(n.Rarg), + UsingClause: convertSlice(n.UsingClause), + Quals: convertNode(n.Quals), + Alias: convertAlias(n.Alias), + Rtindex: int(n.Rtindex), + } +} + +func convertListenStmt(n *pg.ListenStmt) *ast.ListenStmt { + if n == nil { + return nil + } + return &ast.ListenStmt{ + Conditionname: makeString(n.Conditionname), + } +} + +func convertLoadStmt(n *pg.LoadStmt) *ast.LoadStmt { + if n == nil { + return nil + } + return &ast.LoadStmt{ + Filename: makeString(n.Filename), + } +} + +func convertLockStmt(n *pg.LockStmt) *ast.LockStmt { + if n == nil { + return nil + } + return &ast.LockStmt{ + Relations: convertSlice(n.Relations), + Mode: int(n.Mode), + Nowait: n.Nowait, + } +} + +func convertLockingClause(n *pg.LockingClause) *ast.LockingClause { + if n == nil { + return nil + } + return &ast.LockingClause{ + LockedRels: convertSlice(n.LockedRels), + Strength: ast.LockClauseStrength(n.Strength), + WaitPolicy: ast.LockWaitPolicy(n.WaitPolicy), + } +} + +func convertMinMaxExpr(n *pg.MinMaxExpr) *ast.MinMaxExpr { + if n == nil { + return nil + } + return &ast.MinMaxExpr{ + Xpr: convertNode(n.Xpr), + Minmaxtype: ast.Oid(n.Minmaxtype), + Minmaxcollid: ast.Oid(n.Minmaxcollid), + Inputcollid: ast.Oid(n.Inputcollid), + Op: ast.MinMaxOp(n.Op), + Args: convertSlice(n.Args), + Location: int(n.Location), + } +} + +func convertMultiAssignRef(n *pg.MultiAssignRef) *ast.MultiAssignRef { + if n == nil { + return nil + } + return &ast.MultiAssignRef{ + Source: convertNode(n.Source), + Colno: int(n.Colno), + Ncolumns: int(n.Ncolumns), + } +} + +func convertNamedArgExpr(n *pg.NamedArgExpr) *ast.NamedArgExpr { + if n == nil { + return nil + } + return &ast.NamedArgExpr{ + Xpr: convertNode(n.Xpr), + Arg: convertNode(n.Arg), + Name: makeString(n.Name), + Argnumber: int(n.Argnumber), + Location: int(n.Location), + } +} + +func convertNextValueExpr(n *pg.NextValueExpr) *ast.NextValueExpr { + if n == nil { + return nil + } + return &ast.NextValueExpr{ + Xpr: convertNode(n.Xpr), + Seqid: ast.Oid(n.Seqid), + TypeId: ast.Oid(n.TypeId), + } +} + +func convertNotifyStmt(n *pg.NotifyStmt) *ast.NotifyStmt { + if n == nil { + return nil + } + return &ast.NotifyStmt{ + Conditionname: makeString(n.Conditionname), + Payload: makeString(n.Payload), + } +} + +func convertNullTest(n *pg.NullTest) *ast.NullTest { + if n == nil { + return nil + } + return &ast.NullTest{ + Xpr: convertNode(n.Xpr), + Arg: convertNode(n.Arg), + Nulltesttype: ast.NullTestType(n.Nulltesttype), + Argisrow: n.Argisrow, + Location: int(n.Location), + } +} + +func convertNullIfExpr(n *pg.NullIfExpr) *ast.NullIfExpr { + if n == nil { + return nil + } + return &ast.NullIfExpr{ + Xpr: convertNode(n.Xpr), + Opno: ast.Oid(n.Opno), + Opresulttype: ast.Oid(n.Opresulttype), + Opretset: n.Opretset, + Opcollid: ast.Oid(n.Opcollid), + Inputcollid: ast.Oid(n.Inputcollid), + Args: convertSlice(n.Args), + Location: int(n.Location), + } +} + +func convertObjectWithArgs(n *pg.ObjectWithArgs) *ast.ObjectWithArgs { + if n == nil { + return nil + } + return &ast.ObjectWithArgs{ + Objname: convertSlice(n.Objname), + Objargs: convertSlice(n.Objargs), + ArgsUnspecified: n.ArgsUnspecified, + } +} + +func convertOnConflictClause(n *pg.OnConflictClause) *ast.OnConflictClause { + if n == nil { + return nil + } + return &ast.OnConflictClause{ + Action: ast.OnConflictAction(n.Action), + Infer: convertInferClause(n.Infer), + TargetList: convertSlice(n.TargetList), + WhereClause: convertNode(n.WhereClause), + Location: int(n.Location), + } +} + +func convertOnConflictExpr(n *pg.OnConflictExpr) *ast.OnConflictExpr { + if n == nil { + return nil + } + return &ast.OnConflictExpr{ + Action: ast.OnConflictAction(n.Action), + ArbiterElems: convertSlice(n.ArbiterElems), + ArbiterWhere: convertNode(n.ArbiterWhere), + Constraint: ast.Oid(n.Constraint), + OnConflictSet: convertSlice(n.OnConflictSet), + OnConflictWhere: convertNode(n.OnConflictWhere), + ExclRelIndex: int(n.ExclRelIndex), + ExclRelTlist: convertSlice(n.ExclRelTlist), + } +} + +func convertOpExpr(n *pg.OpExpr) *ast.OpExpr { + if n == nil { + return nil + } + return &ast.OpExpr{ + Xpr: convertNode(n.Xpr), + Opno: ast.Oid(n.Opno), + Opresulttype: ast.Oid(n.Opresulttype), + Opretset: n.Opretset, + Opcollid: ast.Oid(n.Opcollid), + Inputcollid: ast.Oid(n.Inputcollid), + Args: convertSlice(n.Args), + Location: int(n.Location), + } +} + +func convertParam(n *pg.Param) *ast.Param { + if n == nil { + return nil + } + return &ast.Param{ + Xpr: convertNode(n.Xpr), + Paramkind: ast.ParamKind(n.Paramkind), + Paramid: int(n.Paramid), + Paramtype: ast.Oid(n.Paramtype), + Paramtypmod: n.Paramtypmod, + Paramcollid: ast.Oid(n.Paramcollid), + Location: int(n.Location), + } +} + +func convertParamRef(n *pg.ParamRef) *ast.ParamRef { + if n == nil { + return nil + } + var dollar bool + if n.Number != 0 { + dollar = true + } + return &ast.ParamRef{ + Dollar: dollar, + Number: int(n.Number), + Location: int(n.Location), + } +} + +func convertPartitionBoundSpec(n *pg.PartitionBoundSpec) *ast.PartitionBoundSpec { + if n == nil { + return nil + } + return &ast.PartitionBoundSpec{ + Strategy: makeByte(n.Strategy), + Listdatums: convertSlice(n.Listdatums), + Lowerdatums: convertSlice(n.Lowerdatums), + Upperdatums: convertSlice(n.Upperdatums), + Location: int(n.Location), + } +} + +func convertPartitionCmd(n *pg.PartitionCmd) *ast.PartitionCmd { + if n == nil { + return nil + } + return &ast.PartitionCmd{ + Name: convertRangeVar(n.Name), + Bound: convertPartitionBoundSpec(n.Bound), + } +} + +func convertPartitionElem(n *pg.PartitionElem) *ast.PartitionElem { + if n == nil { + return nil + } + return &ast.PartitionElem{ + Name: makeString(n.Name), + Expr: convertNode(n.Expr), + Collation: convertSlice(n.Collation), + Opclass: convertSlice(n.Opclass), + Location: int(n.Location), + } +} + +func convertPartitionRangeDatum(n *pg.PartitionRangeDatum) *ast.PartitionRangeDatum { + if n == nil { + return nil + } + return &ast.PartitionRangeDatum{ + Kind: ast.PartitionRangeDatumKind(n.Kind), + Value: convertNode(n.Value), + Location: int(n.Location), + } +} + +func convertPartitionSpec(n *pg.PartitionSpec) *ast.PartitionSpec { + if n == nil { + return nil + } + return &ast.PartitionSpec{ + Strategy: makeString(n.Strategy.String()), + PartParams: convertSlice(n.PartParams), + Location: int(n.Location), + } +} + +func convertPrepareStmt(n *pg.PrepareStmt) *ast.PrepareStmt { + if n == nil { + return nil + } + return &ast.PrepareStmt{ + Name: makeString(n.Name), + Argtypes: convertSlice(n.Argtypes), + Query: convertNode(n.Query), + } +} + +func convertQuery(n *pg.Query) *ast.Query { + if n == nil { + return nil + } + return &ast.Query{ + CommandType: ast.CmdType(n.CommandType), + QuerySource: ast.QuerySource(n.QuerySource), + CanSetTag: n.CanSetTag, + UtilityStmt: convertNode(n.UtilityStmt), + ResultRelation: int(n.ResultRelation), + HasAggs: n.HasAggs, + HasWindowFuncs: n.HasWindowFuncs, + HasTargetSrfs: n.HasTargetSrfs, + HasSubLinks: n.HasSubLinks, + HasDistinctOn: n.HasDistinctOn, + HasRecursive: n.HasRecursive, + HasModifyingCte: n.HasModifyingCte, + HasForUpdate: n.HasForUpdate, + HasRowSecurity: n.HasRowSecurity, + CteList: convertSlice(n.CteList), + Rtable: convertSlice(n.Rtable), + Jointree: convertFromExpr(n.Jointree), + TargetList: convertSlice(n.TargetList), + Override: ast.OverridingKind(n.Override), + OnConflict: convertOnConflictExpr(n.OnConflict), + ReturningList: convertSlice(n.ReturningList), + GroupClause: convertSlice(n.GroupClause), + GroupingSets: convertSlice(n.GroupingSets), + HavingQual: convertNode(n.HavingQual), + WindowClause: convertSlice(n.WindowClause), + DistinctClause: convertSlice(n.DistinctClause), + SortClause: convertSlice(n.SortClause), + LimitOffset: convertNode(n.LimitOffset), + LimitCount: convertNode(n.LimitCount), + RowMarks: convertSlice(n.RowMarks), + SetOperations: convertNode(n.SetOperations), + ConstraintDeps: convertSlice(n.ConstraintDeps), + WithCheckOptions: convertSlice(n.WithCheckOptions), + StmtLocation: int(n.StmtLocation), + StmtLen: int(n.StmtLen), + } +} + +func convertRangeFunction(n *pg.RangeFunction) *ast.RangeFunction { + if n == nil { + return nil + } + return &ast.RangeFunction{ + Lateral: n.Lateral, + Ordinality: n.Ordinality, + IsRowsfrom: n.IsRowsfrom, + Functions: convertSlice(n.Functions), + Alias: convertAlias(n.Alias), + Coldeflist: convertSlice(n.Coldeflist), + } +} + +func convertRangeSubselect(n *pg.RangeSubselect) *ast.RangeSubselect { + if n == nil { + return nil + } + return &ast.RangeSubselect{ + Lateral: n.Lateral, + Subquery: convertNode(n.Subquery), + Alias: convertAlias(n.Alias), + } +} + +func convertRangeTableFunc(n *pg.RangeTableFunc) *ast.RangeTableFunc { + if n == nil { + return nil + } + return &ast.RangeTableFunc{ + Lateral: n.Lateral, + Docexpr: convertNode(n.Docexpr), + Rowexpr: convertNode(n.Rowexpr), + Namespaces: convertSlice(n.Namespaces), + Columns: convertSlice(n.Columns), + Alias: convertAlias(n.Alias), + Location: int(n.Location), + } +} + +func convertRangeTableFuncCol(n *pg.RangeTableFuncCol) *ast.RangeTableFuncCol { + if n == nil { + return nil + } + return &ast.RangeTableFuncCol{ + Colname: makeString(n.Colname), + TypeName: convertTypeName(n.TypeName), + ForOrdinality: n.ForOrdinality, + IsNotNull: n.IsNotNull, + Colexpr: convertNode(n.Colexpr), + Coldefexpr: convertNode(n.Coldefexpr), + Location: int(n.Location), + } +} + +func convertRangeTableSample(n *pg.RangeTableSample) *ast.RangeTableSample { + if n == nil { + return nil + } + return &ast.RangeTableSample{ + Relation: convertNode(n.Relation), + Method: convertSlice(n.Method), + Args: convertSlice(n.Args), + Repeatable: convertNode(n.Repeatable), + Location: int(n.Location), + } +} + +func convertRangeTblEntry(n *pg.RangeTblEntry) *ast.RangeTblEntry { + if n == nil { + return nil + } + return &ast.RangeTblEntry{ + Rtekind: ast.RTEKind(n.Rtekind), + Relid: ast.Oid(n.Relid), + Relkind: makeByte(n.Relkind), + Tablesample: convertTableSampleClause(n.Tablesample), + Subquery: convertQuery(n.Subquery), + SecurityBarrier: n.SecurityBarrier, + Jointype: ast.JoinType(n.Jointype), + Joinaliasvars: convertSlice(n.Joinaliasvars), + Functions: convertSlice(n.Functions), + Funcordinality: n.Funcordinality, + Tablefunc: convertTableFunc(n.Tablefunc), + ValuesLists: convertSlice(n.ValuesLists), + Ctename: makeString(n.Ctename), + Ctelevelsup: ast.Index(n.Ctelevelsup), + SelfReference: n.SelfReference, + Coltypes: convertSlice(n.Coltypes), + Coltypmods: convertSlice(n.Coltypmods), + Colcollations: convertSlice(n.Colcollations), + Enrname: makeString(n.Enrname), + Enrtuples: n.Enrtuples, + Alias: convertAlias(n.Alias), + Eref: convertAlias(n.Eref), + Lateral: n.Lateral, + Inh: n.Inh, + InFromCl: n.InFromCl, + SecurityQuals: convertSlice(n.SecurityQuals), + } +} + +func convertRangeTblFunction(n *pg.RangeTblFunction) *ast.RangeTblFunction { + if n == nil { + return nil + } + return &ast.RangeTblFunction{ + Funcexpr: convertNode(n.Funcexpr), + Funccolcount: int(n.Funccolcount), + Funccolnames: convertSlice(n.Funccolnames), + Funccoltypes: convertSlice(n.Funccoltypes), + Funccoltypmods: convertSlice(n.Funccoltypmods), + Funccolcollations: convertSlice(n.Funccolcollations), + Funcparams: makeUint32Slice(n.Funcparams), + } +} + +func convertRangeTblRef(n *pg.RangeTblRef) *ast.RangeTblRef { + if n == nil { + return nil + } + return &ast.RangeTblRef{ + Rtindex: int(n.Rtindex), + } +} + +func convertRangeVar(n *pg.RangeVar) *ast.RangeVar { + if n == nil { + return nil + } + return &ast.RangeVar{ + Catalogname: makeString(n.Catalogname), + Schemaname: makeString(n.Schemaname), + Relname: makeString(n.Relname), + Inh: n.Inh, + Relpersistence: makeByte(n.Relpersistence), + Alias: convertAlias(n.Alias), + Location: int(n.Location), + } +} + +func convertRawStmt(n *pg.RawStmt) *ast.RawStmt { + if n == nil { + return nil + } + return &ast.RawStmt{ + Stmt: convertNode(n.Stmt), + StmtLocation: int(n.StmtLocation), + StmtLen: int(n.StmtLen), + } +} + +func convertReassignOwnedStmt(n *pg.ReassignOwnedStmt) *ast.ReassignOwnedStmt { + if n == nil { + return nil + } + return &ast.ReassignOwnedStmt{ + Roles: convertSlice(n.Roles), + Newrole: convertRoleSpec(n.Newrole), + } +} + +func convertRefreshMatViewStmt(n *pg.RefreshMatViewStmt) *ast.RefreshMatViewStmt { + if n == nil { + return nil + } + return &ast.RefreshMatViewStmt{ + Concurrent: n.Concurrent, + SkipData: n.SkipData, + Relation: convertRangeVar(n.Relation), + } +} + +func convertReindexStmt(n *pg.ReindexStmt) *ast.ReindexStmt { + if n == nil { + return nil + } + return &ast.ReindexStmt{ + Kind: ast.ReindexObjectType(n.Kind), + Relation: convertRangeVar(n.Relation), + Name: makeString(n.Name), + // Options: int(n.Options), TODO: Support params + } +} + +func convertRelabelType(n *pg.RelabelType) *ast.RelabelType { + if n == nil { + return nil + } + return &ast.RelabelType{ + Xpr: convertNode(n.Xpr), + Arg: convertNode(n.Arg), + Resulttype: ast.Oid(n.Resulttype), + Resulttypmod: n.Resulttypmod, + Resultcollid: ast.Oid(n.Resultcollid), + Relabelformat: ast.CoercionForm(n.Relabelformat), + Location: int(n.Location), + } +} + +func convertRenameStmt(n *pg.RenameStmt) *ast.RenameStmt { + if n == nil { + return nil + } + return &ast.RenameStmt{ + RenameType: ast.ObjectType(n.RenameType), + RelationType: ast.ObjectType(n.RelationType), + Relation: convertRangeVar(n.Relation), + Object: convertNode(n.Object), + Subname: makeString(n.Subname), + Newname: makeString(n.Newname), + Behavior: ast.DropBehavior(n.Behavior), + MissingOk: n.MissingOk, + } +} + +func convertReplicaIdentityStmt(n *pg.ReplicaIdentityStmt) *ast.ReplicaIdentityStmt { + if n == nil { + return nil + } + return &ast.ReplicaIdentityStmt{ + IdentityType: makeByte(n.IdentityType), + Name: makeString(n.Name), + } +} + +func convertResTarget(n *pg.ResTarget) *ast.ResTarget { + if n == nil { + return nil + } + return &ast.ResTarget{ + Name: makeString(n.Name), + Indirection: convertSlice(n.Indirection), + Val: convertNode(n.Val), + Location: int(n.Location), + } +} + +func convertRoleSpec(n *pg.RoleSpec) *ast.RoleSpec { + if n == nil { + return nil + } + return &ast.RoleSpec{ + Roletype: ast.RoleSpecType(n.Roletype), + Rolename: makeString(n.Rolename), + Location: int(n.Location), + } +} + +func convertRowCompareExpr(n *pg.RowCompareExpr) *ast.RowCompareExpr { + if n == nil { + return nil + } + return &ast.RowCompareExpr{ + Xpr: convertNode(n.Xpr), + Rctype: ast.RowCompareType(n.Cmptype), + Opnos: convertSlice(n.Opnos), + Opfamilies: convertSlice(n.Opfamilies), + Inputcollids: convertSlice(n.Inputcollids), + Largs: convertSlice(n.Largs), + Rargs: convertSlice(n.Rargs), + } +} + +func convertRowExpr(n *pg.RowExpr) *ast.RowExpr { + if n == nil { + return nil + } + return &ast.RowExpr{ + Xpr: convertNode(n.Xpr), + Args: convertSlice(n.Args), + RowTypeid: ast.Oid(n.RowTypeid), + RowFormat: ast.CoercionForm(n.RowFormat), + Colnames: convertSlice(n.Colnames), + Location: int(n.Location), + } +} + +func convertRowMarkClause(n *pg.RowMarkClause) *ast.RowMarkClause { + if n == nil { + return nil + } + return &ast.RowMarkClause{ + Rti: ast.Index(n.Rti), + Strength: ast.LockClauseStrength(n.Strength), + WaitPolicy: ast.LockWaitPolicy(n.WaitPolicy), + PushedDown: n.PushedDown, + } +} + +func convertRuleStmt(n *pg.RuleStmt) *ast.RuleStmt { + if n == nil { + return nil + } + return &ast.RuleStmt{ + Relation: convertRangeVar(n.Relation), + Rulename: makeString(n.Rulename), + WhereClause: convertNode(n.WhereClause), + Event: ast.CmdType(n.Event), + Instead: n.Instead, + Actions: convertSlice(n.Actions), + Replace: n.Replace, + } +} + +func convertSQLValueFunction(n *pg.SQLValueFunction) *ast.SQLValueFunction { + if n == nil { + return nil + } + return &ast.SQLValueFunction{ + Xpr: convertNode(n.Xpr), + Op: ast.SQLValueFunctionOp(n.Op), + Type: ast.Oid(n.Type), + Typmod: n.Typmod, + Location: int(n.Location), + } +} + +func convertScalarArrayOpExpr(n *pg.ScalarArrayOpExpr) *ast.ScalarArrayOpExpr { + if n == nil { + return nil + } + return &ast.ScalarArrayOpExpr{ + Xpr: convertNode(n.Xpr), + Opno: ast.Oid(n.Opno), + UseOr: n.UseOr, + Inputcollid: ast.Oid(n.Inputcollid), + Args: convertSlice(n.Args), + Location: int(n.Location), + } +} + +func convertSecLabelStmt(n *pg.SecLabelStmt) *ast.SecLabelStmt { + if n == nil { + return nil + } + return &ast.SecLabelStmt{ + Objtype: ast.ObjectType(n.Objtype), + Object: convertNode(n.Object), + Provider: makeString(n.Provider), + Label: makeString(n.Label), + } +} + +func convertSelectStmt(n *pg.SelectStmt) *ast.SelectStmt { + if n == nil { + return nil + } + op, err := convertSetOperation(n.Op) + if err != nil { + panic(err) + } + return &ast.SelectStmt{ + DistinctClause: convertSlice(n.DistinctClause), + IntoClause: convertIntoClause(n.IntoClause), + TargetList: convertSlice(n.TargetList), + FromClause: convertSlice(n.FromClause), + WhereClause: convertNode(n.WhereClause), + GroupClause: convertSlice(n.GroupClause), + HavingClause: convertNode(n.HavingClause), + WindowClause: convertSlice(n.WindowClause), + ValuesLists: convertSlice(n.ValuesLists), + SortClause: convertSlice(n.SortClause), + LimitOffset: convertNode(n.LimitOffset), + LimitCount: convertNode(n.LimitCount), + LockingClause: convertSlice(n.LockingClause), + WithClause: convertWithClause(n.WithClause), + Op: op, + All: n.All, + Larg: convertSelectStmt(n.Larg), + Rarg: convertSelectStmt(n.Rarg), + } +} + +func convertSetOperationStmt(n *pg.SetOperationStmt) *ast.SetOperationStmt { + if n == nil { + return nil + } + op, err := convertSetOperation(n.Op) + if err != nil { + panic(err) + } + return &ast.SetOperationStmt{ + Op: op, + All: n.All, + Larg: convertNode(n.Larg), + Rarg: convertNode(n.Rarg), + ColTypes: convertSlice(n.ColTypes), + ColTypmods: convertSlice(n.ColTypmods), + ColCollations: convertSlice(n.ColCollations), + GroupClauses: convertSlice(n.GroupClauses), + } +} + +func convertSetToDefault(n *pg.SetToDefault) *ast.SetToDefault { + if n == nil { + return nil + } + return &ast.SetToDefault{ + Xpr: convertNode(n.Xpr), + TypeId: ast.Oid(n.TypeId), + TypeMod: n.TypeMod, + Collation: ast.Oid(n.Collation), + Location: int(n.Location), + } +} + +func convertSortBy(n *pg.SortBy) *ast.SortBy { + if n == nil { + return nil + } + return &ast.SortBy{ + Node: convertNode(n.Node), + SortbyDir: ast.SortByDir(n.SortbyDir), + SortbyNulls: ast.SortByNulls(n.SortbyNulls), + UseOp: convertSlice(n.UseOp), + Location: int(n.Location), + } +} + +func convertSortGroupClause(n *pg.SortGroupClause) *ast.SortGroupClause { + if n == nil { + return nil + } + return &ast.SortGroupClause{ + TleSortGroupRef: ast.Index(n.TleSortGroupRef), + Eqop: ast.Oid(n.Eqop), + Sortop: ast.Oid(n.Sortop), + NullsFirst: n.NullsFirst, + Hashable: n.Hashable, + } +} + +func convertString(n *pg.String) *ast.String { + if n == nil { + return nil + } + return &ast.String{ + Str: n.Sval, + } +} + +func convertSubLink(n *pg.SubLink) *ast.SubLink { + if n == nil { + return nil + } + slt, err := convertSubLinkType(n.SubLinkType) + if err != nil { + panic(err) + } + return &ast.SubLink{ + Xpr: convertNode(n.Xpr), + SubLinkType: slt, + SubLinkId: int(n.SubLinkId), + Testexpr: convertNode(n.Testexpr), + OperName: convertSlice(n.OperName), + Subselect: convertNode(n.Subselect), + Location: int(n.Location), + } +} + +func convertSubPlan(n *pg.SubPlan) *ast.SubPlan { + if n == nil { + return nil + } + slt, err := convertSubLinkType(n.SubLinkType) + if err != nil { + panic(err) + } + return &ast.SubPlan{ + Xpr: convertNode(n.Xpr), + SubLinkType: slt, + Testexpr: convertNode(n.Testexpr), + ParamIds: convertSlice(n.ParamIds), + PlanId: int(n.PlanId), + PlanName: makeString(n.PlanName), + FirstColType: ast.Oid(n.FirstColType), + FirstColTypmod: n.FirstColTypmod, + FirstColCollation: ast.Oid(n.FirstColCollation), + UseHashTable: n.UseHashTable, + UnknownEqFalse: n.UnknownEqFalse, + ParallelSafe: n.ParallelSafe, + SetParam: convertSlice(n.SetParam), + ParParam: convertSlice(n.ParParam), + Args: convertSlice(n.Args), + StartupCost: ast.Cost(n.StartupCost), + PerCallCost: ast.Cost(n.PerCallCost), + } +} + +func convertTableFunc(n *pg.TableFunc) *ast.TableFunc { + if n == nil { + return nil + } + return &ast.TableFunc{ + NsUris: convertSlice(n.NsUris), + NsNames: convertSlice(n.NsNames), + Docexpr: convertNode(n.Docexpr), + Rowexpr: convertNode(n.Rowexpr), + Colnames: convertSlice(n.Colnames), + Coltypes: convertSlice(n.Coltypes), + Coltypmods: convertSlice(n.Coltypmods), + Colcollations: convertSlice(n.Colcollations), + Colexprs: convertSlice(n.Colexprs), + Coldefexprs: convertSlice(n.Coldefexprs), + Notnulls: makeUint32Slice(n.Notnulls), + Ordinalitycol: int(n.Ordinalitycol), + Location: int(n.Location), + } +} + +func convertTableLikeClause(n *pg.TableLikeClause) *ast.TableLikeClause { + if n == nil { + return nil + } + return &ast.TableLikeClause{ + Relation: convertRangeVar(n.Relation), + Options: n.Options, + } +} + +func convertTableSampleClause(n *pg.TableSampleClause) *ast.TableSampleClause { + if n == nil { + return nil + } + return &ast.TableSampleClause{ + Tsmhandler: ast.Oid(n.Tsmhandler), + Args: convertSlice(n.Args), + Repeatable: convertNode(n.Repeatable), + } +} + +func convertTargetEntry(n *pg.TargetEntry) *ast.TargetEntry { + if n == nil { + return nil + } + return &ast.TargetEntry{ + Xpr: convertNode(n.Xpr), + Expr: convertNode(n.Expr), + Resno: ast.AttrNumber(n.Resno), + Resname: makeString(n.Resname), + Ressortgroupref: ast.Index(n.Ressortgroupref), + Resorigtbl: ast.Oid(n.Resorigtbl), + Resorigcol: ast.AttrNumber(n.Resorigcol), + Resjunk: n.Resjunk, + } +} + +func convertTransactionStmt(n *pg.TransactionStmt) *ast.TransactionStmt { + if n == nil { + return nil + } + return &ast.TransactionStmt{ + Kind: ast.TransactionStmtKind(n.Kind), + Options: convertSlice(n.Options), + Gid: makeString(n.Gid), + } +} + +func convertTriggerTransition(n *pg.TriggerTransition) *ast.TriggerTransition { + if n == nil { + return nil + } + return &ast.TriggerTransition{ + Name: makeString(n.Name), + IsNew: n.IsNew, + IsTable: n.IsTable, + } +} + +func convertTruncateStmt(n *pg.TruncateStmt) *ast.TruncateStmt { + if n == nil { + return nil + } + return &ast.TruncateStmt{ + Relations: convertSlice(n.Relations), + RestartSeqs: n.RestartSeqs, + Behavior: ast.DropBehavior(n.Behavior), + } +} + +func convertTypeCast(n *pg.TypeCast) *ast.TypeCast { + if n == nil { + return nil + } + return &ast.TypeCast{ + Arg: convertNode(n.Arg), + TypeName: convertTypeName(n.TypeName), + Location: int(n.Location), + } +} + +func convertTypeName(n *pg.TypeName) *ast.TypeName { + if n == nil { + return nil + } + out := &ast.TypeName{ + Names: convertSlice(n.Names), + TypeOid: ast.Oid(n.TypeOid), + Setof: n.Setof, + PctType: n.PctType, + Typmods: convertSlice(n.Typmods), + Typemod: n.Typemod, + ArrayBounds: convertSlice(n.ArrayBounds), + Location: int(n.Location), + } + decodeIntervalTypmods(out) + return out +} + +// decodeIntervalTypmods turns the field mask an interval's first type +// modifier carries — what the parser reports for CAST(x AS interval day to +// second) — into the words format_type prints, as a column definition's +// type does; the full range is dropped. +func decodeIntervalTypmods(tn *ast.TypeName) { + if tn.Typmods == nil || len(tn.Typmods.Items) == 0 || len(tn.Names.Items) == 0 { + return + } + last, ok := tn.Names.Items[len(tn.Names.Items)-1].(*ast.String) + if !ok || last.Str != "interval" { + return + } + c, ok := tn.Typmods.Items[0].(*ast.A_Const) + if !ok { + return + } + mask, ok := c.Val.(*ast.Integer) + if !ok { + return + } + fields, ok := intervalFields[int32(mask.Ival)] + if !ok { + return + } + rest := tn.Typmods.Items[1:] + if fields != "" { + rest = append([]ast.Node{&ast.String{Str: fields}}, rest...) + } + if len(rest) == 0 { + tn.Typmods = nil + return + } + tn.Typmods = &ast.List{Items: rest} +} + +func convertUnlistenStmt(n *pg.UnlistenStmt) *ast.UnlistenStmt { + if n == nil { + return nil + } + return &ast.UnlistenStmt{ + Conditionname: makeString(n.Conditionname), + } +} + +func convertUpdateStmt(n *pg.UpdateStmt) *ast.UpdateStmt { + if n == nil { + return nil + } + + oldAlias, newAlias := convertReturningOptions(n.ReturningClause) + return &ast.UpdateStmt{ + Relations: &ast.List{ + Items: []ast.Node{convertRangeVar(n.Relation)}, + }, + TargetList: convertSlice(n.TargetList), + WhereClause: convertNode(n.WhereClause), + FromClause: convertSlice(n.FromClause), + ReturningList: convertSlice(n.ReturningClause.GetExprs()), + ReturningOldAlias: oldAlias, + ReturningNewAlias: newAlias, + WithClause: convertWithClause(n.WithClause), + } +} + +func convertVacuumStmt(n *pg.VacuumStmt) *ast.VacuumStmt { + if n == nil { + return nil + } + return &ast.VacuumStmt{ + // FIXME: The VacuumStmt node has changed quite a bit + // Options: n.Options + // Relation: convertRangeVar(n.Relation), + // VaCols: convertSlice(n.VaCols), + } +} + +func convertVar(n *pg.Var) *ast.Var { + if n == nil { + return nil + } + return &ast.Var{ + Xpr: convertNode(n.Xpr), + Varno: ast.Index(n.Varno), + Varattno: ast.AttrNumber(n.Varattno), + Vartype: ast.Oid(n.Vartype), + Vartypmod: n.Vartypmod, + Varcollid: ast.Oid(n.Varcollid), + Varlevelsup: ast.Index(n.Varlevelsup), + Location: int(n.Location), + } +} + +func convertVariableSetStmt(n *pg.VariableSetStmt) *ast.VariableSetStmt { + if n == nil { + return nil + } + return &ast.VariableSetStmt{ + Kind: ast.VariableSetKind(n.Kind), + Name: makeString(n.Name), + Args: convertSlice(n.Args), + IsLocal: n.IsLocal, + } +} + +func convertVariableShowStmt(n *pg.VariableShowStmt) *ast.VariableShowStmt { + if n == nil { + return nil + } + return &ast.VariableShowStmt{ + Name: makeString(n.Name), + } +} + +func convertViewStmt(n *pg.ViewStmt) *ast.ViewStmt { + if n == nil { + return nil + } + return &ast.ViewStmt{ + View: convertRangeVar(n.View), + Aliases: convertSlice(n.Aliases), + Query: convertNode(n.Query), + Replace: n.Replace, + Options: convertSlice(n.Options), + WithCheckOption: ast.ViewCheckOption(n.WithCheckOption), + } +} + +func convertWindowClause(n *pg.WindowClause) *ast.WindowClause { + if n == nil { + return nil + } + return &ast.WindowClause{ + Name: makeString(n.Name), + Refname: makeString(n.Refname), + PartitionClause: convertSlice(n.PartitionClause), + OrderClause: convertSlice(n.OrderClause), + FrameOptions: int(n.FrameOptions), + StartOffset: convertNode(n.StartOffset), + EndOffset: convertNode(n.EndOffset), + Winref: ast.Index(n.Winref), + CopiedOrder: n.CopiedOrder, + } +} + +func convertWindowDef(n *pg.WindowDef) *ast.WindowDef { + if n == nil { + return nil + } + return &ast.WindowDef{ + Name: makeString(n.Name), + Refname: makeString(n.Refname), + PartitionClause: convertSlice(n.PartitionClause), + OrderClause: convertSlice(n.OrderClause), + FrameOptions: int(n.FrameOptions), + StartOffset: convertNode(n.StartOffset), + EndOffset: convertNode(n.EndOffset), + Location: int(n.Location), + } +} + +func convertWindowFunc(n *pg.WindowFunc) *ast.WindowFunc { + if n == nil { + return nil + } + return &ast.WindowFunc{ + Xpr: convertNode(n.Xpr), + Winfnoid: ast.Oid(n.Winfnoid), + Wintype: ast.Oid(n.Wintype), + Wincollid: ast.Oid(n.Wincollid), + Inputcollid: ast.Oid(n.Inputcollid), + Args: convertSlice(n.Args), + Aggfilter: convertNode(n.Aggfilter), + Winref: ast.Index(n.Winref), + Winstar: n.Winstar, + Winagg: n.Winagg, + Location: int(n.Location), + } +} + +func convertWithCheckOption(n *pg.WithCheckOption) *ast.WithCheckOption { + if n == nil { + return nil + } + return &ast.WithCheckOption{ + Kind: ast.WCOKind(n.Kind), + Relname: makeString(n.Relname), + Polname: makeString(n.Polname), + Qual: convertNode(n.Qual), + Cascaded: n.Cascaded, + } +} + +func convertWithClause(n *pg.WithClause) *ast.WithClause { + if n == nil { + return nil + } + return &ast.WithClause{ + Ctes: convertSlice(n.Ctes), + Recursive: n.Recursive, + Location: int(n.Location), + } +} + +func convertXmlExpr(n *pg.XmlExpr) *ast.XmlExpr { + if n == nil { + return nil + } + return &ast.XmlExpr{ + Xpr: convertNode(n.Xpr), + Op: ast.XmlExprOp(n.Op), + Name: makeString(n.Name), + NamedArgs: convertSlice(n.NamedArgs), + ArgNames: convertSlice(n.ArgNames), + Args: convertSlice(n.Args), + Xmloption: ast.XmlOptionType(n.Xmloption), + Type: ast.Oid(n.Type), + Typmod: n.Typmod, + Location: int(n.Location), + } +} + +func convertXmlSerialize(n *pg.XmlSerialize) *ast.XmlSerialize { + if n == nil { + return nil + } + return &ast.XmlSerialize{ + Xmloption: ast.XmlOptionType(n.Xmloption), + Expr: convertNode(n.Expr), + TypeName: convertTypeName(n.TypeName), + Location: int(n.Location), + } +} + +func convertNode(node *pg.Node) ast.Node { + if node == nil || node.Node == nil { + return &ast.TODO{} + } + + switch n := node.Node.(type) { + + case *pg.Node_AArrayExpr: + return convertA_ArrayExpr(n.AArrayExpr) + + case *pg.Node_AConst: + return convertA_Const(n.AConst) + + case *pg.Node_AExpr: + return convertA_Expr(n.AExpr) + + case *pg.Node_AIndices: + return convertA_Indices(n.AIndices) + + case *pg.Node_AIndirection: + return convertA_Indirection(n.AIndirection) + + case *pg.Node_AStar: + return convertA_Star(n.AStar) + + case *pg.Node_AccessPriv: + return convertAccessPriv(n.AccessPriv) + + case *pg.Node_Aggref: + return convertAggref(n.Aggref) + + case *pg.Node_Alias: + return convertAlias(n.Alias) + + case *pg.Node_AlterCollationStmt: + return convertAlterCollationStmt(n.AlterCollationStmt) + + case *pg.Node_AlterDatabaseSetStmt: + return convertAlterDatabaseSetStmt(n.AlterDatabaseSetStmt) + + case *pg.Node_AlterDatabaseStmt: + return convertAlterDatabaseStmt(n.AlterDatabaseStmt) + + case *pg.Node_AlterDefaultPrivilegesStmt: + return convertAlterDefaultPrivilegesStmt(n.AlterDefaultPrivilegesStmt) + + case *pg.Node_AlterDomainStmt: + return convertAlterDomainStmt(n.AlterDomainStmt) + + case *pg.Node_AlterEnumStmt: + return convertAlterEnumStmt(n.AlterEnumStmt) + + case *pg.Node_AlterEventTrigStmt: + return convertAlterEventTrigStmt(n.AlterEventTrigStmt) + + case *pg.Node_AlterExtensionContentsStmt: + return convertAlterExtensionContentsStmt(n.AlterExtensionContentsStmt) + + case *pg.Node_AlterExtensionStmt: + return convertAlterExtensionStmt(n.AlterExtensionStmt) + + case *pg.Node_AlterFdwStmt: + return convertAlterFdwStmt(n.AlterFdwStmt) + + case *pg.Node_AlterForeignServerStmt: + return convertAlterForeignServerStmt(n.AlterForeignServerStmt) + + case *pg.Node_AlterFunctionStmt: + return convertAlterFunctionStmt(n.AlterFunctionStmt) + + case *pg.Node_AlterObjectDependsStmt: + return convertAlterObjectDependsStmt(n.AlterObjectDependsStmt) + + case *pg.Node_AlterObjectSchemaStmt: + return convertAlterObjectSchemaStmt(n.AlterObjectSchemaStmt) + + case *pg.Node_AlterOpFamilyStmt: + return convertAlterOpFamilyStmt(n.AlterOpFamilyStmt) + + case *pg.Node_AlterOperatorStmt: + return convertAlterOperatorStmt(n.AlterOperatorStmt) + + case *pg.Node_AlterOwnerStmt: + return convertAlterOwnerStmt(n.AlterOwnerStmt) + + case *pg.Node_AlterPolicyStmt: + return convertAlterPolicyStmt(n.AlterPolicyStmt) + + case *pg.Node_AlterPublicationStmt: + return convertAlterPublicationStmt(n.AlterPublicationStmt) + + case *pg.Node_AlterRoleSetStmt: + return convertAlterRoleSetStmt(n.AlterRoleSetStmt) + + case *pg.Node_AlterRoleStmt: + return convertAlterRoleStmt(n.AlterRoleStmt) + + case *pg.Node_AlterSeqStmt: + return convertAlterSeqStmt(n.AlterSeqStmt) + + case *pg.Node_AlterSubscriptionStmt: + return convertAlterSubscriptionStmt(n.AlterSubscriptionStmt) + + case *pg.Node_AlterSystemStmt: + return convertAlterSystemStmt(n.AlterSystemStmt) + + case *pg.Node_AlterTsconfigurationStmt: + return convertAlterTSConfigurationStmt(n.AlterTsconfigurationStmt) + + case *pg.Node_AlterTsdictionaryStmt: + return convertAlterTSDictionaryStmt(n.AlterTsdictionaryStmt) + + case *pg.Node_AlterTableCmd: + return convertAlterTableCmd(n.AlterTableCmd) + + case *pg.Node_AlterTableMoveAllStmt: + return convertAlterTableMoveAllStmt(n.AlterTableMoveAllStmt) + + case *pg.Node_AlterTableSpaceOptionsStmt: + return convertAlterTableSpaceOptionsStmt(n.AlterTableSpaceOptionsStmt) + + case *pg.Node_AlterTableStmt: + return convertAlterTableStmt(n.AlterTableStmt) + + case *pg.Node_AlterUserMappingStmt: + return convertAlterUserMappingStmt(n.AlterUserMappingStmt) + + case *pg.Node_AlternativeSubPlan: + return convertAlternativeSubPlan(n.AlternativeSubPlan) + + case *pg.Node_ArrayCoerceExpr: + return convertArrayCoerceExpr(n.ArrayCoerceExpr) + + case *pg.Node_ArrayExpr: + return convertArrayExpr(n.ArrayExpr) + + case *pg.Node_BitString: + return convertBitString(n.BitString) + + case *pg.Node_BoolExpr: + return convertBoolExpr(n.BoolExpr) + + case *pg.Node_Boolean: + return convertBoolean(n.Boolean) + + case *pg.Node_BooleanTest: + return convertBooleanTest(n.BooleanTest) + + case *pg.Node_CallStmt: + return convertCallStmt(n.CallStmt) + + case *pg.Node_CaseExpr: + return convertCaseExpr(n.CaseExpr) + + case *pg.Node_CaseTestExpr: + return convertCaseTestExpr(n.CaseTestExpr) + + case *pg.Node_CaseWhen: + return convertCaseWhen(n.CaseWhen) + + case *pg.Node_CheckPointStmt: + return convertCheckPointStmt(n.CheckPointStmt) + + case *pg.Node_ClosePortalStmt: + return convertClosePortalStmt(n.ClosePortalStmt) + + case *pg.Node_ClusterStmt: + return convertClusterStmt(n.ClusterStmt) + + case *pg.Node_CoalesceExpr: + return convertCoalesceExpr(n.CoalesceExpr) + + case *pg.Node_CoerceToDomain: + return convertCoerceToDomain(n.CoerceToDomain) + + case *pg.Node_CoerceToDomainValue: + return convertCoerceToDomainValue(n.CoerceToDomainValue) + + case *pg.Node_CoerceViaIo: + return convertCoerceViaIO(n.CoerceViaIo) + + case *pg.Node_CollateClause: + return convertCollateClause(n.CollateClause) + + case *pg.Node_CollateExpr: + return convertCollateExpr(n.CollateExpr) + + case *pg.Node_ColumnDef: + return convertColumnDef(n.ColumnDef) + + case *pg.Node_ColumnRef: + return convertColumnRef(n.ColumnRef) + + case *pg.Node_CommentStmt: + return convertCommentStmt(n.CommentStmt) + + case *pg.Node_CommonTableExpr: + return convertCommonTableExpr(n.CommonTableExpr) + + case *pg.Node_CompositeTypeStmt: + return convertCompositeTypeStmt(n.CompositeTypeStmt) + + case *pg.Node_Constraint: + return convertConstraint(n.Constraint) + + case *pg.Node_ConstraintsSetStmt: + return convertConstraintsSetStmt(n.ConstraintsSetStmt) + + case *pg.Node_ConvertRowtypeExpr: + return convertConvertRowtypeExpr(n.ConvertRowtypeExpr) + + case *pg.Node_CopyStmt: + return convertCopyStmt(n.CopyStmt) + + case *pg.Node_CreateAmStmt: + return convertCreateAmStmt(n.CreateAmStmt) + + case *pg.Node_CreateCastStmt: + return convertCreateCastStmt(n.CreateCastStmt) + + case *pg.Node_CreateConversionStmt: + return convertCreateConversionStmt(n.CreateConversionStmt) + + case *pg.Node_CreateDomainStmt: + return convertCreateDomainStmt(n.CreateDomainStmt) + + case *pg.Node_CreateEnumStmt: + return convertCreateEnumStmt(n.CreateEnumStmt) + + case *pg.Node_CreateEventTrigStmt: + return convertCreateEventTrigStmt(n.CreateEventTrigStmt) + + case *pg.Node_CreateExtensionStmt: + return convertCreateExtensionStmt(n.CreateExtensionStmt) + + case *pg.Node_CreateFdwStmt: + return convertCreateFdwStmt(n.CreateFdwStmt) + + case *pg.Node_CreateForeignServerStmt: + return convertCreateForeignServerStmt(n.CreateForeignServerStmt) + + case *pg.Node_CreateForeignTableStmt: + return convertCreateForeignTableStmt(n.CreateForeignTableStmt) + + case *pg.Node_CreateFunctionStmt: + return convertCreateFunctionStmt(n.CreateFunctionStmt) + + case *pg.Node_CreateOpClassItem: + return convertCreateOpClassItem(n.CreateOpClassItem) + + case *pg.Node_CreateOpClassStmt: + return convertCreateOpClassStmt(n.CreateOpClassStmt) + + case *pg.Node_CreateOpFamilyStmt: + return convertCreateOpFamilyStmt(n.CreateOpFamilyStmt) + + case *pg.Node_CreatePlangStmt: + return convertCreatePLangStmt(n.CreatePlangStmt) + + case *pg.Node_CreatePolicyStmt: + return convertCreatePolicyStmt(n.CreatePolicyStmt) + + case *pg.Node_CreatePublicationStmt: + return convertCreatePublicationStmt(n.CreatePublicationStmt) + + case *pg.Node_CreateRangeStmt: + return convertCreateRangeStmt(n.CreateRangeStmt) + + case *pg.Node_CreateRoleStmt: + return convertCreateRoleStmt(n.CreateRoleStmt) + + case *pg.Node_CreateSchemaStmt: + return convertCreateSchemaStmt(n.CreateSchemaStmt) + + case *pg.Node_CreateSeqStmt: + return convertCreateSeqStmt(n.CreateSeqStmt) + + case *pg.Node_CreateStatsStmt: + return convertCreateStatsStmt(n.CreateStatsStmt) + + case *pg.Node_CreateStmt: + return convertCreateStmt(n.CreateStmt) + + case *pg.Node_CreateSubscriptionStmt: + return convertCreateSubscriptionStmt(n.CreateSubscriptionStmt) + + case *pg.Node_CreateTableAsStmt: + return convertCreateTableAsStmt(n.CreateTableAsStmt) + + case *pg.Node_CreateTableSpaceStmt: + return convertCreateTableSpaceStmt(n.CreateTableSpaceStmt) + + case *pg.Node_CreateTransformStmt: + return convertCreateTransformStmt(n.CreateTransformStmt) + + case *pg.Node_CreateTrigStmt: + return convertCreateTrigStmt(n.CreateTrigStmt) + + case *pg.Node_CreateUserMappingStmt: + return convertCreateUserMappingStmt(n.CreateUserMappingStmt) + + case *pg.Node_CreatedbStmt: + return convertCreatedbStmt(n.CreatedbStmt) + + case *pg.Node_CurrentOfExpr: + return convertCurrentOfExpr(n.CurrentOfExpr) + + case *pg.Node_DeallocateStmt: + return convertDeallocateStmt(n.DeallocateStmt) + + case *pg.Node_DeclareCursorStmt: + return convertDeclareCursorStmt(n.DeclareCursorStmt) + + case *pg.Node_DefElem: + return convertDefElem(n.DefElem) + + case *pg.Node_DefineStmt: + return convertDefineStmt(n.DefineStmt) + + case *pg.Node_DeleteStmt: + return convertDeleteStmt(n.DeleteStmt) + + case *pg.Node_DiscardStmt: + return convertDiscardStmt(n.DiscardStmt) + + case *pg.Node_DoStmt: + return convertDoStmt(n.DoStmt) + + case *pg.Node_DropOwnedStmt: + return convertDropOwnedStmt(n.DropOwnedStmt) + + case *pg.Node_DropRoleStmt: + return convertDropRoleStmt(n.DropRoleStmt) + + case *pg.Node_DropStmt: + return convertDropStmt(n.DropStmt) + + case *pg.Node_DropSubscriptionStmt: + return convertDropSubscriptionStmt(n.DropSubscriptionStmt) + + case *pg.Node_DropTableSpaceStmt: + return convertDropTableSpaceStmt(n.DropTableSpaceStmt) + + case *pg.Node_DropUserMappingStmt: + return convertDropUserMappingStmt(n.DropUserMappingStmt) + + case *pg.Node_DropdbStmt: + return convertDropdbStmt(n.DropdbStmt) + + case *pg.Node_ExecuteStmt: + return convertExecuteStmt(n.ExecuteStmt) + + case *pg.Node_ExplainStmt: + return convertExplainStmt(n.ExplainStmt) + + case *pg.Node_FetchStmt: + return convertFetchStmt(n.FetchStmt) + + case *pg.Node_FieldSelect: + return convertFieldSelect(n.FieldSelect) + + case *pg.Node_FieldStore: + return convertFieldStore(n.FieldStore) + + case *pg.Node_Float: + return convertFloat(n.Float) + + case *pg.Node_FromExpr: + return convertFromExpr(n.FromExpr) + + case *pg.Node_FuncCall: + return convertFuncCall(n.FuncCall) + + case *pg.Node_FuncExpr: + return convertFuncExpr(n.FuncExpr) + + case *pg.Node_FunctionParameter: + return convertFunctionParameter(n.FunctionParameter) + + case *pg.Node_GrantRoleStmt: + return convertGrantRoleStmt(n.GrantRoleStmt) + + case *pg.Node_GrantStmt: + return convertGrantStmt(n.GrantStmt) + + case *pg.Node_GroupingFunc: + return convertGroupingFunc(n.GroupingFunc) + + case *pg.Node_GroupingSet: + return convertGroupingSet(n.GroupingSet) + + case *pg.Node_ImportForeignSchemaStmt: + return convertImportForeignSchemaStmt(n.ImportForeignSchemaStmt) + + case *pg.Node_IndexElem: + return convertIndexElem(n.IndexElem) + + case *pg.Node_IndexStmt: + return convertIndexStmt(n.IndexStmt) + + case *pg.Node_InferClause: + return convertInferClause(n.InferClause) + + case *pg.Node_InferenceElem: + return convertInferenceElem(n.InferenceElem) + + case *pg.Node_InlineCodeBlock: + return convertInlineCodeBlock(n.InlineCodeBlock) + + case *pg.Node_InsertStmt: + return convertInsertStmt(n.InsertStmt) + + case *pg.Node_Integer: + return convertInteger(n.Integer) + + case *pg.Node_IntoClause: + return convertIntoClause(n.IntoClause) + + case *pg.Node_JoinExpr: + return convertJoinExpr(n.JoinExpr) + + case *pg.Node_List: + return convertList(n.List) + + case *pg.Node_ListenStmt: + return convertListenStmt(n.ListenStmt) + + case *pg.Node_LoadStmt: + return convertLoadStmt(n.LoadStmt) + + case *pg.Node_LockStmt: + return convertLockStmt(n.LockStmt) + + case *pg.Node_LockingClause: + return convertLockingClause(n.LockingClause) + + case *pg.Node_MinMaxExpr: + return convertMinMaxExpr(n.MinMaxExpr) + + case *pg.Node_MultiAssignRef: + return convertMultiAssignRef(n.MultiAssignRef) + + case *pg.Node_NamedArgExpr: + return convertNamedArgExpr(n.NamedArgExpr) + + case *pg.Node_NextValueExpr: + return convertNextValueExpr(n.NextValueExpr) + + case *pg.Node_NotifyStmt: + return convertNotifyStmt(n.NotifyStmt) + + case *pg.Node_NullTest: + return convertNullTest(n.NullTest) + + case *pg.Node_NullIfExpr: + return convertNullIfExpr(n.NullIfExpr) + + case *pg.Node_ObjectWithArgs: + return convertObjectWithArgs(n.ObjectWithArgs) + + case *pg.Node_OnConflictClause: + return convertOnConflictClause(n.OnConflictClause) + + case *pg.Node_OnConflictExpr: + return convertOnConflictExpr(n.OnConflictExpr) + + case *pg.Node_OpExpr: + return convertOpExpr(n.OpExpr) + + case *pg.Node_Param: + return convertParam(n.Param) + + case *pg.Node_ParamRef: + return convertParamRef(n.ParamRef) + + case *pg.Node_PartitionBoundSpec: + return convertPartitionBoundSpec(n.PartitionBoundSpec) + + case *pg.Node_PartitionCmd: + return convertPartitionCmd(n.PartitionCmd) + + case *pg.Node_PartitionElem: + return convertPartitionElem(n.PartitionElem) + + case *pg.Node_PartitionRangeDatum: + return convertPartitionRangeDatum(n.PartitionRangeDatum) + + case *pg.Node_PartitionSpec: + return convertPartitionSpec(n.PartitionSpec) + + case *pg.Node_PrepareStmt: + return convertPrepareStmt(n.PrepareStmt) + + case *pg.Node_Query: + return convertQuery(n.Query) + + case *pg.Node_RangeFunction: + return convertRangeFunction(n.RangeFunction) + + case *pg.Node_RangeSubselect: + return convertRangeSubselect(n.RangeSubselect) + + case *pg.Node_RangeTableFunc: + return convertRangeTableFunc(n.RangeTableFunc) + + case *pg.Node_RangeTableFuncCol: + return convertRangeTableFuncCol(n.RangeTableFuncCol) + + case *pg.Node_RangeTableSample: + return convertRangeTableSample(n.RangeTableSample) + + case *pg.Node_RangeTblEntry: + return convertRangeTblEntry(n.RangeTblEntry) + + case *pg.Node_RangeTblFunction: + return convertRangeTblFunction(n.RangeTblFunction) + + case *pg.Node_RangeTblRef: + return convertRangeTblRef(n.RangeTblRef) + + case *pg.Node_RangeVar: + return convertRangeVar(n.RangeVar) + + case *pg.Node_RawStmt: + return convertRawStmt(n.RawStmt) + + case *pg.Node_ReassignOwnedStmt: + return convertReassignOwnedStmt(n.ReassignOwnedStmt) + + case *pg.Node_RefreshMatViewStmt: + return convertRefreshMatViewStmt(n.RefreshMatViewStmt) + + case *pg.Node_ReindexStmt: + return convertReindexStmt(n.ReindexStmt) + + case *pg.Node_RelabelType: + return convertRelabelType(n.RelabelType) + + case *pg.Node_RenameStmt: + return convertRenameStmt(n.RenameStmt) + + case *pg.Node_ReplicaIdentityStmt: + return convertReplicaIdentityStmt(n.ReplicaIdentityStmt) + + case *pg.Node_ResTarget: + return convertResTarget(n.ResTarget) + + case *pg.Node_RoleSpec: + return convertRoleSpec(n.RoleSpec) + + case *pg.Node_RowCompareExpr: + return convertRowCompareExpr(n.RowCompareExpr) + + case *pg.Node_RowExpr: + return convertRowExpr(n.RowExpr) + + case *pg.Node_RowMarkClause: + return convertRowMarkClause(n.RowMarkClause) + + case *pg.Node_RuleStmt: + return convertRuleStmt(n.RuleStmt) + + case *pg.Node_SqlvalueFunction: + return convertSQLValueFunction(n.SqlvalueFunction) + + case *pg.Node_ScalarArrayOpExpr: + return convertScalarArrayOpExpr(n.ScalarArrayOpExpr) + + case *pg.Node_SecLabelStmt: + return convertSecLabelStmt(n.SecLabelStmt) + + case *pg.Node_SelectStmt: + return convertSelectStmt(n.SelectStmt) + + case *pg.Node_SetOperationStmt: + return convertSetOperationStmt(n.SetOperationStmt) + + case *pg.Node_SetToDefault: + return convertSetToDefault(n.SetToDefault) + + case *pg.Node_SortBy: + return convertSortBy(n.SortBy) + + case *pg.Node_SortGroupClause: + return convertSortGroupClause(n.SortGroupClause) + + case *pg.Node_String_: + return convertString(n.String_) + + case *pg.Node_SubLink: + return convertSubLink(n.SubLink) + + case *pg.Node_SubPlan: + return convertSubPlan(n.SubPlan) + + case *pg.Node_TableFunc: + return convertTableFunc(n.TableFunc) + + case *pg.Node_TableLikeClause: + return convertTableLikeClause(n.TableLikeClause) + + case *pg.Node_TableSampleClause: + return convertTableSampleClause(n.TableSampleClause) + + case *pg.Node_TargetEntry: + return convertTargetEntry(n.TargetEntry) + + case *pg.Node_TransactionStmt: + return convertTransactionStmt(n.TransactionStmt) + + case *pg.Node_TriggerTransition: + return convertTriggerTransition(n.TriggerTransition) + + case *pg.Node_TruncateStmt: + return convertTruncateStmt(n.TruncateStmt) + + case *pg.Node_TypeCast: + return convertTypeCast(n.TypeCast) + + case *pg.Node_TypeName: + return convertTypeName(n.TypeName) + + case *pg.Node_UnlistenStmt: + return convertUnlistenStmt(n.UnlistenStmt) + + case *pg.Node_UpdateStmt: + return convertUpdateStmt(n.UpdateStmt) + + case *pg.Node_VacuumStmt: + return convertVacuumStmt(n.VacuumStmt) + + case *pg.Node_Var: + return convertVar(n.Var) + + case *pg.Node_VariableSetStmt: + return convertVariableSetStmt(n.VariableSetStmt) + + case *pg.Node_VariableShowStmt: + return convertVariableShowStmt(n.VariableShowStmt) + + case *pg.Node_ViewStmt: + return convertViewStmt(n.ViewStmt) + + case *pg.Node_WindowClause: + return convertWindowClause(n.WindowClause) + + case *pg.Node_WindowDef: + return convertWindowDef(n.WindowDef) + + case *pg.Node_WindowFunc: + return convertWindowFunc(n.WindowFunc) + + case *pg.Node_WithCheckOption: + return convertWithCheckOption(n.WithCheckOption) + + case *pg.Node_WithClause: + return convertWithClause(n.WithClause) + + case *pg.Node_XmlExpr: + return convertXmlExpr(n.XmlExpr) + + case *pg.Node_XmlSerialize: + return convertXmlSerialize(n.XmlSerialize) + + default: + return &ast.TODO{} + } +} diff --git a/internal/engine/postgresql/dialect/dialect.json b/internal/engine/postgresql/dialect/dialect.json new file mode 100644 index 0000000..d8ae141 --- /dev/null +++ b/internal/engine/postgresql/dialect/dialect.json @@ -0,0 +1,15 @@ +{ + "dialect": "postgresql", + "const": { + "integer": "integer", + "float": "numeric", + "string": "text", + "bool": "boolean" + }, + "bool": "boolean", + "comparison": ["=", "<>", "!=", "<", "<=", ">", ">=", "IS DISTINCT FROM", "IS NOT DISTINCT FROM"], + "comparison_categories": "BNSDTU", + "arithmetic": ["+", "-", "*", "/", "%"], + "arithmetic_categories": "N", + "cast_categories": "NSD" +} diff --git a/internal/engine/postgresql/dialect/extensions/adminpack/functions.jsonl b/internal/engine/postgresql/dialect/extensions/adminpack/functions.jsonl new file mode 100644 index 0000000..2cc6fca --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/adminpack/functions.jsonl @@ -0,0 +1,6 @@ +{"name":"pg_file_rename","args":[{"type":"text"},{"type":"text"}],"returns":"boolean"} +{"name":"pg_file_rename","args":[{"type":"text"},{"type":"text"},{"type":"text"}],"returns":"boolean"} +{"name":"pg_file_sync","args":[{"type":"text"}],"returns":"void"} +{"name":"pg_file_unlink","args":[{"type":"text"}],"returns":"boolean"} +{"name":"pg_file_write","args":[{"type":"text"},{"type":"text"},{"type":"boolean"}],"returns":"bigint"} +{"name":"pg_logdir_ls","returns":"record"} diff --git a/internal/engine/postgresql/dialect/extensions/amcheck/functions.jsonl b/internal/engine/postgresql/dialect/extensions/amcheck/functions.jsonl new file mode 100644 index 0000000..c0502f1 --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/amcheck/functions.jsonl @@ -0,0 +1,6 @@ +{"name":"bt_index_check","args":[{"name":"index","type":"regclass"}],"returns":"void"} +{"name":"bt_index_check","args":[{"name":"index","type":"regclass"},{"name":"heapallindexed","type":"boolean"}],"returns":"void"} +{"name":"bt_index_parent_check","args":[{"name":"index","type":"regclass"}],"returns":"void"} +{"name":"bt_index_parent_check","args":[{"name":"index","type":"regclass"},{"name":"heapallindexed","type":"boolean"}],"returns":"void"} +{"name":"bt_index_parent_check","args":[{"name":"index","type":"regclass"},{"name":"heapallindexed","type":"boolean"},{"name":"rootdescend","type":"boolean"}],"returns":"void"} +{"name":"verify_heapam","args":[{"name":"relation","type":"regclass"},{"name":"on_error_stop","type":"boolean","has_default":true},{"name":"check_toast","type":"boolean","has_default":true},{"name":"skip","type":"text","has_default":true},{"name":"startblock","type":"bigint","has_default":true},{"name":"endblock","type":"bigint","has_default":true}],"returns":"record"} diff --git a/internal/engine/postgresql/dialect/extensions/btree_gin/functions.jsonl b/internal/engine/postgresql/dialect/extensions/btree_gin/functions.jsonl new file mode 100644 index 0000000..4145ef3 --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/btree_gin/functions.jsonl @@ -0,0 +1,2 @@ +{"name":"gin_enum_cmp","args":[{"type":"anyenum"},{"type":"anyenum"}],"returns":"integer"} +{"name":"gin_numeric_cmp","args":[{"type":"numeric"},{"type":"numeric"}],"returns":"integer"} diff --git a/internal/engine/postgresql/dialect/extensions/btree_gist/functions.jsonl b/internal/engine/postgresql/dialect/extensions/btree_gist/functions.jsonl new file mode 100644 index 0000000..f160e66 --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/btree_gist/functions.jsonl @@ -0,0 +1,24 @@ +{"name":"cash_dist","args":[{"type":"money"},{"type":"money"}],"returns":"money"} +{"name":"date_dist","args":[{"type":"date"},{"type":"date"}],"returns":"integer"} +{"name":"float4_dist","args":[{"type":"real"},{"type":"real"}],"returns":"real"} +{"name":"float8_dist","args":[{"type":"double precision"},{"type":"double precision"}],"returns":"double precision"} +{"name":"gbtreekey16_in","args":[{"type":"cstring"}],"returns":"gbtreekey16"} +{"name":"gbtreekey16_out","args":[{"type":"gbtreekey16"}],"returns":"cstring"} +{"name":"gbtreekey2_in","args":[{"type":"cstring"}],"returns":"gbtreekey2"} +{"name":"gbtreekey2_out","args":[{"type":"gbtreekey2"}],"returns":"cstring"} +{"name":"gbtreekey32_in","args":[{"type":"cstring"}],"returns":"gbtreekey32"} +{"name":"gbtreekey32_out","args":[{"type":"gbtreekey32"}],"returns":"cstring"} +{"name":"gbtreekey4_in","args":[{"type":"cstring"}],"returns":"gbtreekey4"} +{"name":"gbtreekey4_out","args":[{"type":"gbtreekey4"}],"returns":"cstring"} +{"name":"gbtreekey8_in","args":[{"type":"cstring"}],"returns":"gbtreekey8"} +{"name":"gbtreekey8_out","args":[{"type":"gbtreekey8"}],"returns":"cstring"} +{"name":"gbtreekey_var_in","args":[{"type":"cstring"}],"returns":"gbtreekey_var"} +{"name":"gbtreekey_var_out","args":[{"type":"gbtreekey_var"}],"returns":"cstring"} +{"name":"int2_dist","args":[{"type":"smallint"},{"type":"smallint"}],"returns":"smallint"} +{"name":"int4_dist","args":[{"type":"integer"},{"type":"integer"}],"returns":"integer"} +{"name":"int8_dist","args":[{"type":"bigint"},{"type":"bigint"}],"returns":"bigint"} +{"name":"interval_dist","args":[{"type":"interval"},{"type":"interval"}],"returns":"interval"} +{"name":"oid_dist","args":[{"type":"oid"},{"type":"oid"}],"returns":"oid"} +{"name":"time_dist","args":[{"type":"time without time zone"},{"type":"time without time zone"}],"returns":"interval"} +{"name":"ts_dist","args":[{"type":"timestamp without time zone"},{"type":"timestamp without time zone"}],"returns":"interval"} +{"name":"tstz_dist","args":[{"type":"timestamp with time zone"},{"type":"timestamp with time zone"}],"returns":"interval"} diff --git a/internal/engine/postgresql/dialect/extensions/btree_gist/types.jsonl b/internal/engine/postgresql/dialect/extensions/btree_gist/types.jsonl new file mode 100644 index 0000000..63d38cd --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/btree_gist/types.jsonl @@ -0,0 +1,6 @@ +{"name":"gbtreekey4","category":"U"} +{"name":"gbtreekey8","category":"U"} +{"name":"gbtreekey16","category":"U"} +{"name":"gbtreekey32","category":"U"} +{"name":"gbtreekey_var","category":"U"} +{"name":"gbtreekey2","category":"U"} diff --git a/internal/engine/postgresql/dialect/extensions/citext/functions.jsonl b/internal/engine/postgresql/dialect/extensions/citext/functions.jsonl new file mode 100644 index 0000000..38ab953 --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/citext/functions.jsonl @@ -0,0 +1,46 @@ +{"name":"citext","args":[{"type":"boolean"}],"returns":"citext"} +{"name":"citext","args":[{"type":"character"}],"returns":"citext"} +{"name":"citext","args":[{"type":"inet"}],"returns":"citext"} +{"name":"citext_cmp","args":[{"type":"citext"},{"type":"citext"}],"returns":"integer"} +{"name":"citext_eq","args":[{"type":"citext"},{"type":"citext"}],"returns":"boolean"} +{"name":"citext_ge","args":[{"type":"citext"},{"type":"citext"}],"returns":"boolean"} +{"name":"citext_gt","args":[{"type":"citext"},{"type":"citext"}],"returns":"boolean"} +{"name":"citext_hash","args":[{"type":"citext"}],"returns":"integer"} +{"name":"citext_hash_extended","args":[{"type":"citext"},{"type":"bigint"}],"returns":"bigint"} +{"name":"citext_larger","args":[{"type":"citext"},{"type":"citext"}],"returns":"citext"} +{"name":"citext_le","args":[{"type":"citext"},{"type":"citext"}],"returns":"boolean"} +{"name":"citext_lt","args":[{"type":"citext"},{"type":"citext"}],"returns":"boolean"} +{"name":"citext_ne","args":[{"type":"citext"},{"type":"citext"}],"returns":"boolean"} +{"name":"citext_pattern_cmp","args":[{"type":"citext"},{"type":"citext"}],"returns":"integer"} +{"name":"citext_pattern_ge","args":[{"type":"citext"},{"type":"citext"}],"returns":"boolean"} +{"name":"citext_pattern_gt","args":[{"type":"citext"},{"type":"citext"}],"returns":"boolean"} +{"name":"citext_pattern_le","args":[{"type":"citext"},{"type":"citext"}],"returns":"boolean"} +{"name":"citext_pattern_lt","args":[{"type":"citext"},{"type":"citext"}],"returns":"boolean"} +{"name":"citext_smaller","args":[{"type":"citext"},{"type":"citext"}],"returns":"citext"} +{"name":"citextin","args":[{"type":"cstring"}],"returns":"citext"} +{"name":"citextout","args":[{"type":"citext"}],"returns":"cstring"} +{"name":"citextsend","args":[{"type":"citext"}],"returns":"bytea"} +{"name":"max","args":[{"type":"citext"}],"returns":"citext"} +{"name":"min","args":[{"type":"citext"}],"returns":"citext"} +{"name":"regexp_match","args":[{"type":"citext"},{"type":"citext"}],"returns":"text[]"} +{"name":"regexp_match","args":[{"type":"citext"},{"type":"citext"},{"type":"text"}],"returns":"text[]"} +{"name":"regexp_matches","args":[{"type":"citext"},{"type":"citext"}],"returns":"text[]"} +{"name":"regexp_matches","args":[{"type":"citext"},{"type":"citext"},{"type":"text"}],"returns":"text[]"} +{"name":"regexp_replace","args":[{"type":"citext"},{"type":"citext"},{"type":"text"}],"returns":"text"} +{"name":"regexp_replace","args":[{"type":"citext"},{"type":"citext"},{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"regexp_split_to_array","args":[{"type":"citext"},{"type":"citext"}],"returns":"text[]"} +{"name":"regexp_split_to_array","args":[{"type":"citext"},{"type":"citext"},{"type":"text"}],"returns":"text[]"} +{"name":"regexp_split_to_table","args":[{"type":"citext"},{"type":"citext"}],"returns":"text"} +{"name":"regexp_split_to_table","args":[{"type":"citext"},{"type":"citext"},{"type":"text"}],"returns":"text"} +{"name":"replace","args":[{"type":"citext"},{"type":"citext"},{"type":"citext"}],"returns":"text"} +{"name":"split_part","args":[{"type":"citext"},{"type":"citext"},{"type":"integer"}],"returns":"text"} +{"name":"strpos","args":[{"type":"citext"},{"type":"citext"}],"returns":"integer"} +{"name":"texticlike","args":[{"type":"citext"},{"type":"citext"}],"returns":"boolean"} +{"name":"texticlike","args":[{"type":"citext"},{"type":"text"}],"returns":"boolean"} +{"name":"texticnlike","args":[{"type":"citext"},{"type":"citext"}],"returns":"boolean"} +{"name":"texticnlike","args":[{"type":"citext"},{"type":"text"}],"returns":"boolean"} +{"name":"texticregexeq","args":[{"type":"citext"},{"type":"citext"}],"returns":"boolean"} +{"name":"texticregexeq","args":[{"type":"citext"},{"type":"text"}],"returns":"boolean"} +{"name":"texticregexne","args":[{"type":"citext"},{"type":"citext"}],"returns":"boolean"} +{"name":"texticregexne","args":[{"type":"citext"},{"type":"text"}],"returns":"boolean"} +{"name":"translate","args":[{"type":"citext"},{"type":"citext"},{"type":"text"}],"returns":"text"} diff --git a/internal/engine/postgresql/dialect/extensions/citext/types.jsonl b/internal/engine/postgresql/dialect/extensions/citext/types.jsonl new file mode 100644 index 0000000..ec2056c --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/citext/types.jsonl @@ -0,0 +1 @@ +{"name":"citext","category":"S"} diff --git a/internal/engine/postgresql/dialect/extensions/cube/functions.jsonl b/internal/engine/postgresql/dialect/extensions/cube/functions.jsonl new file mode 100644 index 0000000..662689d --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/cube/functions.jsonl @@ -0,0 +1,33 @@ +{"name":"cube","args":[{"type":"cube"},{"type":"double precision"}],"returns":"cube"} +{"name":"cube","args":[{"type":"cube"},{"type":"double precision"},{"type":"double precision"}],"returns":"cube"} +{"name":"cube","args":[{"type":"double precision"}],"returns":"cube"} +{"name":"cube","args":[{"type":"double precision"},{"type":"double precision"}],"returns":"cube"} +{"name":"cube","args":[{"type":"double precision[]"}],"returns":"cube"} +{"name":"cube","args":[{"type":"double precision[]"},{"type":"double precision[]"}],"returns":"cube"} +{"name":"cube_cmp","args":[{"type":"cube"},{"type":"cube"}],"returns":"integer"} +{"name":"cube_contained","args":[{"type":"cube"},{"type":"cube"}],"returns":"boolean"} +{"name":"cube_contains","args":[{"type":"cube"},{"type":"cube"}],"returns":"boolean"} +{"name":"cube_coord","args":[{"type":"cube"},{"type":"integer"}],"returns":"double precision"} +{"name":"cube_coord_llur","args":[{"type":"cube"},{"type":"integer"}],"returns":"double precision"} +{"name":"cube_dim","args":[{"type":"cube"}],"returns":"integer"} +{"name":"cube_distance","args":[{"type":"cube"},{"type":"cube"}],"returns":"double precision"} +{"name":"cube_enlarge","args":[{"type":"cube"},{"type":"double precision"},{"type":"integer"}],"returns":"cube"} +{"name":"cube_eq","args":[{"type":"cube"},{"type":"cube"}],"returns":"boolean"} +{"name":"cube_ge","args":[{"type":"cube"},{"type":"cube"}],"returns":"boolean"} +{"name":"cube_gt","args":[{"type":"cube"},{"type":"cube"}],"returns":"boolean"} +{"name":"cube_in","args":[{"type":"cstring"}],"returns":"cube"} +{"name":"cube_inter","args":[{"type":"cube"},{"type":"cube"}],"returns":"cube"} +{"name":"cube_is_point","args":[{"type":"cube"}],"returns":"boolean"} +{"name":"cube_le","args":[{"type":"cube"},{"type":"cube"}],"returns":"boolean"} +{"name":"cube_ll_coord","args":[{"type":"cube"},{"type":"integer"}],"returns":"double precision"} +{"name":"cube_lt","args":[{"type":"cube"},{"type":"cube"}],"returns":"boolean"} +{"name":"cube_ne","args":[{"type":"cube"},{"type":"cube"}],"returns":"boolean"} +{"name":"cube_out","args":[{"type":"cube"}],"returns":"cstring"} +{"name":"cube_overlap","args":[{"type":"cube"},{"type":"cube"}],"returns":"boolean"} +{"name":"cube_send","args":[{"type":"cube"}],"returns":"bytea"} +{"name":"cube_size","args":[{"type":"cube"}],"returns":"double precision"} +{"name":"cube_subset","args":[{"type":"cube"},{"type":"integer[]"}],"returns":"cube"} +{"name":"cube_union","args":[{"type":"cube"},{"type":"cube"}],"returns":"cube"} +{"name":"cube_ur_coord","args":[{"type":"cube"},{"type":"integer"}],"returns":"double precision"} +{"name":"distance_chebyshev","args":[{"type":"cube"},{"type":"cube"}],"returns":"double precision"} +{"name":"distance_taxicab","args":[{"type":"cube"},{"type":"cube"}],"returns":"double precision"} diff --git a/internal/engine/postgresql/dialect/extensions/cube/types.jsonl b/internal/engine/postgresql/dialect/extensions/cube/types.jsonl new file mode 100644 index 0000000..128600a --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/cube/types.jsonl @@ -0,0 +1 @@ +{"name":"cube","category":"U"} diff --git a/internal/engine/postgresql/dialect/extensions/dblink/functions.jsonl b/internal/engine/postgresql/dialect/extensions/dblink/functions.jsonl new file mode 100644 index 0000000..1e6518b --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/dblink/functions.jsonl @@ -0,0 +1,41 @@ +{"name":"dblink","args":[{"type":"text"}],"returns":"record"} +{"name":"dblink","args":[{"type":"text"},{"type":"boolean"}],"returns":"record"} +{"name":"dblink","args":[{"type":"text"},{"type":"text"}],"returns":"record"} +{"name":"dblink","args":[{"type":"text"},{"type":"text"},{"type":"boolean"}],"returns":"record"} +{"name":"dblink_build_sql_delete","args":[{"type":"text"},{"type":"int2vector"},{"type":"integer"},{"type":"text[]"}],"returns":"text"} +{"name":"dblink_build_sql_insert","args":[{"type":"text"},{"type":"int2vector"},{"type":"integer"},{"type":"text[]"},{"type":"text[]"}],"returns":"text"} +{"name":"dblink_build_sql_update","args":[{"type":"text"},{"type":"int2vector"},{"type":"integer"},{"type":"text[]"},{"type":"text[]"}],"returns":"text"} +{"name":"dblink_cancel_query","args":[{"type":"text"}],"returns":"text"} +{"name":"dblink_close","args":[{"type":"text"}],"returns":"text"} +{"name":"dblink_close","args":[{"type":"text"},{"type":"boolean"}],"returns":"text"} +{"name":"dblink_close","args":[{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"dblink_close","args":[{"type":"text"},{"type":"text"},{"type":"boolean"}],"returns":"text"} +{"name":"dblink_connect","args":[{"type":"text"}],"returns":"text"} +{"name":"dblink_connect","args":[{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"dblink_connect_u","args":[{"type":"text"}],"returns":"text"} +{"name":"dblink_connect_u","args":[{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"dblink_current_query","returns":"text"} +{"name":"dblink_disconnect","returns":"text"} +{"name":"dblink_disconnect","args":[{"type":"text"}],"returns":"text"} +{"name":"dblink_error_message","args":[{"type":"text"}],"returns":"text"} +{"name":"dblink_exec","args":[{"type":"text"}],"returns":"text"} +{"name":"dblink_exec","args":[{"type":"text"},{"type":"boolean"}],"returns":"text"} +{"name":"dblink_exec","args":[{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"dblink_exec","args":[{"type":"text"},{"type":"text"},{"type":"boolean"}],"returns":"text"} +{"name":"dblink_fdw_validator","args":[{"name":"options","type":"text[]"},{"name":"catalog","type":"oid"}],"returns":"void"} +{"name":"dblink_fetch","args":[{"type":"text"},{"type":"integer"}],"returns":"record"} +{"name":"dblink_fetch","args":[{"type":"text"},{"type":"integer"},{"type":"boolean"}],"returns":"record"} +{"name":"dblink_fetch","args":[{"type":"text"},{"type":"text"},{"type":"integer"}],"returns":"record"} +{"name":"dblink_fetch","args":[{"type":"text"},{"type":"text"},{"type":"integer"},{"type":"boolean"}],"returns":"record"} +{"name":"dblink_get_connections","returns":"text[]"} +{"name":"dblink_get_notify","returns":"record"} +{"name":"dblink_get_notify","args":[{"name":"conname","type":"text"}],"returns":"record"} +{"name":"dblink_get_pkey","args":[{"type":"text"}],"returns":"dblink_pkey_results"} +{"name":"dblink_get_result","args":[{"type":"text"}],"returns":"record"} +{"name":"dblink_get_result","args":[{"type":"text"},{"type":"boolean"}],"returns":"record"} +{"name":"dblink_is_busy","args":[{"type":"text"}],"returns":"integer"} +{"name":"dblink_open","args":[{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"dblink_open","args":[{"type":"text"},{"type":"text"},{"type":"boolean"}],"returns":"text"} +{"name":"dblink_open","args":[{"type":"text"},{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"dblink_open","args":[{"type":"text"},{"type":"text"},{"type":"text"},{"type":"boolean"}],"returns":"text"} +{"name":"dblink_send_query","args":[{"type":"text"},{"type":"text"}],"returns":"integer"} diff --git a/internal/engine/postgresql/dialect/extensions/dblink/types.jsonl b/internal/engine/postgresql/dialect/extensions/dblink/types.jsonl new file mode 100644 index 0000000..cf267d5 --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/dblink/types.jsonl @@ -0,0 +1 @@ +{"name":"dblink_pkey_results","category":"C"} diff --git a/internal/engine/postgresql/dialect/extensions/earthdistance/functions.jsonl b/internal/engine/postgresql/dialect/extensions/earthdistance/functions.jsonl new file mode 100644 index 0000000..c2159f5 --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/earthdistance/functions.jsonl @@ -0,0 +1,9 @@ +{"name":"earth","returns":"double precision"} +{"name":"earth_box","args":[{"type":"earth"},{"type":"double precision"}],"returns":"cube"} +{"name":"earth_distance","args":[{"type":"earth"},{"type":"earth"}],"returns":"double precision"} +{"name":"gc_to_sec","args":[{"type":"double precision"}],"returns":"double precision"} +{"name":"geo_distance","args":[{"type":"point"},{"type":"point"}],"returns":"double precision"} +{"name":"latitude","args":[{"type":"earth"}],"returns":"double precision"} +{"name":"ll_to_earth","args":[{"type":"double precision"},{"type":"double precision"}],"returns":"earth"} +{"name":"longitude","args":[{"type":"earth"}],"returns":"double precision"} +{"name":"sec_to_gc","args":[{"type":"double precision"}],"returns":"double precision"} diff --git a/internal/engine/postgresql/dialect/extensions/earthdistance/types.jsonl b/internal/engine/postgresql/dialect/extensions/earthdistance/types.jsonl new file mode 100644 index 0000000..49893bb --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/earthdistance/types.jsonl @@ -0,0 +1 @@ +{"name":"earth","category":"U"} diff --git a/internal/engine/postgresql/dialect/extensions/file_fdw/functions.jsonl b/internal/engine/postgresql/dialect/extensions/file_fdw/functions.jsonl new file mode 100644 index 0000000..7232d0d --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/file_fdw/functions.jsonl @@ -0,0 +1,2 @@ +{"name":"file_fdw_handler","returns":"fdw_handler"} +{"name":"file_fdw_validator","args":[{"type":"text[]"},{"type":"oid"}],"returns":"void"} diff --git a/internal/engine/postgresql/dialect/extensions/fuzzystrmatch/functions.jsonl b/internal/engine/postgresql/dialect/extensions/fuzzystrmatch/functions.jsonl new file mode 100644 index 0000000..b6e46b4 --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/fuzzystrmatch/functions.jsonl @@ -0,0 +1,11 @@ +{"name":"daitch_mokotoff","args":[{"type":"text"}],"returns":"text[]"} +{"name":"difference","args":[{"type":"text"},{"type":"text"}],"returns":"integer"} +{"name":"dmetaphone","args":[{"type":"text"}],"returns":"text"} +{"name":"dmetaphone_alt","args":[{"type":"text"}],"returns":"text"} +{"name":"levenshtein","args":[{"type":"text"},{"type":"text"}],"returns":"integer"} +{"name":"levenshtein","args":[{"type":"text"},{"type":"text"},{"type":"integer"},{"type":"integer"},{"type":"integer"}],"returns":"integer"} +{"name":"levenshtein_less_equal","args":[{"type":"text"},{"type":"text"},{"type":"integer"}],"returns":"integer"} +{"name":"levenshtein_less_equal","args":[{"type":"text"},{"type":"text"},{"type":"integer"},{"type":"integer"},{"type":"integer"},{"type":"integer"}],"returns":"integer"} +{"name":"metaphone","args":[{"type":"text"},{"type":"integer"}],"returns":"text"} +{"name":"soundex","args":[{"type":"text"}],"returns":"text"} +{"name":"text_soundex","args":[{"type":"text"}],"returns":"text"} diff --git a/internal/engine/postgresql/dialect/extensions/hstore/functions.jsonl b/internal/engine/postgresql/dialect/extensions/hstore/functions.jsonl new file mode 100644 index 0000000..4bb9f7a --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/hstore/functions.jsonl @@ -0,0 +1,47 @@ +{"name":"akeys","args":[{"type":"hstore"}],"returns":"text[]"} +{"name":"avals","args":[{"type":"hstore"}],"returns":"text[]"} +{"name":"defined","args":[{"type":"hstore"},{"type":"text"}],"returns":"boolean"} +{"name":"delete","args":[{"type":"hstore"},{"type":"hstore"}],"returns":"hstore"} +{"name":"delete","args":[{"type":"hstore"},{"type":"text"}],"returns":"hstore"} +{"name":"delete","args":[{"type":"hstore"},{"type":"text[]"}],"returns":"hstore"} +{"name":"each","args":[{"name":"hs","type":"hstore"}],"returns":"record"} +{"name":"exist","args":[{"type":"hstore"},{"type":"text"}],"returns":"boolean"} +{"name":"exists_all","args":[{"type":"hstore"},{"type":"text[]"}],"returns":"boolean"} +{"name":"exists_any","args":[{"type":"hstore"},{"type":"text[]"}],"returns":"boolean"} +{"name":"fetchval","args":[{"type":"hstore"},{"type":"text"}],"returns":"text"} +{"name":"ghstore_in","args":[{"type":"cstring"}],"returns":"ghstore"} +{"name":"ghstore_out","args":[{"type":"ghstore"}],"returns":"cstring"} +{"name":"hs_concat","args":[{"type":"hstore"},{"type":"hstore"}],"returns":"hstore"} +{"name":"hs_contained","args":[{"type":"hstore"},{"type":"hstore"}],"returns":"boolean"} +{"name":"hs_contains","args":[{"type":"hstore"},{"type":"hstore"}],"returns":"boolean"} +{"name":"hstore","args":[{"type":"record"}],"returns":"hstore"} +{"name":"hstore","args":[{"type":"text"},{"type":"text"}],"returns":"hstore"} +{"name":"hstore","args":[{"type":"text[]"}],"returns":"hstore"} +{"name":"hstore","args":[{"type":"text[]"},{"type":"text[]"}],"returns":"hstore"} +{"name":"hstore_cmp","args":[{"type":"hstore"},{"type":"hstore"}],"returns":"integer"} +{"name":"hstore_eq","args":[{"type":"hstore"},{"type":"hstore"}],"returns":"boolean"} +{"name":"hstore_ge","args":[{"type":"hstore"},{"type":"hstore"}],"returns":"boolean"} +{"name":"hstore_gt","args":[{"type":"hstore"},{"type":"hstore"}],"returns":"boolean"} +{"name":"hstore_hash","args":[{"type":"hstore"}],"returns":"integer"} +{"name":"hstore_hash_extended","args":[{"type":"hstore"},{"type":"bigint"}],"returns":"bigint"} +{"name":"hstore_in","args":[{"type":"cstring"}],"returns":"hstore"} +{"name":"hstore_le","args":[{"type":"hstore"},{"type":"hstore"}],"returns":"boolean"} +{"name":"hstore_lt","args":[{"type":"hstore"},{"type":"hstore"}],"returns":"boolean"} +{"name":"hstore_ne","args":[{"type":"hstore"},{"type":"hstore"}],"returns":"boolean"} +{"name":"hstore_out","args":[{"type":"hstore"}],"returns":"cstring"} +{"name":"hstore_send","args":[{"type":"hstore"}],"returns":"bytea"} +{"name":"hstore_to_array","args":[{"type":"hstore"}],"returns":"text[]"} +{"name":"hstore_to_json","args":[{"type":"hstore"}],"returns":"json"} +{"name":"hstore_to_json_loose","args":[{"type":"hstore"}],"returns":"json"} +{"name":"hstore_to_jsonb","args":[{"type":"hstore"}],"returns":"jsonb"} +{"name":"hstore_to_jsonb_loose","args":[{"type":"hstore"}],"returns":"jsonb"} +{"name":"hstore_to_matrix","args":[{"type":"hstore"}],"returns":"text[]"} +{"name":"hstore_version_diag","args":[{"type":"hstore"}],"returns":"integer"} +{"name":"isdefined","args":[{"type":"hstore"},{"type":"text"}],"returns":"boolean"} +{"name":"isexists","args":[{"type":"hstore"},{"type":"text"}],"returns":"boolean"} +{"name":"populate_record","args":[{"type":"anyelement"},{"type":"hstore"}],"returns":"anyelement"} +{"name":"skeys","args":[{"type":"hstore"}],"returns":"text"} +{"name":"slice","args":[{"type":"hstore"},{"type":"text[]"}],"returns":"hstore"} +{"name":"slice_array","args":[{"type":"hstore"},{"type":"text[]"}],"returns":"text[]"} +{"name":"svals","args":[{"type":"hstore"}],"returns":"text"} +{"name":"tconvert","args":[{"type":"text"},{"type":"text"}],"returns":"hstore"} diff --git a/internal/engine/postgresql/dialect/extensions/hstore/types.jsonl b/internal/engine/postgresql/dialect/extensions/hstore/types.jsonl new file mode 100644 index 0000000..9329a0b --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/hstore/types.jsonl @@ -0,0 +1,2 @@ +{"name":"hstore","category":"U"} +{"name":"ghstore","category":"U"} diff --git a/internal/engine/postgresql/dialect/extensions/intagg/functions.jsonl b/internal/engine/postgresql/dialect/extensions/intagg/functions.jsonl new file mode 100644 index 0000000..98ac268 --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/intagg/functions.jsonl @@ -0,0 +1,2 @@ +{"name":"int_array_aggregate","args":[{"type":"integer"}],"returns":"integer[]"} +{"name":"int_array_enum","args":[{"type":"integer[]"}],"returns":"integer"} diff --git a/internal/engine/postgresql/dialect/extensions/intarray/functions.jsonl b/internal/engine/postgresql/dialect/extensions/intarray/functions.jsonl new file mode 100644 index 0000000..2374c69 --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/intarray/functions.jsonl @@ -0,0 +1,29 @@ +{"name":"_int_contained","args":[{"type":"integer[]"},{"type":"integer[]"}],"returns":"boolean"} +{"name":"_int_contains","args":[{"type":"integer[]"},{"type":"integer[]"}],"returns":"boolean"} +{"name":"_int_different","args":[{"type":"integer[]"},{"type":"integer[]"}],"returns":"boolean"} +{"name":"_int_inter","args":[{"type":"integer[]"},{"type":"integer[]"}],"returns":"integer[]"} +{"name":"_int_overlap","args":[{"type":"integer[]"},{"type":"integer[]"}],"returns":"boolean"} +{"name":"_int_same","args":[{"type":"integer[]"},{"type":"integer[]"}],"returns":"boolean"} +{"name":"_int_union","args":[{"type":"integer[]"},{"type":"integer[]"}],"returns":"integer[]"} +{"name":"_intbig_in","args":[{"type":"cstring"}],"returns":"intbig_gkey"} +{"name":"_intbig_out","args":[{"type":"intbig_gkey"}],"returns":"cstring"} +{"name":"boolop","args":[{"type":"integer[]"},{"type":"query_int"}],"returns":"boolean"} +{"name":"bqarr_in","args":[{"type":"cstring"}],"returns":"query_int"} +{"name":"bqarr_out","args":[{"type":"query_int"}],"returns":"cstring"} +{"name":"icount","args":[{"type":"integer[]"}],"returns":"integer"} +{"name":"idx","args":[{"type":"integer[]"},{"type":"integer"}],"returns":"integer"} +{"name":"intarray_del_elem","args":[{"type":"integer[]"},{"type":"integer"}],"returns":"integer[]"} +{"name":"intarray_push_array","args":[{"type":"integer[]"},{"type":"integer[]"}],"returns":"integer[]"} +{"name":"intarray_push_elem","args":[{"type":"integer[]"},{"type":"integer"}],"returns":"integer[]"} +{"name":"intset","args":[{"type":"integer"}],"returns":"integer[]"} +{"name":"intset_subtract","args":[{"type":"integer[]"},{"type":"integer[]"}],"returns":"integer[]"} +{"name":"intset_union_elem","args":[{"type":"integer[]"},{"type":"integer"}],"returns":"integer[]"} +{"name":"querytree","args":[{"type":"query_int"}],"returns":"text"} +{"name":"rboolop","args":[{"type":"query_int"},{"type":"integer[]"}],"returns":"boolean"} +{"name":"sort","args":[{"type":"integer[]"}],"returns":"integer[]"} +{"name":"sort","args":[{"type":"integer[]"},{"type":"text"}],"returns":"integer[]"} +{"name":"sort_asc","args":[{"type":"integer[]"}],"returns":"integer[]"} +{"name":"sort_desc","args":[{"type":"integer[]"}],"returns":"integer[]"} +{"name":"subarray","args":[{"type":"integer[]"},{"type":"integer"}],"returns":"integer[]"} +{"name":"subarray","args":[{"type":"integer[]"},{"type":"integer"},{"type":"integer"}],"returns":"integer[]"} +{"name":"uniq","args":[{"type":"integer[]"}],"returns":"integer[]"} diff --git a/internal/engine/postgresql/dialect/extensions/intarray/types.jsonl b/internal/engine/postgresql/dialect/extensions/intarray/types.jsonl new file mode 100644 index 0000000..fd41d4d --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/intarray/types.jsonl @@ -0,0 +1,2 @@ +{"name":"query_int","category":"U"} +{"name":"intbig_gkey","category":"U"} diff --git a/internal/engine/postgresql/dialect/extensions/isn/functions.jsonl b/internal/engine/postgresql/dialect/extensions/isn/functions.jsonl new file mode 100644 index 0000000..1b5d123 --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/isn/functions.jsonl @@ -0,0 +1,245 @@ +{"name":"btean13cmp","args":[{"type":"ean13"},{"type":"ean13"}],"returns":"integer"} +{"name":"btean13cmp","args":[{"type":"ean13"},{"type":"isbn"}],"returns":"integer"} +{"name":"btean13cmp","args":[{"type":"ean13"},{"type":"isbn13"}],"returns":"integer"} +{"name":"btean13cmp","args":[{"type":"ean13"},{"type":"ismn"}],"returns":"integer"} +{"name":"btean13cmp","args":[{"type":"ean13"},{"type":"ismn13"}],"returns":"integer"} +{"name":"btean13cmp","args":[{"type":"ean13"},{"type":"issn"}],"returns":"integer"} +{"name":"btean13cmp","args":[{"type":"ean13"},{"type":"issn13"}],"returns":"integer"} +{"name":"btean13cmp","args":[{"type":"ean13"},{"type":"upc"}],"returns":"integer"} +{"name":"btisbn13cmp","args":[{"type":"isbn13"},{"type":"ean13"}],"returns":"integer"} +{"name":"btisbn13cmp","args":[{"type":"isbn13"},{"type":"isbn"}],"returns":"integer"} +{"name":"btisbn13cmp","args":[{"type":"isbn13"},{"type":"isbn13"}],"returns":"integer"} +{"name":"btisbncmp","args":[{"type":"isbn"},{"type":"ean13"}],"returns":"integer"} +{"name":"btisbncmp","args":[{"type":"isbn"},{"type":"isbn"}],"returns":"integer"} +{"name":"btisbncmp","args":[{"type":"isbn"},{"type":"isbn13"}],"returns":"integer"} +{"name":"btismn13cmp","args":[{"type":"ismn13"},{"type":"ean13"}],"returns":"integer"} +{"name":"btismn13cmp","args":[{"type":"ismn13"},{"type":"ismn"}],"returns":"integer"} +{"name":"btismn13cmp","args":[{"type":"ismn13"},{"type":"ismn13"}],"returns":"integer"} +{"name":"btismncmp","args":[{"type":"ismn"},{"type":"ean13"}],"returns":"integer"} +{"name":"btismncmp","args":[{"type":"ismn"},{"type":"ismn"}],"returns":"integer"} +{"name":"btismncmp","args":[{"type":"ismn"},{"type":"ismn13"}],"returns":"integer"} +{"name":"btissn13cmp","args":[{"type":"issn13"},{"type":"ean13"}],"returns":"integer"} +{"name":"btissn13cmp","args":[{"type":"issn13"},{"type":"issn"}],"returns":"integer"} +{"name":"btissn13cmp","args":[{"type":"issn13"},{"type":"issn13"}],"returns":"integer"} +{"name":"btissncmp","args":[{"type":"issn"},{"type":"ean13"}],"returns":"integer"} +{"name":"btissncmp","args":[{"type":"issn"},{"type":"issn"}],"returns":"integer"} +{"name":"btissncmp","args":[{"type":"issn"},{"type":"issn13"}],"returns":"integer"} +{"name":"btupccmp","args":[{"type":"upc"},{"type":"ean13"}],"returns":"integer"} +{"name":"btupccmp","args":[{"type":"upc"},{"type":"upc"}],"returns":"integer"} +{"name":"ean13_in","args":[{"type":"cstring"}],"returns":"ean13"} +{"name":"ean13_out","args":[{"type":"ean13"}],"returns":"cstring"} +{"name":"ean13_out","args":[{"type":"isbn13"}],"returns":"cstring"} +{"name":"ean13_out","args":[{"type":"ismn13"}],"returns":"cstring"} +{"name":"ean13_out","args":[{"type":"issn13"}],"returns":"cstring"} +{"name":"hashean13","args":[{"type":"ean13"}],"returns":"integer"} +{"name":"hashisbn","args":[{"type":"isbn"}],"returns":"integer"} +{"name":"hashisbn13","args":[{"type":"isbn13"}],"returns":"integer"} +{"name":"hashismn","args":[{"type":"ismn"}],"returns":"integer"} +{"name":"hashismn13","args":[{"type":"ismn13"}],"returns":"integer"} +{"name":"hashissn","args":[{"type":"issn"}],"returns":"integer"} +{"name":"hashissn13","args":[{"type":"issn13"}],"returns":"integer"} +{"name":"hashupc","args":[{"type":"upc"}],"returns":"integer"} +{"name":"is_valid","args":[{"type":"ean13"}],"returns":"boolean"} +{"name":"is_valid","args":[{"type":"isbn"}],"returns":"boolean"} +{"name":"is_valid","args":[{"type":"isbn13"}],"returns":"boolean"} +{"name":"is_valid","args":[{"type":"ismn"}],"returns":"boolean"} +{"name":"is_valid","args":[{"type":"ismn13"}],"returns":"boolean"} +{"name":"is_valid","args":[{"type":"issn"}],"returns":"boolean"} +{"name":"is_valid","args":[{"type":"issn13"}],"returns":"boolean"} +{"name":"is_valid","args":[{"type":"upc"}],"returns":"boolean"} +{"name":"isbn","args":[{"type":"ean13"}],"returns":"isbn"} +{"name":"isbn13","args":[{"type":"ean13"}],"returns":"isbn13"} +{"name":"isbn13_in","args":[{"type":"cstring"}],"returns":"isbn13"} +{"name":"isbn_in","args":[{"type":"cstring"}],"returns":"isbn"} +{"name":"ismn","args":[{"type":"ean13"}],"returns":"ismn"} +{"name":"ismn13","args":[{"type":"ean13"}],"returns":"ismn13"} +{"name":"ismn13_in","args":[{"type":"cstring"}],"returns":"ismn13"} +{"name":"ismn_in","args":[{"type":"cstring"}],"returns":"ismn"} +{"name":"isn_out","args":[{"type":"isbn"}],"returns":"cstring"} +{"name":"isn_out","args":[{"type":"ismn"}],"returns":"cstring"} +{"name":"isn_out","args":[{"type":"issn"}],"returns":"cstring"} +{"name":"isn_out","args":[{"type":"upc"}],"returns":"cstring"} +{"name":"isn_weak","returns":"boolean"} +{"name":"isn_weak","args":[{"type":"boolean"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"ean13"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"ean13"},{"type":"isbn"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"ean13"},{"type":"isbn13"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"ean13"},{"type":"ismn"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"ean13"},{"type":"ismn13"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"ean13"},{"type":"issn"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"ean13"},{"type":"issn13"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"ean13"},{"type":"upc"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"isbn"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"isbn"},{"type":"isbn"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"isbn"},{"type":"isbn13"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"isbn13"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"isbn13"},{"type":"isbn"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"isbn13"},{"type":"isbn13"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"ismn"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"ismn"},{"type":"ismn"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"ismn"},{"type":"ismn13"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"ismn13"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"ismn13"},{"type":"ismn"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"ismn13"},{"type":"ismn13"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"issn"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"issn"},{"type":"issn"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"issn"},{"type":"issn13"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"issn13"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"issn13"},{"type":"issn"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"issn13"},{"type":"issn13"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"upc"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isneq","args":[{"type":"upc"},{"type":"upc"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"ean13"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"ean13"},{"type":"isbn"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"ean13"},{"type":"isbn13"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"ean13"},{"type":"ismn"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"ean13"},{"type":"ismn13"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"ean13"},{"type":"issn"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"ean13"},{"type":"issn13"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"ean13"},{"type":"upc"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"isbn"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"isbn"},{"type":"isbn"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"isbn"},{"type":"isbn13"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"isbn13"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"isbn13"},{"type":"isbn"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"isbn13"},{"type":"isbn13"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"ismn"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"ismn"},{"type":"ismn"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"ismn"},{"type":"ismn13"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"ismn13"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"ismn13"},{"type":"ismn"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"ismn13"},{"type":"ismn13"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"issn"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"issn"},{"type":"issn"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"issn"},{"type":"issn13"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"issn13"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"issn13"},{"type":"issn"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"issn13"},{"type":"issn13"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"upc"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnge","args":[{"type":"upc"},{"type":"upc"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"ean13"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"ean13"},{"type":"isbn"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"ean13"},{"type":"isbn13"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"ean13"},{"type":"ismn"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"ean13"},{"type":"ismn13"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"ean13"},{"type":"issn"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"ean13"},{"type":"issn13"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"ean13"},{"type":"upc"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"isbn"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"isbn"},{"type":"isbn"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"isbn"},{"type":"isbn13"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"isbn13"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"isbn13"},{"type":"isbn"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"isbn13"},{"type":"isbn13"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"ismn"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"ismn"},{"type":"ismn"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"ismn"},{"type":"ismn13"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"ismn13"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"ismn13"},{"type":"ismn"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"ismn13"},{"type":"ismn13"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"issn"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"issn"},{"type":"issn"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"issn"},{"type":"issn13"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"issn13"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"issn13"},{"type":"issn"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"issn13"},{"type":"issn13"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"upc"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isngt","args":[{"type":"upc"},{"type":"upc"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"ean13"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"ean13"},{"type":"isbn"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"ean13"},{"type":"isbn13"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"ean13"},{"type":"ismn"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"ean13"},{"type":"ismn13"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"ean13"},{"type":"issn"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"ean13"},{"type":"issn13"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"ean13"},{"type":"upc"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"isbn"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"isbn"},{"type":"isbn"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"isbn"},{"type":"isbn13"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"isbn13"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"isbn13"},{"type":"isbn"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"isbn13"},{"type":"isbn13"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"ismn"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"ismn"},{"type":"ismn"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"ismn"},{"type":"ismn13"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"ismn13"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"ismn13"},{"type":"ismn"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"ismn13"},{"type":"ismn13"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"issn"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"issn"},{"type":"issn"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"issn"},{"type":"issn13"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"issn13"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"issn13"},{"type":"issn"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"issn13"},{"type":"issn13"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"upc"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnle","args":[{"type":"upc"},{"type":"upc"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"ean13"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"ean13"},{"type":"isbn"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"ean13"},{"type":"isbn13"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"ean13"},{"type":"ismn"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"ean13"},{"type":"ismn13"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"ean13"},{"type":"issn"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"ean13"},{"type":"issn13"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"ean13"},{"type":"upc"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"isbn"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"isbn"},{"type":"isbn"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"isbn"},{"type":"isbn13"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"isbn13"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"isbn13"},{"type":"isbn"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"isbn13"},{"type":"isbn13"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"ismn"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"ismn"},{"type":"ismn"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"ismn"},{"type":"ismn13"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"ismn13"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"ismn13"},{"type":"ismn"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"ismn13"},{"type":"ismn13"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"issn"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"issn"},{"type":"issn"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"issn"},{"type":"issn13"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"issn13"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"issn13"},{"type":"issn"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"issn13"},{"type":"issn13"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"upc"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnlt","args":[{"type":"upc"},{"type":"upc"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"ean13"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"ean13"},{"type":"isbn"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"ean13"},{"type":"isbn13"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"ean13"},{"type":"ismn"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"ean13"},{"type":"ismn13"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"ean13"},{"type":"issn"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"ean13"},{"type":"issn13"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"ean13"},{"type":"upc"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"isbn"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"isbn"},{"type":"isbn"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"isbn"},{"type":"isbn13"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"isbn13"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"isbn13"},{"type":"isbn"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"isbn13"},{"type":"isbn13"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"ismn"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"ismn"},{"type":"ismn"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"ismn"},{"type":"ismn13"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"ismn13"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"ismn13"},{"type":"ismn"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"ismn13"},{"type":"ismn13"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"issn"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"issn"},{"type":"issn"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"issn"},{"type":"issn13"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"issn13"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"issn13"},{"type":"issn"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"issn13"},{"type":"issn13"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"upc"},{"type":"ean13"}],"returns":"boolean"} +{"name":"isnne","args":[{"type":"upc"},{"type":"upc"}],"returns":"boolean"} +{"name":"issn","args":[{"type":"ean13"}],"returns":"issn"} +{"name":"issn13","args":[{"type":"ean13"}],"returns":"issn13"} +{"name":"issn13_in","args":[{"type":"cstring"}],"returns":"issn13"} +{"name":"issn_in","args":[{"type":"cstring"}],"returns":"issn"} +{"name":"make_valid","args":[{"type":"ean13"}],"returns":"ean13"} +{"name":"make_valid","args":[{"type":"isbn"}],"returns":"isbn"} +{"name":"make_valid","args":[{"type":"isbn13"}],"returns":"isbn13"} +{"name":"make_valid","args":[{"type":"ismn"}],"returns":"ismn"} +{"name":"make_valid","args":[{"type":"ismn13"}],"returns":"ismn13"} +{"name":"make_valid","args":[{"type":"issn"}],"returns":"issn"} +{"name":"make_valid","args":[{"type":"issn13"}],"returns":"issn13"} +{"name":"make_valid","args":[{"type":"upc"}],"returns":"upc"} +{"name":"upc","args":[{"type":"ean13"}],"returns":"upc"} +{"name":"upc_in","args":[{"type":"cstring"}],"returns":"upc"} diff --git a/internal/engine/postgresql/dialect/extensions/isn/types.jsonl b/internal/engine/postgresql/dialect/extensions/isn/types.jsonl new file mode 100644 index 0000000..83539d1 --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/isn/types.jsonl @@ -0,0 +1,8 @@ +{"name":"ean13","category":"U"} +{"name":"isbn13","category":"U"} +{"name":"ismn13","category":"U"} +{"name":"issn13","category":"U"} +{"name":"isbn","category":"U"} +{"name":"ismn","category":"U"} +{"name":"issn","category":"U"} +{"name":"upc","category":"U"} diff --git a/internal/engine/postgresql/dialect/extensions/lo/functions.jsonl b/internal/engine/postgresql/dialect/extensions/lo/functions.jsonl new file mode 100644 index 0000000..f6f0f2b --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/lo/functions.jsonl @@ -0,0 +1,2 @@ +{"name":"lo_manage","returns":"trigger"} +{"name":"lo_oid","args":[{"type":"lo"}],"returns":"oid"} diff --git a/internal/engine/postgresql/dialect/extensions/lo/types.jsonl b/internal/engine/postgresql/dialect/extensions/lo/types.jsonl new file mode 100644 index 0000000..c28ad45 --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/lo/types.jsonl @@ -0,0 +1 @@ +{"name":"lo","category":"N"} diff --git a/internal/engine/postgresql/dialect/extensions/ltree/functions.jsonl b/internal/engine/postgresql/dialect/extensions/ltree/functions.jsonl new file mode 100644 index 0000000..3f237ee --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/ltree/functions.jsonl @@ -0,0 +1,59 @@ +{"name":"_lt_q_regex","args":[{"type":"ltree[]"},{"type":"lquery[]"}],"returns":"boolean"} +{"name":"_lt_q_rregex","args":[{"type":"lquery[]"},{"type":"ltree[]"}],"returns":"boolean"} +{"name":"_ltq_extract_regex","args":[{"type":"ltree[]"},{"type":"lquery"}],"returns":"ltree"} +{"name":"_ltq_regex","args":[{"type":"ltree[]"},{"type":"lquery"}],"returns":"boolean"} +{"name":"_ltq_rregex","args":[{"type":"lquery"},{"type":"ltree[]"}],"returns":"boolean"} +{"name":"_ltree_extract_isparent","args":[{"type":"ltree[]"},{"type":"ltree"}],"returns":"ltree"} +{"name":"_ltree_extract_risparent","args":[{"type":"ltree[]"},{"type":"ltree"}],"returns":"ltree"} +{"name":"_ltree_isparent","args":[{"type":"ltree[]"},{"type":"ltree"}],"returns":"boolean"} +{"name":"_ltree_r_isparent","args":[{"type":"ltree"},{"type":"ltree[]"}],"returns":"boolean"} +{"name":"_ltree_r_risparent","args":[{"type":"ltree"},{"type":"ltree[]"}],"returns":"boolean"} +{"name":"_ltree_risparent","args":[{"type":"ltree[]"},{"type":"ltree"}],"returns":"boolean"} +{"name":"_ltxtq_exec","args":[{"type":"ltree[]"},{"type":"ltxtquery"}],"returns":"boolean"} +{"name":"_ltxtq_extract_exec","args":[{"type":"ltree[]"},{"type":"ltxtquery"}],"returns":"ltree"} +{"name":"_ltxtq_rexec","args":[{"type":"ltxtquery"},{"type":"ltree[]"}],"returns":"boolean"} +{"name":"index","args":[{"type":"ltree"},{"type":"ltree"}],"returns":"integer"} +{"name":"index","args":[{"type":"ltree"},{"type":"ltree"},{"type":"integer"}],"returns":"integer"} +{"name":"lca","args":[{"type":"ltree"},{"type":"ltree"}],"returns":"ltree"} +{"name":"lca","args":[{"type":"ltree"},{"type":"ltree"},{"type":"ltree"}],"returns":"ltree"} +{"name":"lca","args":[{"type":"ltree"},{"type":"ltree"},{"type":"ltree"},{"type":"ltree"}],"returns":"ltree"} +{"name":"lca","args":[{"type":"ltree"},{"type":"ltree"},{"type":"ltree"},{"type":"ltree"},{"type":"ltree"}],"returns":"ltree"} +{"name":"lca","args":[{"type":"ltree"},{"type":"ltree"},{"type":"ltree"},{"type":"ltree"},{"type":"ltree"},{"type":"ltree"}],"returns":"ltree"} +{"name":"lca","args":[{"type":"ltree"},{"type":"ltree"},{"type":"ltree"},{"type":"ltree"},{"type":"ltree"},{"type":"ltree"},{"type":"ltree"}],"returns":"ltree"} +{"name":"lca","args":[{"type":"ltree"},{"type":"ltree"},{"type":"ltree"},{"type":"ltree"},{"type":"ltree"},{"type":"ltree"},{"type":"ltree"},{"type":"ltree"}],"returns":"ltree"} +{"name":"lca","args":[{"type":"ltree[]"}],"returns":"ltree"} +{"name":"lquery_in","args":[{"type":"cstring"}],"returns":"lquery"} +{"name":"lquery_out","args":[{"type":"lquery"}],"returns":"cstring"} +{"name":"lquery_send","args":[{"type":"lquery"}],"returns":"bytea"} +{"name":"lt_q_regex","args":[{"type":"ltree"},{"type":"lquery[]"}],"returns":"boolean"} +{"name":"lt_q_rregex","args":[{"type":"lquery[]"},{"type":"ltree"}],"returns":"boolean"} +{"name":"ltq_regex","args":[{"type":"ltree"},{"type":"lquery"}],"returns":"boolean"} +{"name":"ltq_rregex","args":[{"type":"lquery"},{"type":"ltree"}],"returns":"boolean"} +{"name":"ltree2text","args":[{"type":"ltree"}],"returns":"text"} +{"name":"ltree_addltree","args":[{"type":"ltree"},{"type":"ltree"}],"returns":"ltree"} +{"name":"ltree_addtext","args":[{"type":"ltree"},{"type":"text"}],"returns":"ltree"} +{"name":"ltree_cmp","args":[{"type":"ltree"},{"type":"ltree"}],"returns":"integer"} +{"name":"ltree_eq","args":[{"type":"ltree"},{"type":"ltree"}],"returns":"boolean"} +{"name":"ltree_ge","args":[{"type":"ltree"},{"type":"ltree"}],"returns":"boolean"} +{"name":"ltree_gist_in","args":[{"type":"cstring"}],"returns":"ltree_gist"} +{"name":"ltree_gist_out","args":[{"type":"ltree_gist"}],"returns":"cstring"} +{"name":"ltree_gt","args":[{"type":"ltree"},{"type":"ltree"}],"returns":"boolean"} +{"name":"ltree_in","args":[{"type":"cstring"}],"returns":"ltree"} +{"name":"ltree_isparent","args":[{"type":"ltree"},{"type":"ltree"}],"returns":"boolean"} +{"name":"ltree_le","args":[{"type":"ltree"},{"type":"ltree"}],"returns":"boolean"} +{"name":"ltree_lt","args":[{"type":"ltree"},{"type":"ltree"}],"returns":"boolean"} +{"name":"ltree_ne","args":[{"type":"ltree"},{"type":"ltree"}],"returns":"boolean"} +{"name":"ltree_out","args":[{"type":"ltree"}],"returns":"cstring"} +{"name":"ltree_risparent","args":[{"type":"ltree"},{"type":"ltree"}],"returns":"boolean"} +{"name":"ltree_send","args":[{"type":"ltree"}],"returns":"bytea"} +{"name":"ltree_textadd","args":[{"type":"text"},{"type":"ltree"}],"returns":"ltree"} +{"name":"ltxtq_exec","args":[{"type":"ltree"},{"type":"ltxtquery"}],"returns":"boolean"} +{"name":"ltxtq_in","args":[{"type":"cstring"}],"returns":"ltxtquery"} +{"name":"ltxtq_out","args":[{"type":"ltxtquery"}],"returns":"cstring"} +{"name":"ltxtq_rexec","args":[{"type":"ltxtquery"},{"type":"ltree"}],"returns":"boolean"} +{"name":"ltxtq_send","args":[{"type":"ltxtquery"}],"returns":"bytea"} +{"name":"nlevel","args":[{"type":"ltree"}],"returns":"integer"} +{"name":"subltree","args":[{"type":"ltree"},{"type":"integer"},{"type":"integer"}],"returns":"ltree"} +{"name":"subpath","args":[{"type":"ltree"},{"type":"integer"}],"returns":"ltree"} +{"name":"subpath","args":[{"type":"ltree"},{"type":"integer"},{"type":"integer"}],"returns":"ltree"} +{"name":"text2ltree","args":[{"type":"text"}],"returns":"ltree"} diff --git a/internal/engine/postgresql/dialect/extensions/ltree/types.jsonl b/internal/engine/postgresql/dialect/extensions/ltree/types.jsonl new file mode 100644 index 0000000..94063ca --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/ltree/types.jsonl @@ -0,0 +1,4 @@ +{"name":"ltree","category":"U"} +{"name":"lquery","category":"U"} +{"name":"ltxtquery","category":"U"} +{"name":"ltree_gist","category":"U"} diff --git a/internal/engine/postgresql/dialect/extensions/pageinspect/functions.jsonl b/internal/engine/postgresql/dialect/extensions/pageinspect/functions.jsonl new file mode 100644 index 0000000..56f363c --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/pageinspect/functions.jsonl @@ -0,0 +1,31 @@ +{"name":"brin_metapage_info","args":[{"name":"page","type":"bytea"}],"returns":"record"} +{"name":"brin_page_items","args":[{"name":"page","type":"bytea"},{"name":"index_oid","type":"regclass"}],"returns":"record"} +{"name":"brin_page_type","args":[{"name":"page","type":"bytea"}],"returns":"text"} +{"name":"brin_revmap_data","args":[{"name":"page","type":"bytea"}],"returns":"tid"} +{"name":"bt_metap","args":[{"name":"relname","type":"text"}],"returns":"record"} +{"name":"bt_multi_page_stats","args":[{"name":"relname","type":"text"},{"name":"blkno","type":"bigint"},{"name":"blk_count","type":"bigint"}],"returns":"record"} +{"name":"bt_page_items","args":[{"name":"page","type":"bytea"}],"returns":"record"} +{"name":"bt_page_items","args":[{"name":"relname","type":"text"},{"name":"blkno","type":"bigint"}],"returns":"record"} +{"name":"bt_page_stats","args":[{"name":"relname","type":"text"},{"name":"blkno","type":"bigint"}],"returns":"record"} +{"name":"fsm_page_contents","args":[{"name":"page","type":"bytea"}],"returns":"text"} +{"name":"get_raw_page","args":[{"type":"text"},{"type":"bigint"}],"returns":"bytea"} +{"name":"get_raw_page","args":[{"type":"text"},{"type":"text"},{"type":"bigint"}],"returns":"bytea"} +{"name":"gin_leafpage_items","args":[{"name":"page","type":"bytea"}],"returns":"record"} +{"name":"gin_metapage_info","args":[{"name":"page","type":"bytea"}],"returns":"record"} +{"name":"gin_page_opaque_info","args":[{"name":"page","type":"bytea"}],"returns":"record"} +{"name":"gist_page_items","args":[{"name":"page","type":"bytea"},{"name":"index_oid","type":"regclass"}],"returns":"record"} +{"name":"gist_page_items_bytea","args":[{"name":"page","type":"bytea"}],"returns":"record"} +{"name":"gist_page_opaque_info","args":[{"name":"page","type":"bytea"}],"returns":"record"} +{"name":"hash_bitmap_info","args":[{"name":"index_oid","type":"regclass"},{"name":"blkno","type":"bigint"}],"returns":"record"} +{"name":"hash_metapage_info","args":[{"name":"page","type":"bytea"}],"returns":"record"} +{"name":"hash_page_items","args":[{"name":"page","type":"bytea"}],"returns":"record"} +{"name":"hash_page_stats","args":[{"name":"page","type":"bytea"}],"returns":"record"} +{"name":"hash_page_type","args":[{"name":"page","type":"bytea"}],"returns":"text"} +{"name":"heap_page_item_attrs","args":[{"name":"page","type":"bytea"},{"name":"rel_oid","type":"regclass"}],"returns":"record"} +{"name":"heap_page_item_attrs","args":[{"name":"page","type":"bytea"},{"name":"rel_oid","type":"regclass"},{"name":"do_detoast","type":"boolean"}],"returns":"record"} +{"name":"heap_page_items","args":[{"name":"page","type":"bytea"}],"returns":"record"} +{"name":"heap_tuple_infomask_flags","args":[{"name":"t_infomask","type":"integer"},{"name":"t_infomask2","type":"integer"}],"returns":"record"} +{"name":"page_checksum","args":[{"name":"page","type":"bytea"},{"name":"blkno","type":"bigint"}],"returns":"smallint"} +{"name":"page_header","args":[{"name":"page","type":"bytea"}],"returns":"record"} +{"name":"tuple_data_split","args":[{"name":"rel_oid","type":"oid"},{"name":"t_data","type":"bytea"},{"name":"t_infomask","type":"integer"},{"name":"t_infomask2","type":"integer"},{"name":"t_bits","type":"text"}],"returns":"bytea[]"} +{"name":"tuple_data_split","args":[{"name":"rel_oid","type":"oid"},{"name":"t_data","type":"bytea"},{"name":"t_infomask","type":"integer"},{"name":"t_infomask2","type":"integer"},{"name":"t_bits","type":"text"},{"name":"do_detoast","type":"boolean"}],"returns":"bytea[]"} diff --git a/internal/engine/postgresql/dialect/extensions/pg_buffercache/functions.jsonl b/internal/engine/postgresql/dialect/extensions/pg_buffercache/functions.jsonl new file mode 100644 index 0000000..b0f446e --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/pg_buffercache/functions.jsonl @@ -0,0 +1,3 @@ +{"name":"pg_buffercache_pages","returns":"record"} +{"name":"pg_buffercache_summary","returns":"record"} +{"name":"pg_buffercache_usage_counts","returns":"record"} diff --git a/internal/engine/postgresql/dialect/extensions/pg_freespacemap/functions.jsonl b/internal/engine/postgresql/dialect/extensions/pg_freespacemap/functions.jsonl new file mode 100644 index 0000000..19ffb50 --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/pg_freespacemap/functions.jsonl @@ -0,0 +1,2 @@ +{"name":"pg_freespace","args":[{"name":"rel","type":"regclass"}],"returns":"record"} +{"name":"pg_freespace","args":[{"type":"regclass"},{"type":"bigint"}],"returns":"smallint"} diff --git a/internal/engine/postgresql/dialect/extensions/pg_prewarm/functions.jsonl b/internal/engine/postgresql/dialect/extensions/pg_prewarm/functions.jsonl new file mode 100644 index 0000000..3f6721e --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/pg_prewarm/functions.jsonl @@ -0,0 +1,3 @@ +{"name":"autoprewarm_dump_now","returns":"bigint"} +{"name":"autoprewarm_start_worker","returns":"void"} +{"name":"pg_prewarm","args":[{"type":"regclass"},{"name":"mode","type":"text","has_default":true},{"name":"fork","type":"text","has_default":true},{"name":"first_block","type":"bigint","has_default":true},{"name":"last_block","type":"bigint","has_default":true}],"returns":"bigint"} diff --git a/internal/engine/postgresql/dialect/extensions/pg_stat_statements/functions.jsonl b/internal/engine/postgresql/dialect/extensions/pg_stat_statements/functions.jsonl new file mode 100644 index 0000000..990af04 --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/pg_stat_statements/functions.jsonl @@ -0,0 +1,3 @@ +{"name":"pg_stat_statements","args":[{"name":"showtext","type":"boolean"}],"returns":"record"} +{"name":"pg_stat_statements_info","returns":"record"} +{"name":"pg_stat_statements_reset","args":[{"name":"userid","type":"oid","has_default":true},{"name":"dbid","type":"oid","has_default":true},{"name":"queryid","type":"bigint","has_default":true}],"returns":"void"} diff --git a/internal/engine/postgresql/dialect/extensions/pg_trgm/functions.jsonl b/internal/engine/postgresql/dialect/extensions/pg_trgm/functions.jsonl new file mode 100644 index 0000000..160e43a --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/pg_trgm/functions.jsonl @@ -0,0 +1,18 @@ +{"name":"gtrgm_in","args":[{"type":"cstring"}],"returns":"gtrgm"} +{"name":"gtrgm_out","args":[{"type":"gtrgm"}],"returns":"cstring"} +{"name":"set_limit","args":[{"type":"real"}],"returns":"real"} +{"name":"show_limit","returns":"real"} +{"name":"show_trgm","args":[{"type":"text"}],"returns":"text[]"} +{"name":"similarity","args":[{"type":"text"},{"type":"text"}],"returns":"real"} +{"name":"similarity_dist","args":[{"type":"text"},{"type":"text"}],"returns":"real"} +{"name":"similarity_op","args":[{"type":"text"},{"type":"text"}],"returns":"boolean"} +{"name":"strict_word_similarity","args":[{"type":"text"},{"type":"text"}],"returns":"real"} +{"name":"strict_word_similarity_commutator_op","args":[{"type":"text"},{"type":"text"}],"returns":"boolean"} +{"name":"strict_word_similarity_dist_commutator_op","args":[{"type":"text"},{"type":"text"}],"returns":"real"} +{"name":"strict_word_similarity_dist_op","args":[{"type":"text"},{"type":"text"}],"returns":"real"} +{"name":"strict_word_similarity_op","args":[{"type":"text"},{"type":"text"}],"returns":"boolean"} +{"name":"word_similarity","args":[{"type":"text"},{"type":"text"}],"returns":"real"} +{"name":"word_similarity_commutator_op","args":[{"type":"text"},{"type":"text"}],"returns":"boolean"} +{"name":"word_similarity_dist_commutator_op","args":[{"type":"text"},{"type":"text"}],"returns":"real"} +{"name":"word_similarity_dist_op","args":[{"type":"text"},{"type":"text"}],"returns":"real"} +{"name":"word_similarity_op","args":[{"type":"text"},{"type":"text"}],"returns":"boolean"} diff --git a/internal/engine/postgresql/dialect/extensions/pg_trgm/types.jsonl b/internal/engine/postgresql/dialect/extensions/pg_trgm/types.jsonl new file mode 100644 index 0000000..6823fc4 --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/pg_trgm/types.jsonl @@ -0,0 +1 @@ +{"name":"gtrgm","category":"U"} diff --git a/internal/engine/postgresql/dialect/extensions/pg_visibility/functions.jsonl b/internal/engine/postgresql/dialect/extensions/pg_visibility/functions.jsonl new file mode 100644 index 0000000..97503f9 --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/pg_visibility/functions.jsonl @@ -0,0 +1,8 @@ +{"name":"pg_check_frozen","args":[{"type":"regclass"}],"returns":"tid"} +{"name":"pg_check_visible","args":[{"type":"regclass"}],"returns":"tid"} +{"name":"pg_truncate_visibility_map","args":[{"type":"regclass"}],"returns":"void"} +{"name":"pg_visibility","args":[{"type":"regclass"}],"returns":"record"} +{"name":"pg_visibility","args":[{"type":"regclass"},{"name":"blkno","type":"bigint"}],"returns":"record"} +{"name":"pg_visibility_map","args":[{"type":"regclass"}],"returns":"record"} +{"name":"pg_visibility_map","args":[{"type":"regclass"},{"name":"blkno","type":"bigint"}],"returns":"record"} +{"name":"pg_visibility_map_summary","args":[{"type":"regclass"}],"returns":"record"} diff --git a/internal/engine/postgresql/dialect/extensions/pgcrypto/functions.jsonl b/internal/engine/postgresql/dialect/extensions/pgcrypto/functions.jsonl new file mode 100644 index 0000000..1574f8e --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/pgcrypto/functions.jsonl @@ -0,0 +1,35 @@ +{"name":"armor","args":[{"type":"bytea"}],"returns":"text"} +{"name":"armor","args":[{"type":"bytea"},{"type":"text[]"},{"type":"text[]"}],"returns":"text"} +{"name":"crypt","args":[{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"dearmor","args":[{"type":"text"}],"returns":"bytea"} +{"name":"decrypt","args":[{"type":"bytea"},{"type":"bytea"},{"type":"text"}],"returns":"bytea"} +{"name":"decrypt_iv","args":[{"type":"bytea"},{"type":"bytea"},{"type":"bytea"},{"type":"text"}],"returns":"bytea"} +{"name":"digest","args":[{"type":"text"},{"type":"text"}],"returns":"bytea"} +{"name":"digest","args":[{"type":"bytea"},{"type":"text"}],"returns":"bytea"} +{"name":"encrypt","args":[{"type":"bytea"},{"type":"bytea"},{"type":"text"}],"returns":"bytea"} +{"name":"encrypt_iv","args":[{"type":"bytea"},{"type":"bytea"},{"type":"bytea"},{"type":"text"}],"returns":"bytea"} +{"name":"gen_random_bytes","args":[{"type":"integer"}],"returns":"bytea"} +{"name":"gen_salt","args":[{"type":"text"}],"returns":"text"} +{"name":"gen_salt","args":[{"type":"text"},{"type":"integer"}],"returns":"text"} +{"name":"hmac","args":[{"type":"bytea"},{"type":"bytea"},{"type":"text"}],"returns":"bytea"} +{"name":"hmac","args":[{"type":"text"},{"type":"text"},{"type":"text"}],"returns":"bytea"} +{"name":"pgp_armor_headers","args":[{"type":"text"}],"returns":"record"} +{"name":"pgp_key_id","args":[{"type":"bytea"}],"returns":"text"} +{"name":"pgp_pub_decrypt","args":[{"type":"bytea"},{"type":"bytea"}],"returns":"text"} +{"name":"pgp_pub_decrypt","args":[{"type":"bytea"},{"type":"bytea"},{"type":"text"}],"returns":"text"} +{"name":"pgp_pub_decrypt","args":[{"type":"bytea"},{"type":"bytea"},{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"pgp_pub_decrypt_bytea","args":[{"type":"bytea"},{"type":"bytea"}],"returns":"bytea"} +{"name":"pgp_pub_decrypt_bytea","args":[{"type":"bytea"},{"type":"bytea"},{"type":"text"}],"returns":"bytea"} +{"name":"pgp_pub_decrypt_bytea","args":[{"type":"bytea"},{"type":"bytea"},{"type":"text"},{"type":"text"}],"returns":"bytea"} +{"name":"pgp_pub_encrypt","args":[{"type":"text"},{"type":"bytea"}],"returns":"bytea"} +{"name":"pgp_pub_encrypt","args":[{"type":"text"},{"type":"bytea"},{"type":"text"}],"returns":"bytea"} +{"name":"pgp_pub_encrypt_bytea","args":[{"type":"bytea"},{"type":"bytea"}],"returns":"bytea"} +{"name":"pgp_pub_encrypt_bytea","args":[{"type":"bytea"},{"type":"bytea"},{"type":"text"}],"returns":"bytea"} +{"name":"pgp_sym_decrypt","args":[{"type":"bytea"},{"type":"text"}],"returns":"text"} +{"name":"pgp_sym_decrypt","args":[{"type":"bytea"},{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"pgp_sym_decrypt_bytea","args":[{"type":"bytea"},{"type":"text"}],"returns":"bytea"} +{"name":"pgp_sym_decrypt_bytea","args":[{"type":"bytea"},{"type":"text"},{"type":"text"}],"returns":"bytea"} +{"name":"pgp_sym_encrypt","args":[{"type":"text"},{"type":"text"}],"returns":"bytea"} +{"name":"pgp_sym_encrypt","args":[{"type":"text"},{"type":"text"},{"type":"text"}],"returns":"bytea"} +{"name":"pgp_sym_encrypt_bytea","args":[{"type":"bytea"},{"type":"text"}],"returns":"bytea"} +{"name":"pgp_sym_encrypt_bytea","args":[{"type":"bytea"},{"type":"text"},{"type":"text"}],"returns":"bytea"} diff --git a/internal/engine/postgresql/dialect/extensions/pgrowlocks/functions.jsonl b/internal/engine/postgresql/dialect/extensions/pgrowlocks/functions.jsonl new file mode 100644 index 0000000..c40d0a4 --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/pgrowlocks/functions.jsonl @@ -0,0 +1 @@ +{"name":"pgrowlocks","args":[{"name":"relname","type":"text"}],"returns":"record"} diff --git a/internal/engine/postgresql/dialect/extensions/pgstattuple/functions.jsonl b/internal/engine/postgresql/dialect/extensions/pgstattuple/functions.jsonl new file mode 100644 index 0000000..ac9ee05 --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/pgstattuple/functions.jsonl @@ -0,0 +1,9 @@ +{"name":"pg_relpages","args":[{"name":"relname","type":"regclass"}],"returns":"bigint"} +{"name":"pg_relpages","args":[{"name":"relname","type":"text"}],"returns":"bigint"} +{"name":"pgstatginindex","args":[{"name":"relname","type":"regclass"}],"returns":"record"} +{"name":"pgstathashindex","args":[{"name":"relname","type":"regclass"}],"returns":"record"} +{"name":"pgstatindex","args":[{"name":"relname","type":"regclass"}],"returns":"record"} +{"name":"pgstatindex","args":[{"name":"relname","type":"text"}],"returns":"record"} +{"name":"pgstattuple","args":[{"name":"reloid","type":"regclass"}],"returns":"record"} +{"name":"pgstattuple","args":[{"name":"relname","type":"text"}],"returns":"record"} +{"name":"pgstattuple_approx","args":[{"name":"reloid","type":"regclass"}],"returns":"record"} diff --git a/internal/engine/postgresql/dialect/extensions/postgres_fdw/functions.jsonl b/internal/engine/postgresql/dialect/extensions/postgres_fdw/functions.jsonl new file mode 100644 index 0000000..9ccf9f0 --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/postgres_fdw/functions.jsonl @@ -0,0 +1,5 @@ +{"name":"postgres_fdw_disconnect","args":[{"type":"text"}],"returns":"boolean"} +{"name":"postgres_fdw_disconnect_all","returns":"boolean"} +{"name":"postgres_fdw_get_connections","returns":"record"} +{"name":"postgres_fdw_handler","returns":"fdw_handler"} +{"name":"postgres_fdw_validator","args":[{"type":"text[]"},{"type":"oid"}],"returns":"void"} diff --git a/internal/engine/postgresql/dialect/extensions/seg/functions.jsonl b/internal/engine/postgresql/dialect/extensions/seg/functions.jsonl new file mode 100644 index 0000000..63f0cdb --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/seg/functions.jsonl @@ -0,0 +1,22 @@ +{"name":"seg_center","args":[{"type":"seg"}],"returns":"real"} +{"name":"seg_cmp","args":[{"type":"seg"},{"type":"seg"}],"returns":"integer"} +{"name":"seg_contained","args":[{"type":"seg"},{"type":"seg"}],"returns":"boolean"} +{"name":"seg_contains","args":[{"type":"seg"},{"type":"seg"}],"returns":"boolean"} +{"name":"seg_different","args":[{"type":"seg"},{"type":"seg"}],"returns":"boolean"} +{"name":"seg_ge","args":[{"type":"seg"},{"type":"seg"}],"returns":"boolean"} +{"name":"seg_gt","args":[{"type":"seg"},{"type":"seg"}],"returns":"boolean"} +{"name":"seg_in","args":[{"type":"cstring"}],"returns":"seg"} +{"name":"seg_inter","args":[{"type":"seg"},{"type":"seg"}],"returns":"seg"} +{"name":"seg_le","args":[{"type":"seg"},{"type":"seg"}],"returns":"boolean"} +{"name":"seg_left","args":[{"type":"seg"},{"type":"seg"}],"returns":"boolean"} +{"name":"seg_lower","args":[{"type":"seg"}],"returns":"real"} +{"name":"seg_lt","args":[{"type":"seg"},{"type":"seg"}],"returns":"boolean"} +{"name":"seg_out","args":[{"type":"seg"}],"returns":"cstring"} +{"name":"seg_over_left","args":[{"type":"seg"},{"type":"seg"}],"returns":"boolean"} +{"name":"seg_over_right","args":[{"type":"seg"},{"type":"seg"}],"returns":"boolean"} +{"name":"seg_overlap","args":[{"type":"seg"},{"type":"seg"}],"returns":"boolean"} +{"name":"seg_right","args":[{"type":"seg"},{"type":"seg"}],"returns":"boolean"} +{"name":"seg_same","args":[{"type":"seg"},{"type":"seg"}],"returns":"boolean"} +{"name":"seg_size","args":[{"type":"seg"}],"returns":"real"} +{"name":"seg_union","args":[{"type":"seg"},{"type":"seg"}],"returns":"seg"} +{"name":"seg_upper","args":[{"type":"seg"}],"returns":"real"} diff --git a/internal/engine/postgresql/dialect/extensions/seg/types.jsonl b/internal/engine/postgresql/dialect/extensions/seg/types.jsonl new file mode 100644 index 0000000..d09b313 --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/seg/types.jsonl @@ -0,0 +1 @@ +{"name":"seg","category":"U"} diff --git a/internal/engine/postgresql/dialect/extensions/sslinfo/functions.jsonl b/internal/engine/postgresql/dialect/extensions/sslinfo/functions.jsonl new file mode 100644 index 0000000..18b86c9 --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/sslinfo/functions.jsonl @@ -0,0 +1,10 @@ +{"name":"ssl_cipher","returns":"text"} +{"name":"ssl_client_cert_present","returns":"boolean"} +{"name":"ssl_client_dn","returns":"text"} +{"name":"ssl_client_dn_field","args":[{"type":"text"}],"returns":"text"} +{"name":"ssl_client_serial","returns":"numeric"} +{"name":"ssl_extension_info","returns":"record"} +{"name":"ssl_is_used","returns":"boolean"} +{"name":"ssl_issuer_dn","returns":"text"} +{"name":"ssl_issuer_field","args":[{"type":"text"}],"returns":"text"} +{"name":"ssl_version","returns":"text"} diff --git a/internal/engine/postgresql/dialect/extensions/tablefunc/functions.jsonl b/internal/engine/postgresql/dialect/extensions/tablefunc/functions.jsonl new file mode 100644 index 0000000..5b7bd5d --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/tablefunc/functions.jsonl @@ -0,0 +1,11 @@ +{"name":"connectby","args":[{"type":"text"},{"type":"text"},{"type":"text"},{"type":"text"},{"type":"integer"}],"returns":"record"} +{"name":"connectby","args":[{"type":"text"},{"type":"text"},{"type":"text"},{"type":"text"},{"type":"integer"},{"type":"text"}],"returns":"record"} +{"name":"connectby","args":[{"type":"text"},{"type":"text"},{"type":"text"},{"type":"text"},{"type":"text"},{"type":"integer"}],"returns":"record"} +{"name":"connectby","args":[{"type":"text"},{"type":"text"},{"type":"text"},{"type":"text"},{"type":"text"},{"type":"integer"},{"type":"text"}],"returns":"record"} +{"name":"crosstab","args":[{"type":"text"}],"returns":"record"} +{"name":"crosstab","args":[{"type":"text"},{"type":"integer"}],"returns":"record"} +{"name":"crosstab","args":[{"type":"text"},{"type":"text"}],"returns":"record"} +{"name":"crosstab2","args":[{"type":"text"}],"returns":"tablefunc_crosstab_2"} +{"name":"crosstab3","args":[{"type":"text"}],"returns":"tablefunc_crosstab_3"} +{"name":"crosstab4","args":[{"type":"text"}],"returns":"tablefunc_crosstab_4"} +{"name":"normal_rand","args":[{"type":"integer"},{"type":"double precision"},{"type":"double precision"}],"returns":"double precision"} diff --git a/internal/engine/postgresql/dialect/extensions/tablefunc/types.jsonl b/internal/engine/postgresql/dialect/extensions/tablefunc/types.jsonl new file mode 100644 index 0000000..099110a --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/tablefunc/types.jsonl @@ -0,0 +1,3 @@ +{"name":"tablefunc_crosstab_2","category":"C"} +{"name":"tablefunc_crosstab_3","category":"C"} +{"name":"tablefunc_crosstab_4","category":"C"} diff --git a/internal/engine/postgresql/dialect/extensions/tcn/functions.jsonl b/internal/engine/postgresql/dialect/extensions/tcn/functions.jsonl new file mode 100644 index 0000000..208a10b --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/tcn/functions.jsonl @@ -0,0 +1 @@ +{"name":"triggered_change_notification","returns":"trigger"} diff --git a/internal/engine/postgresql/dialect/extensions/unaccent/functions.jsonl b/internal/engine/postgresql/dialect/extensions/unaccent/functions.jsonl new file mode 100644 index 0000000..2db64e2 --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/unaccent/functions.jsonl @@ -0,0 +1,2 @@ +{"name":"unaccent","args":[{"type":"regdictionary"},{"type":"text"}],"returns":"text"} +{"name":"unaccent","args":[{"type":"text"}],"returns":"text"} diff --git a/internal/engine/postgresql/dialect/extensions/uuid-ossp/functions.jsonl b/internal/engine/postgresql/dialect/extensions/uuid-ossp/functions.jsonl new file mode 100644 index 0000000..b80703f --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/uuid-ossp/functions.jsonl @@ -0,0 +1,10 @@ +{"name":"uuid_generate_v1","returns":"uuid"} +{"name":"uuid_generate_v1mc","returns":"uuid"} +{"name":"uuid_generate_v3","args":[{"name":"namespace","type":"uuid"},{"name":"name","type":"text"}],"returns":"uuid"} +{"name":"uuid_generate_v4","returns":"uuid"} +{"name":"uuid_generate_v5","args":[{"name":"namespace","type":"uuid"},{"name":"name","type":"text"}],"returns":"uuid"} +{"name":"uuid_nil","returns":"uuid"} +{"name":"uuid_ns_dns","returns":"uuid"} +{"name":"uuid_ns_oid","returns":"uuid"} +{"name":"uuid_ns_url","returns":"uuid"} +{"name":"uuid_ns_x500","returns":"uuid"} diff --git a/internal/engine/postgresql/dialect/extensions/xml2/functions.jsonl b/internal/engine/postgresql/dialect/extensions/xml2/functions.jsonl new file mode 100644 index 0000000..8124863 --- /dev/null +++ b/internal/engine/postgresql/dialect/extensions/xml2/functions.jsonl @@ -0,0 +1,13 @@ +{"name":"xml_encode_special_chars","args":[{"type":"text"}],"returns":"text"} +{"name":"xml_valid","args":[{"type":"text"}],"returns":"boolean"} +{"name":"xpath_bool","args":[{"type":"text"},{"type":"text"}],"returns":"boolean"} +{"name":"xpath_list","args":[{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"xpath_list","args":[{"type":"text"},{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"xpath_nodeset","args":[{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"xpath_nodeset","args":[{"type":"text"},{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"xpath_nodeset","args":[{"type":"text"},{"type":"text"},{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"xpath_number","args":[{"type":"text"},{"type":"text"}],"returns":"real"} +{"name":"xpath_string","args":[{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"xpath_table","args":[{"type":"text"},{"type":"text"},{"type":"text"},{"type":"text"},{"type":"text"}],"returns":"record"} +{"name":"xslt_process","args":[{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"xslt_process","args":[{"type":"text"},{"type":"text"},{"type":"text"}],"returns":"text"} diff --git a/internal/engine/postgresql/dialect/operators.jsonl b/internal/engine/postgresql/dialect/operators.jsonl new file mode 100644 index 0000000..8772649 --- /dev/null +++ b/internal/engine/postgresql/dialect/operators.jsonl @@ -0,0 +1,21 @@ +{"name": "||", "left": "text", "right": "text", "result": "text"} +{"name": "~~", "left": "text", "right": "text", "result": "bool"} +{"name": "!~~", "left": "text", "right": "text", "result": "bool"} +{"name": "~~*", "left": "text", "right": "text", "result": "bool"} +{"name": "!~~*", "left": "text", "right": "text", "result": "bool"} +{"name": "~", "left": "text", "right": "text", "result": "bool"} +{"name": "!~", "left": "text", "right": "text", "result": "bool"} +{"name": "~*", "left": "text", "right": "text", "result": "bool"} +{"name": "!~*", "left": "text", "right": "text", "result": "bool"} +{"name": "@>", "left": "jsonb", "right": "jsonb", "result": "bool"} +{"name": "<@", "left": "jsonb", "right": "jsonb", "result": "bool"} +{"name": "->", "left": "jsonb", "right": "text", "result": "jsonb"} +{"name": "->>", "left": "jsonb", "right": "text", "result": "text"} +{"name": "->", "left": "json", "right": "text", "result": "json"} +{"name": "->>", "left": "json", "right": "text", "result": "text"} +{"name": "+", "left": "date", "right": "int4", "result": "date"} +{"name": "-", "left": "date", "right": "int4", "result": "date"} +{"name": "+", "left": "timestamptz", "right": "interval", "result": "timestamptz"} +{"name": "-", "left": "timestamptz", "right": "interval", "result": "timestamptz"} +{"name": "+", "left": "timestamp", "right": "interval", "result": "timestamp"} +{"name": "-", "left": "timestamp", "right": "interval", "result": "timestamp"} diff --git a/internal/engine/postgresql/dialect/types.jsonl b/internal/engine/postgresql/dialect/types.jsonl new file mode 100644 index 0000000..ac394f1 --- /dev/null +++ b/internal/engine/postgresql/dialect/types.jsonl @@ -0,0 +1,48 @@ +{"name": "boolean", "category": "B", "aliases": ["bool"]} +{"name": "smallint", "category": "N", "aliases": ["int2", "smallserial", "serial2"]} +{"name": "integer", "category": "N", "aliases": ["int4", "int", "serial", "serial4"]} +{"name": "bigint", "category": "N", "aliases": ["int8", "bigserial", "serial8"]} +{"name": "real", "category": "N", "aliases": ["float4"]} +{"name": "double precision", "category": "N", "aliases": ["float8"]} +{"name": "numeric", "category": "N", "aliases": ["decimal"]} +{"name": "money", "category": "N"} +{"name": "oid", "category": "N"} +{"name": "text", "category": "S"} +{"name": "character varying", "category": "S", "aliases": ["varchar"]} +{"name": "character", "category": "S", "aliases": ["bpchar", "char"]} +{"name": "name", "category": "S"} +{"name": "citext", "category": "S"} +{"name": "date", "category": "D"} +{"name": "time without time zone", "category": "D", "aliases": ["time"]} +{"name": "time with time zone", "category": "D", "aliases": ["timetz"]} +{"name": "timestamp without time zone", "category": "D", "aliases": ["timestamp"]} +{"name": "timestamp with time zone", "category": "D", "aliases": ["timestamptz"]} +{"name": "interval", "category": "T"} +{"name": "uuid", "category": "U"} +{"name": "bytea", "category": "U"} +{"name": "json", "category": "U"} +{"name": "jsonb", "category": "U"} +{"name": "xml", "category": "U"} +{"name": "inet", "category": "U"} +{"name": "cidr", "category": "U"} +{"name": "macaddr", "category": "U"} +{"name": "macaddr8", "category": "U"} +{"name": "bit", "category": "U"} +{"name": "bit varying", "category": "U", "aliases": ["varbit"]} +{"name": "tsvector", "category": "U"} +{"name": "tsquery", "category": "U"} +{"name": "point", "category": "U"} +{"name": "line", "category": "U"} +{"name": "lseg", "category": "U"} +{"name": "box", "category": "U"} +{"name": "path", "category": "U"} +{"name": "polygon", "category": "U"} +{"name": "circle", "category": "U"} +{"name": "int4range", "category": "U"} +{"name": "int8range", "category": "U"} +{"name": "numrange", "category": "U"} +{"name": "tsrange", "category": "U"} +{"name": "tstzrange", "category": "U"} +{"name": "daterange", "category": "U"} +{"name": "anyarray", "category": "A"} +{"name": "array", "category": "A"} diff --git a/internal/engine/postgresql/extension.go b/internal/engine/postgresql/extension.go new file mode 100644 index 0000000..6d81f9f --- /dev/null +++ b/internal/engine/postgresql/extension.go @@ -0,0 +1,27 @@ +package postgresql + +import ( + "io/fs" + "path" + + "github.com/sqlc-dev/sqlc/internal/core/seed" + "github.com/sqlc-dev/sqlc/internal/sql/catalog" +) + +// loadExtension reads the named extension's function list from the dialect +// directory, where goldeneye writes one directory per extension. An +// extension sqlc does not know is nil, which CREATE EXTENSION treats as +// nothing to add. +func loadExtension(name string) *catalog.Schema { + dir := path.Join("dialect", "extensions", name) + if _, err := fs.Stat(dialectFS, path.Join(dir, seed.FunctionsFile)); err != nil { + return nil + } + funcs, err := seed.Functions(dialectFS, dir) + if err != nil { + // The list is embedded in the binary: a failure here means sqlc was + // built from a broken tree, which no caller can do anything about. + panic(err) + } + return &catalog.Schema{Name: "pg_catalog", Funcs: funcs} +} diff --git a/internal/engine/postgresql/parse.go b/internal/engine/postgresql/parse.go new file mode 100644 index 0000000..58f7c3d --- /dev/null +++ b/internal/engine/postgresql/parse.go @@ -0,0 +1,798 @@ +package postgresql + +import ( + "errors" + "fmt" + "io" + "strings" + + nodes "github.com/sqlc-dev/oliphant" + "github.com/sqlc-dev/oliphant/parser" + + "github.com/sqlc-dev/sqlc/internal/source" + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/sqlerr" +) + +var Parse = nodes.Parse +var Fingerprint = nodes.Fingerprint + +func stringSlice(list *nodes.List) []string { + items := []string{} + for _, item := range list.Items { + if n, ok := item.Node.(*nodes.Node_String_); ok { + items = append(items, n.String_.Sval) + } + } + return items +} + +func stringSliceFromNodes(s []*nodes.Node) []string { + var items []string + for _, item := range s { + if n, ok := item.Node.(*nodes.Node_String_); ok { + items = append(items, n.String_.Sval) + } + } + return items +} + +type relation struct { + Catalog string + Schema string + Name string +} + +func (r relation) TableName() *ast.TableName { + return &ast.TableName{ + Catalog: r.Catalog, + Schema: r.Schema, + Name: r.Name, + } +} + +func (r relation) TypeName() *ast.TypeName { + return &ast.TypeName{ + Catalog: r.Catalog, + Schema: r.Schema, + Name: r.Name, + } +} + +func (r relation) FuncName() *ast.FuncName { + return &ast.FuncName{ + Catalog: r.Catalog, + Schema: r.Schema, + Name: r.Name, + } +} + +func parseRelationFromNodes(list []*nodes.Node) (*relation, error) { + parts := stringSliceFromNodes(list) + switch len(parts) { + case 1: + return &relation{ + Name: parts[0], + }, nil + case 2: + return &relation{ + Schema: parts[0], + Name: parts[1], + }, nil + case 3: + return &relation{ + Catalog: parts[0], + Schema: parts[1], + Name: parts[2], + }, nil + default: + return nil, fmt.Errorf("invalid name: %s", joinNodes(list, ".")) + } +} + +func parseRelationFromRangeVar(rv *nodes.RangeVar) *relation { + return &relation{ + Catalog: rv.Catalogname, + Schema: rv.Schemaname, + Name: rv.Relname, + } +} + +func parseRelation(in *nodes.Node) (*relation, error) { + switch n := in.Node.(type) { + case *nodes.Node_List: + return parseRelationFromNodes(n.List.Items) + case *nodes.Node_RangeVar: + return parseRelationFromRangeVar(n.RangeVar), nil + case *nodes.Node_TypeName: + return parseRelationFromNodes(n.TypeName.Names) + default: + return nil, fmt.Errorf("unexpected node type: %T", n) + } +} + +func parseColName(node *nodes.Node) (*ast.ColumnRef, *ast.TableName, error) { + switch n := node.Node.(type) { + case *nodes.Node_List: + parts := stringSlice(n.List) + var tbl *ast.TableName + var ref *ast.ColumnRef + switch len(parts) { + case 2: + tbl = &ast.TableName{Name: parts[0]} + ref = &ast.ColumnRef{Name: parts[1]} + case 3: + tbl = &ast.TableName{Schema: parts[0], Name: parts[1]} + ref = &ast.ColumnRef{Name: parts[2]} + case 4: + tbl = &ast.TableName{Catalog: parts[0], Schema: parts[1], Name: parts[2]} + ref = &ast.ColumnRef{Name: parts[3]} + default: + return nil, nil, fmt.Errorf("column specifier %q is not the proper format, expected '[catalog.][schema.]colname.tablename'", strings.Join(parts, ".")) + } + return ref, tbl, nil + default: + return nil, nil, fmt.Errorf("parseColName: unexpected node type: %T", n) + } +} + +func joinNodes(list []*nodes.Node, sep string) string { + return strings.Join(stringSliceFromNodes(list), sep) +} + +func NewParser() *Parser { + return &Parser{} +} + +type Parser struct { +} + +var errSkip = errors.New("skip stmt") + +func (p *Parser) Parse(r io.Reader) ([]ast.Statement, error) { + f, err := p.ParseFile(r) + if err != nil { + return nil, err + } + return f.Stmts, nil +} + +// ParseFile parses like Parse and also carries the file's comments, which +// oliphant's parser collects from the same pass its scanner already makes +// over the input. +func (p *Parser) ParseFile(r io.Reader) (*ast.File, error) { + blob, err := io.ReadAll(r) + if err != nil { + return nil, err + } + contents := string(blob) + parsed, err := parser.ParseFile(contents) + if err != nil { + pErr := normalizeErr(err) + return nil, pErr + } + tree := parsed.ParseResult + + var stmts []ast.Statement + // PostgreSQL 18 changed stmt_location to point at the statement's first + // token. The rest of the compiler expects the earlier convention, where a + // statement begins where the previous one ended and so carries its leading + // comments (that's where `-- name:` lives). + loc := 0 + for _, raw := range tree.Stmts { + start := loc + end := int(raw.StmtLocation) + int(raw.StmtLen) + next := end + for next < len(contents) && contents[next] != ';' { + next++ + } + terminated := next < len(contents) + if terminated { + next++ + } + loc = next + length := end - start + if !terminated { + // A zero length marked an unterminated final statement before + // PostgreSQL 18, and the compiler still reports it that way. + length = 0 + } + + n, err := translate(raw.Stmt) + if err == errSkip { + continue + } + if err != nil { + return nil, err + } + if n == nil { + return nil, fmt.Errorf("unexpected nil node") + } + stmts = append(stmts, ast.Statement{ + Raw: &ast.RawStmt{ + Stmt: n, + StmtLocation: start, + StmtLen: length, + }, + }) + } + + var comments []ast.Comment + for _, tok := range parsed.Comments { + comments = append(comments, ast.Comment{ + Text: strings.TrimRight(contents[tok.Start:tok.End], " \t\r\n"), + Start: int(tok.Start), + End: int(tok.End), + OwnLine: ownLine(contents, int(tok.Start)), + }) + } + return &ast.File{Stmts: stmts, Comments: comments}, nil +} + +// ownLine reports that only blank space sits between the preceding line +// break and pos. +func ownLine(src string, pos int) bool { + for j := pos - 1; j >= 0; j-- { + switch src[j] { + case '\n': + return true + case ' ', '\t', '\r': + continue + default: + return false + } + } + return true +} + +func normalizeErr(err error) error { + //TODO: errors.As complains that *parser.Error does not implement error + if pErr, ok := err.(*parser.Error); ok { + sErr := &sqlerr.Error{ + Message: pErr.Message, + //Err: pErr, + Line: pErr.Lineno, + Location: pErr.Cursorpos, + } + return sErr + } + + return err +} + +// https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-COMMENTS +func (p *Parser) CommentSyntax() source.CommentSyntax { + return source.CommentSyntax{ + Dash: true, + SlashStar: true, + } +} + +func translate(node *nodes.Node) (ast.Node, error) { + switch inner := node.Node.(type) { + + case *nodes.Node_AlterEnumStmt: + n := inner.AlterEnumStmt + rel, err := parseRelationFromNodes(n.TypeName) + if err != nil { + return nil, err + } + if n.OldVal != "" { + return &ast.AlterTypeRenameValueStmt{ + Type: rel.TypeName(), + OldValue: makeString(n.OldVal), + NewValue: makeString(n.NewVal), + }, nil + } else { + return &ast.AlterTypeAddValueStmt{ + Type: rel.TypeName(), + NewValue: makeString(n.NewVal), + NewValHasNeighbor: len(n.NewValNeighbor) > 0, + NewValNeighbor: makeString(n.NewValNeighbor), + NewValIsAfter: n.NewValIsAfter, + SkipIfNewValExists: n.SkipIfNewValExists, + }, nil + } + + case *nodes.Node_AlterObjectSchemaStmt: + n := inner.AlterObjectSchemaStmt + switch n.ObjectType { + + case nodes.ObjectType_OBJECT_TABLE, nodes.ObjectType_OBJECT_VIEW, nodes.ObjectType_OBJECT_MATVIEW: + rel := parseRelationFromRangeVar(n.Relation) + return &ast.AlterTableSetSchemaStmt{ + Table: rel.TableName(), + NewSchema: makeString(n.Newschema), + MissingOk: n.MissingOk, + }, nil + + case nodes.ObjectType_OBJECT_TYPE: + rel, err := parseRelation(n.Object) + if err != nil { + return nil, err + } + return &ast.AlterTypeSetSchemaStmt{ + Type: rel.TypeName(), + NewSchema: makeString(n.Newschema), + }, nil + } + return nil, errSkip + + case *nodes.Node_AlterTableStmt: + n := inner.AlterTableStmt + rel := parseRelationFromRangeVar(n.Relation) + at := &ast.AlterTableStmt{ + Table: rel.TableName(), + Cmds: &ast.List{}, + MissingOk: n.MissingOk, + } + for _, cmd := range n.Cmds { + switch cmdOneOf := cmd.Node.(type) { + case *nodes.Node_AlterTableCmd: + altercmd := cmdOneOf.AlterTableCmd + item := &ast.AlterTableCmd{Name: &altercmd.Name, MissingOk: altercmd.MissingOk} + + switch altercmd.Subtype { + case nodes.AlterTableType_AT_AddColumn: + d, ok := altercmd.Def.Node.(*nodes.Node_ColumnDef) + if !ok { + return nil, fmt.Errorf("expected alter table definition to be a ColumnDef") + } + + rel, err := parseRelationFromNodes(d.ColumnDef.TypeName.Names) + if err != nil { + return nil, err + } + item.Subtype = ast.AT_AddColumn + item.Def = &ast.ColumnDef{ + Colname: d.ColumnDef.Colname, + TypeName: columnTypeName(rel, d.ColumnDef.TypeName), + IsNotNull: isNotNull(d.ColumnDef), + IsArray: isArray(d.ColumnDef.TypeName), + ArrayDims: len(d.ColumnDef.TypeName.ArrayBounds), + } + + case nodes.AlterTableType_AT_AlterColumnType: + d, ok := altercmd.Def.Node.(*nodes.Node_ColumnDef) + if !ok { + return nil, fmt.Errorf("expected alter table definition to be a ColumnDef") + } + col := "" + if altercmd.Name != "" { + col = altercmd.Name + } else if d.ColumnDef.Colname != "" { + col = d.ColumnDef.Colname + } else { + return nil, fmt.Errorf("unknown name for alter column type") + } + rel, err := parseRelationFromNodes(d.ColumnDef.TypeName.Names) + if err != nil { + return nil, err + } + item.Subtype = ast.AT_AlterColumnType + item.Def = &ast.ColumnDef{ + Colname: col, + TypeName: columnTypeName(rel, d.ColumnDef.TypeName), + IsNotNull: isNotNull(d.ColumnDef), + IsArray: isArray(d.ColumnDef.TypeName), + ArrayDims: len(d.ColumnDef.TypeName.ArrayBounds), + } + + case nodes.AlterTableType_AT_DropColumn: + item.Subtype = ast.AT_DropColumn + + case nodes.AlterTableType_AT_DropNotNull: + item.Subtype = ast.AT_DropNotNull + + case nodes.AlterTableType_AT_SetNotNull: + item.Subtype = ast.AT_SetNotNull + + default: + continue + } + + at.Cmds.Items = append(at.Cmds.Items, item) + } + } + return at, nil + + case *nodes.Node_CommentStmt: + n := inner.CommentStmt + switch n.Objtype { + + case nodes.ObjectType_OBJECT_COLUMN: + col, tbl, err := parseColName(n.Object) + if err != nil { + return nil, fmt.Errorf("COMMENT ON COLUMN: %w", err) + } + return &ast.CommentOnColumnStmt{ + Col: col, + Table: tbl, + Comment: makeString(n.Comment), + }, nil + + case nodes.ObjectType_OBJECT_SCHEMA: + o, ok := n.Object.Node.(*nodes.Node_String_) + if !ok { + return nil, fmt.Errorf("COMMENT ON SCHEMA: unexpected node type: %T", n.Object) + } + return &ast.CommentOnSchemaStmt{ + Schema: &ast.String{Str: o.String_.Sval}, + Comment: makeString(n.Comment), + }, nil + + case nodes.ObjectType_OBJECT_TABLE: + rel, err := parseRelation(n.Object) + if err != nil { + return nil, fmt.Errorf("COMMENT ON TABLE: %w", err) + } + return &ast.CommentOnTableStmt{ + Table: rel.TableName(), + Comment: makeString(n.Comment), + }, nil + + case nodes.ObjectType_OBJECT_TYPE: + rel, err := parseRelation(n.Object) + if err != nil { + return nil, err + } + return &ast.CommentOnTypeStmt{ + Type: rel.TypeName(), + Comment: makeString(n.Comment), + }, nil + + case nodes.ObjectType_OBJECT_VIEW: + rel, err := parseRelation(n.Object) + if err != nil { + return nil, fmt.Errorf("COMMENT ON VIEW: %w", err) + } + return &ast.CommentOnViewStmt{ + View: rel.TableName(), + Comment: makeString(n.Comment), + }, nil + + } + return nil, errSkip + + case *nodes.Node_CompositeTypeStmt: + n := inner.CompositeTypeStmt + rel := parseRelationFromRangeVar(n.Typevar) + stmt := &ast.CompositeTypeStmt{ + TypeName: rel.TypeName(), + Coldeflist: &ast.List{}, + } + for _, node := range n.Coldeflist { + field, ok := node.Node.(*nodes.Node_ColumnDef) + if !ok { + continue + } + rel, err := parseRelationFromNodes(field.ColumnDef.TypeName.Names) + if err != nil { + return nil, err + } + stmt.Coldeflist.Items = append(stmt.Coldeflist.Items, &ast.ColumnDef{ + Colname: field.ColumnDef.Colname, + TypeName: columnTypeName(rel, field.ColumnDef.TypeName), + IsArray: isArray(field.ColumnDef.TypeName), + ArrayDims: len(field.ColumnDef.TypeName.ArrayBounds), + }) + } + return stmt, nil + + case *nodes.Node_CreateStmt: + n := inner.CreateStmt + rel := parseRelationFromRangeVar(n.Relation) + create := &ast.CreateTableStmt{ + Name: rel.TableName(), + IfNotExists: n.IfNotExists, + } + for _, node := range n.InhRelations { + switch item := node.Node.(type) { + case *nodes.Node_RangeVar: + if item.RangeVar.Inh { + rel := parseRelationFromRangeVar(item.RangeVar) + create.Inherits = append(create.Inherits, rel.TableName()) + } + } + } + primaryKey := make(map[string]bool) + for _, elt := range n.TableElts { + switch item := elt.Node.(type) { + case *nodes.Node_Constraint: + if item.Constraint.Contype == nodes.ConstrType_CONSTR_PRIMARY { + for _, key := range item.Constraint.Keys { + // FIXME: Possible nil pointer dereference + primaryKey[key.Node.(*nodes.Node_String_).String_.Sval] = true + } + } + + case *nodes.Node_TableLikeClause: + rel := parseRelationFromRangeVar(item.TableLikeClause.Relation) + create.ReferTable = rel.TableName() + } + } + for _, elt := range n.TableElts { + switch item := elt.Node.(type) { + case *nodes.Node_ColumnDef: + rel, err := parseRelationFromNodes(item.ColumnDef.TypeName.Names) + if err != nil { + return nil, err + } + + primary := false + for _, con := range item.ColumnDef.Constraints { + if constraint, ok := con.Node.(*nodes.Node_Constraint); ok { + primary = constraint.Constraint.Contype == nodes.ConstrType_CONSTR_PRIMARY + } + } + + create.Cols = append(create.Cols, &ast.ColumnDef{ + Colname: item.ColumnDef.Colname, + TypeName: columnTypeName(rel, item.ColumnDef.TypeName), + IsNotNull: isNotNull(item.ColumnDef) || primaryKey[item.ColumnDef.Colname], + IsArray: isArray(item.ColumnDef.TypeName), + ArrayDims: len(item.ColumnDef.TypeName.ArrayBounds), + PrimaryKey: primary, + }) + } + } + return create, nil + + case *nodes.Node_CreateEnumStmt: + n := inner.CreateEnumStmt + rel, err := parseRelationFromNodes(n.TypeName) + if err != nil { + return nil, err + } + stmt := &ast.CreateEnumStmt{ + TypeName: rel.TypeName(), + Vals: &ast.List{}, + } + for _, val := range n.Vals { + switch v := val.Node.(type) { + case *nodes.Node_String_: + stmt.Vals.Items = append(stmt.Vals.Items, &ast.String{ + Str: v.String_.Sval, + }) + } + } + return stmt, nil + + case *nodes.Node_CreateFunctionStmt: + n := inner.CreateFunctionStmt + fn, err := parseRelationFromNodes(n.Funcname) + if err != nil { + return nil, err + } + var rt *ast.TypeName + if n.ReturnType != nil { + rel, err := parseRelationFromNodes(n.ReturnType.Names) + if err != nil { + return nil, err + } + rt = rel.TypeName() + } + stmt := &ast.CreateFunctionStmt{ + Func: fn.FuncName(), + ReturnType: rt, + Replace: n.Replace, + Params: &ast.List{}, + Options: convertSlice(n.Options), + } + for _, item := range n.Parameters { + arg := item.Node.(*nodes.Node_FunctionParameter).FunctionParameter + rel, err := parseRelationFromNodes(arg.ArgType.Names) + if err != nil { + return nil, err + } + mode, err := convertFuncParamMode(arg.Mode) + if err != nil { + return nil, err + } + fp := &ast.FuncParam{ + Name: &arg.Name, + Type: rel.TypeName(), + Mode: mode, + } + if arg.Defexpr != nil { + fp.DefExpr = &ast.TODO{} + } + stmt.Params.Items = append(stmt.Params.Items, fp) + } + return stmt, nil + + case *nodes.Node_CreateSchemaStmt: + n := inner.CreateSchemaStmt + return &ast.CreateSchemaStmt{ + Name: makeString(n.Schemaname), + IfNotExists: n.IfNotExists, + }, nil + + case *nodes.Node_DropStmt: + n := inner.DropStmt + switch n.RemoveType { + + case nodes.ObjectType_OBJECT_FUNCTION: + drop := &ast.DropFunctionStmt{ + MissingOk: n.MissingOk, + } + for _, obj := range n.Objects { + nowa, ok := obj.Node.(*nodes.Node_ObjectWithArgs) + if !ok { + return nil, fmt.Errorf("nodes.DropStmt: FUNCTION: unknown type in objects list: %T", obj) + } + owa := nowa.ObjectWithArgs + fn, err := parseRelationFromNodes(owa.Objname) + if err != nil { + return nil, fmt.Errorf("nodes.DropStmt: FUNCTION: %w", err) + } + args := make([]*ast.TypeName, len(owa.Objargs)) + for i, objarg := range owa.Objargs { + tn, ok := objarg.Node.(*nodes.Node_TypeName) + if !ok { + return nil, fmt.Errorf("nodes.DropStmt: FUNCTION: unknown type in objargs list: %T", objarg) + } + at, err := parseRelationFromNodes(tn.TypeName.Names) + if err != nil { + return nil, fmt.Errorf("nodes.DropStmt: FUNCTION: %w", err) + } + args[i] = at.TypeName() + } + drop.Funcs = append(drop.Funcs, &ast.FuncSpec{ + Name: fn.FuncName(), + Args: args, + HasArgs: !owa.ArgsUnspecified, + }) + } + return drop, nil + + case nodes.ObjectType_OBJECT_SCHEMA: + drop := &ast.DropSchemaStmt{ + MissingOk: n.MissingOk, + } + for _, obj := range n.Objects { + val, ok := obj.Node.(*nodes.Node_String_) + if !ok { + return nil, fmt.Errorf("nodes.DropStmt: SCHEMA: unknown type in objects list: %T", obj) + } + drop.Schemas = append(drop.Schemas, &ast.String{Str: val.String_.Sval}) + } + return drop, nil + + case nodes.ObjectType_OBJECT_TABLE, nodes.ObjectType_OBJECT_VIEW, nodes.ObjectType_OBJECT_MATVIEW: + drop := &ast.DropTableStmt{ + IfExists: n.MissingOk, + } + for _, obj := range n.Objects { + name, err := parseRelation(obj) + if err != nil { + return nil, fmt.Errorf("nodes.DropStmt: TABLE: %w", err) + } + drop.Tables = append(drop.Tables, name.TableName()) + } + return drop, nil + + case nodes.ObjectType_OBJECT_TYPE: + drop := &ast.DropTypeStmt{ + IfExists: n.MissingOk, + } + for _, obj := range n.Objects { + name, err := parseRelation(obj) + if err != nil { + return nil, fmt.Errorf("nodes.DropStmt: TYPE: %w", err) + } + drop.Types = append(drop.Types, name.TypeName()) + } + return drop, nil + + } + return nil, errSkip + + case *nodes.Node_RenameStmt: + n := inner.RenameStmt + switch n.RenameType { + + case nodes.ObjectType_OBJECT_COLUMN: + rel := parseRelationFromRangeVar(n.Relation) + return &ast.RenameColumnStmt{ + Table: rel.TableName(), + Col: &ast.ColumnRef{Name: n.Subname}, + NewName: makeString(n.Newname), + MissingOk: n.MissingOk, + }, nil + + case nodes.ObjectType_OBJECT_TABLE, nodes.ObjectType_OBJECT_MATVIEW, nodes.ObjectType_OBJECT_VIEW: + rel := parseRelationFromRangeVar(n.Relation) + return &ast.RenameTableStmt{ + Table: rel.TableName(), + NewName: makeString(n.Newname), + MissingOk: n.MissingOk, + }, nil + + case nodes.ObjectType_OBJECT_TYPE: + rel, err := parseRelation(n.Object) + if err != nil { + return nil, fmt.Errorf("nodes.RenameStmt: TYPE: %w", err) + } + return &ast.RenameTypeStmt{ + Type: rel.TypeName(), + NewName: makeString(n.Newname), + }, nil + + } + return nil, errSkip + + default: + return convert(node) + } +} + +// columnTypeName is a column's type as the catalog needs it: the name the +// relation resolves, with the type modifiers the parser reported. Every +// modifier is an integer constant, except that an interval's first one is a +// bit mask of the fields it keeps, which is decoded into the words +// format_type prints, so that "interval day to second" carries "day to +// second" as its first argument. +func columnTypeName(rel *relation, tn *nodes.TypeName) *ast.TypeName { + out := rel.TypeName() + if tn == nil || len(tn.Typmods) == 0 { + return out + } + out.Typmods = &ast.List{} + for i, mod := range tn.Typmods { + c, ok := mod.Node.(*nodes.Node_AConst) + if !ok { + continue + } + ival, ok := c.AConst.Val.(*nodes.A_Const_Ival) + if !ok { + continue + } + if i == 0 && rel.Name == "interval" { + fields, ok := intervalFields[ival.Ival.Ival] + if !ok { + continue + } + if fields != "" { + out.Typmods.Items = append(out.Typmods.Items, &ast.String{Str: fields}) + } + continue + } + out.Typmods.Items = append(out.Typmods.Items, &ast.A_Const{Val: &ast.Integer{Ival: int64(ival.Ival.Ival)}}) + } + if len(out.Typmods.Items) == 0 { + out.Typmods = nil + } + return out +} + +// intervalFields decodes the field mask an interval typmod starts with — +// INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH) and so on, with the field +// numbers PostgreSQL's datetime.h assigns — into the words a declaration +// spells. The full range is written as nothing. +var intervalFields = func() map[int32]string { + const ( + month = 1 << 1 + year = 1 << 2 + day = 1 << 3 + hour = 1 << 10 + minute = 1 << 11 + second = 1 << 12 + ) + return map[int32]string{ + 0x7FFF: "", + year: "year", + month: "month", + day: "day", + hour: "hour", + minute: "minute", + second: "second", + year | month: "year to month", + day | hour: "day to hour", + day | hour | minute: "day to minute", + day | hour | minute | second: "day to second", + hour | minute: "hour to minute", + hour | minute | second: "hour to second", + minute | second: "minute to second", + } +}() diff --git a/internal/engine/postgresql/pg_temp.go b/internal/engine/postgresql/pg_temp.go new file mode 100644 index 0000000..bedf105 --- /dev/null +++ b/internal/engine/postgresql/pg_temp.go @@ -0,0 +1,9 @@ +package postgresql + +import ( + "github.com/sqlc-dev/sqlc/internal/sql/catalog" +) + +func pgTemp() *catalog.Schema { + return &catalog.Schema{Name: "pg_temp"} +} diff --git a/internal/engine/postgresql/reserved.go b/internal/engine/postgresql/reserved.go new file mode 100644 index 0000000..12522fe --- /dev/null +++ b/internal/engine/postgresql/reserved.go @@ -0,0 +1,187 @@ +package postgresql + +import ( + "fmt" + "strings" +) + +// hasMixedCase returns true if the string has any uppercase letters +// (identifiers with mixed case need quoting in PostgreSQL) +func hasMixedCase(s string) bool { + for _, r := range s { + if r >= 'A' && r <= 'Z' { + return true + } + } + return false +} + +// QuoteIdent returns a quoted identifier if it needs quoting. +// This implements the format.Dialect interface. +func (p *Parser) QuoteIdent(s string) string { + if p.IsReservedKeyword(s) || hasMixedCase(s) { + return `"` + s + `"` + } + return s +} + +// TypeName returns the SQL type name for the given namespace and name. +// This implements the format.Dialect interface. +func (p *Parser) TypeName(ns, name string) string { + if ns == "pg_catalog" { + switch name { + case "int4": + return "integer" + case "int8": + return "bigint" + case "int2": + return "smallint" + case "float4": + return "real" + case "float8": + return "double precision" + case "bool": + return "boolean" + case "bpchar": + return "character" + case "timestamptz": + return "timestamp with time zone" + case "timetz": + return "time with time zone" + default: + return name + } + } + if ns != "" { + return ns + "." + name + } + return name +} + +// Param returns the parameter placeholder for the given number. +// PostgreSQL numbers every parameter: $1, $2, etc. +func (p *Parser) Param(n int, numbered bool) string { + return fmt.Sprintf("$%d", n) +} + +// Cast returns a type cast expression. +// PostgreSQL uses expr::type syntax. +func (p *Parser) Cast(arg, typeName string) string { + return arg + "::" + typeName +} + +// Fingerprint reduces a query to pg_query's fingerprint, which survives +// changes in whitespace, case and layout. sqlc fmt uses it to prove a +// formatted statement still parses to the same query. +func (p *Parser) Fingerprint(sql string) (string, error) { + return Fingerprint(sql) +} + +// https://www.postgresql.org/docs/current/sql-keywords-appendix.html +func (p *Parser) IsReservedKeyword(s string) bool { + switch strings.ToLower(s) { + case "all": + case "analyse": + case "analyze": + case "and": + case "any": + case "array": + case "as": + case "asc": + case "asymmetric": + case "authorization": + case "binary": + case "both": + case "case": + case "cast": + case "check": + case "collate": + case "collation": + case "column": + case "concurrently": + case "constraint": + case "create": + case "cross": + case "current_catalog": + case "current_date": + case "current_role": + case "current_schema": + case "current_time": + case "current_timestamp": + case "current_user": + case "default": + case "deferrable": + case "desc": + case "distinct": + case "do": + case "else": + case "end": + case "except": + case "false": + case "fetch": + case "for": + case "foreign": + case "freeze": + case "from": + case "full": + case "grant": + case "group": + case "having": + case "ilike": + case "in": + case "initially": + case "inner": + case "intersect": + case "into": + case "is": + case "isnull": + case "join": + case "lateral": + case "leading": + case "left": + case "like": + case "limit": + case "localtime": + case "localtimestamp": + case "natural": + case "not": + case "notnull": + case "null": + case "offset": + case "on": + case "only": + case "or": + case "order": + case "outer": + case "overlaps": + case "placing": + case "primary": + case "references": + case "returning": + case "right": + case "select": + case "session_user": + case "similar": + case "some": + case "symmetric": + case "table": + case "tablesample": + case "then": + case "to": + case "trailing": + case "true": + case "union": + case "unique": + case "user": + case "using": + case "variadic": + case "verbose": + case "when": + case "where": + case "window": + case "with": + default: + return false + } + return true +} diff --git a/internal/engine/postgresql/rewrite_test.go b/internal/engine/postgresql/rewrite_test.go new file mode 100644 index 0000000..4a2460c --- /dev/null +++ b/internal/engine/postgresql/rewrite_test.go @@ -0,0 +1,45 @@ +package postgresql + +import ( + "strings" + "testing" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/astutils" + + "github.com/google/go-cmp/cmp" +) + +func TestApply(t *testing.T) { + p := NewParser() + + input, err := p.Parse(strings.NewReader("SELECT sqlc.arg(name)")) + if err != nil { + t.Fatal(err) + } + output, err := p.Parse(strings.NewReader("SELECT $1")) + if err != nil { + t.Fatal(err) + } + + expect := &output[0] + actual := astutils.Apply(&input[0], func(cr *astutils.Cursor) bool { + fun, ok := cr.Node().(*ast.FuncCall) + if !ok { + return true + } + if astutils.Join(fun.Funcname, ".") == "sqlc.arg" { + cr.Replace(&ast.ParamRef{ + Dollar: true, + Number: 1, + Location: fun.Location, + }) + return false + } + return true + }, nil) + + if diff := cmp.Diff(expect, actual); diff != "" { + t.Errorf("rewrite mismatch:\n%s", diff) + } +} diff --git a/internal/engine/postgresql/seed.go b/internal/engine/postgresql/seed.go new file mode 100644 index 0000000..9cf184c --- /dev/null +++ b/internal/engine/postgresql/seed.go @@ -0,0 +1,45 @@ +package postgresql + +import ( + "embed" + "sync" + + "github.com/sqlc-dev/sqlc/internal/core" + "github.com/sqlc-dev/sqlc/internal/core/seed" + "github.com/sqlc-dev/sqlc/internal/sql/catalog" +) + +// The dialect directory describes PostgreSQL's type system. Two things in it +// are worth knowing about: the serial types are column definition sugar for an +// integer plus a sequence, but they are what a schema declares, so the catalog +// carries them as types of their own; and the numeric, string and datetime +// categories are listed as mutually castable, which is what an unadorned +// "WHERE bigint_col = 1" depends on. +// +// functions.jsonl and relations.jsonl are pg_catalog's functions and the +// tables and views of pg_catalog and information_schema, all generated from +// a live PostgreSQL 16 server by goldeneye (internal/goldeneye), which also +// checks them against one. Both the analysis core and the catalog the legacy +// compiler builds read them. Each contrib extension sqlc knows is a directory +// under extensions/ holding the types and functions CREATE EXTENSION adds. +// +//go:embed dialect +var dialectFS embed.FS + +// Dialect returns the catalog option that seeds PostgreSQL's type system. +func Dialect() core.Option { + return seed.Dialect(dialectFS, "dialect") +} + +// pgCatalogFuncs is pg_catalog's functions in the form the catalog uses. The +// list runs to thousands of entries and never changes within a run, so it is +// read once. +var pgCatalogFuncs = sync.OnceValue(func() []*catalog.Function { + funcs, err := seed.Functions(dialectFS, "dialect") + if err != nil { + // The list is embedded in the binary: a failure here means sqlc was + // built from a broken tree, which no caller can do anything about. + panic(err) + } + return funcs +}) diff --git a/internal/engine/postgresql/utils.go b/internal/engine/postgresql/utils.go new file mode 100644 index 0000000..3dbe6d8 --- /dev/null +++ b/internal/engine/postgresql/utils.go @@ -0,0 +1,53 @@ +package postgresql + +import ( + nodes "github.com/sqlc-dev/oliphant" +) + +func isArray(n *nodes.TypeName) bool { + if n == nil { + return false + } + return len(n.ArrayBounds) > 0 +} + +func isNotNull(n *nodes.ColumnDef) bool { + if n.IsNotNull { + return true + } + for _, c := range n.Constraints { + switch inner := c.Node.(type) { + case *nodes.Node_Constraint: + if inner.Constraint.Contype == nodes.ConstrType_CONSTR_NOTNULL { + return true + } + if inner.Constraint.Contype == nodes.ConstrType_CONSTR_PRIMARY { + return true + } + } + } + return false +} + +func makeByte(s string) byte { + var b byte + if s == "" { + return b + } + return []byte(s)[0] +} + +func makeUint32Slice(in []uint64) []uint32 { + out := make([]uint32, len(in)) + for i, v := range in { + out[i] = uint32(v) + } + return out +} + +func makeString(s string) *string { + if s == "" { + return nil + } + return &s +} diff --git a/internal/engine/sqlite/analyzer/analyze.go b/internal/engine/sqlite/analyzer/analyze.go new file mode 100644 index 0000000..a9e7d9f --- /dev/null +++ b/internal/engine/sqlite/analyzer/analyze.go @@ -0,0 +1,233 @@ +package analyzer + +import ( + "context" + "fmt" + "strings" + "sync" + + "github.com/ncruces/go-sqlite3" + + core "github.com/sqlc-dev/sqlc/internal/analysis" + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/shfmt" + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/named" + "github.com/sqlc-dev/sqlc/internal/sql/sqlerr" + "github.com/sqlc-dev/sqlc/internal/sqlcdebug" + _ "github.com/sqlc-dev/sqlc/internal/sqlite3ext" +) + +var debugDatabases = sqlcdebug.New("databases") + +type Analyzer struct { + db config.Database + conn *sqlite3.Conn + replacer *shfmt.Replacer + mu sync.Mutex +} + +func New(db config.Database) *Analyzer { + return &Analyzer{ + db: db, + replacer: shfmt.NewReplacer(nil), + } +} + +func (a *Analyzer) Analyze(ctx context.Context, n ast.Node, query string, migrations []string, ps *named.ParamSet) (*core.Analysis, error) { + a.mu.Lock() + defer a.mu.Unlock() + + if a.conn == nil { + var uri string + applyMigrations := a.db.Managed + if a.db.Managed { + // For managed databases, create an in-memory database + uri = ":memory:" + } else if debugDatabases.Value() == "managed" { + return nil, fmt.Errorf("database: connections disabled via SQLCDEBUG=databases=managed") + } else { + uri = a.replacer.Replace(a.db.URI) + // For in-memory databases, we need to apply migrations since the database starts empty + if isInMemoryDatabase(uri) { + applyMigrations = true + } + } + + conn, err := sqlite3.Open(uri) + if err != nil { + return nil, fmt.Errorf("failed to open sqlite database: %w", err) + } + a.conn = conn + + // Apply migrations for managed or in-memory databases + if applyMigrations { + for _, m := range migrations { + if len(strings.TrimSpace(m)) == 0 { + continue + } + if err := a.conn.Exec(m); err != nil { + a.conn.Close() + a.conn = nil + return nil, fmt.Errorf("migration failed: %s: %w", m, err) + } + } + } + } + + // Prepare the statement to get column and parameter information + stmt, _, err := a.conn.Prepare(query) + if err != nil { + return nil, a.extractSqlErr(n, err) + } + defer stmt.Close() + + var result core.Analysis + + // Get column information + colCount := stmt.ColumnCount() + for i := range colCount { + name := stmt.ColumnName(i) + declType := stmt.ColumnDeclType(i) + dbName := stmt.ColumnDatabaseName(i) + tableName := stmt.ColumnTableName(i) + originName := stmt.ColumnOriginName(i) + + // Determine if column is NOT NULL + var notNull bool + var dataType string + if originName != "" { + declType, _, notNull, _, _, _ = a.conn.TableColumnMetadata( + dbName, tableName, originName) + } + + // Normalize the data type + dataType = normalizeType(declType) + + col := &core.Column{ + Name: name, + OriginalName: originName, + DataType: dataType, + NotNull: notNull, + } + + if tableName != "" { + col.Table = &core.Identifier{ + Schema: dbName, + Name: tableName, + } + } + + result.Columns = append(result.Columns, col) + } + + // Get parameter information + bindCount := stmt.BindCount() + for i := 1; i <= bindCount; i++ { + paramName := stmt.BindName(i) + + // SQLite doesn't provide parameter types from prepared statements + // We use "any" as the default type + name := "" + if paramName != "" { + // Remove the prefix (?, :, @, $) from parameter names + name = strings.TrimLeft(paramName, "?:@$") + } + if ps != nil { + if n, ok := ps.NameFor(i); ok { + name = n + } + } + + result.Params = append(result.Params, &core.Parameter{ + Number: int32(i), + Column: &core.Column{ + Name: name, + DataType: "any", + NotNull: false, + }, + }) + } + + return &result, nil +} + +func (a *Analyzer) extractSqlErr(n ast.Node, err error) error { + if err == nil { + return nil + } + // Try to extract SQLite error details + var sqliteErr *sqlite3.Error + if e, ok := err.(*sqlite3.Error); ok { + sqliteErr = e + } + if sqliteErr != nil { + return &sqlerr.Error{ + Code: fmt.Sprintf("%d", sqliteErr.Code()), + Message: sqliteErr.Error(), + Location: n.Pos(), + } + } + return &sqlerr.Error{ + Message: err.Error(), + Location: n.Pos(), + } +} + +func (a *Analyzer) Close(_ context.Context) error { + a.mu.Lock() + defer a.mu.Unlock() + if a.conn != nil { + err := a.conn.Close() + a.conn = nil + return err + } + return nil +} + +// isInMemoryDatabase checks if a SQLite URI refers to an in-memory database +func isInMemoryDatabase(uri string) bool { + if uri == ":memory:" || uri == "" { + return true + } + // Check for file URI with mode=memory parameter + // e.g., "file:test?mode=memory&cache=shared" + if strings.Contains(uri, "mode=memory") { + return true + } + return false +} + +// normalizeType converts SQLite type declarations to standard type names +func normalizeType(declType string) string { + if declType == "" { + return "any" + } + + // Convert to lowercase for comparison + lower := strings.ToLower(declType) + + // SQLite type affinity rules (https://www.sqlite.org/datatype3.html) + switch { + case strings.Contains(lower, "int"): + return "integer" + case strings.Contains(lower, "char"), + strings.Contains(lower, "clob"), + strings.Contains(lower, "text"): + return "text" + case strings.Contains(lower, "blob"): + return "blob" + case strings.Contains(lower, "real"), + strings.Contains(lower, "floa"), + strings.Contains(lower, "doub"): + return "real" + case strings.Contains(lower, "bool"): + return "boolean" + case strings.Contains(lower, "date"), + strings.Contains(lower, "time"): + return "datetime" + default: + // Return as-is for numeric or other types + return lower + } +} diff --git a/internal/engine/sqlite/catalog.go b/internal/engine/sqlite/catalog.go new file mode 100644 index 0000000..54d198e --- /dev/null +++ b/internal/engine/sqlite/catalog.go @@ -0,0 +1,15 @@ +package sqlite + +import "github.com/sqlc-dev/sqlc/internal/sql/catalog" + +func NewCatalog() *catalog.Catalog { + def := "main" + return &catalog.Catalog{ + DefaultSchema: def, + Schemas: []*catalog.Schema{ + defaultSchema(def), + }, + LoadExtension: loadExtension, + Extensions: map[string]struct{}{}, + } +} diff --git a/internal/engine/sqlite/convert.go b/internal/engine/sqlite/convert.go new file mode 100644 index 0000000..dad36d4 --- /dev/null +++ b/internal/engine/sqlite/convert.go @@ -0,0 +1,1185 @@ +package sqlite + +import ( + "fmt" + "log" + "strconv" + "strings" + + meyer "github.com/sqlc-dev/meyer/ast" + + "github.com/sqlc-dev/sqlc/internal/debug" + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +// cc converts a meyer syntax tree into sqlc's engine-independent AST. One +// converter is used per statement; paramCount numbers the anonymous "?" +// markers within it, and src is the source the statement was parsed from. +type cc struct { + paramCount int + src string +} + +func todo(funcname string, n meyer.Node) *ast.TODO { + if debug.Active { + log.Printf("sqlite.%s: Unknown node type %T\n", funcname, n) + } + return &ast.TODO{} +} + +func (c *cc) convert(node meyer.Node) ast.Node { + switch n := node.(type) { + + // Statements + + case *meyer.AlterTableStmt: + return c.convertAlterTableStmt(n) + + case *meyer.AttachStmt: + return c.convertAttachStmt(n) + + case *meyer.CreateTableStmt: + return c.convertCreateTableStmt(n) + + case *meyer.CreateViewStmt: + return c.convertCreateViewStmt(n) + + case *meyer.CreateVirtualTableStmt: + return c.convertCreateVirtualTableStmt(n) + + case *meyer.DeleteStmt: + return c.convertDeleteStmt(n) + + case *meyer.DropTableStmt: + return c.convertDropStmt(n.Name, n.IfExists) + + case *meyer.DropViewStmt: + return c.convertDropStmt(n.Name, n.IfExists) + + case *meyer.ExplainStmt: + return c.convert(n.Stmt) + + case *meyer.InsertStmt: + return c.convertInsertStmt(n) + + case *meyer.SelectStmt: + return c.convertSelectStmt(n) + + case *meyer.UpdateStmt: + return c.convertUpdateStmt(n) + + // Expressions + + case *meyer.BetweenExpr: + return c.convertBetweenExpr(n) + + case *meyer.BinaryExpr: + return c.convertBinaryExpr(n) + + case *meyer.BindParam: + return c.convertBindParam(n) + + case *meyer.CaseExpr: + return c.convertCaseExpr(n) + + case *meyer.CastExpr: + return c.convertCastExpr(n) + + case *meyer.CollateExpr: + return c.convertCollateExpr(n) + + case *meyer.ExistsExpr: + return &ast.SubLink{ + SubLinkType: ast.EXISTS_SUBLINK, + Subselect: c.convert(n.Select), + Location: n.Pos(), + } + + case *meyer.FuncCall: + return c.convertFuncCall(n) + + case *meyer.Ident: + return c.columnRef(n.Pos(), n) + + case *meyer.InExpr: + return c.convertInExpr(n) + + case *meyer.IsExpr: + return c.convertIsExpr(n) + + case *meyer.LikeExpr: + return c.convertLikeExpr(n) + + case *meyer.Literal: + return c.convertLiteral(n) + + case *meyer.NullCheckExpr: + return c.convertNullCheckExpr(n) + + case *meyer.ParenExpr: + return c.convert(n.X) + + case *meyer.QualifiedRef: + return c.columnRef(n.Pos(), n.Parts...) + + case *meyer.Star: + return c.convertStar(n) + + case *meyer.SubqueryExpr: + return &ast.SubLink{ + SubLinkType: ast.EXPR_SUBLINK, + Subselect: c.convert(n.Select), + Location: n.Pos(), + } + + case *meyer.UnaryExpr: + return c.convertUnaryExpr(n) + + case *meyer.VectorExpr: + return c.convertExprList(n.List) + + default: + return todo("convert(case=default)", node) + } +} + +// convertExpr converts an optional expression, mapping an absent one to a +// nil node rather than to a TODO. +func (c *cc) convertExpr(e meyer.Expr) ast.Node { + if e == nil { + return nil + } + return c.convert(e) +} + +func (c *cc) convertExprList(exprs []meyer.Expr) *ast.List { + list := &ast.List{Items: []ast.Node{}} + for _, e := range exprs { + list.Items = append(list.Items, c.convert(e)) + } + return list +} + +// columnRef builds the dotted reference sqlc uses for a column: a one, two +// or three part name of the form [[schema.]table.]column. +func (c *cc) columnRef(loc int, parts ...*meyer.Ident) *ast.ColumnRef { + items := make([]ast.Node, 0, len(parts)) + for _, p := range parts { + items = append(items, NewIdentifier(p)) + } + return &ast.ColumnRef{ + Fields: &ast.List{Items: items}, + Location: loc, + } +} + +func (c *cc) convertStar(n *meyer.Star) *ast.ColumnRef { + items := []ast.Node{} + if n.Table != nil { + items = append(items, NewIdentifier(n.Table)) + } + items = append(items, &ast.A_Star{}) + return &ast.ColumnRef{ + Fields: &ast.List{Items: items}, + Location: n.Pos(), + } +} + +// +// Statements +// + +func (c *cc) convertAlterTableStmt(n *meyer.AlterTableStmt) ast.Node { + switch n.Action { + case meyer.AlterRenameTable: + name := identifier(n.NewName) + return &ast.RenameTableStmt{ + Table: parseTableName(n.Table), + NewName: &name, + } + + case meyer.AlterRenameColumn: + name := identifier(n.NewName) + return &ast.RenameColumnStmt{ + Table: parseTableName(n.Table), + Col: &ast.ColumnRef{ + Name: identifier(n.Column), + }, + NewName: &name, + } + + case meyer.AlterAddColumn: + def := n.ColumnDef + if def == nil { + break + } + name := identifier(def.Name) + return &ast.AlterTableStmt{ + Table: parseTableName(n.Table), + Incomplete: !representableColumn(def), + Cmds: &ast.List{Items: []ast.Node{ + &ast.AlterTableCmd{ + Name: &name, + Subtype: ast.AT_AddColumn, + Def: &ast.ColumnDef{ + Colname: name, + TypeName: &ast.TypeName{ + Name: columnTypeName(def.Type), + Spelling: typeSpelling(def.Type), + }, + Typeless: def.Type == nil, + IsNotNull: hasNotNullConstraint(def.Constraints), + PrimaryKey: hasPrimaryKeyConstraint(def.Constraints), + }, + }, + }}, + } + + case meyer.AlterDropColumn: + name := identifier(n.Column) + return &ast.AlterTableStmt{ + Table: parseTableName(n.Table), + Cmds: &ast.List{Items: []ast.Node{ + &ast.AlterTableCmd{ + Name: &name, + Subtype: ast.AT_DropColumn, + }, + }}, + } + } + return todo("convertAlterTableStmt", n) +} + +// convertAttachStmt records an attached database as a schema. Only the name +// matters to sqlc; the file expression is a runtime concern. +func (c *cc) convertAttachStmt(n *meyer.AttachStmt) ast.Node { + name := schemaName(n.Name) + return &ast.CreateSchemaStmt{ + Name: &name, + } +} + +// schemaName reads the schema out of the "AS " operand of ATTACH, +// which the grammar accepts as an arbitrary expression. +func schemaName(e meyer.Expr) string { + switch n := e.(type) { + case *meyer.Ident: + return identifier(n) + case *meyer.Literal: + return n.Value + default: + return "" + } +} + +// columnTypeName returns the declared type of a column, defaulting to +// SQLite's untyped "any" when the declaration omits one. +func columnTypeName(t *meyer.TypeName) string { + if t == nil { + return "any" + } + return typeName(t) +} + +func (c *cc) convertCreateTableStmt(n *meyer.CreateTableStmt) ast.Node { + stmt := &ast.CreateTableStmt{ + Name: parseTableName(n.Name), + IfNotExists: n.IfNotExists, + // The node models none of these, so a statement carrying them has + // no faithful rendering and the formatter keeps it as written. + Incomplete: n.Temp || n.Select != nil || len(n.Constraints) > 0 || len(n.Options) > 0, + } + for _, def := range n.Columns { + if !representableColumn(def) { + stmt.Incomplete = true + } + stmt.Cols = append(stmt.Cols, &ast.ColumnDef{ + Colname: identifier(def.Name), + IsNotNull: hasNotNullConstraint(def.Constraints), + PrimaryKey: hasPrimaryKeyConstraint(def.Constraints), + TypeName: &ast.TypeName{ + Name: columnTypeName(def.Type), + Spelling: typeSpelling(def.Type), + }, + Typeless: def.Type == nil, + Location: def.Pos(), + }) + } + return stmt +} + +func (c *cc) convertCreateVirtualTableStmt(n *meyer.CreateVirtualTableStmt) ast.Node { + switch moduleName := identifier(n.Module); moduleName { + case "fts5": + // https://www.sqlite.org/fts5.html + return c.convertCreateVirtualTableFTS5(n) + default: + return todo( + fmt.Sprintf("create_virtual_table. unsupported module name: %q", moduleName), + n, + ) + } +} + +func (c *cc) convertCreateVirtualTableFTS5(n *meyer.CreateVirtualTableStmt) ast.Node { + stmt := &ast.CreateTableStmt{ + Name: parseTableName(n.Name), + IfNotExists: n.IfNotExists, + Using: identifier(n.Module), + } + if n.HasArgs { + stmt.ModuleArgs = n.Args + if stmt.ModuleArgs == nil { + stmt.ModuleArgs = []string{} + } + // The arguments carry no spans of their own, so the author's exact + // breaks cannot be kept; a declaration written across lines keeps + // the canonical broken form instead. + if n.Pos() >= 0 && n.End() <= len(c.src) { + stmt.ModuleArgsMultiline = strings.Contains(c.src[n.Pos():n.End()], "\n") + } + } + + // The module arguments of a virtual table are an arbitrary token + // sequence, so meyer hands them back as source text. For fts5 an + // argument is either a column ("b", or "c UNINDEXED") or one of the + // module's own options, which are always written as "key = value". + for _, arg := range n.Args { + name := fts5ColumnName(arg) + if name == "" { + continue + } + stmt.Cols = append(stmt.Cols, &ast.ColumnDef{ + Colname: name, + // fts5 accepts no column constraints, so we supply them here + IsNotNull: true, + TypeName: &ast.TypeName{Name: "text"}, + }) + } + + // An fts5 table also offers hidden columns: one named after the table, + // matched against the whole row (`tbl MATCH ?`) and passed to the + // auxiliary functions (`bm25(tbl)`), `rank`, the current match's score, + // and `rowid`, which an external-content table maps to its content + // table. Hidden keeps them out of star expansions and the table's model. + stmt.Cols = append(stmt.Cols, + &ast.ColumnDef{ + Colname: stmt.Name.Name, + IsNotNull: true, + IsHidden: true, + TypeName: &ast.TypeName{Name: "text"}, + }, + &ast.ColumnDef{ + Colname: "rank", + IsHidden: true, + TypeName: &ast.TypeName{Name: "real"}, + }, + &ast.ColumnDef{ + Colname: "rowid", + IsNotNull: true, + IsHidden: true, + TypeName: &ast.TypeName{Name: "integer"}, + }, + ) + + return stmt +} + +// fts5ColumnName returns the column an fts5 module argument declares, or the +// empty string when the argument configures the module instead. +func fts5ColumnName(arg string) string { + if strings.ContainsRune(arg, '=') { + return "" + } + name, _, _ := strings.Cut(strings.TrimSpace(arg), " ") + return unquoteIdent(name) +} + +// unquoteIdent folds a name that has not been through the lexer, as happens +// for the raw module arguments of a virtual table. +func unquoteIdent(s string) string { + if len(s) >= 2 { + switch { + case s[0] == '"' && s[len(s)-1] == '"': + return strings.ReplaceAll(s[1:len(s)-1], `""`, `"`) + case s[0] == '`' && s[len(s)-1] == '`': + return strings.ReplaceAll(s[1:len(s)-1], "``", "`") + case s[0] == '[' && s[len(s)-1] == ']': + return s[1 : len(s)-1] + case s[0] == '\'' && s[len(s)-1] == '\'': + return strings.ReplaceAll(s[1:len(s)-1], `''`, `'`) + } + } + return strings.ToLower(s) +} + +func (c *cc) convertCreateViewStmt(n *meyer.CreateViewStmt) ast.Node { + return &ast.ViewStmt{ + View: parseRangeVar(n.Name, nil), + Aliases: &ast.List{}, + Query: c.convert(n.Select), + Replace: false, + Options: &ast.List{}, + WithCheckOption: ast.ViewCheckOption(0), + } +} + +func (c *cc) convertDropStmt(name *meyer.QualifiedName, ifExists bool) ast.Node { + return &ast.DropTableStmt{ + IfExists: ifExists, + Tables: []*ast.TableName{parseTableName(name)}, + } +} + +func (c *cc) convertDeleteStmt(n *meyer.DeleteStmt) ast.Node { + return &ast.DeleteStmt{ + Relations: &ast.List{Items: []ast.Node{parseRangeVar(n.Table, n.Alias)}}, + WhereClause: c.convertExpr(n.Where), + LimitCount: c.limitCount(n.Limit), + ReturningList: c.convertReturning(n.Returning), + WithClause: c.convertWith(n.With), + } +} + +// limitCount converts the LIMIT of an UPDATE or DELETE. sqlc has no place to +// put the OFFSET or the ORDER BY that can accompany it, so they are dropped. +func (c *cc) limitCount(n *meyer.Limit) ast.Node { + if n == nil { + return nil + } + return c.convertExpr(n.Count) +} + +func (c *cc) convertInsertStmt(n *meyer.InsertStmt) ast.Node { + insert := &ast.InsertStmt{ + Relation: parseRangeVar(n.Table, n.Alias), + Cols: c.convertColumnNames(n.Columns), + ReturningList: c.convertReturning(n.Returning), + WithClause: c.convertWith(n.With), + DefaultValues: n.DefaultValues, + } + if n.Select != nil { + if sel, ok := c.convertSelectStmt(n.Select).(*ast.SelectStmt); ok { + insert.SelectStmt = sel + } + } + if len(n.Upserts) > 0 { + insert.OnConflictClause = c.convertUpsert(n.Upserts[0]) + } + return insert +} + +func (c *cc) convertUpsert(n *meyer.Upsert) *ast.OnConflictClause { + clause := &ast.OnConflictClause{ + Action: ast.OnConflictActionNothing, + Location: n.Pos(), + } + if len(n.Target) > 0 || n.TargetWhere != nil { + clause.Infer = &ast.InferClause{ + IndexElems: &ast.List{Items: c.convertOrderBy(n.Target)}, + WhereClause: c.convertExpr(n.TargetWhere), + } + } + if n.DoNothing { + return clause + } + clause.Action = ast.OnConflictActionUpdate + clause.TargetList = c.convertSetPairs(n.Set) + clause.WhereClause = c.convertExpr(n.Where) + return clause +} + +func (c *cc) convertColumnNames(cols []*meyer.Ident) *ast.List { + list := &ast.List{Items: []ast.Node{}} + for _, col := range cols { + name := identifier(col) + list.Items = append(list.Items, &ast.ResTarget{ + Name: &name, + Location: col.Pos(), + }) + } + return list +} + +// convertSetPairs converts the assignment list of an UPDATE or of an upsert's +// DO UPDATE. SQLite allows "(a, b) = expr"; sqlc has no node for a +// multi-column assignment, so each name is given the same value expression. +func (c *cc) convertSetPairs(pairs []*meyer.SetPair) *ast.List { + list := &ast.List{} + for _, pair := range pairs { + val := c.convertExpr(pair.Value) + for _, col := range pair.Columns { + name := identifier(col) + list.Items = append(list.Items, &ast.ResTarget{ + Name: &name, + Val: val, + Location: col.Pos(), + }) + } + } + return list +} + +func (c *cc) convertUpdateStmt(n *meyer.UpdateStmt) ast.Node { + return &ast.UpdateStmt{ + Relations: &ast.List{Items: []ast.Node{parseRangeVar(n.Table, n.Alias)}}, + TargetList: c.convertSetPairs(n.Set), + FromClause: &ast.List{Items: c.convertFrom(n.From)}, + WhereClause: c.convertExpr(n.Where), + LimitCount: c.limitCount(n.Limit), + ReturningList: c.convertReturning(n.Returning), + WithClause: c.convertWith(n.With), + } +} + +func (c *cc) convertReturning(cols []*meyer.ResultColumn) *ast.List { + list := &ast.List{Items: []ast.Node{}} + for _, col := range cols { + list.Items = append(list.Items, &ast.ResTarget{ + Indirection: &ast.List{}, + Val: c.convertExpr(col.Expr), + Location: col.Pos(), + }) + } + return list +} + +// +// SELECT +// + +func (c *cc) convertSelectStmt(n *meyer.SelectStmt) ast.Node { + var stmt *ast.SelectStmt + for i, core := range n.Cores { + sel := c.convertSelectCore(core) + if stmt == nil { + stmt = sel + continue + } + op, all := ast.None, false + if i-1 < len(n.Ops) { + switch n.Ops[i-1].Op { + case "UNION": + op = ast.Union + all = n.Ops[i-1].All + case "INTERSECT": + op = ast.Intersect + case "EXCEPT": + op = ast.Except + } + } + stmt = &ast.SelectStmt{ + TargetList: &ast.List{}, + FromClause: &ast.List{}, + Op: op, + All: all, + Larg: stmt, + Rarg: sel, + } + // ORDER BY and LIMIT are written on the last core of a compound + // select but apply to the compound as a whole. + hoistTail(stmt, stmt.Rarg) + } + if stmt == nil { + return todo("convertSelectStmt", n) + } + stmt.WithClause = c.convertWith(n.With) + return stmt +} + +// hoistTail moves the sort and limit clauses of a compound select's final +// core up onto the compound itself. +func hoistTail(outer, inner *ast.SelectStmt) { + outer.SortClause, inner.SortClause = inner.SortClause, nil + outer.LimitCount, inner.LimitCount = inner.LimitCount, nil + outer.LimitOffset, inner.LimitOffset = inner.LimitOffset, nil +} + +func (c *cc) convertSelectCore(core meyer.SelectCore) *ast.SelectStmt { + switch n := core.(type) { + case *meyer.SelectQuery: + stmt := &ast.SelectStmt{ + TargetList: &ast.List{Items: c.convertResultColumns(n.Columns)}, + FromClause: &ast.List{Items: c.convertFrom(n.From)}, + WhereClause: c.convertExpr(n.Where), + GroupClause: &ast.List{}, + HavingClause: c.convertExpr(n.Having), + WindowClause: &ast.List{}, + ValuesLists: &ast.List{}, + } + for _, g := range n.GroupBy { + stmt.GroupClause.Items = append(stmt.GroupClause.Items, c.convert(g)) + } + if n.Distinct == meyer.DistinctDistinct { + // SQLite has no DISTINCT ON, so the clause carries no columns. + stmt.DistinctClause = &ast.List{Items: []ast.Node{&ast.TODO{}}} + } + for _, w := range n.Windows { + stmt.WindowClause.Items = append(stmt.WindowClause.Items, c.convertWindowDef(w)) + } + if len(n.OrderBy) > 0 { + stmt.SortClause = &ast.List{Items: c.convertOrderBy(n.OrderBy)} + } + if n.Limit != nil { + stmt.LimitCount = c.convertExpr(n.Limit.Count) + stmt.LimitOffset = c.convertExpr(n.Limit.Offset) + } + return stmt + + case *meyer.ValuesClause: + values := &ast.List{} + for _, row := range n.Rows { + values.Items = append(values.Items, c.convertExprList(row)) + } + return &ast.SelectStmt{ + TargetList: &ast.List{}, + FromClause: &ast.List{}, + ValuesLists: values, + } + + default: + return &ast.SelectStmt{ + TargetList: &ast.List{}, + FromClause: &ast.List{}, + ValuesLists: &ast.List{}, + } + } +} + +func (c *cc) convertResultColumns(cols []*meyer.ResultColumn) []ast.Node { + var out []ast.Node + for _, col := range cols { + val := c.convertExpr(col.Expr) + if val == nil { + continue + } + target := &ast.ResTarget{ + Val: val, + Location: col.Pos(), + } + if col.Alias != nil { + name := identifier(col.Alias) + target.Name = &name + } + out = append(out, target) + } + return out +} + +func (c *cc) convertOrderBy(terms []*meyer.OrderingTerm) []ast.Node { + var out []ast.Node + for _, term := range terms { + sortBy := &ast.SortBy{ + Node: c.convertExpr(term.Expr), + UseOp: &ast.List{}, + Location: term.Pos(), + } + switch term.Order { + case meyer.SortAsc: + sortBy.SortbyDir = ast.SortByDirAsc + case meyer.SortDesc: + sortBy.SortbyDir = ast.SortByDirDesc + default: + sortBy.SortbyDir = ast.SortByDirDefault + } + switch term.Nulls { + case meyer.NullsFirst: + sortBy.SortbyNulls = ast.SortByNullsFirst + case meyer.NullsLast: + sortBy.SortbyNulls = ast.SortByNullsLast + default: + sortBy.SortbyNulls = ast.SortByNullsDefault + } + out = append(out, sortBy) + } + return out +} + +func (c *cc) convertWindowDef(n *meyer.WindowDef) ast.Node { + def := &ast.WindowDef{ + PartitionClause: c.convertExprList(n.Partition), + OrderClause: &ast.List{Items: c.convertOrderBy(n.OrderBy)}, + Location: n.Pos(), + } + if n.Name != nil { + name := identifier(n.Name) + def.Name = &name + } + if n.Base != nil { + base := identifier(n.Base) + def.Refname = &base + } + return def +} + +func (c *cc) convertWith(n *meyer.With) *ast.WithClause { + if n == nil || len(n.CTEs) == 0 { + return nil + } + ctes := &ast.List{} + for _, cte := range n.CTEs { + name := identifier(cte.Name) + cols := &ast.List{} + for _, col := range cte.Columns { + cols.Items = append(cols.Items, NewIdentifier(col)) + } + ctes.Items = append(ctes.Items, &ast.CommonTableExpr{ + Ctename: &name, + Ctequery: c.convert(cte.Select), + Location: cte.Pos(), + Cterecursive: n.Recursive, + Ctecolnames: cols, + }) + } + return &ast.WithClause{ + Ctes: ctes, + Recursive: n.Recursive, + Location: n.Pos(), + } +} + +// convertFrom converts a SQLite source list. The list is flat, with each +// item recording how it attaches to the one before it, so a chain of joins +// is rebuilt here as a left-leaning tree. A list joined only by commas has +// no join conditions to carry and stays flat. +func (c *cc) convertFrom(refs []*meyer.TableRef) []ast.Node { + if len(refs) == 0 { + return nil + } + if commaOnly(refs) { + out := make([]ast.Node, 0, len(refs)) + for _, ref := range refs { + out = append(out, c.convertTableRef(ref)) + } + return out + } + table := c.convertTableRef(refs[0]) + for _, ref := range refs[1:] { + join := &ast.JoinExpr{ + Larg: table, + Rarg: c.convertTableRef(ref), + } + if op := ref.Join; op != nil { + join.IsNatural = op.Type&meyer.JoinNatural != 0 + left := op.Type&meyer.JoinLeft != 0 + right := op.Type&meyer.JoinRight != 0 + switch { + case left && right: + join.Jointype = ast.JoinTypeFull + case left: + join.Jointype = ast.JoinTypeLeft + case right: + join.Jointype = ast.JoinTypeRight + case op.Type&meyer.JoinComma != 0: + join.Jointype = ast.JoinTypeComma + case op.Type&meyer.JoinCross != 0: + join.Jointype = ast.JoinTypeCross + default: + join.Jointype = ast.JoinTypeInner + } + } + if ref.On != nil { + join.Quals = c.convert(ref.On) + } + if len(ref.Using) > 0 { + using := &ast.List{} + for _, col := range ref.Using { + using.Items = append(using.Items, NewIdentifier(col)) + } + join.UsingClause = using + } + table = join + } + return []ast.Node{table} +} + +func commaOnly(refs []*meyer.TableRef) bool { + for _, ref := range refs[1:] { + if ref.Join == nil || ref.Join.Type&meyer.JoinComma == 0 { + return false + } + } + return true +} + +func (c *cc) convertTableRef(n *meyer.TableRef) ast.Node { + switch { + case n.Name != nil && n.HasArgs: + // A table-valued function, such as generate_series(1, 10). + fn := &ast.FuncCall{ + Func: &ast.FuncName{Name: identifier(n.Name.Name)}, + Funcname: &ast.List{Items: []ast.Node{NewIdentifier(n.Name.Name)}}, + Args: c.convertExprList(n.Args), + Location: n.Pos(), + } + if n.Name.Schema != nil { + fn.Func.Schema = identifier(n.Name.Schema) + } + rf := &ast.RangeFunction{ + Functions: &ast.List{Items: []ast.Node{fn}}, + } + if n.Alias != nil { + alias := identifier(n.Alias) + rf.Alias = &ast.Alias{Aliasname: &alias} + } + return rf + + case n.Name != nil: + rv := parseRangeVar(n.Name, n.Alias) + rv.Location = n.Pos() + return rv + + case n.Select != nil: + rs := &ast.RangeSubselect{ + Subquery: c.convert(n.Select), + } + if n.Alias != nil { + alias := identifier(n.Alias) + rs.Alias = &ast.Alias{Aliasname: &alias} + } + return rs + + case len(n.List) > 0: + // A parenthesized source list, as in "FROM (a JOIN b ON ...)". + nested := c.convertFrom(n.List) + if len(nested) == 1 { + return nested[0] + } + return &ast.List{Items: nested} + } + return todo("convertTableRef", n) +} + +// +// Expressions +// + +func (c *cc) convertLiteral(n *meyer.Literal) ast.Node { + switch n.Kind { + case meyer.LitInteger: + if i, ok := parseInteger(n.Value); ok { + return &ast.A_Const{ + Val: &ast.Integer{Ival: i}, + Location: n.Pos(), + } + } + // Too wide for an int64, or written with the digit separators + // SQLite accepts. Either way the value is still numeric. + return &ast.A_Const{ + Val: &ast.Float{Str: n.Value}, + Location: n.Pos(), + } + + case meyer.LitFloat: + return &ast.A_Const{ + Val: &ast.Float{Str: n.Value}, + Location: n.Pos(), + } + + case meyer.LitString, meyer.LitBlob: + return &ast.A_Const{ + Val: &ast.String{Str: n.Value}, + Location: n.Pos(), + } + + case meyer.LitNull: + return &ast.A_Const{ + Val: &ast.Null{}, + Location: n.Pos(), + } + } + // CURRENT_DATE, CURRENT_TIME and CURRENT_TIMESTAMP are keywords rather + // than function calls, but behave like niladic functions. + name := strings.ToLower(n.Raw) + return &ast.FuncCall{ + Func: &ast.FuncName{Name: name}, + Funcname: &ast.List{Items: []ast.Node{&ast.String{Str: name}}}, + Args: &ast.List{}, + AggOrder: &ast.List{}, + Location: n.Pos(), + } +} + +// parseInteger reads an integer literal in either of the two forms SQLite +// writes: decimal, where a leading zero is not an octal prefix, and +// hexadecimal. +func parseInteger(s string) (int64, bool) { + if len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') { + i, err := strconv.ParseInt(s[2:], 16, 64) + return i, err == nil + } + i, err := strconv.ParseInt(s, 10, 64) + return i, err == nil +} + +func (c *cc) convertBindParam(n *meyer.BindParam) ast.Node { + switch n.Kind { + case meyer.ParamAnon, meyer.ParamNumber: + // Parameter numbers start at one. + c.paramCount += 1 + number := c.paramCount + if n.Kind == meyer.ParamNumber { + number = n.Number + } + return &ast.ParamRef{ + Number: number, + Location: n.Pos(), + Dollar: n.Kind == meyer.ParamNumber, + } + default: + // A named parameter. sqlc carries the name through as the operand of + // a pseudo-operator and resolves it later. The operator is the + // parameter's own sigil, so the formatter can print the spelling the + // author chose — SQLite accepts :name, @name and $name, but sqlc + // gives them different meanings, so they must never be rewritten + // into one another. + sigil := "@" + switch n.Kind { + case meyer.ParamColon: + sigil = ":" + case meyer.ParamDollar: + sigil = "$" + } + return &ast.A_Expr{ + Name: &ast.List{Items: []ast.Node{&ast.String{Str: sigil}}}, + Rexpr: &ast.String{Str: n.Name}, + Location: n.Pos(), + } + } +} + +func (c *cc) convertBinaryExpr(n *meyer.BinaryExpr) ast.Node { + switch n.Op { + case meyer.OpAnd, meyer.OpOr: + op := ast.BoolExprTypeAnd + if n.Op == meyer.OpOr { + op = ast.BoolExprTypeOr + } + return &ast.BoolExpr{ + Boolop: op, + Args: &ast.List{Items: []ast.Node{ + c.convert(n.X), + c.convert(n.Y), + }}, + Location: n.Pos(), + } + } + // SQLite spells some operators two ways (<> and !=, = and ==) and the + // tree keeps only the kind, so read the author's choice back out of the + // source between the operands; the compiler recognizes every spelling. + op := n.Op.String() + switch n.Op { + case meyer.OpNe: + if strings.Contains(c.operatorText(n.X, n.Y), "!=") { + op = "!=" + } + case meyer.OpEq: + if strings.Contains(c.operatorText(n.X, n.Y), "==") { + op = "==" + } + } + return &ast.A_Expr{ + Name: &ast.List{Items: []ast.Node{&ast.String{Str: op}}}, + Lexpr: c.convert(n.X), + Rexpr: c.convert(n.Y), + Location: n.Pos(), + } +} + +// operatorText returns the source text separating two adjacent operands, +// where the operator token sits. +func (c *cc) operatorText(x, y meyer.Expr) string { + start, end := x.End(), y.Pos() + if start < 0 || end > len(c.src) || start > end { + return "" + } + return c.src[start:end] +} + +func (c *cc) convertUnaryExpr(n *meyer.UnaryExpr) ast.Node { + expr := c.convert(n.X) + switch n.Op { + case meyer.OpNot: + return &ast.BoolExpr{ + Boolop: ast.BoolExprTypeNot, + Args: &ast.List{Items: []ast.Node{expr}}, + Location: n.Pos(), + } + case meyer.OpPlus: + // A unary plus is a no-op on every operand SQLite accepts. + return expr + default: + return &ast.A_Expr{ + Name: &ast.List{Items: []ast.Node{&ast.String{Str: n.Op.String()}}}, + Rexpr: expr, + Location: n.Pos(), + } + } +} + +func (c *cc) convertIsExpr(n *meyer.IsExpr) ast.Node { + expr := &ast.A_Expr{ + Lexpr: c.convert(n.X), + Rexpr: c.convert(n.Y), + Location: n.Pos(), + } + var name string + switch { + case n.Distinct && n.Not: + expr.Kind = ast.A_Expr_Kind_NOT_DISTINCT + name = "IS NOT DISTINCT FROM" + case n.Distinct: + expr.Kind = ast.A_Expr_Kind_DISTINCT + name = "IS DISTINCT FROM" + case n.Not: + name = "IS NOT" + default: + name = "IS" + } + expr.Name = &ast.List{Items: []ast.Node{&ast.String{Str: name}}} + return expr +} + +func (c *cc) convertNullCheckExpr(n *meyer.NullCheckExpr) ast.Node { + name := "NOT NULL" + switch n.Test { + case meyer.TestIsNull: + name = "ISNULL" + case meyer.TestNotNull: + name = "NOTNULL" + } + return &ast.A_Expr{ + Name: &ast.List{Items: []ast.Node{&ast.String{Str: name}}}, + Lexpr: c.convert(n.X), + Location: n.Pos(), + } +} + +func (c *cc) convertLikeExpr(n *meyer.LikeExpr) ast.Node { + name := strings.ToUpper(n.Op.Name) + if n.Not { + name = "NOT " + name + } + return &ast.A_Expr{ + Name: &ast.List{Items: []ast.Node{&ast.String{Str: name}}}, + Lexpr: c.convert(n.X), + Rexpr: c.convert(n.Y), + Location: n.Pos(), + } +} + +func (c *cc) convertInExpr(n *meyer.InExpr) ast.Node { + if n.Select != nil { + sublink := &ast.SubLink{ + SubLinkType: ast.ANY_SUBLINK, + Testexpr: c.convert(n.X), + Subselect: c.convertSelectStmt(n.Select), + Location: n.Pos(), + } + if !n.Not { + return sublink + } + return &ast.BoolExpr{ + Boolop: ast.BoolExprTypeNot, + Args: &ast.List{Items: []ast.Node{sublink}}, + Location: n.Pos(), + } + } + + in := &ast.In{ + Expr: c.convert(n.X), + Not: n.Not, + Location: n.Pos(), + } + if n.Table != nil { + // "expr IN table" tests membership in the table's single column. + in.Sel = parseRangeVar(n.Table, nil) + return in + } + for _, e := range n.List { + in.List = append(in.List, c.convert(e)) + } + return in +} + +func (c *cc) convertBetweenExpr(n *meyer.BetweenExpr) ast.Node { + return &ast.BetweenExpr{ + Expr: c.convert(n.X), + Left: c.convert(n.Lo), + Right: c.convert(n.Hi), + Not: n.Not, + Location: n.Pos(), + } +} + +func (c *cc) convertCastExpr(n *meyer.CastExpr) ast.Node { + name := typeName(n.Type) + return &ast.TypeCast{ + Arg: c.convert(n.X), + TypeName: &ast.TypeName{ + Name: name, + Spelling: typeSpelling(n.Type), + Names: &ast.List{Items: []ast.Node{&ast.String{Str: strings.ToLower(name)}}}, + ArrayBounds: &ast.List{}, + }, + Location: n.Pos(), + } +} + +func (c *cc) convertCollateExpr(n *meyer.CollateExpr) ast.Node { + return &ast.CollateExpr{ + Xpr: c.convert(n.X), + Arg: NewIdentifier(n.Name), + Location: n.Pos(), + } +} + +func (c *cc) convertCaseExpr(n *meyer.CaseExpr) ast.Node { + expr := &ast.CaseExpr{ + Arg: c.convertExpr(n.Operand), + Args: &ast.List{}, + Defresult: c.convertExpr(n.Else), + Location: n.Pos(), + } + for _, when := range n.Whens { + expr.Args.Items = append(expr.Args.Items, &ast.CaseWhen{ + Expr: c.convert(when.When), + Result: c.convert(when.Then), + Location: when.Pos(), + }) + } + return expr +} + +func (c *cc) convertFuncCall(n *meyer.FuncCall) ast.Node { + funcName := identifier(n.Name) + args := c.convertExprList(n.Args) + + if funcName == "coalesce" { + return &ast.CoalesceExpr{ + Args: args, + Location: n.Pos(), + } + } + + call := &ast.FuncCall{ + Func: &ast.FuncName{ + Name: funcName, + }, + Funcname: &ast.List{Items: []ast.Node{ + &ast.String{Str: funcName}, + }}, + AggStar: n.Star, + Args: args, + AggOrder: &ast.List{Items: c.convertOrderBy(n.OrderBy)}, + AggDistinct: n.Distinct, + AggFilter: c.convertExpr(n.Filter), + Location: n.Pos(), + } + if n.Over != nil { + if over, ok := c.convertWindowDef(n.Over).(*ast.WindowDef); ok { + call.Over = over + } + } + return call +} diff --git a/internal/engine/sqlite/dialect/dialect.json b/internal/engine/sqlite/dialect/dialect.json new file mode 100644 index 0000000..60bce0e --- /dev/null +++ b/internal/engine/sqlite/dialect/dialect.json @@ -0,0 +1,45 @@ +{ + "dialect": "sqlite", + "alias": "base", + "const": { + "integer": "integer", + "float": "real", + "string": "text", + "bool": "boolean" + }, + "bool": "boolean", + "comparison": ["=", "==", "<>", "!=", "<", "<=", ">", ">=", "IS", "IS NOT", "LIKE", "NOT LIKE", "GLOB", "NOT GLOB", "REGEXP", "NOT REGEXP", "MATCH", "NOT MATCH"], + "comparison_categories": "BNSDU", + "arithmetic": ["+", "-", "*", "/", "%"], + "arithmetic_categories": "N", + "cast_categories": "*", + "modules": { + "fts3": "enable_fts3", + "fts4": "enable_fts3", + "fts5": "enable_fts5", + "geopoly": "enable_geopoly", + "rtree": "enable_rtree", + "rtree_i32": "enable_rtree" + }, + "affinity": [ + { + "contains": ["INT"], + "type": "integer" + }, + { + "contains": ["CHAR", "CLOB", "TEXT"], + "type": "text" + }, + { + "contains": ["BLOB"], + "type": "blob" + }, + { + "contains": ["REAL", "FLOA", "DOUB"], + "type": "real" + }, + { + "type": "numeric" + } + ] +} diff --git a/internal/engine/sqlite/dialect/extensions/enable_fts3/functions.jsonl b/internal/engine/sqlite/dialect/extensions/enable_fts3/functions.jsonl new file mode 100644 index 0000000..5f04bc6 --- /dev/null +++ b/internal/engine/sqlite/dialect/extensions/enable_fts3/functions.jsonl @@ -0,0 +1,5 @@ +{"name":"matchinfo","args":[{"type":"any"}],"returns":"blob"} +{"name":"matchinfo","args":[{"type":"any"},{"type":"text"}],"returns":"blob"} +{"name":"offsets","args":[{"type":"any"}],"returns":"text"} +{"name":"optimize","args":[{"type":"any"}],"returns":"text"} +{"name":"snippet","args":[{"type":"any","has_default":true},{"type":"any","has_default":true},{"type":"text","has_default":true},{"type":"text","has_default":true},{"type":"integer","has_default":true},{"type":"integer","has_default":true},{"type":"any","mode":"v"}],"returns":"text"} diff --git a/internal/engine/sqlite/dialect/extensions/enable_fts5/functions.jsonl b/internal/engine/sqlite/dialect/extensions/enable_fts5/functions.jsonl new file mode 100644 index 0000000..aac7a81 --- /dev/null +++ b/internal/engine/sqlite/dialect/extensions/enable_fts5/functions.jsonl @@ -0,0 +1,7 @@ +{"name":"bm25","args":[{"type":"any","has_default":true},{"type":"real","mode":"v"}],"returns":"real"} +{"name":"fts5_get_locale","args":[{"type":"any","has_default":true},{"type":"integer","has_default":true},{"type":"any","mode":"v"}],"returns":"text","nullable":true} +{"name":"fts5_insttoken","args":[{"type":"any"}],"returns":"any"} +{"name":"fts5_locale","args":[{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"fts5_source_id","returns":"text"} +{"name":"highlight","args":[{"type":"any","has_default":true},{"type":"integer","has_default":true},{"type":"text","has_default":true},{"type":"text","has_default":true},{"type":"any","mode":"v"}],"returns":"text"} +{"name":"snippet","args":[{"type":"any","has_default":true},{"type":"any","has_default":true},{"type":"text","has_default":true},{"type":"text","has_default":true},{"type":"integer","has_default":true},{"type":"integer","has_default":true},{"type":"any","mode":"v"}],"returns":"text"} diff --git a/internal/engine/sqlite/dialect/extensions/enable_geopoly/functions.jsonl b/internal/engine/sqlite/dialect/extensions/enable_geopoly/functions.jsonl new file mode 100644 index 0000000..a37aa98 --- /dev/null +++ b/internal/engine/sqlite/dialect/extensions/enable_geopoly/functions.jsonl @@ -0,0 +1,15 @@ +{"name":"geopoly_area","args":[{"type":"any"}],"returns":"real","nullable":true} +{"name":"geopoly_bbox","args":[{"type":"any"}],"returns":"blob","nullable":true} +{"name":"geopoly_blob","args":[{"type":"any"}],"returns":"blob","nullable":true} +{"name":"geopoly_ccw","args":[{"type":"any"}],"returns":"blob","nullable":true} +{"name":"geopoly_contains_point","args":[{"type":"any"},{"type":"real"},{"type":"real"}],"returns":"integer","nullable":true} +{"name":"geopoly_group_bbox","kind":"a","args":[{"type":"any"}],"returns":"blob","nullable":true} +{"name":"geopoly_json","args":[{"type":"any"}],"returns":"text","nullable":true} +{"name":"geopoly_overlap","args":[{"type":"any"},{"type":"any"}],"returns":"integer","nullable":true} +{"name":"geopoly_regular","args":[{"type":"real"},{"type":"real"},{"type":"real"},{"type":"integer"}],"returns":"blob"} +{"name":"geopoly_svg","args":[{"type":"text","mode":"v"}],"returns":"text","nullable":true} +{"name":"geopoly_within","args":[{"type":"any"},{"type":"any"}],"returns":"integer","nullable":true} +{"name":"geopoly_xform","args":[{"type":"any"},{"type":"real"},{"type":"real"},{"type":"real"},{"type":"real"},{"type":"real"},{"type":"real"}],"returns":"blob","nullable":true} +{"name":"rtreecheck","args":[{"type":"text","has_default":true},{"type":"text","has_default":true},{"type":"any","mode":"v"}],"returns":"text"} +{"name":"rtreedepth","args":[{"type":"blob"}],"returns":"integer"} +{"name":"rtreenode","args":[{"type":"integer"},{"type":"blob"}],"returns":"text"} diff --git a/internal/engine/sqlite/dialect/extensions/enable_offset_sql_func/functions.jsonl b/internal/engine/sqlite/dialect/extensions/enable_offset_sql_func/functions.jsonl new file mode 100644 index 0000000..7e8563d --- /dev/null +++ b/internal/engine/sqlite/dialect/extensions/enable_offset_sql_func/functions.jsonl @@ -0,0 +1 @@ +{"name":"sqlite_offset","args":[{"type":"any"}],"returns":"integer","nullable":true} diff --git a/internal/engine/sqlite/dialect/extensions/enable_percentile/functions.jsonl b/internal/engine/sqlite/dialect/extensions/enable_percentile/functions.jsonl new file mode 100644 index 0000000..d872692 --- /dev/null +++ b/internal/engine/sqlite/dialect/extensions/enable_percentile/functions.jsonl @@ -0,0 +1,4 @@ +{"name":"median","kind":"a","args":[{"type":"real"}],"returns":"real","nullable":true} +{"name":"percentile","kind":"a","args":[{"type":"real"},{"type":"real"}],"returns":"real","nullable":true} +{"name":"percentile_cont","kind":"a","args":[{"type":"real"},{"type":"real"}],"returns":"real","nullable":true} +{"name":"percentile_disc","kind":"a","args":[{"type":"real"},{"type":"real"}],"returns":"real","nullable":true} diff --git a/internal/engine/sqlite/dialect/extensions/enable_rtree/functions.jsonl b/internal/engine/sqlite/dialect/extensions/enable_rtree/functions.jsonl new file mode 100644 index 0000000..a154d3b --- /dev/null +++ b/internal/engine/sqlite/dialect/extensions/enable_rtree/functions.jsonl @@ -0,0 +1,3 @@ +{"name":"rtreecheck","args":[{"type":"text","has_default":true},{"type":"text","has_default":true},{"type":"any","mode":"v"}],"returns":"text"} +{"name":"rtreedepth","args":[{"type":"blob"}],"returns":"integer"} +{"name":"rtreenode","args":[{"type":"integer"},{"type":"blob"}],"returns":"text"} diff --git a/internal/engine/sqlite/dialect/extensions/soundex/functions.jsonl b/internal/engine/sqlite/dialect/extensions/soundex/functions.jsonl new file mode 100644 index 0000000..2644ef5 --- /dev/null +++ b/internal/engine/sqlite/dialect/extensions/soundex/functions.jsonl @@ -0,0 +1 @@ +{"name":"soundex","args":[{"type":"text"}],"returns":"text"} diff --git a/internal/engine/sqlite/dialect/functions.jsonl b/internal/engine/sqlite/dialect/functions.jsonl new file mode 100644 index 0000000..1801254 --- /dev/null +++ b/internal/engine/sqlite/dialect/functions.jsonl @@ -0,0 +1,236 @@ +{"name":"-\u003e","args":[{"type":"any"},{"type":"any"}],"returns":"text","nullable":true} +{"name":"-\u003e\u003e","args":[{"type":"any"},{"type":"any"}],"returns":"any","nullable":true} +{"name":"abs","args":[{"type":"any"}],"returns":"real"} +{"name":"abs","args":[{"type":"integer"}],"returns":"integer"} +{"name":"abs","args":[{"type":"int"}],"returns":"integer"} +{"name":"abs","args":[{"type":"tinyint"}],"returns":"integer"} +{"name":"abs","args":[{"type":"smallint"}],"returns":"integer"} +{"name":"abs","args":[{"type":"mediumint"}],"returns":"integer"} +{"name":"abs","args":[{"type":"bigint"}],"returns":"integer"} +{"name":"abs","args":[{"type":"unsigned big int"}],"returns":"integer"} +{"name":"abs","args":[{"type":"int2"}],"returns":"integer"} +{"name":"abs","args":[{"type":"int8"}],"returns":"integer"} +{"name":"abs","args":[{"type":"real"}],"returns":"real"} +{"name":"abs","args":[{"type":"double"}],"returns":"real"} +{"name":"abs","args":[{"type":"double precision"}],"returns":"real"} +{"name":"abs","args":[{"type":"float"}],"returns":"real"} +{"name":"acos","args":[{"type":"real"}],"returns":"real"} +{"name":"acosh","args":[{"type":"real"}],"returns":"real"} +{"name":"asin","args":[{"type":"real"}],"returns":"real"} +{"name":"asinh","args":[{"type":"real"}],"returns":"real"} +{"name":"atan","args":[{"type":"real"}],"returns":"real"} +{"name":"atan2","args":[{"type":"real"},{"type":"real"}],"returns":"real"} +{"name":"atanh","args":[{"type":"real"}],"returns":"real"} +{"name":"avg","kind":"a","args":[{"type":"any"}],"returns":"real","nullable":true} +{"name":"ceil","args":[{"type":"any"}],"returns":"real"} +{"name":"ceil","args":[{"type":"integer"}],"returns":"integer"} +{"name":"ceil","args":[{"type":"int"}],"returns":"integer"} +{"name":"ceil","args":[{"type":"tinyint"}],"returns":"integer"} +{"name":"ceil","args":[{"type":"smallint"}],"returns":"integer"} +{"name":"ceil","args":[{"type":"mediumint"}],"returns":"integer"} +{"name":"ceil","args":[{"type":"bigint"}],"returns":"integer"} +{"name":"ceil","args":[{"type":"unsigned big int"}],"returns":"integer"} +{"name":"ceil","args":[{"type":"int2"}],"returns":"integer"} +{"name":"ceil","args":[{"type":"int8"}],"returns":"integer"} +{"name":"ceil","args":[{"type":"real"}],"returns":"real"} +{"name":"ceil","args":[{"type":"double"}],"returns":"real"} +{"name":"ceil","args":[{"type":"double precision"}],"returns":"real"} +{"name":"ceil","args":[{"type":"float"}],"returns":"real"} +{"name":"ceiling","args":[{"type":"any"}],"returns":"real"} +{"name":"ceiling","args":[{"type":"integer"}],"returns":"integer"} +{"name":"ceiling","args":[{"type":"int"}],"returns":"integer"} +{"name":"ceiling","args":[{"type":"tinyint"}],"returns":"integer"} +{"name":"ceiling","args":[{"type":"smallint"}],"returns":"integer"} +{"name":"ceiling","args":[{"type":"mediumint"}],"returns":"integer"} +{"name":"ceiling","args":[{"type":"bigint"}],"returns":"integer"} +{"name":"ceiling","args":[{"type":"unsigned big int"}],"returns":"integer"} +{"name":"ceiling","args":[{"type":"int2"}],"returns":"integer"} +{"name":"ceiling","args":[{"type":"int8"}],"returns":"integer"} +{"name":"ceiling","args":[{"type":"real"}],"returns":"real"} +{"name":"ceiling","args":[{"type":"double"}],"returns":"real"} +{"name":"ceiling","args":[{"type":"double precision"}],"returns":"real"} +{"name":"ceiling","args":[{"type":"float"}],"returns":"real"} +{"name":"changes","returns":"integer"} +{"name":"char","args":[{"type":"integer","mode":"v"}],"returns":"text"} +{"name":"coalesce","args":[{"type":"any"},{"type":"any"},{"type":"any","mode":"v"}],"returns":"any"} +{"name":"concat","args":[{"type":"any"},{"type":"any","mode":"v"}],"returns":"text"} +{"name":"concat_ws","args":[{"type":"text"},{"type":"any"},{"type":"any","mode":"v"}],"returns":"text"} +{"name":"cos","args":[{"type":"real"}],"returns":"real"} +{"name":"cosh","args":[{"type":"real"}],"returns":"real"} +{"name":"count","kind":"a","returns":"integer"} +{"name":"count","kind":"a","args":[{"type":"any"}],"returns":"integer"} +{"name":"cume_dist","kind":"w","returns":"real"} +{"name":"current_date","returns":"text"} +{"name":"current_time","returns":"text"} +{"name":"current_timestamp","returns":"text"} +{"name":"date","args":[{"type":"any","mode":"v"}],"returns":"text","nullable":true} +{"name":"datetime","args":[{"type":"any","mode":"v"}],"returns":"text","nullable":true} +{"name":"degrees","args":[{"type":"real"}],"returns":"real"} +{"name":"dense_rank","kind":"w","returns":"integer"} +{"name":"exp","args":[{"type":"real"}],"returns":"real"} +{"name":"first_value","kind":"w","args":[{"type":"any"}],"returns":"any","nullable":true} +{"name":"floor","args":[{"type":"any"}],"returns":"real"} +{"name":"floor","args":[{"type":"integer"}],"returns":"integer"} +{"name":"floor","args":[{"type":"int"}],"returns":"integer"} +{"name":"floor","args":[{"type":"tinyint"}],"returns":"integer"} +{"name":"floor","args":[{"type":"smallint"}],"returns":"integer"} +{"name":"floor","args":[{"type":"mediumint"}],"returns":"integer"} +{"name":"floor","args":[{"type":"bigint"}],"returns":"integer"} +{"name":"floor","args":[{"type":"unsigned big int"}],"returns":"integer"} +{"name":"floor","args":[{"type":"int2"}],"returns":"integer"} +{"name":"floor","args":[{"type":"int8"}],"returns":"integer"} +{"name":"floor","args":[{"type":"real"}],"returns":"real"} +{"name":"floor","args":[{"type":"double"}],"returns":"real"} +{"name":"floor","args":[{"type":"double precision"}],"returns":"real"} +{"name":"floor","args":[{"type":"float"}],"returns":"real"} +{"name":"format","args":[{"type":"text","has_default":true},{"type":"any","mode":"v"}],"returns":"text"} +{"name":"glob","args":[{"type":"text"},{"type":"text"}],"returns":"integer"} +{"name":"group_concat","kind":"a","args":[{"type":"text"}],"returns":"text","nullable":true} +{"name":"group_concat","kind":"a","args":[{"type":"text"},{"type":"text"}],"returns":"text","nullable":true} +{"name":"hex","args":[{"type":"blob"}],"returns":"text"} +{"name":"if","args":[{"type":"any"},{"type":"any"},{"type":"any","mode":"v"}],"returns":"any"} +{"name":"ifnull","args":[{"type":"any"},{"type":"any"}],"returns":"any"} +{"name":"iif","args":[{"type":"any"},{"type":"any"},{"type":"any","mode":"v"}],"returns":"any"} +{"name":"instr","args":[{"type":"any"},{"type":"any"}],"returns":"integer"} +{"name":"json","args":[{"type":"any"}],"returns":"text"} +{"name":"json_array","args":[{"type":"any","mode":"v"}],"returns":"text"} +{"name":"json_array_insert","args":[{"type":"any","mode":"v"}],"returns":"text"} +{"name":"json_array_length","args":[{"type":"any"}],"returns":"integer","nullable":true} +{"name":"json_array_length","args":[{"type":"any"},{"type":"text"}],"returns":"integer","nullable":true} +{"name":"json_error_position","args":[{"type":"text"}],"returns":"integer"} +{"name":"json_extract","args":[{"type":"text","mode":"v"}],"returns":"any","nullable":true} +{"name":"json_group_array","kind":"a","args":[{"type":"any"}],"returns":"text"} +{"name":"json_group_object","kind":"a","args":[{"type":"text"},{"type":"any"}],"returns":"text"} +{"name":"json_insert","args":[{"type":"any","mode":"v"}],"returns":"text"} +{"name":"json_object","args":[{"type":"text","mode":"v"}],"returns":"text"} +{"name":"json_patch","args":[{"type":"any"},{"type":"any"}],"returns":"text"} +{"name":"json_pretty","args":[{"type":"any"}],"returns":"text"} +{"name":"json_pretty","args":[{"type":"any"},{"type":"text"}],"returns":"text"} +{"name":"json_quote","args":[{"type":"any"}],"returns":"text"} +{"name":"json_remove","args":[{"type":"text","mode":"v"}],"returns":"text"} +{"name":"json_replace","args":[{"type":"any","mode":"v"}],"returns":"text"} +{"name":"json_set","args":[{"type":"any","mode":"v"}],"returns":"text"} +{"name":"json_type","args":[{"type":"any"}],"returns":"text","nullable":true} +{"name":"json_type","args":[{"type":"any"},{"type":"text"}],"returns":"text","nullable":true} +{"name":"json_valid","args":[{"type":"any"}],"returns":"integer"} +{"name":"json_valid","args":[{"type":"any"},{"type":"integer"}],"returns":"integer"} +{"name":"jsonb","args":[{"type":"any"}],"returns":"blob"} +{"name":"jsonb_array","args":[{"type":"any","mode":"v"}],"returns":"blob"} +{"name":"jsonb_array_insert","args":[{"type":"any","mode":"v"}],"returns":"blob"} +{"name":"jsonb_extract","args":[{"type":"text","mode":"v"}],"returns":"any","nullable":true} +{"name":"jsonb_group_array","kind":"a","args":[{"type":"any"}],"returns":"blob"} +{"name":"jsonb_group_object","kind":"a","args":[{"type":"text"},{"type":"any"}],"returns":"blob"} +{"name":"jsonb_insert","args":[{"type":"any","mode":"v"}],"returns":"blob"} +{"name":"jsonb_object","args":[{"type":"text","mode":"v"}],"returns":"blob"} +{"name":"jsonb_patch","args":[{"type":"any"},{"type":"any"}],"returns":"blob"} +{"name":"jsonb_remove","args":[{"type":"text","mode":"v"}],"returns":"blob"} +{"name":"jsonb_replace","args":[{"type":"any","mode":"v"}],"returns":"blob"} +{"name":"jsonb_set","args":[{"type":"any","mode":"v"}],"returns":"blob"} +{"name":"julianday","args":[{"type":"any","mode":"v"}],"returns":"real","nullable":true} +{"name":"lag","kind":"w","args":[{"type":"any"}],"returns":"any","nullable":true} +{"name":"lag","kind":"w","args":[{"type":"any"},{"type":"any"}],"returns":"any","nullable":true} +{"name":"lag","kind":"w","args":[{"type":"any"},{"type":"any"},{"type":"any"}],"returns":"any","nullable":true} +{"name":"last_insert_rowid","returns":"integer"} +{"name":"last_value","kind":"w","args":[{"type":"any"}],"returns":"any","nullable":true} +{"name":"lead","kind":"w","args":[{"type":"any"}],"returns":"any","nullable":true} +{"name":"lead","kind":"w","args":[{"type":"any"},{"type":"any"}],"returns":"any","nullable":true} +{"name":"lead","kind":"w","args":[{"type":"any"},{"type":"any"},{"type":"any"}],"returns":"any","nullable":true} +{"name":"length","args":[{"type":"text"}],"returns":"integer"} +{"name":"like","args":[{"type":"text"},{"type":"text"}],"returns":"integer"} +{"name":"like","args":[{"type":"text"},{"type":"text"},{"type":"text"}],"returns":"integer"} +{"name":"likelihood","args":[{"type":"any"},{"type":"any"}],"returns":"any"} +{"name":"likely","args":[{"type":"any"}],"returns":"any"} +{"name":"ln","args":[{"type":"real"}],"returns":"real"} +{"name":"log","args":[{"type":"real"}],"returns":"real"} +{"name":"log","args":[{"type":"real"},{"type":"real"}],"returns":"real"} +{"name":"log10","args":[{"type":"real"}],"returns":"real"} +{"name":"log2","args":[{"type":"real"}],"returns":"real"} +{"name":"lower","args":[{"type":"text"}],"returns":"text"} +{"name":"ltrim","args":[{"type":"text"}],"returns":"text"} +{"name":"ltrim","args":[{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"max","kind":"a","args":[{"type":"any"}],"returns":"any","nullable":true} +{"name":"max","args":[{"type":"any"},{"type":"any","mode":"v"}],"returns":"any"} +{"name":"min","kind":"a","args":[{"type":"any"}],"returns":"any","nullable":true} +{"name":"min","args":[{"type":"any"},{"type":"any","mode":"v"}],"returns":"any"} +{"name":"mod","args":[{"type":"real"},{"type":"real"}],"returns":"real"} +{"name":"nth_value","kind":"w","args":[{"type":"any"},{"type":"any"}],"returns":"any","nullable":true} +{"name":"ntile","kind":"w","args":[{"type":"integer"}],"returns":"integer"} +{"name":"nullif","args":[{"type":"any"},{"type":"any"}],"returns":"any","nullable":true} +{"name":"octet_length","args":[{"type":"any"}],"returns":"integer"} +{"name":"percent_rank","kind":"w","returns":"real"} +{"name":"pi","returns":"real"} +{"name":"pow","args":[{"type":"real"},{"type":"real"}],"returns":"real"} +{"name":"power","args":[{"type":"real"},{"type":"real"}],"returns":"real"} +{"name":"printf","args":[{"type":"text","has_default":true},{"type":"any","mode":"v"}],"returns":"text"} +{"name":"quote","args":[{"type":"any"}],"returns":"text"} +{"name":"radians","args":[{"type":"real"}],"returns":"real"} +{"name":"random","returns":"integer"} +{"name":"randomblob","args":[{"type":"integer"}],"returns":"blob"} +{"name":"rank","kind":"w","returns":"integer"} +{"name":"replace","args":[{"type":"text"},{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"round","args":[{"type":"real"}],"returns":"real"} +{"name":"round","args":[{"type":"real"},{"type":"integer"}],"returns":"real"} +{"name":"row_number","kind":"w","returns":"integer"} +{"name":"rtrim","args":[{"type":"text"}],"returns":"text"} +{"name":"rtrim","args":[{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"sign","args":[{"type":"real"}],"returns":"integer","nullable":true} +{"name":"sin","args":[{"type":"real"}],"returns":"real"} +{"name":"sinh","args":[{"type":"real"}],"returns":"real"} +{"name":"sqlite_compileoption_get","args":[{"type":"integer"}],"returns":"text","nullable":true} +{"name":"sqlite_compileoption_used","args":[{"type":"text"}],"returns":"integer"} +{"name":"sqlite_source_id","returns":"text"} +{"name":"sqlite_version","returns":"text"} +{"name":"sqrt","args":[{"type":"real"}],"returns":"real"} +{"name":"strftime","args":[{"type":"text","has_default":true},{"type":"any","mode":"v"}],"returns":"text","nullable":true} +{"name":"string_agg","kind":"a","args":[{"type":"text"},{"type":"text"}],"returns":"text","nullable":true} +{"name":"substr","args":[{"type":"any"},{"type":"integer"}],"returns":"text"} +{"name":"substr","args":[{"type":"any"},{"type":"integer"},{"type":"integer"}],"returns":"text"} +{"name":"substring","args":[{"type":"any"},{"type":"integer"}],"returns":"text"} +{"name":"substring","args":[{"type":"any"},{"type":"integer"},{"type":"integer"}],"returns":"text"} +{"name":"subtype","args":[{"type":"any"}],"returns":"integer"} +{"name":"sum","kind":"a","args":[{"type":"any"}],"returns":"real","nullable":true} +{"name":"sum","kind":"a","args":[{"type":"integer"}],"returns":"integer","nullable":true} +{"name":"sum","kind":"a","args":[{"type":"int"}],"returns":"integer","nullable":true} +{"name":"sum","kind":"a","args":[{"type":"tinyint"}],"returns":"integer","nullable":true} +{"name":"sum","kind":"a","args":[{"type":"smallint"}],"returns":"integer","nullable":true} +{"name":"sum","kind":"a","args":[{"type":"mediumint"}],"returns":"integer","nullable":true} +{"name":"sum","kind":"a","args":[{"type":"bigint"}],"returns":"integer","nullable":true} +{"name":"sum","kind":"a","args":[{"type":"unsigned big int"}],"returns":"integer","nullable":true} +{"name":"sum","kind":"a","args":[{"type":"int2"}],"returns":"integer","nullable":true} +{"name":"sum","kind":"a","args":[{"type":"int8"}],"returns":"integer","nullable":true} +{"name":"sum","kind":"a","args":[{"type":"real"}],"returns":"real","nullable":true} +{"name":"sum","kind":"a","args":[{"type":"double"}],"returns":"real","nullable":true} +{"name":"sum","kind":"a","args":[{"type":"double precision"}],"returns":"real","nullable":true} +{"name":"sum","kind":"a","args":[{"type":"float"}],"returns":"real","nullable":true} +{"name":"tan","args":[{"type":"real"}],"returns":"real"} +{"name":"tanh","args":[{"type":"real"}],"returns":"real"} +{"name":"time","args":[{"type":"any","mode":"v"}],"returns":"text","nullable":true} +{"name":"timediff","args":[{"type":"any"},{"type":"any"}],"returns":"text","nullable":true} +{"name":"total","kind":"a","args":[{"type":"any"}],"returns":"real"} +{"name":"total_changes","returns":"integer"} +{"name":"trim","args":[{"type":"text"}],"returns":"text"} +{"name":"trim","args":[{"type":"text"},{"type":"text"}],"returns":"text"} +{"name":"trunc","args":[{"type":"any"}],"returns":"real"} +{"name":"trunc","args":[{"type":"integer"}],"returns":"integer"} +{"name":"trunc","args":[{"type":"int"}],"returns":"integer"} +{"name":"trunc","args":[{"type":"tinyint"}],"returns":"integer"} +{"name":"trunc","args":[{"type":"smallint"}],"returns":"integer"} +{"name":"trunc","args":[{"type":"mediumint"}],"returns":"integer"} +{"name":"trunc","args":[{"type":"bigint"}],"returns":"integer"} +{"name":"trunc","args":[{"type":"unsigned big int"}],"returns":"integer"} +{"name":"trunc","args":[{"type":"int2"}],"returns":"integer"} +{"name":"trunc","args":[{"type":"int8"}],"returns":"integer"} +{"name":"trunc","args":[{"type":"real"}],"returns":"real"} +{"name":"trunc","args":[{"type":"double"}],"returns":"real"} +{"name":"trunc","args":[{"type":"double precision"}],"returns":"real"} +{"name":"trunc","args":[{"type":"float"}],"returns":"real"} +{"name":"typeof","args":[{"type":"any"}],"returns":"text"} +{"name":"unhex","args":[{"type":"text"}],"returns":"blob","nullable":true} +{"name":"unhex","args":[{"type":"text"},{"type":"text"}],"returns":"blob","nullable":true} +{"name":"unicode","args":[{"type":"text"}],"returns":"integer"} +{"name":"unistr","args":[{"type":"text"}],"returns":"text"} +{"name":"unistr_quote","args":[{"type":"any"}],"returns":"text"} +{"name":"unixepoch","args":[{"type":"any","mode":"v"}],"returns":"real","nullable":true} +{"name":"unlikely","args":[{"type":"any"}],"returns":"any"} +{"name":"upper","args":[{"type":"text"}],"returns":"text"} +{"name":"zeroblob","args":[{"type":"integer"}],"returns":"blob"} diff --git a/internal/engine/sqlite/dialect/operators.jsonl b/internal/engine/sqlite/dialect/operators.jsonl new file mode 100644 index 0000000..9ed8bea --- /dev/null +++ b/internal/engine/sqlite/dialect/operators.jsonl @@ -0,0 +1 @@ +{"name": "||", "left": "text", "right": "text", "result": "text"} diff --git a/internal/engine/sqlite/dialect/types.jsonl b/internal/engine/sqlite/dialect/types.jsonl new file mode 100644 index 0000000..055975e --- /dev/null +++ b/internal/engine/sqlite/dialect/types.jsonl @@ -0,0 +1,10 @@ +{"name": "integer", "category": "N", "aliases": ["int", "tinyint", "smallint", "mediumint", "bigint", "unsigned big int", "int2", "int8"]} +{"name": "real", "category": "N", "aliases": ["double", "double precision", "float"]} +{"name": "numeric", "category": "N", "aliases": ["decimal"]} +{"name": "boolean", "category": "B", "aliases": ["bool"]} +{"name": "text", "category": "S", "aliases": ["character", "varchar", "varying character", "nchar", "native character", "nvarchar", "clob"]} +{"name": "blob", "category": "U"} +{"name": "any", "category": "U"} +{"name": "date", "category": "D"} +{"name": "datetime", "category": "D"} +{"name": "timestamp", "category": "D"} diff --git a/internal/engine/sqlite/extension.go b/internal/engine/sqlite/extension.go new file mode 100644 index 0000000..4426548 --- /dev/null +++ b/internal/engine/sqlite/extension.go @@ -0,0 +1,26 @@ +package sqlite + +import ( + "github.com/sqlc-dev/sqlc/internal/core/seed" + "github.com/sqlc-dev/sqlc/internal/sql/catalog" +) + +// loadExtension returns the functions a compile option adds, read from the +// option's directory under the dialect's extensions/. The name is either the +// directory's — enable_fts5 — or a virtual table module the dialect maps to +// one, since a schema that says CREATE VIRTUAL TABLE ... USING fts5 has said +// which build of SQLite it runs on. An option the dialect has no data for +// adds nothing. +func loadExtension(name string) *catalog.Schema { + dir, ok := seed.ExtensionDir(dialectFS, "dialect", name) + if !ok { + return nil + } + funcs, err := seed.Functions(dialectFS, dir) + if err != nil { + // The list is embedded in the binary: a failure here means sqlc was + // built from a broken tree, which no caller can do anything about. + panic(err) + } + return &catalog.Schema{Name: "main", Funcs: funcs} +} diff --git a/internal/engine/sqlite/format.go b/internal/engine/sqlite/format.go new file mode 100644 index 0000000..d79e30d --- /dev/null +++ b/internal/engine/sqlite/format.go @@ -0,0 +1,59 @@ +package sqlite + +import ( + "strconv" + "strings" +) + +// QuoteIdent quotes an identifier when printing it bare would change what it +// names: the parser folds unquoted identifiers to lower case, so any name +// that is not already a plain lower-case identifier — or that collides with +// a keyword — only survives a parse round-trip inside double quotes. +func (p *Parser) QuoteIdent(s string) string { + if s == "" || p.IsReservedKeyword(s) || !plainIdent(s) { + return `"` + strings.ReplaceAll(s, `"`, `""`) + `"` + } + return s +} + +// plainIdent reports whether s parses back as itself unquoted: ASCII +// lower-case letters, digits and underscores, not starting with a digit. +func plainIdent(s string) bool { + for i, r := range s { + switch { + case r >= 'a' && r <= 'z', r == '_': + case r >= '0' && r <= '9': + if i == 0 { + return false + } + default: + return false + } + } + return true +} + +// TypeName returns the SQL type name for the given namespace and name. +func (p *Parser) TypeName(ns, name string) string { + if ns != "" { + return ns + "." + name + } + return name +} + +// Param returns the parameter placeholder for the given number. SQLite +// takes both a bare ? (the next index) and an explicit ?N, and they are +// not interchangeable — reordered ?N parameters bind by their numbers — +// so the one the author wrote is the one printed. +func (p *Parser) Param(n int, numbered bool) string { + if numbered { + return "?" + strconv.Itoa(n) + } + return "?" +} + +// Cast returns a type cast expression. +// SQLite uses CAST(expr AS type) syntax. +func (p *Parser) Cast(arg, typeName string) string { + return "CAST(" + arg + " AS " + typeName + ")" +} diff --git a/internal/engine/sqlite/parse.go b/internal/engine/sqlite/parse.go new file mode 100644 index 0000000..ce0a729 --- /dev/null +++ b/internal/engine/sqlite/parse.go @@ -0,0 +1,158 @@ +package sqlite + +import ( + "errors" + "io" + "strings" + + meyer "github.com/sqlc-dev/meyer/ast" + "github.com/sqlc-dev/meyer/parser" + mtoken "github.com/sqlc-dev/meyer/token" + + "github.com/sqlc-dev/sqlc/internal/source" + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/sqlerr" +) + +func NewParser() *Parser { + return &Parser{} +} + +type Parser struct { +} + +// parseOptions accepts ORDER BY and LIMIT on UPDATE and DELETE. SQLite has +// them only when built with SQLITE_ENABLE_UPDATE_DELETE_LIMIT, which meyer +// cannot tell from the SQL, so the caller has to ask. sqlc has always +// accepted them. +var parseOptions = parser.Options{UpdateDeleteLimit: true} + +func (p *Parser) Parse(r io.Reader) ([]ast.Statement, error) { + f, err := p.ParseFile(r) + if err != nil { + return nil, err + } + // The compiler skips statements sqlc has no node for (PRAGMA and + // friends); the formatter must see them, so the filter lives here, + // not in ParseFile. + var stmts []ast.Statement + for _, stmt := range f.Stmts { + if _, ok := stmt.Raw.Stmt.(*ast.TODO); ok { + continue + } + stmts = append(stmts, stmt) + } + return stmts, nil +} + +// ParseFile parses like Parse and also carries the file's comments, taken +// from the trivia meyer's single lexer pass produces alongside the tokens. +func (p *Parser) ParseFile(r io.Reader) (*ast.File, error) { + blob, err := io.ReadAll(r) + if err != nil { + return nil, err + } + src := string(blob) + parsed, err := parseOptions.ParseFile(src) + if err != nil { + return nil, normalizeErr(err) + } + + var stmts []ast.Statement + // loc tracks the first byte after the previous statement's terminator, so + // that a statement's extent covers the comments written above it. sqlc + // reads the "-- name:" annotation out of that range. + loc := 0 + for _, raw := range parsed.Stmts { + converter := &cc{src: src} + // A statement sqlc has no node for converts to a TODO and stays in + // the list: the formatter needs its extent to keep it as written, + // and Parse filters it out for the compiler. + stmts = append(stmts, ast.Statement{ + Raw: &ast.RawStmt{ + Stmt: converter.convert(raw), + StmtLocation: loc, + StmtLen: trimTerminator(src, raw) - loc, + }, + }) + loc = raw.End() + } + + var comments []ast.Comment + for _, tr := range parsed.Trivia { + if tr.Kind != mtoken.COMMENT { + continue + } + comments = append(comments, ast.Comment{ + Text: strings.TrimRight(tr.Text(src), " \t\r\n"), + Start: tr.Pos, + End: tr.End, + OwnLine: ownLine(src, tr.Pos), + }) + } + return &ast.File{Stmts: stmts, Comments: comments}, nil +} + +// ownLine reports that only blank space sits between the preceding line +// break and pos. +func ownLine(src string, pos int) bool { + for j := pos - 1; j >= 0; j-- { + switch src[j] { + case '\n': + return true + case ' ', '\t', '\r': + continue + default: + return false + } + } + return true +} + +// trimTerminator returns the end of stmt with its terminating semicolon, and +// any space before it, removed. A statement's span runs through the +// semicolon, but sqlc's statement text does not include it. +func trimTerminator(src string, stmt meyer.Stmt) int { + end := stmt.End() + if end > stmt.Pos() && end <= len(src) && src[end-1] == ';' { + end-- + } + for end > stmt.Pos() && isSpace(src[end-1]) { + end-- + } + return end +} + +func isSpace(b byte) bool { + switch b { + case ' ', '\t', '\n', '\r', '\f': + return true + } + return false +} + +// normalizeErr turns a meyer parse failure into the positioned error sqlc +// reports to the user. meyer's message and byte offset match SQLite's own. +func normalizeErr(err error) error { + var perr *parser.Error + if !errors.As(err, &perr) { + return err + } + line, column := parser.LineCol(perr.SQL, perr.Offset) + if line == 0 { + return errors.New(perr.Message) + } + return &sqlerr.Error{ + Message: perr.Message, + Line: line, + Column: column, + } +} + +func (p *Parser) CommentSyntax() source.CommentSyntax { + return source.CommentSyntax{ + Dash: true, + Hash: false, + SlashStar: true, + } +} diff --git a/internal/engine/sqlite/reserved.go b/internal/engine/sqlite/reserved.go new file mode 100644 index 0000000..eb6ed2f --- /dev/null +++ b/internal/engine/sqlite/reserved.go @@ -0,0 +1,10 @@ +package sqlite + +import "github.com/sqlc-dev/meyer/token" + +// IsReservedKeyword reports whether s is a keyword in SQLite; see +// https://sqlite.org/lang_keywords.html. The table lives in meyer, which +// transcribes it from SQLite's own aKeywordTable. +func (p *Parser) IsReservedKeyword(s string) bool { + return token.Lookup(s) != token.ID +} diff --git a/internal/engine/sqlite/seed.go b/internal/engine/sqlite/seed.go new file mode 100644 index 0000000..cc439b4 --- /dev/null +++ b/internal/engine/sqlite/seed.go @@ -0,0 +1,34 @@ +package sqlite + +import ( + "embed" + "sync" + + "github.com/sqlc-dev/sqlc/internal/core" + "github.com/sqlc-dev/sqlc/internal/core/seed" + "github.com/sqlc-dev/sqlc/internal/sql/catalog" +) + +// The dialect directory describes SQLite's type system, and functions.jsonl is +// its standard library. Both the analysis core and the catalog the legacy +// compiler builds read them. +// +//go:embed dialect +var dialectFS embed.FS + +// Dialect returns the catalog option that seeds SQLite's type system. +func Dialect() core.Option { + return seed.Dialect(dialectFS, "dialect") +} + +// stdlib is SQLite's functions in the form the catalog uses. They are embedded +// in the binary and never change within a run, so they are read once. +var stdlib = sync.OnceValue(func() []*catalog.Function { + funcs, err := seed.Functions(dialectFS, "dialect") + if err != nil { + // A failure here means sqlc was built from a broken tree, which no + // caller can do anything about. + panic(err) + } + return funcs +}) diff --git a/internal/engine/sqlite/stdlib.go b/internal/engine/sqlite/stdlib.go new file mode 100644 index 0000000..210aa29 --- /dev/null +++ b/internal/engine/sqlite/stdlib.go @@ -0,0 +1,13 @@ +package sqlite + +import ( + "github.com/sqlc-dev/sqlc/internal/sql/catalog" +) + +// defaultSchema is SQLite's standard library, read from the dialect +// directory's functions.jsonl, which internal/goldeneye generates from a +// default build of SQLite. The functions further compile options add live +// under the dialect's extensions/, one directory per option. +func defaultSchema(name string) *catalog.Schema { + return &catalog.Schema{Name: name, Funcs: stdlib()} +} diff --git a/internal/engine/sqlite/utils.go b/internal/engine/sqlite/utils.go new file mode 100644 index 0000000..3e4a03e --- /dev/null +++ b/internal/engine/sqlite/utils.go @@ -0,0 +1,144 @@ +package sqlite + +import ( + "strings" + + meyer "github.com/sqlc-dev/meyer/ast" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +// identifier folds a name the way SQLite resolves one: an unquoted name is +// case-insensitive and normalizes to lower case, while a quoted name keeps +// the spelling that appeared between the quotes. +func identifier(n *meyer.Ident) string { + if n == nil { + return "" + } + if n.Quote == meyer.QuoteNone { + return strings.ToLower(n.Name) + } + return n.Name +} + +// NewIdentifier returns the folded name of id as an ast.String, the shape +// sqlc uses for the parts of a ColumnRef or a function name. +func NewIdentifier(id *meyer.Ident) *ast.String { + return &ast.String{Str: identifier(id)} +} + +func parseTableName(n *meyer.QualifiedName) *ast.TableName { + if n == nil { + return &ast.TableName{} + } + return &ast.TableName{ + Schema: identifier(n.Schema), + Name: identifier(n.Name), + } +} + +// parseRangeVar builds the relation reference sqlc expects for a table named +// in a FROM, INSERT, UPDATE or DELETE clause. +func parseRangeVar(n *meyer.QualifiedName, alias *meyer.Ident) *ast.RangeVar { + rv := &ast.RangeVar{} + if n == nil { + return rv + } + rv.Location = n.Pos() + name := identifier(n.Name) + rv.Relname = &name + if n.Schema != nil { + schema := identifier(n.Schema) + rv.Schemaname = &schema + } + if alias != nil { + aliasName := identifier(alias) + rv.Alias = &ast.Alias{Aliasname: &aliasName} + } + return rv +} + +// typeName renders a type the way sqlc's type resolution expects to see it: +// the tokens joined without separators, matching what the ANTLR parser's +// GetText produced. "UNSIGNED BIG INT" becomes "UNSIGNEDBIGINT" and +// "DECIMAL(10, 5)" becomes "DECIMAL(10,5)". +func typeName(n *meyer.TypeName) string { + if n == nil { + return "" + } + var sb strings.Builder + sb.WriteString(strings.ReplaceAll(n.Name, " ", "")) + if len(n.Args) > 0 { + sb.WriteString("(") + sb.WriteString(strings.Join(n.Args, ",")) + sb.WriteString(")") + } + return sb.String() +} + +// typeSpelling returns the type as the author wrote it — identifier tokens +// space-joined, arguments as written — for the formatter to print back. +// typeName folds the spaces out for catalog matching. +func typeSpelling(n *meyer.TypeName) string { + if n == nil { + return "" + } + var sb strings.Builder + sb.WriteString(n.Name) + if len(n.Args) > 0 { + sb.WriteString("(") + sb.WriteString(strings.Join(n.Args, ",")) + sb.WriteString(")") + } + return sb.String() +} + +// representableColumn reports whether a column definition round-trips +// through the fields ast.ColumnDef models: a plain NOT NULL, a plain +// PRIMARY KEY, or nothing. Anything else — a named constraint, a conflict +// clause, ASC/DESC or AUTOINCREMENT, DEFAULT, UNIQUE, CHECK, COLLATE, +// REFERENCES, GENERATED — is parsed away, so a statement printing such a +// column would lose it. NOT NULL next to PRIMARY KEY is also beyond the +// node: SQLite's PRIMARY KEY does not imply NOT NULL, and the printed form +// carries only one of the pair. +func representableColumn(def *meyer.ColumnDef) bool { + var notNull, primary bool + for _, con := range def.Constraints { + switch { + case con.Name != nil: + return false + case con.Kind == meyer.ColumnNotNull && con.OnConflict == meyer.ConflictDefault: + notNull = true + case con.Kind == meyer.ColumnPrimaryKey && con.OnConflict == meyer.ConflictDefault && + con.Order == meyer.SortDefault && !con.AutoIncrement: + primary = true + default: + return false + } + } + return !(notNull && primary) +} + +// hasPrimaryKeyConstraint reports whether a column definition carries a +// PRIMARY KEY constraint. +func hasPrimaryKeyConstraint(constraints []*meyer.ColumnConstraint) bool { + for _, constraint := range constraints { + if constraint.Kind == meyer.ColumnPrimaryKey { + return true + } + } + return false +} + +// hasNotNullConstraint reports whether a column definition guarantees a +// value. A PRIMARY KEY implies NOT NULL for the purposes of code +// generation, matching the behavior of the previous parser. +func hasNotNullConstraint(constraints []*meyer.ColumnConstraint) bool { + for _, constraint := range constraints { + switch constraint.Kind { + case meyer.ColumnNotNull, meyer.ColumnPrimaryKey: + return true + } + } + return false +} diff --git a/internal/ext/handler.go b/internal/ext/handler.go new file mode 100644 index 0000000..2542dc1 --- /dev/null +++ b/internal/ext/handler.go @@ -0,0 +1,52 @@ +package ext + +import ( + "context" + "fmt" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/sqlc-dev/sqlc/internal/plugin" +) + +type Handler interface { + Generate(context.Context, *plugin.GenerateRequest) (*plugin.GenerateResponse, error) + + Invoke(ctx context.Context, method string, args any, reply any, opts ...grpc.CallOption) error + NewStream(ctx context.Context, desc *grpc.StreamDesc, method string, opts ...grpc.CallOption) (grpc.ClientStream, error) +} + +type wrapper struct { + fn func(context.Context, *plugin.GenerateRequest) (*plugin.GenerateResponse, error) +} + +func (w *wrapper) Generate(ctx context.Context, req *plugin.GenerateRequest) (*plugin.GenerateResponse, error) { + return w.fn(ctx, req) +} + +func (w *wrapper) Invoke(ctx context.Context, method string, args any, reply any, opts ...grpc.CallOption) error { + req, ok := args.(*plugin.GenerateRequest) + if !ok { + return fmt.Errorf("args isn't a GenerateRequest") + } + resp, ok := reply.(*plugin.GenerateResponse) + if !ok { + return fmt.Errorf("reply isn't a GenerateResponse") + } + res, err := w.Generate(ctx, req) + if err != nil { + return err + } + resp.Files = res.Files + return nil +} + +func (w *wrapper) NewStream(ctx context.Context, desc *grpc.StreamDesc, method string, opts ...grpc.CallOption) (grpc.ClientStream, error) { + return nil, status.Error(codes.Unimplemented, "") +} + +func HandleFunc(fn func(context.Context, *plugin.GenerateRequest) (*plugin.GenerateResponse, error)) Handler { + return &wrapper{fn} +} diff --git a/internal/ext/process/gen.go b/internal/ext/process/gen.go new file mode 100644 index 0000000..b5720db --- /dev/null +++ b/internal/ext/process/gen.go @@ -0,0 +1,105 @@ +package process + +import ( + "bytes" + "context" + "errors" + "fmt" + "os" + "os/exec" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" + + "github.com/sqlc-dev/sqlc/internal/info" +) + +type Runner struct { + Cmd string + Format string + Env []string +} + +func (r *Runner) Invoke(ctx context.Context, method string, args any, reply any, opts ...grpc.CallOption) error { + req, ok := args.(protoreflect.ProtoMessage) + if !ok { + return fmt.Errorf("args isn't a protoreflect.ProtoMessage") + } + + var stdin []byte + var err error + switch r.Format { + case "json": + m := &protojson.MarshalOptions{ + EmitUnpopulated: true, + Indent: "", + UseProtoNames: true, + } + stdin, err = m.Marshal(req) + + if err != nil { + return fmt.Errorf("failed to encode codegen request: %w", err) + } + case "", "protobuf": + stdin, err = proto.Marshal(req) + if err != nil { + return fmt.Errorf("failed to encode codegen request: %w", err) + } + default: + return fmt.Errorf("unknown plugin format: %s", r.Format) + } + + // Check if the output plugin exists + path, err := exec.LookPath(r.Cmd) + if err != nil { + return fmt.Errorf("process: %s not found", r.Cmd) + } + + cmd := exec.CommandContext(ctx, path, method) + cmd.Stdin = bytes.NewReader(stdin) + cmd.Env = []string{ + fmt.Sprintf("SQLC_VERSION=%s", info.Version), + } + for _, key := range r.Env { + if key == "SQLC_AUTH_TOKEN" { + continue + } + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", key, os.Getenv(key))) + } + + out, err := cmd.Output() + if err != nil { + stderr := err.Error() + var exit *exec.ExitError + if errors.As(err, &exit) { + stderr = string(exit.Stderr) + } + return fmt.Errorf("process: error running command %s", stderr) + } + + resp, ok := reply.(protoreflect.ProtoMessage) + if !ok { + return fmt.Errorf("reply isn't a protoreflect.ProtoMessage") + } + + switch r.Format { + case "json": + if err := protojson.Unmarshal(out, resp); err != nil { + return fmt.Errorf("process: failed to read codegen resp: %w", err) + } + default: + if err := proto.Unmarshal(out, resp); err != nil { + return fmt.Errorf("process: failed to read codegen resp: %w", err) + } + } + + return nil +} + +func (r *Runner) NewStream(ctx context.Context, desc *grpc.StreamDesc, method string, opts ...grpc.CallOption) (grpc.ClientStream, error) { + return nil, status.Error(codes.Unimplemented, "") +} diff --git a/internal/ext/wasm/runner.go b/internal/ext/wasm/runner.go new file mode 100644 index 0000000..352d827 --- /dev/null +++ b/internal/ext/wasm/runner.go @@ -0,0 +1,7 @@ +package wasm + +type Runner struct { + URL string + SHA256 string + Env []string +} diff --git a/internal/ext/wasm/wasm.go b/internal/ext/wasm/wasm.go new file mode 100644 index 0000000..e313ac2 --- /dev/null +++ b/internal/ext/wasm/wasm.go @@ -0,0 +1,291 @@ +package wasm + +import ( + "bytes" + "context" + "crypto/sha256" + "errors" + "fmt" + "io" + "log/slog" + "net/http" + "os" + "runtime" + "strings" + + "github.com/tetratelabs/wazero" + "github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1" + "github.com/tetratelabs/wazero/sys" + "golang.org/x/sync/singleflight" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" + + "github.com/sqlc-dev/sqlc/internal/cache" + "github.com/sqlc-dev/sqlc/internal/info" + "github.com/sqlc-dev/sqlc/internal/plugin" +) + +var flight singleflight.Group + +type runtimeAndCode struct { + rt wazero.Runtime + code wazero.CompiledModule +} + +// Verify the provided sha256 is valid. +func (r *Runner) getChecksum(ctx context.Context) (string, error) { + if r.SHA256 != "" { + return r.SHA256, nil + } + // TODO: Add a log line here about something + _, sum, err := r.fetch(ctx, r.URL) + if err != nil { + return "", err + } + slog.Warn("fetching WASM binary to calculate sha256. Set this value in sqlc.yaml to prevent unneeded work", "sha256", sum) + return sum, nil +} + +func (r *Runner) loadAndCompile(ctx context.Context) (*runtimeAndCode, error) { + expected, err := r.getChecksum(ctx) + if err != nil { + return nil, err + } + store, err := cache.Open() + if err != nil { + return nil, err + } + defer store.Close() + value, err, _ := flight.Do(expected, func() (any, error) { + return r.loadAndCompileWASM(ctx, store, expected) + }) + if err != nil { + return nil, err + } + data, ok := value.(*runtimeAndCode) + if !ok { + return nil, fmt.Errorf("returned value was not a compiled module") + } + return data, nil +} + +func (r *Runner) fetch(ctx context.Context, uri string) ([]byte, string, error) { + var body io.ReadCloser + + switch { + + case strings.HasPrefix(uri, "file://"): + file, err := os.Open(strings.TrimPrefix(uri, "file://")) + if err != nil { + return nil, "", fmt.Errorf("os.Open: %s %w", uri, err) + } + body = file + + case strings.HasPrefix(uri, "https://"): + req, err := http.NewRequestWithContext(ctx, "GET", uri, nil) + if err != nil { + return nil, "", fmt.Errorf("http.Get: %s %w", uri, err) + } + req.Header.Set("User-Agent", fmt.Sprintf("sqlc/%s Go/%s (%s %s)", info.Version, runtime.Version(), runtime.GOOS, runtime.GOARCH)) + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, "", fmt.Errorf("http.Get: %s %w", r.URL, err) + } + body = resp.Body + + default: + return nil, "", fmt.Errorf("unknown scheme: %s", r.URL) + } + + defer body.Close() + + wmod, err := io.ReadAll(body) + if err != nil { + return nil, "", fmt.Errorf("readall: %w", err) + } + + sum := sha256.Sum256(wmod) + actual := fmt.Sprintf("%x", sum) + + return wmod, actual, nil +} + +func (r *Runner) loadAndCompileWASM(ctx context.Context, store *cache.Cache, expected string) (*runtimeAndCode, error) { + // The sha256 declared in sqlc's configuration is a content address, so + // the plugin binary is looked up in the CAS directly by that checksum — + // no action cache entry is needed, and Get re-verifies the checksum on + // every hit. + wmod, err := store.CAS.Get(cache.SHA256Digest(expected)) + if errors.Is(err, cache.ErrNotFound) { + var actual string + wmod, actual, err = r.fetch(ctx, r.URL) + if err != nil { + return nil, err + } + if expected != actual { + return nil, fmt.Errorf("invalid checksum: expected %s, got %s", expected, actual) + } + if _, err := store.CAS.Put(wmod); err != nil { + return nil, fmt.Errorf("cache wasm: %w", err) + } + } else if err != nil { + return nil, err + } + + // Compiling the module to machine code is itself a cacheable action. + // Its only declared input is the module's checksum: the embedded wazero + // version and the target platform are determined by the sqlc binary, + // which is an implicit input of every action. Compiled artifacts are + // materialized into a private exec directory for wazero's compilation + // cache to find; the authoritative copies live in the CAS. Once wazero + // has loaded the module into memory the directory is no longer needed. + compileAction := store.NewAction("CompileModule"). + AddInput("wasm", []byte(expected)). + Digest() + + execDir, err := store.ExecDir(compileAction) + if err != nil { + return nil, err + } + defer os.RemoveAll(execDir) + compiled := true + if err := store.Actions.GetTree(compileAction, execDir); errors.Is(err, cache.ErrNotFound) { + compiled = false + } else if err != nil { + return nil, err + } + + wazeroCache, err := wazero.NewCompilationCacheWithDir(execDir) + if err != nil { + return nil, fmt.Errorf("wazero.NewCompilationCacheWithDir: %w", err) + } + + config := wazero.NewRuntimeConfig().WithCompilationCache(wazeroCache) + rt := wazero.NewRuntimeWithConfig(ctx, config) + + if _, err := wasi_snapshot_preview1.Instantiate(ctx, rt); err != nil { + return nil, fmt.Errorf("wasi_snapshot_preview1 instantiate: %w", err) + } + + // Compile the Wasm binary once so that we can skip the entire compilation + // time during instantiation. On an action cache hit this loads the + // materialized machine code instead of compiling. + code, err := rt.CompileModule(ctx, wmod) + if err != nil { + return nil, fmt.Errorf("compile module: %w", err) + } + + if !compiled { + if err := store.Actions.PutTree(compileAction, execDir); err != nil { + slog.Warn("caching compiled module failed", "err", err) + } + } + + return &runtimeAndCode{rt: rt, code: code}, nil +} + +// removePGCatalog removes the pg_catalog schema from the request. There is a +// mysterious (reason unknown) bug with wasm plugins when a large amount of +// tables (like there are in the catalog) are sent. +// @see https://github.com/sqlc-dev/sqlc/pull/1748 +func removePGCatalog(req *plugin.GenerateRequest) { + if req.Catalog == nil || req.Catalog.Schemas == nil { + return + } + + filtered := make([]*plugin.Schema, 0, len(req.Catalog.Schemas)) + for _, schema := range req.Catalog.Schemas { + if schema.Name == "pg_catalog" || schema.Name == "information_schema" { + continue + } + + filtered = append(filtered, schema) + } + + req.Catalog.Schemas = filtered +} + +func (r *Runner) Invoke(ctx context.Context, method string, args any, reply any, opts ...grpc.CallOption) error { + req, ok := args.(protoreflect.ProtoMessage) + if !ok { + return status.Error(codes.InvalidArgument, "args isn't a protoreflect.ProtoMessage") + } + + // Remove the pg_catalog schema. Its sheer size causes unknown issues with wasm plugins + genReq, ok := req.(*plugin.GenerateRequest) + if ok { + removePGCatalog(genReq) + req = genReq + } + + stdinBlob, err := proto.Marshal(req) + if err != nil { + return fmt.Errorf("failed to encode codegen request: %w", err) + } + + runtimeAndCode, err := r.loadAndCompile(ctx) + if err != nil { + return fmt.Errorf("loadBytes: %w", err) + } + + var stderr, stdout bytes.Buffer + + conf := wazero.NewModuleConfig(). + WithName(""). + WithArgs("plugin.wasm", method). + WithStdin(bytes.NewReader(stdinBlob)). + WithStdout(&stdout). + WithStderr(&stderr). + WithEnv("SQLC_VERSION", info.Version) + for _, key := range r.Env { + conf = conf.WithEnv(key, os.Getenv(key)) + } + + result, err := runtimeAndCode.rt.InstantiateModule(ctx, runtimeAndCode.code, conf) + if err == nil { + defer result.Close(ctx) + } + if cerr := checkError(err, stderr); cerr != nil { + return cerr + } + + // Print WASM stdout + stdoutBlob := stdout.Bytes() + + resp, ok := reply.(protoreflect.ProtoMessage) + if !ok { + return fmt.Errorf("reply isn't a GenerateResponse") + } + + if err := proto.Unmarshal(stdoutBlob, resp); err != nil { + return err + } + + return nil +} + +func (r *Runner) NewStream(ctx context.Context, desc *grpc.StreamDesc, method string, opts ...grpc.CallOption) (grpc.ClientStream, error) { + return nil, status.Error(codes.Unimplemented, "") +} + +func checkError(err error, stderr bytes.Buffer) error { + if err == nil { + return err + } + + if exitErr, ok := err.(*sys.ExitError); ok { + if exitErr.ExitCode() == 0 { + return nil + } + } + + // Print WASM stdout + stderrBlob := stderr.String() + if len(stderrBlob) > 0 { + return errors.New(stderrBlob) + } + return fmt.Errorf("call: %w", err) +} diff --git a/internal/goldeneye/README.md b/internal/goldeneye/README.md new file mode 100644 index 0000000..e4e8374 --- /dev/null +++ b/internal/goldeneye/README.md @@ -0,0 +1,342 @@ +# goldeneye + +`goldeneye` generates the dialect seeds under `internal/engine//dialect` +from a live database, and verifies the committed ones against it. A dialect +is the JSONL that gives an engine its type system and standard library — +`types.jsonl`, `functions.jsonl`, `operators.jsonl`, `relations.jsonl` and +the `extensions/` bundles — read by `internal/core/seed`. Each engine package +here asks the database what it knows, writes the answer in that shape, and +the tests compare it with what is committed, byte for byte. A difference +means the committed dialect has drifted from the database. + +It is a nested Go module, so its only dependencies beyond the standard +library are the database clients — PostgreSQL's, MySQL's and SQL Server's +drivers, and Spanner's gRPC client with what it stands on — and it never +shares code with the analysis that reads the files: the files are the +contract. Run it from this directory: + +```bash +go run ./cmd/goldeneye install clickhouse # download the pinned clickhouse binary once +go run ./cmd/goldeneye install duckdb # download the current DuckDB 2.0 preview build once +go run ./cmd/goldeneye install sqlite # build the pinned sqlite3 shells once; needs a C compiler +go run ./cmd/goldeneye check # check every engine whose database is available +go run ./cmd/goldeneye check postgresql # check one engine +go run ./cmd/goldeneye check spanner # SPANNER_SERVER_URI=localhost:15000, a Spanner Omni container +go run ./cmd/goldeneye generate [engine] # rewrite the generated files from the database +go test ./... # the same checks as tests; engines without a database skip +``` + +`generate` and `check` say which engines they skipped for lack of a +database; naming an engine makes its database required. + +## What is generated, and what is not + +A generator owns only the files it produces; `dialect.json` is always written +by hand, and so are the lists an engine cannot describe. Both commands leave +the hand-written files alone, and the checks do not look at them. + +- **`postgresql`** reads a live server named by `POSTGRESQL_SERVER_URI`: + `functions.jsonl` is `pg_catalog`'s functions, `relations.jsonl` the tables + and views of `pg_catalog` and `information_schema`, and each contrib + extension gets a directory under `extensions/` holding the types and + functions `CREATE EXTENSION` adds, so the server needs contrib installed. + A function that one of those extensions puts in `pg_catalog`, as + `adminpack` does, belongs to the extension's directory rather than the + catalog's list. The server has to be the major release pinned in + `postgresql.Major`, since every release adds to the catalogs; the top-level + `types.jsonl` and `operators.jsonl` are hand-written. +- **`mysql`** reads a live server named by `MYSQL_SERVER_URI`, a go-sql-driver + DSN such as `root:mysecretpassword@tcp(127.0.0.1:3306)/mysql`, and writes + into `internal/engine/dolphin/dialect`, since sqlc's MySQL engine is named + after its parser. MySQL keeps no catalog of its types, functions or + operators — the help tables describe a built-in function no further than + its name — so `types.jsonl`, `functions.jsonl` and `operators.jsonl` are + hand-written. What it does describe is its data dictionary: + `relations.jsonl` is every view of `information_schema`, read from + `information_schema` itself, with their names in lower case, since MySQL + matches them in any case and sqlc's parser lowercases every identifier. A + column's type is spelled the way a declaration does, `bigint unsigned` + included, which `types.jsonl` lists as an alias of `bigint`. The other + schemas `mysqld --initialize` creates — `mysql`, `performance_schema`, `sys` + — are tables rather than views, and every table a dialect seeds is one the + analysis core hands codegen as a model, so they are left out until codegen + knows a system schema when it sees one. The server has to be the major + release pinned in `mysql.Major`, since every release adds to + `information_schema`. +- **`duckdb`** reads the DuckDB CLI named by `DUCKDB`, or the one `install` + put in the user cache directory, or `duckdb` on `PATH`: `types.jsonl`, + `functions.jsonl` and `operators.jsonl` come from `duckdb_types()` and + `duckdb_functions()`. The CLI has to be a DuckDB 2.0 build, the release + darkwing is pinned against, which has no release to download yet: until + 2.0 is out, `install` downloads the current build of DuckDB's v2.0 + preview channel, `duckdb.DefaultVersion`, a rolling tarball per platform + under `artifacts.duckdb.org` with no per-build download and no checksum + to pin, so what a run logs is the version the CLI reports, and + `duckdb.GeneratedFrom` records the build the committed dialect came + from. A check against a later build reports what the later build added; + regenerate, and update `GeneratedFrom`, to move the dialect along. Once + 2.0 is released, the installer should pin the release and its checksums + the way the clickhouse one does. +- **`clickhouse`** needs no server: `types.jsonl` comes from + `system.data_type_families` of an ephemeral `clickhouse local` process, + every family that is not an alias becoming a type carrying the spellings + that alias it, with a category decided by its name. The binary is + downloaded once per pinned release by `install` into the user cache + directory, or supplied through the `CLICKHOUSE` environment variable; the + pinned release and the SHA-512 of each platform's download live in + `clickhouse/install.go`, and a download that does not match is discarded. + ClickHouse describes its functions no further than their names, so + `functions.jsonl` is hand-written. +- **`mssql`** reads a live server named by `MSSQL_SERVER_URI`, in any form + the go-mssqldb driver accepts, such as + `sqlserver://sa:password@127.0.0.1:1433?encrypt=disable`. SQL Server keeps + no catalog of its intrinsic functions or its operators — GETDATE and LEN + are not objects — so `types.jsonl` and `functions.jsonl` are hand-written. + What it does describe is its catalog: `relations.jsonl` is every view of + the `sys` and `INFORMATION_SCHEMA` schemas, listed from a database of its + own, since the views a query sees are the ones a user database has and + `master` lists internal views no query can name; each view's columns are + what `sys.dm_exec_describe_first_result_set` says a `SELECT *` from it + returns, the type spelled the way a declaration spells it — + `nvarchar(128)`, `decimal(10,2)`, `varbinary(max)` — and the nullability + the server computes. Names are written in lower case, since SQL Server + matches them in any case under its default collations and sqlc's parser + lowercases every identifier. Both schemas hold nothing but views, so no + table is seeded that codegen would take for a model. The server has to + be the major release pinned in `mssql.Major`, since every release adds + to the catalog views. +- **`spanner`** reads a live Spanner Omni server — the downloadable + Spanner, run from its container image — named by `SPANNER_SERVER_URI`, + the gRPC endpoint such as `localhost:15000`, reached without TLS or + credentials as Omni is, and writes into `internal/engine/googlesql/dialect`, + since sqlc's engine is named after the language Spanner speaks. Spanner + keeps no catalog of its types, functions or operators, so `types.jsonl`, + `functions.jsonl` and `operators.jsonl` are hand-written. What it does + describe is its information schema: `relations.jsonl` is every view of + `INFORMATION_SCHEMA` and `SPANNER_SYS`, read from `INFORMATION_SCHEMA` + itself in a database created for the purpose in the instance Omni's + single server provides, `projects/default/instances/default`. Names are + kept as the catalog spells them, in upper case: Spanner matches a name + in any case, but sqlc's GoogleSQL engine matches one as it is spelled, + so a query reaches these views by their upper-case names until the + engine folds case; a column's type is spelled in lower case the way the seed + spells one, an `ARRAY` as `T` with the array flag, a `STRUCT` as + `struct(a: t)` and a `PROTO` as `proto('p.M')`, since a seed writes + a type's arguments in parentheses. The container image is pinned in the + gen workflow and `docker-compose.yml`. +- **`sqlite`** needs no server either: `functions.jsonl` comes from + `pragma_function_list` of a `sqlite3` shell run against an in-memory + database. Which functions a SQLite has is decided when it is compiled, so + `install` downloads the pinned release's amalgamation, checked against the + SHA3-256 the download page lists, and compiles the shell from it with the + compiler `CC` names, or `cc` — once with the options sqlite.org's own + configure turns on by default, which gives `functions.jsonl`, and once + more per option in `sqlite/install.go`'s extension list, each of which + gets a directory under `extensions/` holding the functions its build adds + over the default one, the way each PostgreSQL contrib extension holds what + `CREATE EXTENSION` adds; a schema that says `CREATE VIRTUAL TABLE ... USING + fts5` loads the option's directory, through the `modules` map in the + hand-written `dialect.json`. SQLite describes its functions as far as their + names, their kinds and the number of arguments each overload takes, and no + further — it types values, not functions — so what each returns and what + its arguments hold is read from the amalgamation: every function is + registered with the C functions that implement it, and those set their + result through `sqlite3_result_*` and read their arguments through + `sqlite3_value_*`. A function a shell reports that the source does not + register fails the run rather than being guessed at. Whether an aggregate + returns NULL over no rows is found by running it over none; the scalar + functions that return NULL for arguments that are not are a short list in + `sqlite/signatures.go`, since a SQLite function returns NULL as often by + setting no result as by saying so. The pinned release is the one the main module's + driver embeds. SQLite has no catalog of types or operators, so + `types.jsonl` and `operators.jsonl` are hand-written. A function that + returns an integer for an integer and a real for a real — `abs`, `ceil`, + `floor`, `trunc`, `sum` — is written once over `any`, returning the real + that a text or blob argument gets, and once more per spelling + `types.jsonl` gives integer and real, returning that type, the way + PostgreSQL's catalog has a `sum` per numeric type; the overload over `any` + comes first, since the legacy compiler resolves by arity alone and takes + it. `install` builds one more shell, for the analysis check below; + nothing is generated from it. + +## Layout + +- `dialect/` — the record types the files are made of, mirrored from + `internal/core/seed`, and the helpers that write a generated set of files + into an engine directory or diff it against what is committed. +- `endtoend/` — finds the analyze cases, splits their query files, and + compares an engine's answer with a case's committed output. +- `analysis/` — the shape of that answer: the JSON `sqlc analyze` prints. +- `postgresql/`, `mysql/`, `mssql/`, `spanner/`, `duckdb/`, `clickhouse/`, + `sqlite/` — one package per engine, each exposing `Locate`, `Version` and + `Generate`, `Analyze` where the engine has an analysis check, and tests + that run the checks. +- `cmd/goldeneye/` — the command. + +## Analysis checks + +`check` also verifies the `analyze_*` cases under `internal/endtoend/testdata` +against what the database itself reports. A case is an +`analyze_/` directory whose `exec.json` runs the analyze +command; `endtoend/` finds them. The engine package loads the case's +`schema.sql` and optional `fixture.sql` into the database, runs `query.sql` +there, prints what the database reports in the JSON shape `sqlc analyze` +prints, and compares it with the committed `stdout.json` byte for byte. A +difference means sqlc's analysis disagrees with the database. A case that +asks for `--ast` is skipped, since only sqlc can print that. + +- **`clickhouse`** runs each case in an ephemeral `clickhouse local` process. + Column types come from the executed query's result header, provenance from + `EXPLAIN QUERY TREE`, and parameters from sentinel constants substituted for + `?`, `sqlc.arg()` and `sqlc.narg()`, since ClickHouse itself never sees a + placeholder; `INSERT ... VALUES` parameters map onto `DESCRIBE TABLE`. +- **`sqlite`** runs each case through one more shell `install` builds, under + `analysis/`: every extension option at once, so that any case's schema + loads, and `SQLITE_ENABLE_COLUMN_METADATA`, which lets the shell's `.stats + stmt` say which table column each result column of a statement is read + from. That column's declared type is the result column's, and its NOT + NULL decides nullability, the rowid counting as NOT NULL. SQLite types + values rather than expressions, so a column the library has no origin for + — an aggregate, an arithmetic result — is typed by the storage class of + the value it returns, which is why a case wants a `fixture.sql`: the query + is run over the fixture, with each parameter bound to a value of the + column it stands in for, and again over no rows, and a column is nullable + when either run returns a NULL for it — an aggregate over nothing, the far + side of an outer join. The library reports nothing about a parameter but + its number, so parameters are found in the bytecode `EXPLAIN` prints, the + way ClickHouse's are found in its query tree: each is followed from the + register its `Variable` loads, through copies and the expressions it is an + argument of, to the first opcode that uses it against something the + catalog can name — the other operand of a comparison, the row a seek lands + on, the position in the record an `Insert` writes, the column of an IN + list's ephemeral table it comes back out of. One that reaches nothing + nameable is described by what the program requires of it, when it + requires anything: `MustBeInt` makes LIMIT's an integer. `sqlc.arg(name)` + becomes `?N`, numbered as sqlc numbers them, so a repeated name is one + parameter. Two things the check reports that sqlc does not: a bare column + selected alongside an aggregate is NULL over no rows, and so nullable, and + a comparison such as `x IS NULL` is an integer, since that is what SQLite + returns. + +- **`mysql`** runs each case in a database of its own on the server named by + `MYSQL_SERVER_URI`, and asks the server three things about a query. What a + driver sees: the query is run, with every parameter a user variable set to + NULL, and each result column's name, type and nullability are read from + the result set's metadata as go-sql-driver reports them. What the resolver + made of it: the optimizer trace prints each query block back after name + resolution and before optimisation, with every column qualified, every + alias kept and every `SELECT *` expanded, which says which table a result + column is read from and what a parameter is compared with or assigned to. + And for a statement the trace does not expand — an `INSERT ... VALUES`, a + single-table `UPDATE` or `DELETE` — the note `EXPLAIN` leaves, which prints + the statement the same way; a `SELECT` cannot be read from the note, since + it is printed after optimisation, and a lookup on a unique key against an + empty table has folded to `NULL = (@x)` there. Views and derived tables are + kept as the query wrote them rather than merged, so that a column read + through one is reported as its column and an `information_schema` view is + not resolved away into the dictionary tables behind it. MySQL itself + reports nothing about a parameter but its position, so a parameter is + described by its partner: a column's type and nullability come from + `information_schema`, a column of a derived table or CTE from what its + block projects, and an expression's from running it, over the tables it + reads, as a query of its own; a `LIMIT` or `OFFSET` count is a `bigint + unsigned`. Two things the driver keeps to itself: the table a result + column comes from, which is why the trace is read for it, and the length + beside the one wire type every size of `TEXT` and `BLOB` is sent as, which + is why a column read from a table, directly or through a derived table, + is spelled the way the table declares it. + +- **`duckdb`** runs each case through the CLI, which loads the schema and + fixture into an in-memory database of their own, one process per + question, and is asked four things about each query. What its + parameters are: the query is prepared and explained as JSON with a + string sentinel bound to each parameter, `EXECUTE q('goldeneye_1', + ...)`, and the unoptimized logical plan the CLI prints under + `explain_output = 'all'` shows each as `CAST('goldeneye_k' AS T)`, `T` + being the type the binder gave the parameter, or bare when that type is + `VARCHAR`; a sentinel the binder converts on the spot, as an `INSERT`'s + `VALUES` are, is bound to NULL instead. What its result columns are: `DESCRIBE`, with each parameter + replaced by a NULL of its type, names and types them; DuckDB describes + no DML, so a `RETURNING` column is the target table's column it names. + Which table a result column is read from and which column a parameter + stands in for: DuckDB prints a plan with every column by its bare name + and every aliased expression by its alias, so these are read from the + query text, the select list's items, a star expanded to its table's + columns, and the operand beside each parameter, resolved against the + `FROM` clause and the catalog, `duckdb_columns()`, from which a column + read from a table takes its declared type and nullability; a parameter + the query casts takes the cast's type as DuckDB spells it, and one + inside a subquery, whose tables the statement's scope does not name, + takes the binder's. And whether + an expression can be NULL, which DuckDB does not track: the query is + run, with each parameter bound to a value of its type, over the fixture + and over no rows, and a column is nullable when either run returns a + NULL for it. DuckDB spells an enum column by its labels whether the + schema named the type or not, so labels that are those of an enum the + schema created name that type, and a spelling `types.jsonl` lists as an + alias — `json`, which DuckDB's own catalog lists as a spelling of + `varchar` — is reported by the dialect's name for it. +- **`mssql`** describes each case in a database of its own on the server + named by `MSSQL_SERVER_URI`, without running anything: the schema is + loaded one statement at a time, since a `CREATE TYPE` has to be its own + batch before a table can use the type, and the server is asked three + things about each query. What a driver would see: + `sys.dm_exec_describe_first_result_set` describes each result column — + its name, its type spelled the way a declaration spells it, whether it + can be NULL, and which table column it is read from. What each parameter + would be: `sp_describe_undeclared_parameters` says what type the server + would give each parameter the query leaves undeclared, which is the type + of a `CAST(@p AS T)`; it describes a parameter only when it is used + once, so each appearance of a repeated one becomes a variable of its + own. And what each parameter stands in for: the estimated showplan, + compiled with `SET SHOWPLAN_XML ON` and the parameters declared as those + types, prints every column as a reference naming its table and every + variable as `@variable`, and a parameter's partner is the column on the + other side of the `Compare` it is an operand of, the column an `Assign` + sets to it, or the column of a seek whose range expression it is, with a + named expression such as `Expr1002` followed to its definition; a + parameter under a `CONVERT` the query wrote has no partner, since the + cast says what it is. A parameter with a partner is described as that + column, from the catalog of the case's database. Three things the + describing function keeps to itself: a `json` or `vector` column is + described by the `nvarchar(max)` it is sent to a driver as, so a column + read from a table is typed from `sys.columns` instead; a type the + schema created is reported beside the system type it stands on, and the + dialect reports it by its own name; and a spelling `types.jsonl` lists + as an alias — `numeric`, `timestamp` — is reported by the dialect's name + for it, `decimal`, `rowversion`. One thing it says that sqlc does not: a + computed column — a cast, an arithmetic — is nullable whatever its + arguments, since a conversion that fails under `ANSI_WARNINGS OFF` + yields NULL, where sqlc follows the arguments, and a computed column + names the column it is computed from, as the one an update through the + result set would write, where sqlc gives an expression no table. The + cases compute over nullable columns, and a computed column is reported + without a table. +- **`spanner`** creates a database of each case's own from its schema in + the instance named by `SPANNER_SERVER_URI`, writes its fixture there in a + read-write transaction, and compiles each query in `PLAN` mode, which + runs nothing: a DML statement is compiled in a read-write transaction + that is rolled back. The server reports the name and type of each + result column and the type of each parameter the query leaves + undeclared, the way the wire spells them — `STRING`, `ARRAY` — + without the length a declaration gives a `STRING(10)` or whether a + column can be NULL, and the query plan, which says where each comes + from: the children of `Serialize Result` after the relation it + serializes are the result columns, a `Scan` of a table defines a + variable per column it reads, and a comparison is a `Function` whose + description reads `($col = @param)`. A result column the plan reads + from a table column, directly or through the variables a join or a + batch passes it through, is described from the case's + `INFORMATION_SCHEMA`, with its declared length and nullability; one the + plan reads as a parameter is the column the parameter is compared with, + which is why the optimizer substituted it. A parameter compared with a + table column is described as that column. A DML plan lists the values + it writes before the columns it returns — the table's key columns, then + the columns an `UPDATE` sets or an `INSERT` inserts, read from the + statement — and a parameter written to a column is described as it, + while a `THEN RETURN` column is the table's column of that name. Two + things Spanner does not say: whether an expression can be NULL, which + is reported as it is not, and anything about a `STRUCT` returned as a + column, which Spanner rejects. + +The other engines have no analysis check yet. diff --git a/internal/goldeneye/analysis/analysis.go b/internal/goldeneye/analysis/analysis.go new file mode 100644 index 0000000..1433f50 --- /dev/null +++ b/internal/goldeneye/analysis/analysis.go @@ -0,0 +1,64 @@ +// Package analysis is the shape of an engine's answer about a query: the +// JSON `sqlc analyze` prints, so that a case's committed stdout.json can be +// compared with what the database itself reports, byte for byte. +package analysis + +import ( + "bytes" + "encoding/json" +) + +// Query is what was found out about one query. +type Query struct { + Name string `json:"name"` + Cmd string `json:"cmd"` + Columns []Column `json:"columns"` + Params []Param `json:"params"` +} + +// Column describes a result column, or the column a parameter stands in +// for. +type Column struct { + Name string `json:"name"` + Type *TypeExpr `json:"type,omitempty"` + Table string `json:"table,omitempty"` +} + +// Param is one parameter and what it is compared with or assigned to. +type Param struct { + Number int `json:"number"` + Column Column `json:"column"` +} + +// TypeExpr is a type as a call expression: a lowercased name applied to an +// ordered argument list, each argument another type, an integer, a boolean +// or a quoted string, optionally labelled. Nullability is an attribute of +// the type rather than a wrapper. +type TypeExpr struct { + Name string `json:"name"` + Nullable bool `json:"nullable,omitempty"` + Args []TypeArg `json:"args,omitempty"` +} + +// TypeArg is one argument of a TypeExpr: a type, an integer, a boolean, a +// quoted string, or an identifier — a bare word that is not a type, such as +// the function an AggregateFunction names. +type TypeArg struct { + Label string `json:"label,omitempty"` + Type *TypeExpr `json:"type,omitempty"` + Int *int64 `json:"int,omitempty"` + Bool *bool `json:"bool,omitempty"` + String *string `json:"string,omitempty"` + Ident *string `json:"ident,omitempty"` +} + +// Encode prints the answer the way sqlc analyze does. +func Encode(queries []Query) ([]byte, error) { + var buf bytes.Buffer + enc := json.NewEncoder(&buf) + enc.SetIndent("", " ") + if err := enc.Encode(queries); err != nil { + return nil, err + } + return buf.Bytes(), nil +} diff --git a/internal/goldeneye/clickhouse/analyze.go b/internal/goldeneye/clickhouse/analyze.go new file mode 100644 index 0000000..ff2148f --- /dev/null +++ b/internal/goldeneye/clickhouse/analyze.go @@ -0,0 +1,272 @@ +package clickhouse + +import ( + "context" + "encoding/json" + "fmt" + "regexp" + "strconv" + "strings" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/analysis" + "github.com/sqlc-dev/sqlc/internal/goldeneye/endtoend" +) + +// analyze runs every query against the schema and fixture and records what +// ClickHouse reports about each. +func analyze(ctx context.Context, l local, schema, fixture string, queries []endtoend.Query) ([]analysis.Query, error) { + out := make([]analysis.Query, 0, len(queries)) + for _, q := range queries { + aq, err := analyzeQuery(ctx, l, schema, fixture, q) + if err != nil { + return nil, fmt.Errorf("%s: %w", q.Name, err) + } + out = append(out, aq) + } + return out, nil +} + +func analyzeQuery(ctx context.Context, l local, schema, fixture string, q endtoend.Query) (analysis.Query, error) { + sql, phs := bindPlaceholders(q.SQL) + explain := returnsRows(sql) + + var script strings.Builder + for _, stmt := range []string{schema, fixture} { + if s := strings.TrimRight(strings.TrimSpace(stmt), ";"); s != "" { + script.WriteString(s) + script.WriteString(";\n") + } + } + if explain { + script.WriteString("EXPLAIN QUERY TREE " + sql + ";\n") + } + script.WriteString(sql + ";\n") + + results, err := l.run(ctx, script.String()) + if err != nil { + return analysis.Query{}, err + } + + aq := analysis.Query{ + Name: q.Name, + Cmd: q.Cmd, + Columns: []analysis.Column{}, + Params: []analysis.Param{}, + } + if !explain { + return analyzeExec(ctx, l, script.String(), sql, phs, aq) + } + if len(results) != 2 { + return analysis.Query{}, fmt.Errorf("expected the query tree and one result set, got %d results", len(results)) + } + + var lines []string + for _, row := range results[0].Data { + var line string + if err := json.Unmarshal(row["explain"], &line); err != nil { + return analysis.Query{}, fmt.Errorf("reading query tree: %w", err) + } + lines = append(lines, line) + } + tree, err := parseQueryTree(lines) + if err != nil { + return analysis.Query{}, err + } + + // Names and types come from the block header of the executed query, the + // same header a driver sees. The tree only adds where each came from. + _, nodes := projection(firstNode(tree.root.children)) + for i, col := range results[1].Meta { + ac := column(col.Name, col.Type) + if i < len(nodes) && len(nodes) == len(results[1].Meta) { + ac.Table = tree.sourceTable(nodes[i]) + } + aq.Columns = append(aq.Columns, ac) + } + + sentinels := tree.sentinels() + for i, ph := range phs { + ac := analysis.Column{} + if sentinel := sentinels[i+1]; sentinel != nil { + ac = tree.paramColumn(sentinel) + } + if ph.Name != "" { + ac.Name = ph.Name + } + aq.Params = append(aq.Params, analysis.Param{Number: ph.Number, Column: ac}) + } + return aq, nil +} + +func column(name, typ string) analysis.Column { + if typ == "" { + return analysis.Column{Name: name} + } + return analysis.Column{Name: name, Type: parseType(typ)} +} + +// returnsRows reports whether a statement produces a result set and so can +// be explained as a query tree. +func returnsRows(sql string) bool { + head := strings.ToLower(strings.TrimSpace(sql)) + if strings.HasPrefix(head, "(") { + return true + } + for _, kw := range []string{"select", "with", "show", "describe", "desc", "exists"} { + if strings.HasPrefix(head, kw) && (len(head) == len(kw) || !isWordByte(head[len(kw)])) { + return true + } + } + return false +} + +// sentinels finds the constants the placeholders were substituted with, +// keyed by placeholder ordinal. +func (t *queryTree) sentinels() map[int]*treeNode { + found := map[int]*treeNode{} + var walk func(n *treeNode) + walk = func(n *treeNode) { + if n.kind == "CONSTANT" { + if k, ok := sentinelOrdinal(n); ok { + found[k] = n + return + } + } + for _, c := range n.children { + walk(c) + } + } + walk(t.root) + return found +} + +// sentinelOrdinal recognises a constant folded directly from `NULL + k` or +// `4294967295 + k`, the shapes sentinelFor produces, and returns k. A +// constant folded from a larger expression that merely contains a sentinel +// does not match; the sentinel is found nested inside it instead. +func sentinelOrdinal(c *treeNode) (int, bool) { + fn := firstNode(c.section("EXPRESSION").childrenOrNil()) + if fn == nil || fn.kind != "FUNCTION" || fn.attrs["function_name"] != "plus" { + return 0, false + } + args := fn.section("ARGUMENTS").list() + if len(args) != 2 || args[0].kind != "CONSTANT" || args[1].kind != "CONSTANT" { + return 0, false + } + base := args[0].attrs["constant_value"] + if base != "NULL" && base != "UInt64_"+limitBase { + return 0, false + } + k, err := strconv.Atoi(strings.TrimPrefix(args[1].attrs["constant_value"], "UInt64_")) + if err != nil { + return 0, false + } + return k, true +} + +// paramColumn describes what a placeholder is compared with or assigned to: +// the other operand of the function it is an argument of, preferring a +// column over an expression, or the projected column it stands for. +func (t *queryTree) paramColumn(sentinel *treeNode) analysis.Column { + list := sentinel.parent + if list != nil && list.kind == "LIST" && list.parent != nil { + switch owner := list.parent; { + case owner.kind == "" && owner.text == "ARGUMENTS": + // Prefer a column operand, then an expression, then a constant. + rank := map[string]int{"COLUMN": 0, "FUNCTION": 1, "CONSTANT": 2} + var best *treeNode + for _, sib := range list.children { + if sib == sentinel { + continue + } + if r, ok := rank[sib.kind]; ok && (best == nil || r < rank[best.kind]) { + best = sib + } + } + if best != nil { + return t.describe(best) + } + case owner.kind == "" && owner.text == "PROJECTION": + names, nodes := projection(owner.parent) + for i, n := range nodes { + if n == sentinel && i < len(names) { + ac := column(names[i], sentinel.attrs["constant_value_type"]) + return ac + } + } + } + } + return column("", sentinel.attrs["constant_value_type"]) +} + +// describe turns a tree expression into a column description. +func (t *queryTree) describe(n *treeNode) analysis.Column { + switch n.kind { + case "COLUMN": + ac := column(n.attrs["column_name"], n.attrs["result_type"]) + ac.Table = t.sourceTable(n) + return ac + case "FUNCTION": + return column(n.attrs["function_name"], n.attrs["result_type"]) + case "CONSTANT": + // A constant folded from a function call, such as toDate(now()), + // still names the function, which is what a placeholder compared + // with it is named after. + name := "" + if fn := firstNode(n.section("EXPRESSION").childrenOrNil()); fn != nil && fn.kind == "FUNCTION" { + name = fn.attrs["function_name"] + } + return column(name, n.attrs["constant_value_type"]) + } + return analysis.Column{} +} + +var insertValuesRe = regexp.MustCompile(`(?is)^insert\s+into\s+(?:table\s+)?([\w.` + "`" + `"]+)\s*(?:\(([^)]*)\))?\s*(?:format\s+)?values\b`) + +// analyzeExec runs a statement that returns no rows. The only parameters it +// can describe are those of an INSERT ... VALUES, which map positionally +// onto the target columns reported by DESCRIBE TABLE. +func analyzeExec(ctx context.Context, l local, script, sql string, phs []placeholder, aq analysis.Query) (analysis.Query, error) { + m := insertValuesRe.FindStringSubmatch(sql) + if m != nil { + script += "DESCRIBE TABLE " + m[1] + ";\n" + } + results, err := l.run(ctx, script) + if err != nil { + return analysis.Query{}, err + } + + var targets []analysis.Column + if m != nil && len(results) == 1 { + byName := map[string]analysis.Column{} + var all []analysis.Column + table := strings.Trim(m[1][strings.LastIndexByte(m[1], '.')+1:], "`\"") + for _, row := range results[0].Data { + var name, typ string + json.Unmarshal(row["name"], &name) + json.Unmarshal(row["type"], &typ) + ac := column(name, typ) + ac.Table = table + byName[name] = ac + all = append(all, ac) + } + if strings.TrimSpace(m[2]) == "" { + targets = all + } else { + for _, name := range strings.Split(m[2], ",") { + targets = append(targets, byName[strings.Trim(strings.TrimSpace(name), "`\"")]) + } + } + } + for i, ph := range phs { + ac := analysis.Column{} + if len(targets) > 0 { + ac = targets[i%len(targets)] + } + if ph.Name != "" { + ac.Name = ph.Name + } + aq.Params = append(aq.Params, analysis.Param{Number: ph.Number, Column: ac}) + } + return aq, nil +} diff --git a/internal/goldeneye/clickhouse/check.go b/internal/goldeneye/clickhouse/check.go new file mode 100644 index 0000000..fab53b8 --- /dev/null +++ b/internal/goldeneye/clickhouse/check.go @@ -0,0 +1,43 @@ +package clickhouse + +import ( + "context" + "os" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/analysis" + "github.com/sqlc-dev/sqlc/internal/goldeneye/endtoend" +) + +// Analyze runs a case's queries through the clickhouse binary and returns +// the analysis in the JSON shape sqlc analyze prints. +func Analyze(ctx context.Context, binary string, c endtoend.Case) ([]byte, error) { + schema, err := os.ReadFile(c.Schema) + if err != nil { + return nil, err + } + var fixture []byte + if c.Fixture != "" { + if fixture, err = os.ReadFile(c.Fixture); err != nil { + return nil, err + } + } + queries, err := c.Queries() + if err != nil { + return nil, err + } + out, err := analyze(ctx, local{binary: binary}, string(schema), string(fixture), queries) + if err != nil { + return nil, err + } + return analysis.Encode(out) +} + +// Check compares what ClickHouse reports for a case with the output the +// case committed, returning a diff when they differ. +func Check(ctx context.Context, binary string, c endtoend.Case) (string, error) { + got, err := Analyze(ctx, binary, c) + if err != nil { + return "", err + } + return c.Compare(got) +} diff --git a/internal/goldeneye/clickhouse/clickhouse.go b/internal/goldeneye/clickhouse/clickhouse.go new file mode 100644 index 0000000..35bfb7c --- /dev/null +++ b/internal/goldeneye/clickhouse/clickhouse.go @@ -0,0 +1,146 @@ +// Package clickhouse generates the ClickHouse dialect seed under +// internal/engine/clickhouse/dialect from a clickhouse binary, run as an +// ephemeral `clickhouse local` process that needs no server. +// +// types.jsonl comes from system.data_type_families: every family that is not +// an alias becomes a type, the families that alias it become its aliases, +// and its category is decided by its name, since ClickHouse records no such +// thing. ClickHouse describes its functions no further than their names — +// system.functions carries no signatures — so functions.jsonl is written by +// hand and is not this package's business. +// +// The package also verifies the ClickHouse analyze cases under +// internal/endtoend/testdata against the same binary: each case's schema and +// fixture are loaded into a `clickhouse local` process and its queries run +// there. Result column types come from the executed query's result header, +// provenance from EXPLAIN QUERY TREE, and parameters from sentinel constants +// substituted for the placeholders, since ClickHouse itself never sees a ?. +// The answer is printed in the JSON shape sqlc analyze prints and compared +// with the case's committed stdout.json byte for byte. +// +// The binary is downloaded once per pinned version by Install, or supplied +// through the CLICKHOUSE environment variable. +package clickhouse + +import ( + "context" + "encoding/json" + "fmt" + "os/exec" + "sort" + "strings" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/dialect" +) + +// Engine is the name of the engine directory the dialect lives under. +const Engine = "clickhouse" + +// typeFamilies lists every data type ClickHouse knows and, for a spelling +// such as INT or VARCHAR, the type it stands for. +const typeFamilies = ` +SELECT name, alias_to +FROM system.data_type_families +ORDER BY name` + +// Version reports the release a binary is. +func Version(ctx context.Context, binary string) (string, error) { + out, err := exec.CommandContext(ctx, binary, "local", "--version").Output() + if err != nil { + return "", fmt.Errorf("clickhouse local --version: %w", err) + } + return strings.TrimSpace(string(out)), nil +} + +// Generate reads the dialect from the binary. +func Generate(ctx context.Context, binary string) (dialect.Files, error) { + results, err := local{binary: binary}.run(ctx, typeFamilies) + if err != nil { + return nil, err + } + if len(results) != 1 { + return nil, fmt.Errorf("clickhouse: expected one result set, got %d", len(results)) + } + var families []family + for _, row := range results[0].Data { + var f family + if err := json.Unmarshal(row["name"], &f.Name); err != nil { + return nil, fmt.Errorf("clickhouse: system.data_type_families: %w", err) + } + if err := json.Unmarshal(row["alias_to"], &f.AliasTo); err != nil { + return nil, fmt.Errorf("clickhouse: system.data_type_families: %w", err) + } + families = append(families, f) + } + types, err := dialect.JSONL(readTypes(families)) + if err != nil { + return nil, err + } + return dialect.Files{dialect.TypesFile: types}, nil +} + +type family struct { + Name string + AliasTo string +} + +// readTypes turns the families into types: one per family that is not an +// alias, carrying the spellings that alias it. The seed reads names without +// regard to case, so an alias that only differs in case from its type — +// bool for Bool, ENUM for Enum — is dropped. +func readTypes(families []family) []dialect.Type { + byName := map[string]*dialect.Type{} + var names []string + for _, f := range families { + if f.AliasTo != "" { + continue + } + byName[f.Name] = &dialect.Type{Name: f.Name, Category: category(f.Name)} + names = append(names, f.Name) + } + for _, f := range families { + if f.AliasTo == "" || strings.EqualFold(f.Name, f.AliasTo) { + continue + } + if t, ok := byName[f.AliasTo]; ok { + t.Aliases = append(t.Aliases, f.Name) + } + } + sort.Strings(names) + types := make([]dialect.Type, 0, len(names)) + for _, name := range names { + types = append(types, *byName[name]) + } + return types +} + +// category assigns a type the PostgreSQL category letter the seed package +// uses, by the family's name: N for numbers, B for booleans, S for strings +// and the identifiers stored as them, D for dates and times, T for time +// spans, A for arrays and U for everything else. +func category(name string) string { + switch { + case name == "Bool": + return "B" + case name == "Array": + return "A" + case strings.HasPrefix(name, "Interval"): + return "T" + case hasPrefix(name, "UInt", "Int", "Float", "BFloat", "Decimal"): + return "N" + case name == "String", name == "FixedString", name == "UUID", name == "IPv4", name == "IPv6": + return "S" + case hasPrefix(name, "Date", "Time"): + return "D" + } + return "U" +} + +func hasPrefix(name string, prefixes ...string) bool { + for _, prefix := range prefixes { + if strings.HasPrefix(name, prefix) { + return true + } + } + return false +} diff --git a/internal/goldeneye/clickhouse/clickhouse_test.go b/internal/goldeneye/clickhouse/clickhouse_test.go new file mode 100644 index 0000000..f4d58b8 --- /dev/null +++ b/internal/goldeneye/clickhouse/clickhouse_test.go @@ -0,0 +1,66 @@ +package clickhouse + +import ( + "context" + "testing" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/dialect" + "github.com/sqlc-dev/sqlc/internal/goldeneye/endtoend" +) + +// TestDialect verifies the committed ClickHouse dialect against what the +// pinned clickhouse binary reports. It skips unless the binary is installed. +func TestDialect(t *testing.T) { + binary, err := Locate() + if err != nil { + t.Skip(err) + } + ctx := context.Background() + version, err := Version(ctx, binary) + if err != nil { + t.Fatal(err) + } + files, err := Generate(ctx, binary) + if err != nil { + t.Fatal(err) + } + dir, err := dialect.Dir(Engine) + if err != nil { + t.Fatal(err) + } + report, err := dialect.Check(dir, files) + if err != nil { + t.Fatal(err) + } + if report != "" { + t.Errorf("%s does not match what %s reports:\n%s", dir, version, report) + } +} + +// TestAnalyzeCases verifies every ClickHouse analyze case under +// internal/endtoend/testdata against what ClickHouse reports. It skips +// unless the binary is installed. +func TestAnalyzeCases(t *testing.T) { + binary, err := Locate() + if err != nil { + t.Skip(err) + } + cases, err := endtoend.Cases(Engine) + if err != nil { + t.Fatal(err) + } + if len(cases) == 0 { + t.Fatal("no clickhouse analyze cases found") + } + for _, c := range cases { + t.Run(c.Name, func(t *testing.T) { + diff, err := Check(context.Background(), binary, c) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Errorf("%s does not match what ClickHouse reports (-committed +clickhouse):\n%s", c.Output, diff) + } + }) + } +} diff --git a/internal/goldeneye/clickhouse/install.go b/internal/goldeneye/clickhouse/install.go new file mode 100644 index 0000000..fb29df4 --- /dev/null +++ b/internal/goldeneye/clickhouse/install.go @@ -0,0 +1,221 @@ +package clickhouse + +import ( + "archive/tar" + "compress/gzip" + "context" + "crypto/sha512" + "encoding/hex" + "errors" + "fmt" + "io" + "net/http" + "os" + "path/filepath" + "strconv" + "strings" +) + +// DefaultVersion is the ClickHouse release the dialect is generated from. +// Bumping it is a deliberate change: the query tree format and type +// inference can shift between releases, so regenerate and review the dialect +// after changing it, and add the new release's assets to the table below. +const DefaultVersion = "25.8.2.29" + +// asset is one downloadable build of ClickHouse. Linux builds are published +// as clickhouse-common-static tarballs holding the binary at +// usr/bin/clickhouse; macOS builds are published as bare binaries. +type asset struct { + Version string + OS string + Arch string + Name string + SHA512 string +} + +// assets lists every build Install knows how to fetch, with the SHA-512 of +// the download. A version that is not in this table cannot be installed: +// verifying the download is the point of the table. +// +// The tarball checksums are the ones in the .sha512 files ClickHouse +// publishes next to them. ClickHouse publishes no checksum for the macOS +// binaries, so those were computed from the downloads. +var assets = []asset{ + {"25.8.2.29", "linux", "amd64", "clickhouse-common-static-25.8.2.29-amd64.tgz", "6ff0aa1ffac6e564970174422ecde0d645cdb96812247a6e544d39cad6d78a514265f90a2bc7b4bad49903cea96eddd16a415a45b2aeaf9164461be76331bdee"}, + {"25.8.2.29", "linux", "arm64", "clickhouse-common-static-25.8.2.29-arm64.tgz", "68204ca4d4e472790f808ee376251fae82e58066a31f35a40d15d442ce5988d697f18a1208d28b8bb8e2dfad4b20b7fcb5107e2178472abcd97251b8de7f058e"}, + {"25.8.2.29", "darwin", "amd64", "clickhouse-macos", "2805805ad2506e37a3e71b4ae9e797bdc010a9368dc28e99bcaaa2c70a72cfdd031c0fce8fc304248fad73211d28d645f75c6432cfae1e1e54d72d04e8626cd4"}, + {"25.8.2.29", "darwin", "arm64", "clickhouse-macos-aarch64", "4c9237e85c8d4e1aced2b339b32e086b4f23fa14f99754b056a7e33dda88c4fb5d52e09e29d20181ec5b580caadb00f36613802e71755ff34927535eb8babf79"}, +} + +// releaseTag returns the GitHub release tag for a version. ClickHouse tags +// its March and August releases as LTS and everything else as stable. +func releaseTag(version string) (string, error) { + parts := strings.Split(version, ".") + if len(parts) != 4 { + return "", fmt.Errorf("invalid ClickHouse version %q: want MAJOR.MINOR.PATCH.BUILD", version) + } + minor, err := strconv.Atoi(parts[1]) + if err != nil { + return "", fmt.Errorf("invalid ClickHouse version %q: %w", version, err) + } + suffix := "-stable" + if minor == 3 || minor == 8 { + suffix = "-lts" + } + return "v" + version + suffix, nil +} + +// releaseAsset finds the build for a platform in the table. +func releaseAsset(version, goos, goarch string) (asset, error) { + for _, a := range assets { + if a.Version == version && a.OS == goos && a.Arch == goarch { + return a, nil + } + } + for _, a := range assets { + if a.Version == version { + return asset{}, fmt.Errorf("no ClickHouse %s build is listed for %s/%s", version, goos, goarch) + } + } + return asset{}, fmt.Errorf("ClickHouse %s is not in the asset table; add its downloads and checksums to install.go", version) +} + +// url is the asset's download address on GitHub. +func (a asset) url() (string, error) { + tag, err := releaseTag(a.Version) + if err != nil { + return "", err + } + return "https://github.com/ClickHouse/ClickHouse/releases/download/" + tag + "/" + a.Name, nil +} + +// tarball reports whether the download is an archive rather than the binary. +func (a asset) tarball() bool { + return strings.HasSuffix(a.Name, ".tgz") +} + +// cachedBinary is where Install puts the binary for a version. +func cachedBinary(version string) (string, error) { + dir, err := os.UserCacheDir() + if err != nil { + return "", err + } + return filepath.Join(dir, "sqlc-clickhouse", version, "clickhouse"), nil +} + +// Locate finds a clickhouse binary: the CLICKHOUSE environment variable wins, +// then the cached copy of DefaultVersion. +func Locate() (string, error) { + if path := os.Getenv("CLICKHOUSE"); path != "" { + return path, nil + } + path, err := cachedBinary(DefaultVersion) + if err != nil { + return "", err + } + if _, err := os.Stat(path); err != nil { + return "", fmt.Errorf("clickhouse %s is not installed: run `go run ./cmd/goldeneye install clickhouse` in internal/goldeneye, or set CLICKHOUSE to a clickhouse binary", DefaultVersion) + } + return path, nil +} + +// Install downloads the clickhouse binary for a version into the cache and +// returns its path. It is a no-op when the version is already cached. The +// download is checked against the table's SHA-512 before it is installed. +func Install(ctx context.Context, version, goos, goarch string, progress io.Writer) (string, error) { + dest, err := cachedBinary(version) + if err != nil { + return "", err + } + if _, err := os.Stat(dest); err == nil { + return dest, nil + } + a, err := releaseAsset(version, goos, goarch) + if err != nil { + return "", err + } + url, err := a.url() + if err != nil { + return "", err + } + if err := os.MkdirAll(filepath.Dir(dest), 0o755); err != nil { + return "", err + } + + fmt.Fprintf(progress, "downloading %s\n", url) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + return "", err + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("downloading %s: %s", url, resp.Status) + } + + // Write next to the destination and rename so a partial or corrupt + // download never masquerades as an installed binary. + tmp, err := os.CreateTemp(filepath.Dir(dest), "clickhouse-*.partial") + if err != nil { + return "", err + } + defer os.Remove(tmp.Name()) + + // Hash every byte that comes off the wire, including the parts of a + // tarball after the binary, which extraction would otherwise not read. + sum := sha512.New() + body := io.TeeReader(resp.Body, sum) + var src io.Reader = body + if a.tarball() { + src, err = binaryInTarball(body) + if err != nil { + return "", fmt.Errorf("downloading %s: %w", url, err) + } + } + if _, err := io.Copy(tmp, src); err != nil { + tmp.Close() + return "", err + } + if _, err := io.Copy(io.Discard, body); err != nil { + tmp.Close() + return "", err + } + if err := tmp.Close(); err != nil { + return "", err + } + if got := hex.EncodeToString(sum.Sum(nil)); got != a.SHA512 { + return "", fmt.Errorf("downloading %s: SHA-512 mismatch: got %s, want %s", url, got, a.SHA512) + } + if err := os.Chmod(tmp.Name(), 0o755); err != nil { + return "", err + } + if err := os.Rename(tmp.Name(), dest); err != nil { + return "", err + } + return dest, nil +} + +// binaryInTarball positions a reader at the clickhouse binary inside a +// clickhouse-common-static tarball. +func binaryInTarball(r io.Reader) (io.Reader, error) { + gz, err := gzip.NewReader(r) + if err != nil { + return nil, err + } + tr := tar.NewReader(gz) + for { + hdr, err := tr.Next() + if errors.Is(err, io.EOF) { + return nil, errors.New("tarball does not contain usr/bin/clickhouse") + } + if err != nil { + return nil, err + } + if hdr.Typeflag == tar.TypeReg && strings.HasSuffix(hdr.Name, "/usr/bin/clickhouse") { + return tr, nil + } + } +} diff --git a/internal/goldeneye/clickhouse/local.go b/internal/goldeneye/clickhouse/local.go new file mode 100644 index 0000000..2a6d882 --- /dev/null +++ b/internal/goldeneye/clickhouse/local.go @@ -0,0 +1,82 @@ +package clickhouse + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "os" + "os/exec" + "path/filepath" + "strings" +) + +// local runs SQL through an ephemeral `clickhouse local` process. +type local struct { + binary string +} + +// resultSet is one JSON-format result printed by clickhouse local. Only +// statements that return rows print one; DDL and INSERT print nothing. +type resultSet struct { + Meta []resultColumn `json:"meta"` + Data []map[string]json.RawMessage `json:"data"` + Rows int `json:"rows"` +} + +type resultColumn struct { + Name string `json:"name"` + Type string `json:"type"` +} + +// run executes a multi-statement script in a fresh process with fresh +// storage and returns the result sets in statement order. Any statement +// failing fails the whole run with ClickHouse's own error message. +func (l local) run(ctx context.Context, script string) ([]resultSet, error) { + dir, err := os.MkdirTemp("", "sqlc-goldeneye-clickhouse-*") + if err != nil { + return nil, err + } + defer os.RemoveAll(dir) + + queries := filepath.Join(dir, "queries.sql") + if err := os.WriteFile(queries, []byte(script), 0o600); err != nil { + return nil, err + } + + // stdin must not be inherited: clickhouse local reads it as table data + // and blocks until it is closed. + cmd := exec.CommandContext(ctx, l.binary, "local", + "--multiquery", + "--queries-file", queries, + "--output-format", "JSON", + "--path", filepath.Join(dir, "data"), + ) + cmd.Stdin = nil + var stdout, stderr bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = &stderr + if err := cmd.Run(); err != nil { + msg := strings.TrimSpace(stderr.String()) + if msg == "" { + msg = err.Error() + } + return nil, errors.New(msg) + } + + var results []resultSet + dec := json.NewDecoder(&stdout) + for { + var rs resultSet + err := dec.Decode(&rs) + if errors.Is(err, io.EOF) { + return results, nil + } + if err != nil { + return nil, fmt.Errorf("decoding clickhouse local output: %w", err) + } + results = append(results, rs) + } +} diff --git a/internal/goldeneye/clickhouse/queries.go b/internal/goldeneye/clickhouse/queries.go new file mode 100644 index 0000000..a9f7787 --- /dev/null +++ b/internal/goldeneye/clickhouse/queries.go @@ -0,0 +1,68 @@ +package clickhouse + +import ( + "fmt" + "strings" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/endtoend" +) + +// placeholder is one parameter reference in a query, in order of appearance. +type placeholder struct { + Number int + Name string // sqlc.arg / sqlc.narg name, empty for ? +} + +// Placeholders are substituted with constant expressions that carry their +// ordinal, so they can be told apart from each other and from literal NULLs +// once ClickHouse has folded them: the query tree prints the expression a +// folded constant came from. NULL coerces to any type, so a comparison +// against it analyzes with the other operand's type. LIMIT and OFFSET +// reject NULL and only accept unsigned integers, so those get a value no +// query would plausibly contain. +const limitBase = "4294967295" + +func sentinelFor(lastWord string, ordinal int) string { + switch strings.ToLower(lastWord) { + case "limit", "offset": + return fmt.Sprintf("toUInt64(%s + %d)", limitBase, ordinal) + } + return fmt.Sprintf("(NULL + %d)", ordinal) +} + +// bindPlaceholders rewrites sqlc's parameter syntax (?, sqlc.arg(name), +// sqlc.narg(name)) into constants ClickHouse can analyze. ClickHouse binds +// every ? positionally, so each placeholder is its own parameter even when +// a name repeats, which is how sqlc numbers them too. +func bindPlaceholders(sql string) (string, []placeholder) { + var phs []placeholder + out := endtoend.Rewrite(sql, func(name, lastWord string) string { + phs = append(phs, placeholder{Number: len(phs) + 1, Name: name}) + return sentinelFor(lastWord, len(phs)) + }) + return out, phs +} + +func isWordByte(c byte) bool { + return c == '_' || c == '.' || c >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' +} + +// skipQuoted returns the index just past the quoted token starting at i, +// honouring backslash escapes and doubled quotes. +func skipQuoted(s string, i int) int { + q := s[i] + j := i + 1 + for j < len(s) { + switch { + case s[j] == '\\' && j+1 < len(s): + j += 2 + case s[j] == q && j+1 < len(s) && s[j+1] == q: + j += 2 + case s[j] == q: + return j + 1 + default: + j++ + } + } + return len(s) +} diff --git a/internal/goldeneye/clickhouse/tree.go b/internal/goldeneye/clickhouse/tree.go new file mode 100644 index 0000000..d0a8a38 --- /dev/null +++ b/internal/goldeneye/clickhouse/tree.go @@ -0,0 +1,236 @@ +package clickhouse + +import ( + "fmt" + "regexp" + "strconv" + "strings" +) + +// treeNode is one line of EXPLAIN QUERY TREE output. Lines of the form +// `KIND id: N, key: value, ...` are nodes with a kind and attributes; every +// other line (section headers such as PROJECTION or ARGUMENTS, and the +// `name Type` lines under PROJECTION COLUMNS) keeps only its text. +type treeNode struct { + kind string + id int + attrs map[string]string + text string + parent *treeNode + children []*treeNode +} + +// queryTree is a parsed EXPLAIN QUERY TREE dump. +type queryTree struct { + root *treeNode + byID map[int]*treeNode +} + +var nodeLineRe = regexp.MustCompile(`^([A-Z_]+) id: (\d+)(?:, (.*))?$`) + +// parseQueryTree builds the tree from the dump's lines, using the two-space +// indentation to recover nesting. +func parseQueryTree(lines []string) (*queryTree, error) { + root := &treeNode{id: -1, text: ""} + t := &queryTree{root: root, byID: map[int]*treeNode{}} + stack := []*treeNode{root} + for _, line := range lines { + if strings.TrimSpace(line) == "" { + continue + } + indent := len(line) - len(strings.TrimLeft(line, " ")) + if indent%2 != 0 { + return nil, fmt.Errorf("query tree: unexpected indentation in %q", line) + } + depth := indent/2 + 1 + if depth > len(stack) { + return nil, fmt.Errorf("query tree: line %q is nested too deeply", line) + } + stack = stack[:depth] + parent := stack[len(stack)-1] + + n := &treeNode{id: -1, text: line[indent:], parent: parent} + if m := nodeLineRe.FindStringSubmatch(n.text); m != nil { + n.kind = m[1] + n.id, _ = strconv.Atoi(m[2]) + n.attrs = parseAttrs(m[3]) + t.byID[n.id] = n + } + parent.children = append(parent.children, n) + stack = append(stack, n) + } + return t, nil +} + +var attrKeyRe = regexp.MustCompile(`^, ([a-z_]+): `) + +// parseAttrs splits `key: value, key: value` where values may themselves +// contain commas inside parentheses or quotes, as types and constants do. +func parseAttrs(s string) map[string]string { + attrs := map[string]string{} + if s == "" { + return attrs + } + // Positions at which a new `, key: ` begins at top level. + var cuts []int + depth := 0 + inQuote := false + for i := 0; i < len(s); i++ { + switch c := s[i]; { + case c == '\'': + inQuote = !inQuote + case inQuote: + case c == '(': + depth++ + case c == ')': + depth-- + case c == ',' && depth == 0 && attrKeyRe.MatchString(s[i:]): + cuts = append(cuts, i) + } + } + cuts = append(cuts, len(s)) + start := 0 + for _, cut := range cuts { + pair := s[start:cut] + if key, value, ok := strings.Cut(pair, ": "); ok { + attrs[key] = value + } + start = cut + 2 + } + return attrs +} + +// section returns the child section header of a node, such as PROJECTION +// or JOIN TREE, or nil. +func (n *treeNode) section(name string) *treeNode { + for _, c := range n.children { + if c.kind == "" && c.text == name { + return c + } + } + return nil +} + +// list returns the nodes of the LIST under a section header. +func (n *treeNode) list() []*treeNode { + if n == nil { + return nil + } + for _, c := range n.children { + if c.kind == "LIST" { + return c.children + } + } + return nil +} + +// firstQuery returns the QUERY node describing a result set: the node itself +// or, for a UNION, its first branch, whose projection names the union's +// columns. +func firstQuery(n *treeNode) *treeNode { + for depth := 0; n != nil && depth < 32; depth++ { + switch n.kind { + case "QUERY": + return n + case "UNION": + n = firstNode(n.section("QUERIES").list()) + default: + return nil + } + } + return nil +} + +func firstNode(nodes []*treeNode) *treeNode { + if len(nodes) == 0 { + return nil + } + return nodes[0] +} + +// projection returns the output column names of a query and the expression +// node producing each, in order. +func projection(q *treeNode) (names []string, nodes []*treeNode) { + q = firstQuery(q) + if q == nil { + return nil, nil + } + if cols := q.section("PROJECTION COLUMNS"); cols != nil { + for _, c := range cols.children { + names = append(names, projectedName(c.text)) + } + } + return names, q.section("PROJECTION").list() +} + +// projectedName strips the trailing type from a `name Type` line. The type +// is a single token that may carry a parenthesised argument list; the name +// may contain spaces of its own, as `plus(id, 1)` does. +func projectedName(line string) string { + end := len(line) + if strings.HasSuffix(line, ")") { + depth := 0 + for end > 0 { + end-- + if line[end] == ')' { + depth++ + } else if line[end] == '(' { + depth-- + if depth == 0 { + break + } + } + } + } + for end > 0 && isWordByte(line[end-1]) { + end-- + } + return strings.TrimSpace(line[:end]) +} + +// sourceTable resolves a COLUMN node to the table it reads from, following +// column references through subqueries and CTEs. Columns computed by an +// expression have no source and yield "". +func (t *queryTree) sourceTable(col *treeNode) string { + for depth := 0; col != nil && col.kind == "COLUMN" && depth < 32; depth++ { + id, err := strconv.Atoi(col.attrs["source_id"]) + if err != nil { + return "" + } + src := t.byID[id] + if src == nil { + return "" + } + switch src.kind { + case "TABLE": + name := src.attrs["table_name"] + if i := strings.LastIndexByte(name, '.'); i >= 0 { + name = name[i+1:] + } + return name + case "QUERY", "UNION": + // The column is one of the subquery's output columns; keep + // following whatever expression produces it there. + want := col.attrs["column_name"] + names, nodes := projection(src) + col = nil + for i, name := range names { + if name == want && i < len(nodes) { + col = nodes[i] + break + } + } + default: + return "" + } + } + return "" +} + +// childrenOrNil returns a node's children, tolerating a nil node. +func (n *treeNode) childrenOrNil() []*treeNode { + if n == nil { + return nil + } + return n.children +} diff --git a/internal/goldeneye/clickhouse/types.go b/internal/goldeneye/clickhouse/types.go new file mode 100644 index 0000000..96de512 --- /dev/null +++ b/internal/goldeneye/clickhouse/types.go @@ -0,0 +1,160 @@ +package clickhouse + +import ( + "strconv" + "strings" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/analysis" +) + +// A type is a call expression, the way ClickHouse itself models one: a +// lowercased name applied to an ordered argument list. Each argument is +// another type, an integer, a boolean or a quoted string, optionally +// labelled, so Array, Map and LowCardinality are ordinary names and nothing +// about a nested type is lost. Nullability is an attribute of a type rather +// than a wrapper, since every engine has it and only ClickHouse spells it as +// a type: Nullable(T) becomes T with nullable set, at whatever depth it +// appears. The shape maps one to one onto a protobuf message with a oneof +// for the argument value: +// +// Map(String, Nullable(UInt32)) +// {"name": "map", "args": [ +// {"type": {"name": "string"}}, +// {"type": {"name": "uint32", "nullable": true}}]} +// +// Tuple(lat Float64, lon Float64) +// {"name": "tuple", "args": [ +// {"label": "lat", "type": {"name": "float64"}}, +// {"label": "lon", "type": {"name": "float64"}}]} +// +// Enum8('a' = 1, 'b' = 2) +// {"name": "enum8", "args": [{"label": "a", "int": 1}, {"label": "b", "int": 2}]} +// +// DateTime64(3, 'UTC') +// {"name": "datetime64", "args": [{"int": 3}, {"string": "UTC"}]} +// +// An identifier argument such as the function in AggregateFunction(uniq, +// String) is a word rather than a type. Resolving names against the +// catalog is the reader's job; the output only records what was said. + +// parseType turns a ClickHouse type string into its expression. +func parseType(t string) *analysis.TypeExpr { + name, args := splitType(t) + name = strings.ToLower(strings.TrimSpace(name)) + if name == "nullable" && len(args) == 1 { + expr := parseType(args[0]) + expr.Nullable = true + return expr + } + if name == "" { + name = "nothing" + } + expr := &analysis.TypeExpr{Name: name} + for _, a := range args { + expr.Args = append(expr.Args, parseArg(a)) + } + // LowCardinality(Nullable(T)) is the only order ClickHouse accepts for + // a nullable low-cardinality column, and the nullability is the + // column's: it reads as a nullable LowCardinality(T). + if name == "lowcardinality" && len(expr.Args) == 1 && expr.Args[0].Type != nil && expr.Args[0].Type.Nullable { + expr.Nullable = true + expr.Args[0].Type.Nullable = false + } + // The function an aggregate-function type names is a word, not a type. + if name == "aggregatefunction" || name == "simpleaggregatefunction" { + if len(expr.Args) > 0 && expr.Args[0].Type != nil && len(expr.Args[0].Type.Args) == 0 { + fn := expr.Args[0].Type.Name + expr.Args[0] = analysis.TypeArg{Ident: &fn} + } + } + return expr +} + +// parseArg parses one argument: a quoted string, an integer, a boolean, a +// labelled argument (`lat Float64` in a Tuple, `'a' = 1` in an Enum), or a +// type. +func parseArg(a string) analysis.TypeArg { + a = strings.TrimSpace(a) + if strings.HasPrefix(a, "'") { + end := skipQuoted(a, 0) + lit := unquote(a[1 : end-1]) + if rest := strings.TrimSpace(a[end:]); strings.HasPrefix(rest, "=") { + arg := parseArg(rest[1:]) + arg.Label = lit + return arg + } + return analysis.TypeArg{String: &lit} + } + if n, err := strconv.ParseInt(a, 10, 64); err == nil { + return analysis.TypeArg{Int: &n} + } + switch strings.ToLower(a) { + case "true", "false": + b := strings.EqualFold(a, "true") + return analysis.TypeArg{Bool: &b} + } + if i := labelEnd(a); i > 0 { + arg := parseArg(a[i+1:]) + arg.Label = a[:i] + return arg + } + return analysis.TypeArg{Type: parseType(a)} +} + +// labelEnd returns the index of the space separating a label from the type +// it labels, or -1 when the argument has no label: a space that comes before +// any parenthesis, as in `lat Float64` or `tags Array(String)`. +func labelEnd(a string) int { + head := a + if p := strings.IndexByte(a, '('); p >= 0 { + head = a[:p] + } + return strings.IndexByte(head, ' ') +} + +// unquote undoes the escaping inside a single-quoted ClickHouse literal. +func unquote(s string) string { + s = strings.ReplaceAll(s, `\'`, `'`) + s = strings.ReplaceAll(s, `''`, `'`) + return strings.ReplaceAll(s, `\\`, `\`) +} + +// splitType splits `Base(arg, arg)` into its base name and top-level +// arguments, leaving nested parentheses and quoted strings intact. +func splitType(t string) (string, []string) { + t = strings.TrimSpace(t) + open := strings.IndexByte(t, '(') + if open < 0 || !strings.HasSuffix(t, ")") { + return t, nil + } + base := strings.TrimSpace(t[:open]) + inner := t[open+1 : len(t)-1] + var ( + args []string + depth int + quote byte + start int + ) + for i := 0; i < len(inner); i++ { + c := inner[i] + switch { + case quote != 0: + if c == '\\' { + i++ + } else if c == quote { + quote = 0 + } + case c == '\'' || c == '"' || c == '`': + quote = c + case c == '(': + depth++ + case c == ')': + depth-- + case c == ',' && depth == 0: + args = append(args, strings.TrimSpace(inner[start:i])) + start = i + 1 + } + } + args = append(args, strings.TrimSpace(inner[start:])) + return base, args +} diff --git a/internal/goldeneye/cmd/goldeneye/main.go b/internal/goldeneye/cmd/goldeneye/main.go new file mode 100644 index 0000000..2eb6f80 --- /dev/null +++ b/internal/goldeneye/cmd/goldeneye/main.go @@ -0,0 +1,277 @@ +// Command goldeneye generates the dialect seeds under +// internal/engine//dialect from a live database, checks the +// committed ones against it, and checks the analyze cases under +// internal/endtoend/testdata against what the database itself reports. +// +// Usage, from internal/goldeneye: +// +// go run ./cmd/goldeneye install clickhouse # download the pinned clickhouse binary +// go run ./cmd/goldeneye install duckdb # download the current DuckDB 2.0 preview build +// go run ./cmd/goldeneye install sqlite # build the pinned sqlite3 shells from source +// go run ./cmd/goldeneye generate [engine] # rewrite the generated files from the database +// go run ./cmd/goldeneye check [engine] # compare the committed files and analyze cases with the database +// +// Without an engine, generate and check cover every engine whose database +// is available and say which ones they skipped. `go test ./...` runs the +// same checks as tests. +package main + +import ( + "context" + "errors" + "flag" + "fmt" + "io" + "os" + "runtime" + "strings" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/clickhouse" + "github.com/sqlc-dev/sqlc/internal/goldeneye/dialect" + "github.com/sqlc-dev/sqlc/internal/goldeneye/duckdb" + "github.com/sqlc-dev/sqlc/internal/goldeneye/endtoend" + "github.com/sqlc-dev/sqlc/internal/goldeneye/mssql" + "github.com/sqlc-dev/sqlc/internal/goldeneye/mysql" + "github.com/sqlc-dev/sqlc/internal/goldeneye/postgresql" + "github.com/sqlc-dev/sqlc/internal/goldeneye/spanner" + "github.com/sqlc-dev/sqlc/internal/goldeneye/sqlite" +) + +func main() { + if err := run(context.Background(), os.Args[1:], os.Stdout, os.Stderr); err != nil { + fmt.Fprintln(os.Stderr, "goldeneye:", err) + os.Exit(1) + } +} + +const usage = `usage: + goldeneye install clickhouse|duckdb|sqlite [-version V] + put the pinned release of an engine into the user cache directory: clickhouse is + downloaded, duckdb is downloaded from its v2.0 preview channel, sqlite is built from + the downloaded amalgamation with cc or $CC + goldeneye generate [engine] + rewrite the generated dialect files from the database, for every available engine or one + goldeneye check [engine] + compare the committed dialect files and analyze cases with the database, for every available engine or one + postgresql, mysql, mssql and spanner read the server POSTGRESQL_SERVER_URI, MYSQL_SERVER_URI, + MSSQL_SERVER_URI and SPANNER_SERVER_URI name + +engines: clickhouse, duckdb, mssql, mysql, postgresql, spanner, sqlite` + +// engine is one database goldeneye knows how to read a dialect from. +type engine struct { + name string + // dir is the engine directory the dialect lives under, when it is not + // named after the engine: MySQL's is dolphin, after its parser, and + // Spanner's is googlesql, after the language. + dir string + // cases is the name of the analyze case directories under + // internal/endtoend/testdata, when it is not the engine's name: + // Spanner's are googlesql's. + cases string + // locate finds the database — a binary or a connection URL — or says + // why it is not available. + locate func() (string, error) + // version describes the release the database is, for the log. + version func(context.Context, string) (string, error) + // generate reads the dialect from the database. + generate func(context.Context, string) (dialect.Files, error) + // analyze asks the database what it reports for an analyze case, in + // the shape sqlc analyze prints. Nil for an engine without one yet. + analyze func(context.Context, string, endtoend.Case) ([]byte, error) +} + +var engines = []engine{ + {clickhouse.Engine, "", "", clickhouse.Locate, clickhouse.Version, clickhouse.Generate, clickhouse.Analyze}, + {duckdb.Engine, "", "", duckdb.Locate, duckdb.Version, duckdb.Generate, duckdb.Analyze}, + {mssql.Engine, "", "", mssql.Locate, mssql.Version, mssql.Generate, mssql.Analyze}, + {mysql.Engine, mysql.Dir, "", mysql.Locate, mysql.Version, mysql.Generate, mysql.Analyze}, + {postgresql.Engine, "", "", postgresql.Locate, postgresql.Version, postgresql.Generate, nil}, + {spanner.Engine, spanner.Dir, spanner.Cases, spanner.Locate, spanner.Version, spanner.Generate, spanner.Analyze}, + {sqlite.Engine, "", "", sqlite.Locate, sqlite.Version, sqlite.Generate, sqlite.Analyze}, +} + +// dialectDir returns the engine's dialect directory. +func (e engine) dialectDir() (string, error) { + if e.dir != "" { + return dialect.Dir(e.dir) + } + return dialect.Dir(e.name) +} + +// installer puts the binary an engine is read through in place, for the +// engines that need no server and whose release is pinned in their package. +type installer struct { + defaultVersion string + install func(ctx context.Context, version, goos, goarch string, progress io.Writer) (string, error) +} + +var installers = map[string]installer{ + clickhouse.Engine: {clickhouse.DefaultVersion, clickhouse.Install}, + duckdb.Engine: {duckdb.DefaultVersion, duckdb.Install}, + sqlite.Engine: {sqlite.DefaultVersion, sqlite.Install}, +} + +func run(ctx context.Context, args []string, stdout, stderr io.Writer) error { + if len(args) == 0 { + fmt.Fprintln(stderr, usage) + return errors.New("a command is required") + } + switch args[0] { + case "install": + return install(ctx, args[1:], stdout, stderr) + case "generate": + return forEach(ctx, args[1:], stderr, generate) + case "check": + return forEach(ctx, args[1:], stderr, check) + case "help", "-h", "--help": + fmt.Fprintln(stdout, usage) + return nil + } + fmt.Fprintln(stderr, usage) + return fmt.Errorf("unknown command %q", args[0]) +} + +func install(ctx context.Context, args []string, stdout, stderr io.Writer) error { + if len(args) == 0 { + return errors.New("install takes the engine to install: clickhouse, duckdb or sqlite") + } + inst, ok := installers[args[0]] + if !ok { + return fmt.Errorf("install takes the engine to install, clickhouse, duckdb or sqlite, not %q", args[0]) + } + fs := flag.NewFlagSet("install "+args[0], flag.ContinueOnError) + fs.SetOutput(stderr) + version := fs.String("version", inst.defaultVersion, args[0]+" release to install") + if err := fs.Parse(args[1:]); err != nil { + return err + } + path, err := inst.install(ctx, *version, runtime.GOOS, runtime.GOARCH, stderr) + if err != nil { + return err + } + fmt.Fprintln(stdout, path) + return nil +} + +// forEach runs a command over the named engine, or over every engine that +// is available when none is named. An engine that is named has to be +// available; one that is not named is skipped with a note when it is not. +func forEach(ctx context.Context, args []string, stderr io.Writer, cmd func(context.Context, engine, string, io.Writer) error) error { + if len(args) > 1 { + return errors.New("at most one engine may be named") + } + name := "" + if len(args) == 1 { + name = args[0] + } + found := false + var failed []string + for _, e := range engines { + if name != "" && e.name != name { + continue + } + found = true + handle, err := e.locate() + if err != nil { + if name != "" { + return err + } + fmt.Fprintf(stderr, "skipping %s: %v\n", e.name, err) + continue + } + if err := cmd(ctx, e, handle, stderr); err != nil { + fmt.Fprintf(stderr, "%s: %v\n", e.name, err) + failed = append(failed, e.name) + } + } + if !found { + return fmt.Errorf("unknown engine %q", name) + } + if len(failed) > 0 { + return fmt.Errorf("%d engine(s) failed: %v", len(failed), failed) + } + return nil +} + +func generate(ctx context.Context, e engine, handle string, stderr io.Writer) error { + version, err := e.version(ctx, handle) + if err != nil { + return err + } + fmt.Fprintf(stderr, "%s: generating from %s\n", e.name, version) + files, err := e.generate(ctx, handle) + if err != nil { + return err + } + dir, err := e.dialectDir() + if err != nil { + return err + } + if err := dialect.Write(dir, files); err != nil { + return err + } + fmt.Fprintf(stderr, "%s: wrote %d file(s) to %s\n", e.name, len(files), dir) + return nil +} + +func check(ctx context.Context, e engine, handle string, stderr io.Writer) error { + version, err := e.version(ctx, handle) + if err != nil { + return err + } + fmt.Fprintf(stderr, "%s: checking against %s\n", e.name, version) + files, err := e.generate(ctx, handle) + if err != nil { + return err + } + dir, err := e.dialectDir() + if err != nil { + return err + } + report, err := dialect.Check(dir, files) + if err != nil { + return err + } + if report != "" { + return fmt.Errorf("%s does not match the database\n%s", dir, report) + } + fmt.Fprintf(stderr, "%s: ok, %d file(s) match\n", e.name, len(files)) + return checkAnalyzeCases(ctx, e, handle, stderr) +} + +// checkAnalyzeCases compares what the database reports for each of the +// engine's analyze cases with the case's committed output. +func checkAnalyzeCases(ctx context.Context, e engine, handle string, stderr io.Writer) error { + if e.analyze == nil { + return nil + } + name := e.cases + if name == "" { + name = e.name + } + cases, err := endtoend.Cases(name) + if err != nil { + return err + } + var report strings.Builder + for _, c := range cases { + got, err := e.analyze(ctx, handle, c) + if err != nil { + fmt.Fprintf(&report, "%s: %v\n", c.Name, err) + continue + } + diff, err := c.Compare(got) + if err != nil { + return err + } + if diff != "" { + fmt.Fprintf(&report, "%s (-committed +database)\n%s", c.Name, diff) + } + } + if report.Len() > 0 { + return fmt.Errorf("analyze cases do not match the database\n%s", report.String()) + } + fmt.Fprintf(stderr, "%s: ok, %d analyze case(s) match\n", e.name, len(cases)) + return nil +} diff --git a/internal/goldeneye/dialect/dialect.go b/internal/goldeneye/dialect/dialect.go new file mode 100644 index 0000000..6085ec9 --- /dev/null +++ b/internal/goldeneye/dialect/dialect.go @@ -0,0 +1,303 @@ +// Package dialect describes the files a dialect seed is made of — the JSONL +// records under internal/engine//dialect that give an engine its +// type system and standard library — and provides what a generator needs to +// write them and a check needs to compare them with what is committed. +// +// The record types mirror the ones in internal/core/seed, which reads the +// files. They are repeated here rather than imported so that this module +// never shares code with the analysis it checks: the files are the contract, +// and a change to their shape has to be made on both sides. +package dialect + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "os" + "path/filepath" + "runtime" + "sort" + "strings" +) + +// The files a dialect directory is made of. +const ( + SettingsFile = "dialect.json" + TypesFile = "types.jsonl" + OperatorsFile = "operators.jsonl" + CastsFile = "casts.jsonl" + FunctionsFile = "functions.jsonl" + RelationsFile = "relations.jsonl" +) + +// ExtensionsDir is the directory under a dialect holding one directory per +// extension the dialect knows, each a smaller bundle of the same files. +const ExtensionsDir = "extensions" + +// Type is a type the dialect defines. Aliases are spellings of the same type +// that a schema may use in a column definition. +type Type struct { + Name string `json:"name"` + Category string `json:"category"` + Aliases []string `json:"aliases,omitempty"` +} + +// Operator is a single operator overload. +type Operator struct { + Name string `json:"name"` + Left string `json:"left"` + Right string `json:"right"` + Result string `json:"result"` +} + +// Cast is a single cast between two types. Context is 'i'mplicit, +// 'a'ssignment or 'e'xplicit. +type Cast struct { + Source string `json:"source"` + Target string `json:"target"` + Context string `json:"context,omitempty"` +} + +// Function is a function the dialect ships with. Kind is 'f'unction, +// 'a'ggregate, 'w'indow or 'p'rocedure. +type Function struct { + Name string `json:"name"` + Kind string `json:"kind,omitempty"` + Args []Arg `json:"args,omitempty"` + Returns string `json:"returns"` + Nullable bool `json:"nullable,omitempty"` +} + +// Arg is one of a function's parameters. Mode is 'i'n, 'o'ut, 'b'oth, +// 't'able or 'v'ariadic, and defaults to in. +type Arg struct { + Name string `json:"name,omitempty"` + Type string `json:"type"` + Mode string `json:"mode,omitempty"` + HasDefault bool `json:"has_default,omitempty"` +} + +// Relation is a table or view the dialect ships with, such as one of +// PostgreSQL's system catalogs. Kind is 'r' for a table or 'v' for a view, +// and defaults to a table. +type Relation struct { + Catalog string `json:"catalog,omitempty"` + Schema string `json:"schema"` + Name string `json:"name"` + Kind string `json:"kind,omitempty"` + Columns []Column `json:"columns"` +} + +// Column is one of a relation's columns. +type Column struct { + Name string `json:"name"` + Type string `json:"type"` + NotNull bool `json:"not_null,omitempty"` + Array bool `json:"array,omitempty"` + Length int `json:"length,omitempty"` +} + +// Files is what a generator produces: the content of each file it writes, +// keyed by slash-separated path relative to the dialect directory, such as +// "functions.jsonl" or "extensions/hstore/types.jsonl". A generator owns +// only the files it produces; the rest of a dialect, dialect.json above all, +// is written by hand and is neither generated nor checked. +type Files map[string][]byte + +// JSONL encodes records one per line, the way the committed files are +// written: encoding/json's compact form, with a newline after each record. +func JSONL[T any](records []T) ([]byte, error) { + var buf bytes.Buffer + enc := json.NewEncoder(&buf) + for _, record := range records { + if err := enc.Encode(record); err != nil { + return nil, err + } + } + return buf.Bytes(), nil +} + +// ReadTypes reads the hand-written types.jsonl of a dialect directory, for +// a generator that writes a function once per spelling of a type. +func ReadTypes(dir string) ([]Type, error) { + blob, err := os.ReadFile(filepath.Join(dir, TypesFile)) + if err != nil { + return nil, err + } + var types []Type + dec := json.NewDecoder(bytes.NewReader(blob)) + for dec.More() { + var t Type + if err := dec.Decode(&t); err != nil { + return nil, fmt.Errorf("%s: %w", filepath.Join(dir, TypesFile), err) + } + types = append(types, t) + } + return types, nil +} + +// Dir returns the dialect directory of an engine, +// internal/engine//dialect, found relative to this source file so +// the working directory does not matter. +func Dir(engine string) (string, error) { + _, file, _, ok := runtime.Caller(0) + if !ok { + return "", errors.New("cannot locate the goldeneye source directory") + } + dir := filepath.Join(filepath.Dir(file), "..", "..", "engine", engine, "dialect") + if _, err := os.Stat(dir); err != nil { + return "", err + } + return filepath.Clean(dir), nil +} + +// Names lists the files in name order, so that a run is reported and +// written the same way every time. +func (f Files) Names() []string { + names := make([]string, 0, len(f)) + for name := range f { + names = append(names, name) + } + sort.Strings(names) + return names +} + +// Write writes the files into dir, creating extension directories as +// needed. Files the generator did not produce are left alone. +func Write(dir string, files Files) error { + for _, name := range files.Names() { + path := filepath.Join(dir, filepath.FromSlash(name)) + if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { + return err + } + if err := os.WriteFile(path, files[name], 0o644); err != nil { + return err + } + } + return nil +} + +// Check compares the files with the ones committed in dir and returns a +// report of every file that differs, or "" when each matches byte for byte. +func Check(dir string, files Files) (string, error) { + var report strings.Builder + for _, name := range files.Names() { + want, err := os.ReadFile(filepath.Join(dir, filepath.FromSlash(name))) + if errors.Is(err, os.ErrNotExist) { + fmt.Fprintf(&report, "%s: not committed\n", name) + continue + } + if err != nil { + return "", err + } + if bytes.Equal(want, files[name]) { + continue + } + fmt.Fprintf(&report, "%s (-committed +database)\n%s", name, Diff(string(want), string(files[name]))) + } + return report.String(), nil +} + +// Diff is a line diff of two texts, marking lines only in want with "-" and +// lines only in got with "+", showing two lines of context around each +// change and eliding the rest. The committed files run to thousands of +// lines and usually differ in a handful, so the common head and tail are +// stripped before the longest common subsequence of the middle is found. +func Diff(want, got string) string { + a := lines(want) + b := lines(got) + head := 0 + for head < len(a) && head < len(b) && a[head] == b[head] { + head++ + } + tail := 0 + for tail < len(a)-head && tail < len(b)-head && a[len(a)-1-tail] == b[len(b)-1-tail] { + tail++ + } + var edits []edit + for _, line := range a[:head] { + edits = append(edits, edit{' ', line}) + } + edits = append(edits, lcsEdits(a[head:len(a)-tail], b[head:len(b)-tail])...) + for _, line := range a[len(a)-tail:] { + edits = append(edits, edit{' ', line}) + } + + const context = 2 + show := make([]bool, len(edits)) + for i, e := range edits { + if e.kind == ' ' { + continue + } + for j := max(0, i-context); j <= min(len(edits)-1, i+context); j++ { + show[j] = true + } + } + var out strings.Builder + elided := false + for i, e := range edits { + if !show[i] { + elided = true + continue + } + if elided && out.Len() > 0 { + out.WriteString("...\n") + } + elided = false + fmt.Fprintf(&out, "%c %s\n", e.kind, e.line) + } + return out.String() +} + +type edit struct { + kind byte // ' ', '-' or '+' + line string +} + +func lines(s string) []string { + if s == "" { + return nil + } + return strings.Split(strings.TrimSuffix(s, "\n"), "\n") +} + +// lcsEdits is the edit script between a and b by longest common subsequence. +func lcsEdits(a, b []string) []edit { + lcs := make([][]int, len(a)+1) + for i := range lcs { + lcs[i] = make([]int, len(b)+1) + } + for i := len(a) - 1; i >= 0; i-- { + for j := len(b) - 1; j >= 0; j-- { + if a[i] == b[j] { + lcs[i][j] = lcs[i+1][j+1] + 1 + } else { + lcs[i][j] = max(lcs[i+1][j], lcs[i][j+1]) + } + } + } + var edits []edit + i, j := 0, 0 + for i < len(a) && j < len(b) { + switch { + case a[i] == b[j]: + edits = append(edits, edit{' ', a[i]}) + i++ + j++ + case lcs[i+1][j] >= lcs[i][j+1]: + edits = append(edits, edit{'-', a[i]}) + i++ + default: + edits = append(edits, edit{'+', b[j]}) + j++ + } + } + for ; i < len(a); i++ { + edits = append(edits, edit{'-', a[i]}) + } + for ; j < len(b); j++ { + edits = append(edits, edit{'+', b[j]}) + } + return edits +} diff --git a/internal/goldeneye/duckdb/analyze.go b/internal/goldeneye/duckdb/analyze.go new file mode 100644 index 0000000..08283ae --- /dev/null +++ b/internal/goldeneye/duckdb/analyze.go @@ -0,0 +1,846 @@ +package duckdb + +import ( + "bytes" + "context" + "encoding/csv" + "encoding/json" + "errors" + "fmt" + "io" + "os" + "os/exec" + "regexp" + "strconv" + "strings" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/analysis" + "github.com/sqlc-dev/sqlc/internal/goldeneye/dialect" + "github.com/sqlc-dev/sqlc/internal/goldeneye/endtoend" +) + +// The analyze cases are checked against the DuckDB CLI, which runs each +// case's schema and fixture into an in-memory database of their own, one +// process per question, and is asked four things about each query. What +// its parameters are: the query is prepared and explained, as JSON, with +// a string sentinel bound to each parameter, and the unoptimized logical +// plan the CLI prints first shows each as CAST('goldeneye_k' AS T), T +// being the type the binder gave the parameter, or bare when that type +// is VARCHAR. What its result columns are: +// DESCRIBE, with each parameter replaced by a NULL of that type, names and +// types them. Which column each is read from and which column a parameter +// stands in for: DuckDB prints a plan with every column by its bare name, +// so these are read from the query text, the select list's items and the +// operand beside each parameter resolved against the FROM clause and the +// catalog, from which a column read from a table takes its declared type +// and nullability. And whether an expression can be NULL, which DuckDB +// does not track: the query is run, with each parameter bound to a value +// of its type, over the fixture and over no rows, and a column is nullable +// when either run returns a NULL for it. + +// placeholder is one parameter of a query as sqlc numbers them: a $n by +// its number, and each $name, sqlc.arg name or ? in turn at its first +// appearance, taking the lowest number no $n took. +type placeholder struct { + Number int + Name string +} + +var ( + numberedRe = regexp.MustCompile(`^\$([0-9]+)`) + namedRe = regexp.MustCompile(`^\$([A-Za-z_][A-Za-z0-9_]*)`) + sqlcArgRe = regexp.MustCompile(`^sqlc\.(n?arg|slice)\(\s*'?([A-Za-z_][A-Za-z0-9_]*)'?\s*\)`) +) + +// bind rewrites the query so that every parameter is a $k numbered as +// sqlc numbers it, and lists the parameters in that order. +func bind(query string) (string, []placeholder) { + type occurrence struct { + start, end int + number int // for $n + name string // for $name or sqlc.arg, "" for ? + } + var occ []occurrence + i := 0 + for i < len(query) { + c := query[i] + switch { + case c == '\'' || c == '"': + i = quotedEnd(query, i) + case strings.HasPrefix(query[i:], "--"): + end := strings.IndexByte(query[i:], '\n') + if end < 0 { + i = len(query) + } else { + i += end + } + case strings.HasPrefix(query[i:], "/*"): + end := strings.Index(query[i:], "*/") + if end < 0 { + i = len(query) + } else { + i += end + 2 + } + case c == '?': + occ = append(occ, occurrence{start: i, end: i + 1}) + i++ + case c == '$' && numberedRe.MatchString(query[i:]): + m := numberedRe.FindStringSubmatch(query[i:]) + n, _ := strconv.Atoi(m[1]) + occ = append(occ, occurrence{start: i, end: i + len(m[0]), number: n}) + i += len(m[0]) + case c == '$' && namedRe.MatchString(query[i:]): + m := namedRe.FindStringSubmatch(query[i:]) + occ = append(occ, occurrence{start: i, end: i + len(m[0]), name: m[1]}) + i += len(m[0]) + case c == 's' && sqlcArgRe.MatchString(query[i:]): + m := sqlcArgRe.FindStringSubmatch(query[i:]) + occ = append(occ, occurrence{start: i, end: i + len(m[0]), name: m[2]}) + i += len(m[0]) + default: + i++ + } + } + taken := map[int]bool{} + for _, o := range occ { + if o.number > 0 { + taken[o.number] = true + } + } + byName := map[string]int{} + next := 1 + assign := func(o occurrence) int { + if o.number > 0 { + return o.number + } + if n, ok := byName[o.name]; ok && o.name != "" { + return n + } + for taken[next] { + next++ + } + n := next + taken[n] = true + if o.name != "" { + byName[o.name] = n + } + return n + } + var phs []placeholder + numbered := map[int]bool{} + var out strings.Builder + last := 0 + for _, o := range occ { + n := assign(o) + if !numbered[n] { + numbered[n] = true + phs = append(phs, placeholder{Number: n, Name: o.name}) + } + out.WriteString(query[last:o.start]) + out.WriteString("$" + strconv.Itoa(n)) + last = o.end + } + out.WriteString(query[last:]) + for i := 1; i < len(phs); i++ { + for j := i; j > 0 && phs[j-1].Number > phs[j].Number; j-- { + phs[j-1], phs[j] = phs[j], phs[j-1] + } + } + return out.String(), phs +} + +// nullMarker is what a NULL is printed as when the CLI prints CSV, unlike +// any value a case holds. +const nullMarker = "" + +// analyzer holds the CLI a case runs through, the case's schema and +// fixture, and the catalog of the schema. +type analyzer struct { + binary string + schema string // the schema's statements, each ending in ; + fixture string // the fixture's, or "" + tables map[string][]column + enums map[string][]string // the labels of each enum type the schema created + // canonical names the type the dialect reports a spelling as, for + // each alias types.jsonl lists: DuckDB spells a JSON column json, + // which its own catalog lists as a spelling of varchar. + canonical map[string]string +} + +// readAliases reads the aliases the generated types.jsonl gives each +// type, keyed by alias. +func readAliases() (map[string]string, error) { + dir, err := dialect.Dir(Engine) + if err != nil { + return nil, err + } + types, err := dialect.ReadTypes(dir) + if err != nil { + return nil, err + } + canonical := map[string]string{} + for _, t := range types { + for _, alias := range t.Aliases { + canonical[strings.ToLower(alias)] = strings.ToLower(t.Name) + } + } + return canonical, nil +} + +// run executes a script in a fresh in-memory database loaded with the +// schema and, unless told otherwise, the fixture, and returns what the +// CLI printed in the mode asked for: "json" prints one JSON array per +// statement that returns rows, "csv" prints rows with a header and NULL +// as nullMarker, and "" prints the CLI's own text, which is how EXPLAIN +// draws a plan. A statement that fails ends the script with DuckDB's own +// error message. +func (a *analyzer) run(ctx context.Context, script, mode string, withFixture bool) (string, error) { + args := []string{"-bail"} + switch mode { + case "json": + args = append(args, "-json") + case "csv": + args = append(args, "-csv", "-header", "-nullvalue", nullMarker) + } + args = append(args, ":memory:") + cmd := exec.CommandContext(ctx, a.binary, args...) + prelude := a.schema + if withFixture { + prelude += a.fixture + } + cmd.Stdin = strings.NewReader(prelude + script) + var stdout, stderr bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = &stderr + if err := cmd.Run(); err != nil { + msg := strings.TrimSpace(stderr.String()) + if msg == "" { + msg = err.Error() + } + return "", errors.New(msg) + } + return stdout.String(), nil +} + +// query runs one statement and decodes the rows it printed. +func (a *analyzer) query(ctx context.Context, statement string) ([]map[string]json.RawMessage, error) { + out, err := a.run(ctx, statement+";\n", "json", true) + if err != nil { + return nil, err + } + var rows []map[string]json.RawMessage + dec := json.NewDecoder(strings.NewReader(out)) + for { + var rs []map[string]json.RawMessage + err := dec.Decode(&rs) + if errors.Is(err, io.EOF) { + break + } + if err != nil { + return nil, fmt.Errorf("decoding duckdb output: %w", err) + } + rows = append(rows, rs...) + } + return rows, nil +} + +func str(v json.RawMessage) string { + var s string + json.Unmarshal(v, &s) + return s +} + +// column is what the catalog says about a column of a table. +type column struct { + name string + spelling string // the type as DuckDB spells it + typ *analysis.TypeExpr + nullable bool +} + +// statements joins a script's statements, each ending in a semicolon. +func statements(src string) string { + s := strings.TrimRight(strings.TrimSpace(src), ";") + if s == "" { + return "" + } + return s + ";\n" +} + +// Analyze runs a case's queries through the CLI and returns what DuckDB +// reports in the JSON shape sqlc analyze prints. +func Analyze(ctx context.Context, binary string, c endtoend.Case) ([]byte, error) { + schema, err := os.ReadFile(c.Schema) + if err != nil { + return nil, err + } + var fixture []byte + if c.Fixture != "" { + if fixture, err = os.ReadFile(c.Fixture); err != nil { + return nil, err + } + } + queries, err := c.Queries() + if err != nil { + return nil, err + } + a := &analyzer{binary: binary, schema: statements(string(schema)), fixture: statements(string(fixture))} + if a.canonical, err = readAliases(); err != nil { + return nil, err + } + if err := a.readCatalog(ctx); err != nil { + return nil, err + } + out := make([]analysis.Query, 0, len(queries)) + for _, q := range queries { + aq, err := a.analyzeQuery(ctx, q) + if err != nil { + return nil, fmt.Errorf("%s: %w", q.Name, err) + } + out = append(out, aq) + } + return analysis.Encode(out) +} + +// Check compares what DuckDB reports for a case with the output the case +// committed, returning a diff when they differ. +func Check(ctx context.Context, binary string, c endtoend.Case) (string, error) { + got, err := Analyze(ctx, binary, c) + if err != nil { + return "", err + } + return c.Compare(got) +} + +// readCatalog reads the tables and enum types the schema created. +func (a *analyzer) readCatalog(ctx context.Context) error { + rows, err := a.query(ctx, `SELECT type_name, labels FROM duckdb_types() WHERE database_name = 'memory' AND NOT internal AND logical_type = 'ENUM' ORDER BY type_name`) + if err != nil { + return err + } + a.enums = map[string][]string{} + for _, row := range rows { + var labels []string + json.Unmarshal(row["labels"], &labels) + a.enums[strings.ToLower(str(row["type_name"]))] = labels + } + rows, err = a.query(ctx, `SELECT table_name, column_name, data_type, is_nullable FROM duckdb_columns() WHERE database_name = 'memory' ORDER BY table_oid, column_index`) + if err != nil { + return err + } + a.tables = map[string][]column{} + for _, row := range rows { + table := strings.ToLower(str(row["table_name"])) + var nullable bool + json.Unmarshal(row["is_nullable"], &nullable) + spelling := str(row["data_type"]) + a.tables[table] = append(a.tables[table], column{ + name: str(row["column_name"]), + spelling: spelling, + typ: a.parseType(spelling), + nullable: nullable, + }) + } + return nil +} + +// lookup finds a column of a table, which DuckDB matches in any case. +func (a *analyzer) lookup(table, name string) (column, bool) { + for _, col := range a.tables[strings.ToLower(table)] { + if strings.EqualFold(col.name, name) { + return col, true + } + } + return column{}, false +} + +// resolve finds the table a reference names in a scope: the table its +// qualifier aliases, or the one table of the scope that has the column. +func (a *analyzer) resolve(sc scope, r ref) (string, column, bool) { + tables := sc.tables + if sc.target.name != "" { + tables = append([]tableRef{sc.target}, tables...) + } + if r.qualifier != "" { + if sc.ctes[r.qualifier] { + return "", column{}, false + } + for _, t := range tables { + if t.alias == r.qualifier || (t.alias == "" && t.name == r.qualifier) { + col, ok := a.lookup(t.name, r.column) + return t.name, col, ok + } + } + return "", column{}, false + } + var found string + var fc column + for _, t := range tables { + if col, ok := a.lookup(t.name, r.column); ok { + if found != "" && found != t.name { + return "", column{}, false + } + found, fc = t.name, col + } + } + return found, fc, found != "" +} + +// describe reads what the catalog says about a column read from a table. +func describe(table string, col column) analysis.Column { + return analysis.Column{Name: col.name, Type: withNullable(col.typ, col.nullable), Table: table} +} + +func withNullable(t *analysis.TypeExpr, nullable bool) *analysis.TypeExpr { + if t == nil { + return nil + } + out := *t + out.Nullable = nullable + return &out +} + +// binding is what is known about one parameter: the type the binder gave +// it, spelled as DuckDB spells it, and the column it stands in for. +type binding struct { + spelling string + typ *analysis.TypeExpr + column *analysis.Column +} + +var ( + sentinelCastRe = regexp.MustCompile(`CAST\('goldeneye_([0-9]+)' AS `) + sentinelRe = regexp.MustCompile(`'goldeneye_([0-9]+)'`) + sentinelErrRe = regexp.MustCompile(`goldeneye_([0-9]+)`) +) + +// explain prepares the query, explains it with a sentinel bound to each +// parameter and returns the type the binder gave each, keyed by number. +// A parameter whose sentinel the binder converts on the spot, as an +// INSERT's VALUES are, is bound to NULL instead and reported by nothing: +// the error names the sentinel for most types, and for the rest the +// parameters not yet bound to NULL are tried in turn. +func (a *analyzer) explain(ctx context.Context, sql string, phs []placeholder) (map[int]string, error) { + null := map[int]bool{} + for attempt := 0; attempt <= len(phs); attempt++ { + args := make([]string, len(phs)) + for i, ph := range phs { + if null[ph.Number] { + args[i] = "NULL" + } else { + args[i] = fmt.Sprintf("'goldeneye_%d'", ph.Number) + } + } + script := "PREPARE goldeneye AS " + sql + ";\nSET explain_output = 'all';\nEXPLAIN (FORMAT json) EXECUTE goldeneye(" + strings.Join(args, ", ") + ");\n" + out, err := a.run(ctx, script, "", true) + if err != nil { + if !strings.Contains(err.Error(), "Conversion Error") && !strings.Contains(err.Error(), "can't be cast") { + return nil, err + } + retry := false + if m := sentinelErrRe.FindStringSubmatch(err.Error()); m != nil { + n, _ := strconv.Atoi(m[1]) + if !null[n] { + null[n] = true + retry = true + } + } + if !retry { + for _, ph := range phs { + if !null[ph.Number] { + null[ph.Number] = true + retry = true + break + } + } + } + if !retry { + return nil, err + } + continue + } + return sentinelTypes(out) + } + return nil, errors.New("could not bind the parameters") +} + +// planNode is one operator of a plan the CLI prints as JSON. Its +// extra_info holds the operator's expressions, each a string or a list +// of strings. +type planNode struct { + Name string `json:"name"` + Children []planNode `json:"children"` + ExtraInfo map[string]json.RawMessage `json:"extra_info"` +} + +// sentinelTypes reads the type each sentinel is cast to out of the plans +// the CLI printed, one JSON array per plan: the unoptimized logical plan +// comes first, and the first cast of a sentinel wins. A sentinel the +// plan prints bare is a VARCHAR, which the binder needs no cast for. +func sentinelTypes(out string) (map[int]string, error) { + var texts []string + var walk func(n planNode) + walk = func(n planNode) { + for _, raw := range n.ExtraInfo { + var one string + if json.Unmarshal(raw, &one) == nil { + texts = append(texts, one) + continue + } + var many []string + if json.Unmarshal(raw, &many) == nil { + texts = append(texts, many...) + } + } + for _, c := range n.Children { + walk(c) + } + } + dec := json.NewDecoder(strings.NewReader(out)) + for { + var plan []planNode + err := dec.Decode(&plan) + if errors.Is(err, io.EOF) { + break + } + if err != nil { + return nil, fmt.Errorf("decoding the plan: %w", err) + } + for _, n := range plan { + walk(n) + } + } + types := map[int]string{} + for _, text := range texts { + for _, m := range sentinelCastRe.FindAllStringSubmatchIndex(text, -1) { + n, _ := strconv.Atoi(text[m[2]:m[3]]) + if _, ok := types[n]; ok { + continue + } + // The type runs to the parenthesis closing the CAST. + depth := 1 + i := m[1] + for ; i < len(text); i++ { + if text[i] == '(' { + depth++ + } else if text[i] == ')' { + depth-- + if depth == 0 { + break + } + } + } + types[n] = strings.Join(strings.Fields(text[m[1]:i]), " ") + } + } + for _, text := range texts { + for _, m := range sentinelRe.FindAllStringSubmatchIndex(text, -1) { + n, _ := strconv.Atoi(text[m[2]:m[3]]) + if _, ok := types[n]; !ok && !strings.HasSuffix(text[:m[0]], "CAST(") { + types[n] = "VARCHAR" + } + } + } + return types, nil +} + +// analyzeQuery describes one query. +func (a *analyzer) analyzeQuery(ctx context.Context, q endtoend.Query) (analysis.Query, error) { + sql, phs := bind(q.SQL) + aq := analysis.Query{ + Name: q.Name, + Cmd: q.Cmd, + Columns: []analysis.Column{}, + Params: []analysis.Param{}, + } + t := text(tokenize(sql)) + sc := t.readScope() + + // Parameters: a partner column first, then the cast the query wraps + // the parameter in, then the type the binder gave it. + bindings := map[int]*binding{} + var casts []string + var castNumbers []int + for _, ph := range phs { + k := strconv.Itoa(ph.Number) + b := &binding{} + bindings[ph.Number] = b + if t.inSubquery(k) { + // A parameter inside a subquery is compared with a column of + // the subquery's own tables, which the statement's scope does + // not name. + if typ, ok := t.castOf(k); ok { + casts = append(casts, typ) + castNumbers = append(castNumbers, ph.Number) + } + continue + } + if sc.kind == "insert" { + if pos, ok := t.valuesPosition(k); ok { + cols := t.insertColumns() + if cols == nil { + for _, col := range a.tables[sc.target.name] { + cols = append(cols, col.name) + } + } + if pos < len(cols) { + if col, ok := a.lookup(sc.target.name, cols[pos]); ok { + c := describe(sc.target.name, col) + b.column, b.spelling, b.typ = &c, col.spelling, col.typ + continue + } + } + } + } + if r, ok := t.partner(k); ok { + if table, col, ok := a.resolve(sc, r); ok { + c := describe(table, col) + b.column, b.spelling, b.typ = &c, col.spelling, col.typ + continue + } + } + if typ, ok := t.castOf(k); ok { + casts = append(casts, typ) + castNumbers = append(castNumbers, ph.Number) + } + } + if len(casts) > 0 { + // DuckDB spells the cast's type: VARCHAR(5) is VARCHAR, mood is + // ENUM('sad', 'ok'). + var items []string + for i, typ := range casts { + items = append(items, fmt.Sprintf("CAST(NULL AS %s) AS p%d", typ, i)) + } + rows, err := a.query(ctx, "DESCRIBE SELECT "+strings.Join(items, ", ")) + if err != nil { + return analysis.Query{}, err + } + for i, row := range rows { + if i < len(castNumbers) { + b := bindings[castNumbers[i]] + b.spelling = str(row["column_type"]) + b.typ = a.parseType(b.spelling) + } + } + } + if len(phs) > 0 { + types, err := a.explain(ctx, sql, phs) + if err != nil { + return analysis.Query{}, err + } + for n, spelling := range types { + if b := bindings[n]; b != nil && b.typ == nil { + b.spelling = spelling + b.typ = a.parseType(spelling) + } + } + } + + // Result columns. + var columns []analysis.Column + switch sc.kind { + case "select": + rows, err := a.query(ctx, "DESCRIBE "+a.substitute(sql, phs, bindings, false)) + if err != nil { + return analysis.Query{}, err + } + for _, row := range rows { + columns = append(columns, analysis.Column{Name: str(row["column_name"]), Type: a.parseType(str(row["column_type"]))}) + } + a.attribute(sc, t.selectItems(), columns) + default: + // A RETURNING column is the target table's column it names; + // DuckDB describes no DML, so an expression is typed by nothing. + for _, it := range t.returningItems() { + switch { + case it.star: + for _, col := range a.tables[sc.target.name] { + columns = append(columns, describe(sc.target.name, col)) + } + case it.ref != nil: + if table, col, ok := a.resolve(sc, *it.ref); ok { + c := describe(table, col) + c.Name = it.name + columns = append(columns, c) + continue + } + columns = append(columns, analysis.Column{Name: it.name}) + default: + columns = append(columns, analysis.Column{Name: it.name}) + } + } + } + if len(columns) > 0 { + nullable := a.observe(ctx, sql, phs, bindings, len(columns)) + for i := range columns { + if columns[i].Table == "" && columns[i].Type != nil && nullable[i] { + columns[i].Type = withNullable(columns[i].Type, true) + } + } + } + aq.Columns = append(aq.Columns, columns...) + + for _, ph := range phs { + b := bindings[ph.Number] + ac := analysis.Column{Type: b.typ} + if b.column != nil { + ac = *b.column + } + aq.Params = append(aq.Params, analysis.Param{Number: ph.Number, Column: ac}) + } + return aq, nil +} + +// attribute says which table each result column is read from, by +// matching the select list's items, a star expanded to its table's +// columns, against the columns DuckDB described. A list that expands to +// another number of columns than DuckDB describes attributes nothing. +func (a *analyzer) attribute(sc scope, items []item, columns []analysis.Column) { + var origins []*analysis.Column + for _, it := range items { + switch { + case it.star && it.ref == nil: + for _, t := range sc.tables { + for _, col := range a.tables[t.name] { + c := describe(t.name, col) + origins = append(origins, &c) + } + } + case it.star: + table, ok := a.aliased(sc, it.ref.qualifier) + if !ok { + return + } + for _, col := range a.tables[table] { + c := describe(table, col) + origins = append(origins, &c) + } + case it.ref != nil: + if table, col, ok := a.resolve(sc, *it.ref); ok { + c := describe(table, col) + origins = append(origins, &c) + } else { + origins = append(origins, nil) + } + default: + origins = append(origins, nil) + } + } + if len(origins) != len(columns) { + return + } + for i, o := range origins { + if o != nil { + columns[i].Type = o.Type + columns[i].Table = o.Table + } + } +} + +// aliased finds the table a qualifier names in a scope. +func (a *analyzer) aliased(sc scope, qualifier string) (string, bool) { + for _, t := range sc.tables { + if t.alias == qualifier || (t.alias == "" && t.name == qualifier) { + if _, ok := a.tables[t.name]; ok { + return t.name, true + } + } + } + return "", false +} + +// substitute replaces each parameter with a NULL of its type, or with a +// value of its type when values is set, for DuckDB to describe or run the +// query. A parameter of unknown type becomes a bare NULL. Strings, +// quoted identifiers and comments are left alone. +func (a *analyzer) substitute(sql string, phs []placeholder, bindings map[int]*binding, values bool) string { + repl := map[int]string{} + for _, ph := range phs { + r := "NULL" + if b := bindings[ph.Number]; b != nil && b.spelling != "" { + r = "CAST(NULL AS " + b.spelling + ")" + if values { + // The value is chosen by the type as spelled, since an + // alias such as JSON takes values its canonical type + // does not. + if v, ok := a.zero(a.parseTypeWith(b.spelling, false)); ok { + r = "CAST('" + strings.ReplaceAll(v, "'", "''") + "' AS " + b.spelling + ")" + } + } + } + repl[ph.Number] = r + } + var out strings.Builder + i := 0 + for i < len(sql) { + c := sql[i] + switch { + case c == '\'' || c == '"': + end := quotedEnd(sql, i) + out.WriteString(sql[i:end]) + i = end + case strings.HasPrefix(sql[i:], "--"): + end := strings.IndexByte(sql[i:], '\n') + if end < 0 { + end = len(sql) + } else { + end += i + } + out.WriteString(sql[i:end]) + i = end + case strings.HasPrefix(sql[i:], "/*"): + end := strings.Index(sql[i:], "*/") + if end < 0 { + end = len(sql) + } else { + end += i + 2 + } + out.WriteString(sql[i:end]) + i = end + case c == '$' && numberedRe.MatchString(sql[i:]): + m := numberedRe.FindStringSubmatch(sql[i:]) + n, _ := strconv.Atoi(m[1]) + if r, ok := repl[n]; ok { + out.WriteString(r) + } else { + out.WriteString(m[0]) + } + i += len(m[0]) + default: + out.WriteByte(c) + i++ + } + } + return out.String() +} + +// observe runs the query with a value bound to each parameter, over the +// fixture and over no rows, and reports which of the first n result +// columns came back NULL in either run. A run the CLI rejects observes +// nothing. +func (a *analyzer) observe(ctx context.Context, sql string, phs []placeholder, bindings map[int]*binding, n int) []bool { + nullable := make([]bool, n) + statement := a.substitute(sql, phs, bindings, true) + ";\n" + runs := []bool{true} + if a.fixture != "" { + runs = append(runs, false) + } + for _, withFixture := range runs { + out, err := a.run(ctx, statement, "csv", withFixture) + if err != nil { + continue + } + records, err := csv.NewReader(strings.NewReader(out)).ReadAll() + if err != nil { + continue + } + for _, rec := range records[min(1, len(records)):] { + for j, v := range rec { + if j < n && v == nullMarker { + nullable[j] = true + } + } + } + } + return nullable +} diff --git a/internal/goldeneye/duckdb/duckdb.go b/internal/goldeneye/duckdb/duckdb.go new file mode 100644 index 0000000..9232117 --- /dev/null +++ b/internal/goldeneye/duckdb/duckdb.go @@ -0,0 +1,351 @@ +// Package duckdb generates the DuckDB dialect seed under +// internal/engine/duckdb/dialect — types.jsonl, functions.jsonl and +// operators.jsonl — from a live DuckDB CLI, the same way the postgresql +// package generates PostgreSQL's from a live server, and verifies the +// DuckDB analyze cases under internal/endtoend/testdata against the same +// CLI. +// +// The CLI is a DuckDB 2.0 build, the release darkwing is pinned against, +// which has no release to download yet: Install fetches the current build +// of DuckDB's v2.0 preview channel into the user cache directory. The CLI +// is located through the DUCKDB environment variable, then the cached +// build, then "duckdb" on PATH. +package duckdb + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "os" + "os/exec" + "sort" + "strings" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/dialect" +) + +// Engine is the name of the engine directory the dialect lives under. +const Engine = "duckdb" + +// Locate finds the DuckDB CLI: the DUCKDB environment variable wins, then +// the cached build of DefaultVersion, then "duckdb" on PATH. +func Locate() (string, error) { + if path := os.Getenv("DUCKDB"); path != "" { + return path, nil + } + if path, err := cachedBinary(DefaultVersion); err == nil { + if _, err := os.Stat(path); err == nil { + return path, nil + } + } + path, err := exec.LookPath("duckdb") + if err != nil { + return "", errors.New("no duckdb CLI found: run `go run ./cmd/goldeneye install duckdb` in internal/goldeneye, set DUCKDB to a DuckDB 2.0 binary, or put duckdb on PATH") + } + return path, nil +} + +// Version reports the release a CLI is. +func Version(ctx context.Context, binary string) (string, error) { + out, err := exec.CommandContext(ctx, binary, "--version").Output() + if err != nil { + return "", fmt.Errorf("duckdb --version: %w", err) + } + return "DuckDB " + strings.TrimSpace(string(out)), nil +} + +// query runs a SQL statement against an in-memory database and decodes the +// CLI's JSON output into rows. +func query(ctx context.Context, binary, sql string, rows any) error { + cmd := exec.CommandContext(ctx, binary, "-json", ":memory:", "-c", sql) + out, err := cmd.Output() + if err != nil { + if exit, ok := err.(*exec.ExitError); ok { + return fmt.Errorf("duckdb: %s: %s", err, exit.Stderr) + } + return fmt.Errorf("duckdb: %w", err) + } + // An empty result set prints nothing rather than []. + if len(out) == 0 { + return nil + } + return json.Unmarshal(out, rows) +} + +type typeRow struct { + TypeName string `json:"type_name"` + LogicalType string `json:"logical_type"` + Category *string `json:"type_category"` +} + +type functionRow struct { + Name string `json:"function_name"` + FunctionType string `json:"function_type"` + ParameterTypes []string `json:"parameter_types"` + Varargs *string `json:"varargs"` + ReturnType *string `json:"return_type"` +} + +// metaTypes are type ids that never describe a column's value: sentinels and +// binder-internal types the dump lists alongside the real ones. +var metaTypes = map[string]bool{ + "null": true, + "unknown": true, + "invalid": true, + "any": true, + "type": true, + "lambda": true, + "table": true, + "pointer": true, +} + +// categoryLetter maps duckdb_types() categories onto the PostgreSQL category +// letters the seed package uses. +func categoryLetter(category *string) string { + if category == nil { + return "U" + } + switch *category { + case "NUMERIC": + return "N" + case "STRING": + return "S" + case "DATETIME": + return "D" + case "BOOLEAN": + return "B" + case "COMPOSITE": + return "C" + default: + return "U" + } +} + +func readTypes(ctx context.Context, binary string) ([]dialect.Type, error) { + var rows []typeRow + err := query(ctx, binary, ` +SELECT type_name, logical_type, type_category +FROM duckdb_types() +WHERE database_name = 'system' +ORDER BY type_name`, &rows) + if err != nil { + return nil, err + } + + // Group the dump's one-row-per-spelling by logical type: the spelling + // matching the logical type id is the canonical name, the rest are + // aliases. A spelling is listed once per schema it is visible in, so + // an alias is kept once. + grouped := map[string]*dialect.Type{} + var order []string + seen := map[string]bool{} + for _, row := range rows { + logical := strings.ToLower(row.LogicalType) + if metaTypes[logical] { + continue + } + t, ok := grouped[logical] + if !ok { + t = &dialect.Type{Name: logical, Category: categoryLetter(row.Category)} + grouped[logical] = t + order = append(order, logical) + } + if t.Category == "U" { + t.Category = categoryLetter(row.Category) + } + if name := strings.ToLower(row.TypeName); name != logical && !seen[logical+"\x00"+name] { + seen[logical+"\x00"+name] = true + t.Aliases = append(t.Aliases, name) + } + } + + sort.Strings(order) + types := make([]dialect.Type, 0, len(order)+1) + // "any" stands in for the generic parameters of DuckDB's polymorphic + // functions (ANY, T, K, V); the analyzer resolves a call returning it + // to the type of the call's first argument. + types = append(types, dialect.Type{Name: "any", Category: "U"}) + for _, name := range order { + types = append(types, *grouped[name]) + } + return types, nil +} + +// typeNames is the set of names the seed declares, for filtering out function +// overloads over generic or binder-internal types. +func typeNames(types []dialect.Type) map[string]bool { + names := map[string]bool{} + for _, t := range types { + names[t.Name] = true + for _, alias := range t.Aliases { + names[alias] = true + } + } + return names +} + +// seedTypeName maps a duckdb_functions() type spelling to a seeded type name: +// lowercased, with modifiers dropped (DECIMAL(18,3) is a decimal), array +// markers kept (fixed sizes and generic bounds included: DOUBLE[3] and +// ANY[] are arrays), and the generic parameters of polymorphic functions +// mapped to "any". It reports false for the internal types a seed cannot +// describe. +func seedTypeName(name string, known map[string]bool) (string, bool) { + name = strings.ToLower(strings.TrimSpace(name)) + if close := strings.LastIndexByte(name, ']'); close == len(name)-1 { + if open := strings.LastIndexByte(name, '['); open != -1 { + elementName, ok := seedTypeName(name[:open], known) + return elementName + "[]", ok + } + } + if open := strings.IndexByte(name, '('); open != -1 { + name = name[:open] + } + switch name { + case "any", "t", "k", "v": + return "any", true + } + if !known[name] { + return "", false + } + return name, true +} + +// isOperatorName reports a function named by symbols rather than an +// identifier — the spelling of a binary or prefix operator. +func isOperatorName(name string) bool { + return strings.IndexFunc(name, func(r rune) bool { + return (r < 'a' || r > 'z') && (r < '0' || r > '9') && r != '_' && r != '$' + }) != -1 +} + +func functionKind(functionType string) string { + switch functionType { + case "aggregate": + return "a" + case "window": + return "w" + default: + return "" + } +} + +func readFunctions(ctx context.Context, binary string, known map[string]bool) ([]dialect.Function, []dialect.Operator, error) { + var rows []functionRow + err := query(ctx, binary, ` +SELECT DISTINCT function_name, function_type, parameter_types, varargs, return_type +FROM duckdb_functions() +WHERE database_name = 'system' + AND schema_name = 'main' + AND function_type IN ('scalar', 'aggregate', 'window', 'macro') +ORDER BY function_name, parameter_types::VARCHAR, return_type`, &rows) + if err != nil { + return nil, nil, err + } + + var funcs []dialect.Function + var operators []dialect.Operator + seenFunc := map[string]bool{} + seenOp := map[string]bool{} + for _, row := range rows { + if row.ReturnType == nil { + continue + } + returns, ok := seedTypeName(*row.ReturnType, known) + if !ok { + continue + } + args := make([]string, 0, len(row.ParameterTypes)) + resolved := true + for _, param := range row.ParameterTypes { + arg, ok := seedTypeName(param, known) + if !ok { + resolved = false + break + } + args = append(args, arg) + } + if !resolved { + continue + } + + if isOperatorName(row.Name) { + // Operator-named functions become operator entries; sqlc's + // engine reports them as operator applications. Only the + // binary form over concrete scalar types is representable — + // the seed's operator table, unlike its function table, does + // not register generic or array types on demand. + if row.FunctionType != "scalar" || len(args) != 2 || row.Varargs != nil { + continue + } + if concrete := !strings.Contains(returns, "any") && !strings.Contains(returns, "[]") && + !strings.Contains(args[0], "any") && !strings.Contains(args[0], "[]") && + !strings.Contains(args[1], "any") && !strings.Contains(args[1], "[]"); !concrete { + continue + } + key := row.Name + "\x00" + strings.Join(args, "\x00") + if seenOp[key] { + continue + } + seenOp[key] = true + operators = append(operators, dialect.Operator{ + Name: row.Name, + Left: args[0], + Right: args[1], + Result: returns, + }) + continue + } + + fn := dialect.Function{ + Name: row.Name, + Kind: functionKind(row.FunctionType), + Returns: returns, + // An aggregate over no rows returns NULL — except count, + // which returns 0. + Nullable: row.FunctionType == "aggregate" && !strings.HasPrefix(row.Name, "count"), + } + for _, arg := range args { + fn.Args = append(fn.Args, dialect.Arg{Type: arg}) + } + if row.Varargs != nil { + vararg, ok := seedTypeName(*row.Varargs, known) + if !ok { + continue + } + fn.Args = append(fn.Args, dialect.Arg{Type: vararg, Mode: "v"}) + } + + key := fn.Name + "\x00" + fn.Kind + "\x00" + strings.Join(args, "\x00") + if seenFunc[key] { + continue + } + seenFunc[key] = true + funcs = append(funcs, fn) + } + return funcs, operators, nil +} + +// Generate reads the dialect from the CLI. +func Generate(ctx context.Context, binary string) (dialect.Files, error) { + types, err := readTypes(ctx, binary) + if err != nil { + return nil, err + } + funcs, operators, err := readFunctions(ctx, binary, typeNames(types)) + if err != nil { + return nil, err + } + files := dialect.Files{} + if files[dialect.TypesFile], err = dialect.JSONL(types); err != nil { + return nil, err + } + if files[dialect.FunctionsFile], err = dialect.JSONL(funcs); err != nil { + return nil, err + } + if files[dialect.OperatorsFile], err = dialect.JSONL(operators); err != nil { + return nil, err + } + return files, nil +} diff --git a/internal/goldeneye/duckdb/duckdb_test.go b/internal/goldeneye/duckdb/duckdb_test.go new file mode 100644 index 0000000..5d600da --- /dev/null +++ b/internal/goldeneye/duckdb/duckdb_test.go @@ -0,0 +1,66 @@ +package duckdb + +import ( + "context" + "testing" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/dialect" + "github.com/sqlc-dev/sqlc/internal/goldeneye/endtoend" +) + +// TestDialect verifies the committed DuckDB dialect against what the DuckDB +// CLI reports. It skips unless a CLI is found. +func TestDialect(t *testing.T) { + binary, err := Locate() + if err != nil { + t.Skip(err) + } + ctx := context.Background() + version, err := Version(ctx, binary) + if err != nil { + t.Fatal(err) + } + files, err := Generate(ctx, binary) + if err != nil { + t.Fatal(err) + } + dir, err := dialect.Dir(Engine) + if err != nil { + t.Fatal(err) + } + report, err := dialect.Check(dir, files) + if err != nil { + t.Fatal(err) + } + if report != "" { + t.Errorf("%s does not match what %s reports:\n%s", dir, version, report) + } +} + +// TestAnalyzeCases verifies every DuckDB analyze case under +// internal/endtoend/testdata against what the CLI reports. It skips +// unless a CLI is found. +func TestAnalyzeCases(t *testing.T) { + binary, err := Locate() + if err != nil { + t.Skip(err) + } + cases, err := endtoend.Cases(Engine) + if err != nil { + t.Fatal(err) + } + if len(cases) == 0 { + t.Fatal("no duckdb analyze cases found") + } + for _, c := range cases { + t.Run(c.Name, func(t *testing.T) { + diff, err := Check(context.Background(), binary, c) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Errorf("%s does not match what DuckDB reports (-committed +duckdb):\n%s", c.Output, diff) + } + }) + } +} diff --git a/internal/goldeneye/duckdb/install.go b/internal/goldeneye/duckdb/install.go new file mode 100644 index 0000000..e7ac080 --- /dev/null +++ b/internal/goldeneye/duckdb/install.go @@ -0,0 +1,136 @@ +package duckdb + +import ( + "archive/tar" + "compress/gzip" + "context" + "errors" + "fmt" + "io" + "net/http" + "os" + "path/filepath" + "strings" +) + +// DefaultVersion is the DuckDB preview channel the CLI is downloaded from: +// the v2.0 development builds, which DuckDB publishes as a rolling tarball +// per platform under https://artifacts.duckdb.org// until 2.0 is +// released. A channel has no per-build download and no checksum to pin, +// so Install fetches whatever build the channel holds and the version the +// CLI reports is what a run logs; GeneratedFrom records the build the +// committed dialect came from, and a check against a later build reports +// what the later build added. Once 2.0 is released, pin the release and +// its checksums here the way the clickhouse package does. +const DefaultVersion = "v2.0-cyanoptera" + +// GeneratedFrom is the build the committed dialect was generated from, as +// `duckdb --version` reports it. Update it when regenerating. +const GeneratedFrom = "v2.0.0-alpha41396 (Cyanoptera) d41e527b18" + +// channelURL is the download address of a channel's CLI tarball for a +// platform. DuckDB publishes one macOS build for both architectures. +func channelURL(channel, goos, goarch string) (string, error) { + var name string + switch { + case goos == "linux" && (goarch == "amd64" || goarch == "arm64"): + name = "duckdb-cli-linux-" + goarch + ".tar.gz" + case goos == "darwin": + name = "duckdb-cli-osx-universal.tar.gz" + default: + return "", fmt.Errorf("no DuckDB %s build is published for %s/%s", channel, goos, goarch) + } + return "https://artifacts.duckdb.org/" + channel + "/" + name, nil +} + +// cachedBinary is where Install puts the binary for a channel. +func cachedBinary(channel string) (string, error) { + dir, err := os.UserCacheDir() + if err != nil { + return "", err + } + return filepath.Join(dir, "sqlc-duckdb", channel, "duckdb"), nil +} + +// Install downloads the channel's current CLI into the cache and returns +// its path. It is a no-op when the channel is already cached: remove the +// cached directory to fetch the channel's newer build. +func Install(ctx context.Context, channel, goos, goarch string, progress io.Writer) (string, error) { + dest, err := cachedBinary(channel) + if err != nil { + return "", err + } + if _, err := os.Stat(dest); err == nil { + return dest, nil + } + url, err := channelURL(channel, goos, goarch) + if err != nil { + return "", err + } + if err := os.MkdirAll(filepath.Dir(dest), 0o755); err != nil { + return "", err + } + + fmt.Fprintf(progress, "downloading %s\n", url) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + return "", err + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("downloading %s: %s", url, resp.Status) + } + + // Write next to the destination and rename so a partial download never + // masquerades as an installed binary. + tmp, err := os.CreateTemp(filepath.Dir(dest), "duckdb-*.partial") + if err != nil { + return "", err + } + defer os.Remove(tmp.Name()) + src, err := binaryInTarball(resp.Body) + if err != nil { + tmp.Close() + return "", fmt.Errorf("downloading %s: %w", url, err) + } + if _, err := io.Copy(tmp, src); err != nil { + tmp.Close() + return "", err + } + if err := tmp.Close(); err != nil { + return "", err + } + if err := os.Chmod(tmp.Name(), 0o755); err != nil { + return "", err + } + if err := os.Rename(tmp.Name(), dest); err != nil { + return "", err + } + return dest, nil +} + +// binaryInTarball positions a reader at the duckdb binary inside a CLI +// tarball, which holds it at the top level. +func binaryInTarball(r io.Reader) (io.Reader, error) { + gz, err := gzip.NewReader(r) + if err != nil { + return nil, err + } + tr := tar.NewReader(gz) + for { + hdr, err := tr.Next() + if errors.Is(err, io.EOF) { + return nil, errors.New("tarball does not contain duckdb") + } + if err != nil { + return nil, err + } + if hdr.Typeflag == tar.TypeReg && strings.TrimPrefix(hdr.Name, "./") == "duckdb" { + return tr, nil + } + } +} diff --git a/internal/goldeneye/duckdb/text.go b/internal/goldeneye/duckdb/text.go new file mode 100644 index 0000000..1c749a6 --- /dev/null +++ b/internal/goldeneye/duckdb/text.go @@ -0,0 +1,657 @@ +package duckdb + +import ( + "strings" +) + +// DuckDB prints a plan with every column by its bare name and every +// aliased expression by its alias, and describes a query no further than +// its result columns' names and types, so which table a result column is +// read from and which column a parameter is compared with are read from +// the query text: the select list's items, the FROM clause's tables and +// aliases, and the operand beside each parameter. The text is tokenized +// and read at the top level of the statement, outside the parentheses a +// subquery or a CTE body sits in. + +// token is one lexical element of a query. +type token struct { + kind byte // 'w' word, 'q' quoted identifier, 's' string, 'n' number, 'p' parameter, 'o' operator or punctuation + text string +} + +var operators = []string{"::", "<>", "!=", "<=", ">=", "!~~", "~~", "->>", "->", "||", "=", "<", ">", "(", ")", ",", ".", "*", "+", "-", "/", "%", "[", "]", ";", "^", "&", "|", "~", "!", ":"} + +// tokenize splits a query into tokens, dropping comments. A parameter is +// $ followed by digits, which is how bind spells every parameter. +func tokenize(src string) []token { + var out []token + i := 0 + for i < len(src) { + c := src[i] + switch { + case c == ' ' || c == '\t' || c == '\n' || c == '\r': + i++ + case strings.HasPrefix(src[i:], "--"): + end := strings.IndexByte(src[i:], '\n') + if end < 0 { + i = len(src) + } else { + i += end + } + case strings.HasPrefix(src[i:], "/*"): + end := strings.Index(src[i:], "*/") + if end < 0 { + i = len(src) + } else { + i += end + 2 + } + case c == '\'': + end := quotedEnd(src, i) + out = append(out, token{'s', src[i:end]}) + i = end + case c == '"': + end := quotedEnd(src, i) + out = append(out, token{'q', strings.ReplaceAll(src[i+1:end-1], `""`, `"`)}) + i = end + case c == '$' && i+1 < len(src) && isDigit(src[i+1]): + end := i + 1 + for end < len(src) && isDigit(src[end]) { + end++ + } + out = append(out, token{'p', src[i+1 : end]}) + i = end + case isDigit(c) || (c == '.' && i+1 < len(src) && isDigit(src[i+1])): + end := i + for end < len(src) && (isDigit(src[end]) || src[end] == '.' || src[end] == 'e' || src[end] == 'E' || src[end] == '_') { + end++ + } + out = append(out, token{'n', src[i:end]}) + i = end + case isWordStart(c): + end := i + for end < len(src) && isWordByte(src[end]) { + end++ + } + out = append(out, token{'w', src[i:end]}) + i = end + default: + matched := false + for _, op := range operators { + if strings.HasPrefix(src[i:], op) { + out = append(out, token{'o', op}) + i += len(op) + matched = true + break + } + } + if !matched { + out = append(out, token{'o', string(c)}) + i++ + } + } + } + return out +} + +// quotedEnd returns the index just past the quoted token starting at i, +// whose delimiter is escaped by doubling it. +func quotedEnd(s string, i int) int { + q := s[i] + j := i + 1 + for j < len(s) { + switch { + case s[j] == q && j+1 < len(s) && s[j+1] == q: + j += 2 + case s[j] == q: + return j + 1 + default: + j++ + } + } + return len(s) +} + +func isDigit(c byte) bool { return c >= '0' && c <= '9' } +func isWordStart(c byte) bool { + return c == '_' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= 0x80 +} +func isWordByte(c byte) bool { return isWordStart(c) || isDigit(c) } + +// text is a tokenized query. +type text []token + +func (t text) at(i int) token { + if i < 0 || i >= len(t) { + return token{} + } + return t[i] +} + +// isWord reports whether token i is the keyword, in any case. +func (t text) isWord(i int, word string) bool { + tok := t.at(i) + return tok.kind == 'w' && strings.EqualFold(tok.text, word) +} + +// isOp reports whether token i is the operator. +func (t text) isOp(i int, op string) bool { + tok := t.at(i) + return tok.kind == 'o' && tok.text == op +} + +// isName reports whether token i can name something: a word or a quoted +// identifier. +func (t text) isName(i int) bool { + k := t.at(i).kind + return k == 'w' || k == 'q' +} + +// group returns the index of the parenthesis closing the one at i. +func (t text) group(i int) int { + depth := 0 + for j := i; j < len(t); j++ { + switch { + case t.isOp(j, "("): + depth++ + case t.isOp(j, ")"): + depth-- + if depth == 0 { + return j + } + } + } + return len(t) - 1 +} + +// ref is a column reference: a qualifier, empty for none, and a column, +// or "*" for every column of the qualifier. +type ref struct { + qualifier, column string +} + +// readRef reads a dotted name starting at i, returning the parts and the +// index after them. +func (t text) readRef(i int) ([]string, int) { + var parts []string + for t.isName(i) || t.isOp(i, "*") { + parts = append(parts, t.at(i).text) + if !t.isOp(i+1, ".") { + return parts, i + 1 + } + i += 2 + } + return parts, i +} + +// keywords that end a list of tables or select items at the top level. +var clauseKeywords = map[string]bool{ + "where": true, "group": true, "order": true, "limit": true, "offset": true, "having": true, + "qualify": true, "window": true, "returning": true, "set": true, "values": true, "select": true, + "union": true, "except": true, "intersect": true, "on": true, "from": true, "join": true, + "left": true, "right": true, "full": true, "inner": true, "cross": true, "outer": true, + "natural": true, "asof": true, "semi": true, "anti": true, "positional": true, "lateral": true, + "using": true, "with": true, "into": true, "default": true, "fetch": true, "for": true, + "tablesample": true, "sample": true, "by": true, "repeatable": true, +} + +// typeWords are the words a multi-word type name continues with: +// TIMESTAMP WITH TIME ZONE, DOUBLE PRECISION, CHARACTER VARYING. +var typeWords = map[string]bool{"with": true, "without": true, "time": true, "zone": true, "precision": true, "varying": true} + +// tableRef is one table of a statement's scope, by name and alias. +type tableRef struct { + name, alias string +} + +// scope is what the statement reads and writes: the tables of its FROM, +// JOIN and USING clauses and the table a DML statement targets, with the +// names of its CTEs, which are not tables. +type scope struct { + kind string // select, insert, update, delete + target tableRef + tables []tableRef + ctes map[string]bool +} + +// readScope reads a statement's scope from its top-level tokens. +func (t text) readScope() scope { + sc := scope{ctes: map[string]bool{}} + i := 0 + // WITH name [(cols)] AS (...), ... + if t.isWord(0, "with") { + i = 1 + if t.isWord(i, "recursive") { + i++ + } + for t.isName(i) { + sc.ctes[strings.ToLower(t.at(i).text)] = true + i++ + if t.isOp(i, "(") { + i = t.group(i) + 1 + } + if t.isWord(i, "as") { + i++ + } + if t.isWord(i, "not") || t.isWord(i, "materialized") { + for !t.isOp(i, "(") && i < len(t) { + i++ + } + } + if t.isOp(i, "(") { + i = t.group(i) + 1 + } + if t.isOp(i, ",") { + i++ + continue + } + break + } + } + sc.kind = "select" + switch { + case t.isWord(i, "insert"): + sc.kind = "insert" + for i < len(t) && !t.isWord(i, "into") { + i++ + } + sc.target, i = t.readTable(i + 1) + case t.isWord(i, "update"): + sc.kind = "update" + sc.target, i = t.readTable(i + 1) + case t.isWord(i, "delete"): + sc.kind = "delete" + if t.isWord(i+1, "from") { + i++ + } + sc.target, i = t.readTable(i + 1) + } + for ; i < len(t); i++ { + switch { + case t.isOp(i, "("): + i = t.group(i) + case t.isWord(i, "from") || t.isWord(i, "join"): + i = t.readTables(i+1, &sc.tables) - 1 + case t.isWord(i, "using") && !t.isOp(i+1, "("): + i = t.readTables(i+1, &sc.tables) - 1 + } + } + // A CTE is not a table, whatever table shares its name. + tables := sc.tables[:0] + for _, ref := range sc.tables { + if !sc.ctes[ref.name] { + tables = append(tables, ref) + } + } + sc.tables = tables + return sc +} + +// readTable reads a table name with an optional alias. +func (t text) readTable(i int) (tableRef, int) { + parts, j := t.readRef(i) + if len(parts) == 0 { + return tableRef{}, i + } + ref := tableRef{name: strings.ToLower(parts[len(parts)-1])} + if t.isWord(j, "as") { + j++ + } + if t.isName(j) && !clauseKeywords[strings.ToLower(t.at(j).text)] { + ref.alias = strings.ToLower(t.at(j).text) + j++ + } + return ref, j +} + +// readTables reads a comma-separated list of table references, skipping +// subqueries and table functions, and returns the index after it. +func (t text) readTables(i int, into *[]tableRef) int { + for i < len(t) { + if t.isOp(i, "(") { + // A derived table or a table function's arguments. + i = t.group(i) + 1 + if t.isWord(i, "as") { + i++ + } + if t.isName(i) && !clauseKeywords[strings.ToLower(t.at(i).text)] { + i++ + } + } else if t.isName(i) && !clauseKeywords[strings.ToLower(t.at(i).text)] { + ref, j := t.readTable(i) + if t.isOp(j, "(") { + // A table function: its result is not a table. + j = t.group(j) + 1 + } else { + *into = append(*into, ref) + } + i = j + } else { + return i + } + if t.isOp(i, ",") { + i++ + continue + } + return i + } + return i +} + +// item is one entry of a select list or a RETURNING list. +type item struct { + star bool // every column of qualifier, or of every table + ref *ref // a column reference, when the item is one + name string // the alias, or the column name of a reference +} + +// items splits a select or RETURNING list into its items, given the index +// of the first token after the keyword. +func (t text) items(start int) []item { + var out []item + i := start + for i < len(t) { + end := i + for end < len(t) && !t.isOp(end, ",") && !(t.at(end).kind == 'w' && clauseKeywords[strings.ToLower(t.at(end).text)] && !t.isWord(end, "on")) && !t.isOp(end, ";") { + if t.isOp(end, "(") { + end = t.group(end) + } + end++ + } + if end > i { + out = append(out, t.item(i, end)) + } + if !t.isOp(end, ",") { + break + } + i = end + 1 + } + return out +} + +// item classifies the tokens of one select item. +func (t text) item(start, end int) item { + parts, j := t.readRef(start) + if len(parts) > 0 && parts[len(parts)-1] == "*" { + it := item{star: true} + if len(parts) > 1 { + it.ref = &ref{qualifier: strings.ToLower(parts[len(parts)-2]), column: "*"} + } + return it + } + var it item + if len(parts) > 0 && j == end { + it.ref = &ref{column: parts[len(parts)-1]} + if len(parts) > 1 { + it.ref.qualifier = strings.ToLower(parts[len(parts)-2]) + } + it.name = parts[len(parts)-1] + return it + } + if len(parts) > 0 && j == end-1 && t.isName(end-1) { + // A reference followed by a bare alias. + it.ref = &ref{column: parts[len(parts)-1]} + if len(parts) > 1 { + it.ref.qualifier = strings.ToLower(parts[len(parts)-2]) + } + it.name = t.at(end - 1).text + return it + } + if len(parts) > 0 && j == end-2 && t.isWord(end-2, "as") && t.isName(end-1) { + it.ref = &ref{column: parts[len(parts)-1]} + if len(parts) > 1 { + it.ref.qualifier = strings.ToLower(parts[len(parts)-2]) + } + it.name = t.at(end - 1).text + return it + } + if t.isWord(end-2, "as") && t.isName(end-1) { + it.name = t.at(end - 1).text + } + return it +} + +// selectItems finds the statement's select list: the items after its +// top-level SELECT, or every column when a FROM-first query has none. +func (t text) selectItems() []item { + for i := 0; i < len(t); i++ { + switch { + case t.isOp(i, "("): + i = t.group(i) + case t.isWord(i, "select"): + j := i + 1 + if t.isWord(j, "distinct") || t.isWord(j, "all") { + j++ + if t.isWord(j, "on") && t.isOp(j+1, "(") { + j = t.group(j+1) + 1 + } + } + return t.items(j) + } + } + if t.isWord(0, "from") { + return []item{{star: true}} + } + return nil +} + +// returningItems finds the items of a top-level RETURNING clause. +func (t text) returningItems() []item { + for i := 0; i < len(t); i++ { + switch { + case t.isOp(i, "("): + i = t.group(i) + case t.isWord(i, "returning"): + return t.items(i + 1) + } + } + return nil +} + +// inSubquery reports whether parameter k sits inside a subquery: a +// parenthesis that a SELECT, WITH, FROM or VALUES opens. +func (t text) inSubquery(k string) bool { + i := t.find(k) + depth := 0 + for j := i - 1; j >= 0; j-- { + switch { + case t.isOp(j, ")"): + depth++ + case t.isOp(j, "("): + if depth > 0 { + depth-- + continue + } + if t.isWord(j+1, "select") || t.isWord(j+1, "with") || t.isWord(j+1, "from") || t.isWord(j+1, "values") { + return true + } + } + } + return false +} + +// find returns the index of parameter k. +func (t text) find(k string) int { + for i, tok := range t { + if tok.kind == 'p' && tok.text == k { + return i + } + } + return -1 +} + +var comparisons = map[string]bool{"=": true, "<>": true, "!=": true, "<": true, ">": true, "<=": true, ">=": true, "~~": true, "!~~": true} + +// partner finds the column a parameter is compared with or assigned to: +// the column reference on the other side of the comparison, LIKE or IN +// it is an operand of, or the column a SET assigns it to. +func (t text) partner(k string) (ref, bool) { + i := t.find(k) + if i < 0 { + return ref{}, false + } + // col op $k, col [NOT] LIKE $k, col IN ($k, ...) + j := i - 1 + if t.isOp(j, "(") || t.isOp(j, ",") { + for j >= 0 && (t.isOp(j, ",") || t.at(j).kind == 'p' || t.at(j).kind == 's' || t.at(j).kind == 'n') { + j-- + } + if t.isOp(j, "(") { + j-- + } + } + if t.at(j).kind == 'o' && comparisons[t.at(j).text] || t.isWord(j, "like") || t.isWord(j, "ilike") || t.isWord(j, "glob") || t.isWord(j, "in") { + if t.isWord(j-1, "not") { + j-- + } + if r, ok := t.refEnding(j - 1); ok { + return r, true + } + } + // $k op col + j = i + 1 + if t.at(j).kind == 'o' && comparisons[t.at(j).text] { + if r, ok := t.refStarting(j + 1); ok { + return r, true + } + } + return ref{}, false +} + +// refEnding reads the column reference whose last token is at i. +func (t text) refEnding(i int) (ref, bool) { + if !t.isName(i) { + return ref{}, false + } + r := ref{column: t.at(i).text} + if t.isOp(i-1, ".") && t.isName(i-2) { + r.qualifier = strings.ToLower(t.at(i - 2).text) + } + return r, true +} + +// refStarting reads the column reference starting at i, which must not be +// a function call. +func (t text) refStarting(i int) (ref, bool) { + parts, j := t.readRef(i) + if len(parts) == 0 || t.isOp(j, "(") { + return ref{}, false + } + r := ref{column: parts[len(parts)-1]} + if len(parts) > 1 { + r.qualifier = strings.ToLower(parts[len(parts)-2]) + } + return r, true +} + +// castOf returns the type a parameter is cast to, as $k::T or CAST($k AS +// T), spelled as the query spells it. +func (t text) castOf(k string) (string, bool) { + i := t.find(k) + if i < 0 { + return "", false + } + if t.isOp(i+1, "::") { + return t.typeText(i + 2), true + } + if t.isWord(i-2, "cast") && t.isOp(i-1, "(") && t.isWord(i+1, "as") { + return t.typeText(i + 2), true + } + return "", false +} + +// typeText reads a type starting at i: a dotted name, optional arguments +// in parentheses and any number of [] or [N] suffixes. +func (t text) typeText(i int) string { + start := i + _, i = t.readRef(i) + for t.at(i).kind == 'w' && typeWords[strings.ToLower(t.at(i).text)] { + // Multi-word names: TIMESTAMP WITH TIME ZONE. + i++ + } + if t.isOp(i, "(") { + i = t.group(i) + 1 + } + for t.isOp(i, "[") { + for i < len(t) && !t.isOp(i, "]") { + i++ + } + i++ + } + var b strings.Builder + for j := start; j < i && j < len(t); j++ { + tok := t.at(j) + if j > start && (tok.kind == 'w' || tok.kind == 'q' || tok.kind == 'n' || tok.kind == 's') && (t.at(j-1).kind == 'w' || t.at(j-1).kind == 'q' || t.isOp(j-1, ",")) { + b.WriteByte(' ') + } + b.WriteString(tok.text) + } + return b.String() +} + +// valuesPosition reports, for a parameter inside an INSERT's VALUES, the +// index of the column it is a value for, counting positions within its +// row. +func (t text) valuesPosition(k string) (int, bool) { + i := t.find(k) + if i < 0 { + return 0, false + } + for j := 0; j < len(t); j++ { + if t.isOp(j, "(") { + j = t.group(j) + continue + } + if !t.isWord(j, "values") { + continue + } + // Rows follow, each a parenthesised list. + for r := j + 1; t.isOp(r, "("); r = t.group(r) + 2 { + end := t.group(r) + if i < r || i > end { + if !t.isOp(end+1, ",") { + break + } + continue + } + pos, depth := 0, 0 + for q := r + 1; q < i; q++ { + switch { + case t.isOp(q, "("): + depth++ + case t.isOp(q, ")"): + depth-- + case t.isOp(q, ",") && depth == 0: + pos++ + } + } + return pos, true + } + return 0, false + } + return 0, false +} + +// insertColumns lists the columns an INSERT names, or nil for all. +func (t text) insertColumns() []string { + for i := 0; i < len(t); i++ { + if t.isWord(i, "into") { + _, j := t.readRef(i + 1) + if t.isWord(j, "as") { + j += 2 + } else if t.isName(j) && !clauseKeywords[strings.ToLower(t.at(j).text)] { + j++ + } + if !t.isOp(j, "(") { + return nil + } + var cols []string + for q := j + 1; q < t.group(j); q++ { + if t.isName(q) { + cols = append(cols, t.at(q).text) + } + } + return cols + } + } + return nil +} diff --git a/internal/goldeneye/duckdb/types.go b/internal/goldeneye/duckdb/types.go new file mode 100644 index 0000000..f97cb76 --- /dev/null +++ b/internal/goldeneye/duckdb/types.go @@ -0,0 +1,220 @@ +package duckdb + +import ( + "sort" + "strconv" + "strings" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/analysis" +) + +// parseType reads a type the way DuckDB spells one — DECIMAL(10,2), +// INTEGER[], INTEGER[3], STRUCT(a INTEGER, b VARCHAR), MAP(VARCHAR, +// INTEGER), UNION(num INTEGER, str VARCHAR), ENUM('a', 'b'), TIMESTAMP +// WITH TIME ZONE — into an expression in lower case, named the way the +// dialect names it when the spelling is one of the aliases types.jsonl +// lists. DuckDB spells an enum column by its labels whether the schema +// named the type or not, so labels that are those of an enum the schema +// created name that type. +func (a *analyzer) parseType(s string) *analysis.TypeExpr { + return a.parseTypeWith(s, true) +} + +// parseTypeWith reads a type, naming an alias as the dialect does when +// canonical is set and as DuckDB spells it otherwise. +func (a *analyzer) parseTypeWith(s string, canonical bool) *analysis.TypeExpr { + s = strings.TrimSpace(s) + if strings.HasSuffix(s, "]") { + open := strings.LastIndexByte(s, '[') + if open > 0 { + t := &analysis.TypeExpr{Name: "array", Args: []analysis.TypeArg{{Type: a.parseTypeWith(s[:open], canonical)}}} + if n, err := strconv.ParseInt(strings.TrimSpace(s[open+1:len(s)-1]), 10, 64); err == nil { + t.Args = append(t.Args, analysis.TypeArg{Int: &n}) + } + return t + } + } + name, args := s, "" + if open := strings.IndexByte(s, '('); open >= 0 && strings.HasSuffix(s, ")") { + name, args = strings.TrimSpace(s[:open]), s[open+1:len(s)-1] + } + name = strings.ToLower(name) + if c, ok := a.canonical[name]; ok && canonical { + name = c + } + t := &analysis.TypeExpr{Name: name} + if args == "" { + return t + } + switch name { + case "struct", "union": + for _, f := range splitTop(args, ',') { + f = strings.TrimSpace(f) + label, typ := f, "" + if strings.HasPrefix(f, `"`) { + end := quotedEnd(f, 0) + label, typ = strings.ReplaceAll(f[1:end-1], `""`, `"`), f[end:] + } else if i := strings.IndexByte(f, ' '); i > 0 { + label, typ = f[:i], f[i+1:] + } + t.Args = append(t.Args, analysis.TypeArg{Label: label, Type: a.parseTypeWith(typ, canonical)}) + } + case "enum": + var labels []string + for _, l := range splitTop(args, ',') { + l = strings.TrimSpace(l) + if strings.HasPrefix(l, "'") && strings.HasSuffix(l, "'") && len(l) >= 2 { + l = strings.ReplaceAll(l[1:len(l)-1], "''", "'") + } + labels = append(labels, l) + } + if named, ok := a.enumNamed(labels); ok { + return &analysis.TypeExpr{Name: named} + } + for _, l := range labels { + l := l + t.Args = append(t.Args, analysis.TypeArg{String: &l}) + } + default: + for _, arg := range splitTop(args, ',') { + arg = strings.TrimSpace(arg) + if n, err := strconv.ParseInt(arg, 10, 64); err == nil { + t.Args = append(t.Args, analysis.TypeArg{Int: &n}) + } else { + t.Args = append(t.Args, analysis.TypeArg{Type: a.parseTypeWith(arg, canonical)}) + } + } + } + return t +} + +// enumNamed finds the enum type the schema created with these labels, +// the first by name when two share them. +func (a *analyzer) enumNamed(labels []string) (string, bool) { + names := make([]string, 0, len(a.enums)) + for name := range a.enums { + names = append(names, name) + } + sort.Strings(names) + for _, name := range names { + have := a.enums[name] + if len(have) != len(labels) { + continue + } + same := true + for i := range have { + if have[i] != labels[i] { + same = false + break + } + } + if same { + return name, true + } + } + return "", false +} + +// splitTop splits on a separator outside parentheses, brackets and +// quotes. +func splitTop(s string, sep byte) []string { + var out []string + depth, start := 0, 0 + var quote byte + for i := 0; i < len(s); i++ { + c := s[i] + switch { + case quote != 0: + if c == quote { + quote = 0 + } + case c == '\'' || c == '"': + quote = c + case c == '(' || c == '[': + depth++ + case c == ')' || c == ']': + depth-- + case c == sep && depth == 0: + out = append(out, s[start:i]) + start = i + 1 + } + } + return append(out, s[start:]) +} + +// zero is a value of a type, spelled as a string DuckDB casts to the type: +// what a parameter is bound to when the query is run to see which of its +// columns can be NULL. A type no value is known for reports false, and +// the parameter is bound to NULL. +func (a *analyzer) zero(t *analysis.TypeExpr) (string, bool) { + if t == nil { + return "", false + } + switch t.Name { + case "tinyint", "smallint", "integer", "bigint", "hugeint", "utinyint", "usmallint", "uinteger", "ubigint", "uhugeint", + "decimal", "float", "double", "bignum", "varint": + return "1", true + case "varchar", "text", "char", "bpchar": + return "x", true + case "json": + return "{}", true + case "blob": + return "", true + case "bit": + return "0", true + case "boolean": + return "true", true + case "uuid": + return "00000000-0000-0000-0000-000000000000", true + case "date": + return "2000-01-01", true + case "time", "time with time zone": + return "00:00:00", true + case "timestamp", "timestamp with time zone", "timestamp_s", "timestamp_ms", "timestamp_ns", "datetime": + return "2000-01-01 00:00:00", true + case "interval": + return "1 day", true + case "map": + return "{}", true + case "array": + if len(t.Args) == 0 || t.Args[0].Type == nil { + return "", false + } + elem, ok := a.zero(t.Args[0].Type) + if !ok { + return "", false + } + n := 1 + if len(t.Args) > 1 && t.Args[1].Int != nil { + n = int(*t.Args[1].Int) + } + elems := make([]string, n) + for i := range elems { + elems[i] = elem + } + return "[" + strings.Join(elems, ", ") + "]", true + case "struct": + var fields []string + for _, f := range t.Args { + v, ok := a.zero(f.Type) + if !ok { + return "", false + } + fields = append(fields, f.Label+": "+v) + } + return "{" + strings.Join(fields, ", ") + "}", true + case "union": + if len(t.Args) == 0 { + return "", false + } + return a.zero(t.Args[0].Type) + case "enum": + if len(t.Args) > 0 && t.Args[0].String != nil { + return *t.Args[0].String, true + } + } + if labels, ok := a.enums[t.Name]; ok && len(labels) > 0 { + return labels[0], true + } + return "", false +} diff --git a/internal/goldeneye/endtoend/endtoend.go b/internal/goldeneye/endtoend/endtoend.go new file mode 100644 index 0000000..0beb494 --- /dev/null +++ b/internal/goldeneye/endtoend/endtoend.go @@ -0,0 +1,140 @@ +// Package endtoend finds the analyze cases under internal/endtoend/testdata +// and compares an engine's own answer with the output a case committed, +// the way the dialect package compares a generated dialect with the +// committed one. +package endtoend + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "os" + "path/filepath" + "runtime" + "strings" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/dialect" +) + +// Case is one analyze case: the files sqlc analyze ran with, the fixture +// loaded before the queries run against a real database, and the output +// sqlc committed. +type Case struct { + Name string // analyze_params/clickhouse + Dir string + Schema string + Query string + Fixture string // empty when the case has no fixture.sql + Output string +} + +// Testdata returns the end-to-end testdata directory, found relative to this +// source file so the working directory does not matter. +func Testdata() (string, error) { + _, file, _, ok := runtime.Caller(0) + if !ok { + return "", errors.New("cannot locate the testcheck source directory") + } + dir := filepath.Join(filepath.Dir(file), "..", "..", "endtoend", "testdata") + if _, err := os.Stat(dir); err != nil { + return "", err + } + return filepath.Clean(dir), nil +} + +// Cases lists the analyze cases for an engine: every analyze_*/ +// directory whose exec.json runs the analyze command. A case that asks for +// the AST is skipped, since only sqlc can print that. +func Cases(engine string) ([]Case, error) { + root, err := Testdata() + if err != nil { + return nil, err + } + dirs, err := filepath.Glob(filepath.Join(root, "analyze_*", engine)) + if err != nil { + return nil, err + } + var cases []Case + for _, dir := range dirs { + c, ok, err := load(dir) + if err != nil { + return nil, fmt.Errorf("%s: %w", dir, err) + } + if ok { + cases = append(cases, c) + } + } + return cases, nil +} + +func load(dir string) (Case, bool, error) { + blob, err := os.ReadFile(filepath.Join(dir, "exec.json")) + if errors.Is(err, os.ErrNotExist) { + return Case{}, false, nil + } + if err != nil { + return Case{}, false, err + } + var exec struct { + Command string `json:"command"` + Args []string `json:"args"` + } + if err := json.Unmarshal(blob, &exec); err != nil { + return Case{}, false, fmt.Errorf("exec.json: %w", err) + } + if exec.Command != "analyze" { + return Case{}, false, nil + } + var schema, query string + for i := 0; i < len(exec.Args); i++ { + switch arg := exec.Args[i]; arg { + case "--schema", "-s", "--dialect", "-d": + i++ + if arg == "--schema" || arg == "-s" { + if i < len(exec.Args) { + schema = exec.Args[i] + } + } + case "--ast": + return Case{}, false, nil + default: + if !strings.HasPrefix(arg, "-") { + query = arg + } + } + } + if schema == "" || query == "" { + return Case{}, false, errors.New("exec.json: analyze needs --schema and a query file") + } + c := Case{ + Name: filepath.Join(filepath.Base(filepath.Dir(dir)), filepath.Base(dir)), + Dir: dir, + Schema: filepath.Join(dir, schema), + Query: filepath.Join(dir, query), + Output: filepath.Join(dir, "stdout.json"), + } + if fixture := filepath.Join(dir, "fixture.sql"); fileExists(fixture) { + c.Fixture = fixture + } + return c, true, nil +} + +func fileExists(path string) bool { + _, err := os.Stat(path) + return err == nil +} + +// Compare checks an engine's answer against the case's committed output +// byte for byte and returns a line diff when they differ, or "" when they +// match. +func (c Case) Compare(got []byte) (string, error) { + want, err := os.ReadFile(c.Output) + if err != nil { + return "", err + } + if bytes.Equal(want, got) { + return "", nil + } + return dialect.Diff(string(want), string(got)), nil +} diff --git a/internal/goldeneye/endtoend/query.go b/internal/goldeneye/endtoend/query.go new file mode 100644 index 0000000..70a8ae7 --- /dev/null +++ b/internal/goldeneye/endtoend/query.go @@ -0,0 +1,183 @@ +package endtoend + +import ( + "fmt" + "os" + "regexp" + "strings" + "unicode" +) + +// Query is one entry of a sqlc query file. +type Query struct { + Name string + Cmd string + SQL string +} + +// Queries reads the case's query file and splits it into its queries. +func (c Case) Queries() ([]Query, error) { + src, err := os.ReadFile(c.Query) + if err != nil { + return nil, err + } + queries, err := ParseQueries(string(src)) + if err != nil { + return nil, fmt.Errorf("%s: %w", c.Query, err) + } + return queries, nil +} + +var headerRe = regexp.MustCompile(`^\s*--\s*name:\s*(\S+)\s+(:\S+)\s*$`) + +// ParseQueries splits a sqlc query file on its `-- name: X :cmd` headers. +func ParseQueries(src string) ([]Query, error) { + var queries []Query + var cur *Query + var body []string + flush := func() error { + if cur == nil { + return nil + } + sql := strings.TrimSpace(strings.Join(body, "\n")) + sql = strings.TrimRight(sql, "; \t\r\n") + if sql == "" { + return fmt.Errorf("query %s has no body", cur.Name) + } + cur.SQL = sql + queries = append(queries, *cur) + return nil + } + for _, line := range strings.Split(src, "\n") { + if m := headerRe.FindStringSubmatch(line); m != nil { + if err := flush(); err != nil { + return nil, err + } + cur = &Query{Name: m[1], Cmd: m[2]} + body = body[:0] + continue + } + if cur != nil { + body = append(body, line) + } + } + if err := flush(); err != nil { + return nil, err + } + if len(queries) == 0 { + return nil, fmt.Errorf("no queries found: expected `-- name: Name :cmd` headers") + } + return queries, nil +} + +var namedArgRe = regexp.MustCompile(`^sqlc\.(n?arg|slice)\(\s*'?([A-Za-z_][A-Za-z0-9_]*)'?\s*\)`) + +// typedParamRe matches ClickHouse's {name:Type} parameter, whose type is +// the query's own business: the engine binds it as it binds any other. +var typedParamRe = regexp.MustCompile(`^\{\s*([A-Za-z_][A-Za-z0-9_]*)\s*:\s*[^}]+\}`) + +// Rewrite replaces every parameter reference in a query — ?, sqlc.arg(name), +// sqlc.narg(name), sqlc.slice(name) and ClickHouse's {name:Type} — with +// what bind returns for it, in order of appearance, skipping string +// literals, quoted identifiers and comments. bind is handed the name, empty for a ?, and the word before the +// reference, so that a LIMIT or OFFSET can be bound differently from a +// value; the second count of a LIMIT ?, ? is handed LIMIT as well. Each +// engine decides what a reference becomes and how the references are +// numbered. +func Rewrite(sql string, bind func(name, lastWord string) string) string { + var ( + out strings.Builder + lastWord string + i = 0 + ) + for i < len(sql) { + c := sql[i] + switch { + case c == '\'' || c == '"' || c == '`': + end := skipQuoted(sql, i) + out.WriteString(sql[i:end]) + i = end + case strings.HasPrefix(sql[i:], "--"): + end := strings.IndexByte(sql[i:], '\n') + if end < 0 { + end = len(sql) + } else { + end += i + } + out.WriteString(sql[i:end]) + i = end + case strings.HasPrefix(sql[i:], "/*"): + end := strings.Index(sql[i:], "*/") + if end < 0 { + end = len(sql) + } else { + end += i + 2 + } + out.WriteString(sql[i:end]) + i = end + case c == '?': + out.WriteString(bind("", lastWord)) + lastWord = afterReference(lastWord) + i++ + case c == 's' && namedArgRe.MatchString(sql[i:]): + m := namedArgRe.FindStringSubmatch(sql[i:]) + out.WriteString(bind(m[2], lastWord)) + lastWord = afterReference(lastWord) + i += len(m[0]) + case c == '{' && typedParamRe.MatchString(sql[i:]): + m := typedParamRe.FindStringSubmatch(sql[i:]) + out.WriteString(bind(m[1], lastWord)) + lastWord = afterReference(lastWord) + i += len(m[0]) + case isWordByte(c): + end := i + for end < len(sql) && isWordByte(sql[end]) { + end++ + } + lastWord = sql[i:end] + out.WriteString(lastWord) + i = end + default: + if !unicode.IsSpace(rune(c)) && c != ',' && c != '(' { + lastWord = "" + } + out.WriteByte(c) + i++ + } + } + return out.String() +} + +// afterReference is the word the reference after one is preceded by: a +// LIMIT's, so that both counts of LIMIT ?, ? are bound as counts, and +// otherwise none. +func afterReference(lastWord string) string { + if strings.EqualFold(lastWord, "limit") { + return lastWord + } + return "" +} + +func isWordByte(c byte) bool { + return c == '_' || c == '.' || c >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' +} + +// skipQuoted returns the index just past the quoted token starting at i, +// honouring backslash escapes and doubled quotes. +func skipQuoted(s string, i int) int { + q := s[i] + j := i + 1 + for j < len(s) { + switch { + case s[j] == '\\' && j+1 < len(s): + j += 2 + case s[j] == q && j+1 < len(s) && s[j+1] == q: + j += 2 + case s[j] == q: + return j + 1 + default: + j++ + } + } + return len(s) +} diff --git a/internal/goldeneye/go.mod b/internal/goldeneye/go.mod new file mode 100644 index 0000000..5811472 --- /dev/null +++ b/internal/goldeneye/go.mod @@ -0,0 +1,52 @@ +module github.com/sqlc-dev/sqlc/internal/goldeneye + +go 1.26.0 + +require ( + cloud.google.com/go/spanner v1.95.1 + github.com/go-sql-driver/mysql v1.10.0 + github.com/jackc/pgx/v5 v5.10.0 + github.com/microsoft/go-mssqldb v1.11.0 + google.golang.org/api v0.297.0 + google.golang.org/grpc v1.83.2 + google.golang.org/protobuf v1.36.12 +) + +require ( + cloud.google.com/go v0.123.0 // indirect + cloud.google.com/go/auth v0.23.2 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect + cloud.google.com/go/compute/metadata v0.9.0 // indirect + cloud.google.com/go/iam v1.12.0 // indirect + cloud.google.com/go/longrunning v1.2.0 // indirect + filippo.io/edwards25519 v1.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect + github.com/golang-sql/sqlexp v0.1.0 // indirect + github.com/google/s2a-go v0.1.9 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.20 // indirect + github.com/googleapis/gax-go/v2 v2.24.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/shopspring/decimal v1.4.0 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 // indirect + go.opentelemetry.io/otel v1.44.0 // indirect + go.opentelemetry.io/otel/metric v1.44.0 // indirect + go.opentelemetry.io/otel/trace v1.44.0 // indirect + golang.org/x/crypto v0.55.0 // indirect + golang.org/x/net v0.58.0 // indirect + golang.org/x/oauth2 v0.36.0 // indirect + golang.org/x/sync v0.22.0 // indirect + golang.org/x/sys v0.47.0 // indirect + golang.org/x/text v0.41.0 // indirect + golang.org/x/time v0.15.0 // indirect + google.golang.org/genproto v0.0.0-20260715232425-e75dac1f907d // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260715232425-e75dac1f907d // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260819154853-08b0e4226688 // indirect +) diff --git a/internal/goldeneye/go.sum b/internal/goldeneye/go.sum new file mode 100644 index 0000000..e312586 --- /dev/null +++ b/internal/goldeneye/go.sum @@ -0,0 +1,137 @@ +cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= +cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= +cloud.google.com/go/auth v0.23.2 h1:pxSCpfiji41hpzpPdMCftEUCezpgpqmmDdYiAjCKXxo= +cloud.google.com/go/auth v0.23.2/go.mod h1:4DhBRcqvtljQN3dJ57qtqbib5ZGCYE5f2crfiiC2EM0= +cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= +cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= +cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= +cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= +cloud.google.com/go/iam v1.12.0 h1:Aki3bX9aHUDKPHfnRJfDcTdVedvy6quGBQcTqx3DRXk= +cloud.google.com/go/iam v1.12.0/go.mod h1:FEZ4lXpADAC2AIpQY7LANNjjwyQ2jK439CI2VaD+sLY= +cloud.google.com/go/longrunning v1.2.0 h1:WjYH3YHBGCxGJP9M4dWGHBfXr/cFIjMkNgWcJj7/iMM= +cloud.google.com/go/longrunning v1.2.0/go.mod h1:5KMQALFGOCtFoi2xSOA1u3H7WKlhmckgiyFw7+LGQp0= +cloud.google.com/go/spanner v1.95.1 h1:9HYr+AAeAOubn0NZAYv34dFHQ3NbIUcWHZmgJvufPzk= +cloud.google.com/go/spanner v1.95.1/go.mod h1:Z2+83J5oVDmd1n5ntVMmjEuiNoXOpAyNeG7y1tuEHk0= +filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo= +filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.23.0 h1:4gRPBpN1f6xt88yi4WR26m7XaD9OlWtVT6bWPdGUIok= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.23.0/go.mod h1:G7QVLxw1j1JVyrO1MA95S8m8HStaaleDZYTcfGgjB2o= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.14.0 h1:CU4+EJeJi3TKYWEcYuSdWsjzw0nVsK/H0MSQOiPcymU= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.14.0/go.mod h1:q0+UTSRvShwUCrR/s5HtyInYphN7Wvxb7snFM3u+SLA= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.12.0 h1:fhqpLE3UEXi9lPaBRpQ6XuRW0nU7hgg4zlmZZa+a9q4= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.12.0/go.mod h1:7dCRMLwisfRH3dBupKeNCioWYUZ4SS09Z14H+7i8ZoY= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.5.0 h1:MaKvxE6D0KkjOg6Wd9M00iqP5PR0kUxCfiezes4JweM= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.5.0/go.mod h1:i2h9fsTFKZorh8RdV2IcSUf/Qj98GlTkrTvUbX/s8as= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 h1:nCYfgcSyHZXJI8J0IWE5MsCGlb2xp9fJiXyxWgmOFg4= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0/go.mod h1:ucUjca2JtSZboY8IoUqyQyuuXvwbMBVwFOm0vdQPNhA= +github.com/AzureAD/microsoft-authentication-library-for-go v1.7.2 h1:RHK7bS+HQMslb1sZpAokUt+zTVmue0hKSs2C791hhzU= +github.com/AzureAD/microsoft-authentication-library-for-go v1.7.2/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 h1:aBangftG7EVZoUb69Os8IaYg++6uMOdKK83QtkkvJik= +github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2/go.mod h1:qwXFYgsP6T7XnJtbKlf1HP8AjxZZyzxMmc+Lq5GjlU4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA= +github.com/envoyproxy/go-control-plane/envoy v1.37.0 h1:u3riX6BoYRfF4Dr7dwSOroNfdSbEPe9Yyl09/B6wBrQ= +github.com/envoyproxy/go-control-plane/envoy v1.37.0/go.mod h1:DReE9MMrmecPy+YvQOAOHNYMALuowAnbjjEMkkWOi6A= +github.com/envoyproxy/protoc-gen-validate v1.3.3 h1:MVQghNeW+LZcmXe7SY1V36Z+WFMDjpqGAGacLe2T0ds= +github.com/envoyproxy/protoc-gen-validate v1.3.3/go.mod h1:TsndJ/ngyIdQRhMcVVGDDHINPLWB7C82oDArY51KfB0= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-sql-driver/mysql v1.10.0 h1:Q+1LV8DkHJvSYAdR83XzuhDaTykuDx0l6fkXxoWCWfw= +github.com/go-sql-driver/mysql v1.10.0/go.mod h1:M+cqaI7+xxXGG9swrdeUIoPG3Y3KCkF0pZej+SK+nWk= +github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= +github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= +github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.20 h1:t/xL64VUoN69MuMRQuJETqYGOw4Z9mSRJK9epIEtwFk= +github.com/googleapis/enterprise-certificate-proxy v0.3.20/go.mod h1:L3D/IQExI6LqEjBdXcZQ1WluSgigQmSwBboFstVPM4w= +github.com/googleapis/gax-go/v2 v2.24.0 h1:myMaPYyF9MecEmvQqMqomIwn9t/4KCZN9qnwsS76wlg= +github.com/googleapis/gax-go/v2 v2.24.0/go.mod h1:IaTHBDd7NHxSCiu0vEs8pQZu4dGZrWwuSoxCnk16OFM= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.10.0 h1:VhSvgU2jSli8o3AqIEOTJr7rZwAEUVo4E4XhR94Zfr0= +github.com/jackc/pgx/v5 v5.10.0/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/microsoft/go-mssqldb v1.11.0 h1:YbDqolEjGH9hBfvKzONTf5/dbl9RKXmizMJE93lVxNs= +github.com/microsoft/go-mssqldb v1.11.0/go.mod h1:goQLDOPlMN/l1REhnNPElMoY/yX+fUWn1+7UoFJPH9Y= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE= +github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0 h1:yI1/OhfEPy7J9eoa6Sj051C7n5dvpj0QX8g4sRchg04= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0/go.mod h1:NoUCKYWK+3ecatC4HjkRktREheMeEtrXoQxrqYFeHSc= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 h1:OyrsyzuttWTSur2qN/Lm0m2a8yqyIjUVBZcxFPuXq2o= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0/go.mod h1:C2NGBr+kAB4bk3xtMXfZ94gqFDtg/GkI7e9zqGh5Beg= +go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= +go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= +go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= +go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= +go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= +go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0= +go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= +go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA= +go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= +go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= +go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw= +go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg= +golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M= +golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis= +golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To= +golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU= +golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= +golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= +golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= +golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= +golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= +golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= +golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= +golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/api v0.297.0 h1:WktxTsnnx0yZNnsR6j0q6hR21RnnK81FHTOPy/ux4OE= +google.golang.org/api v0.297.0/go.mod h1:S4m8x0M6OkQpkOzGk1y9JG2sm4fFQrMh6dxzjCTszhE= +google.golang.org/genproto v0.0.0-20260715232425-e75dac1f907d h1:C9v1o0/4quuhOAfmRXA2j+we0PqZIp8traLdeogF3Ms= +google.golang.org/genproto v0.0.0-20260715232425-e75dac1f907d/go.mod h1:Wz2wFJntZFmLGo7pLDXZ3wYk5hyc0Mb+SkHhDDXT+lU= +google.golang.org/genproto/googleapis/api v0.0.0-20260715232425-e75dac1f907d h1:QwnJwPte4XXAkhPu26LTDIahnsMSUV0kK8HkxbC+Pc4= +google.golang.org/genproto/googleapis/api v0.0.0-20260715232425-e75dac1f907d/go.mod h1:WRrQ7/7N19PypuT0fxLOL5Lq0waoiRri4FbtHDEKrGE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260819154853-08b0e4226688 h1:cYNAzI2sUwhmCcoj9TxvihSrqsxt6uIkj3rDRhSDmW4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260819154853-08b0e4226688/go.mod h1:DjtHYE8FKJLivXcBEjGwndXfIC23G0VpXiXKqG179uA= +google.golang.org/grpc v1.83.2 h1:EManeRomTObA0BU7I8vXgg/78uE5MJ9M8B39EX2WscU= +google.golang.org/grpc v1.83.2/go.mod h1:YPI1hK3kDked6iHvgX3tR0y+nX/qpMFKhPgFsokw1S8= +google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc= +google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/goldeneye/mssql/analyze.go b/internal/goldeneye/mssql/analyze.go new file mode 100644 index 0000000..e4caaf6 --- /dev/null +++ b/internal/goldeneye/mssql/analyze.go @@ -0,0 +1,725 @@ +package mssql + +import ( + "context" + "database/sql" + "fmt" + "os" + "regexp" + "strconv" + "strings" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/analysis" + "github.com/sqlc-dev/sqlc/internal/goldeneye/dialect" + "github.com/sqlc-dev/sqlc/internal/goldeneye/endtoend" +) + +// The analyze cases are checked against a live server, which is asked +// three things about each query, none of which runs it. What a driver +// would see: sys.dm_exec_describe_first_result_set describes each result +// column — its name, its type spelled the way a declaration spells it, +// whether it can be NULL, and which table column it is read from. What +// each parameter would be: sp_describe_undeclared_parameters says what +// type the server would give each parameter the query leaves undeclared. +// And what each parameter stands in for: the estimated showplan, compiled +// with the parameters declared as those types, says which column each is +// compared with or assigned to, and a parameter with such a partner is +// described as that column, from the catalog of the case's database. +// +// Two things the describing function keeps to itself: a json or vector +// column is described by the nvarchar(max) it is sent to a driver as, so +// a column read from a table is typed from the catalog instead, and a +// type SQL Server calls timestamp is written as the rowversion the +// dialect names it. + +// placeholder is one parameter of a query as sqlc numbers them: each ? +// in turn, and each @name or sqlc.arg name once, at its first appearance. +// Each appearance becomes a variable of its own, since the server +// describes an undeclared parameter only when it is used once. +type placeholder struct { + Number int + Name string + Vars []string // the variables its appearances became, without the @ +} + +var identRe = regexp.MustCompile(`^@([A-Za-z_][A-Za-z0-9_]*)`) + +// bind rewrites the query so that every parameter is a variable used once, +// and lists the parameters in sqlc's order. The query's own @name +// references are kept, since that is how sqlc's SQL Server queries name +// their parameters; a sqlc.arg becomes one, and each ? in turn becomes +// one named after its position. +func bind(query string) (string, []placeholder) { + positional := 0 + sql := endtoend.Rewrite(query, func(name, _ string) string { + if name == "" { + positional++ + name = "p" + strconv.Itoa(positional) + } + return "@" + name + }) + var ( + phs []placeholder + numbers = map[string]int{} + out strings.Builder + ) + i := 0 + for i < len(sql) { + c := sql[i] + switch { + case c == '\'' || c == '"' || c == '[': + end := skipQuoted(sql, i) + out.WriteString(sql[i:end]) + i = end + case strings.HasPrefix(sql[i:], "--"): + end := strings.IndexByte(sql[i:], '\n') + if end < 0 { + end = len(sql) + } else { + end += i + } + out.WriteString(sql[i:end]) + i = end + case strings.HasPrefix(sql[i:], "/*"): + end := strings.Index(sql[i:], "*/") + if end < 0 { + end = len(sql) + } else { + end += i + 2 + } + out.WriteString(sql[i:end]) + i = end + case c == '@' && (i == 0 || !isWordByte(sql[i-1])) && identRe.MatchString(sql[i:]): + m := identRe.FindStringSubmatch(sql[i:]) + name := m[1] + n, ok := numbers[name] + if !ok { + n = len(phs) + 1 + numbers[name] = n + phs = append(phs, placeholder{Number: n, Name: name}) + } + ph := &phs[n-1] + v := name + if k := len(ph.Vars); k > 0 { + v = fmt.Sprintf("%s__%d", name, k+1) + } + ph.Vars = append(ph.Vars, v) + out.WriteString("@" + v) + i += len(m[0]) + default: + out.WriteByte(c) + i++ + } + } + return out.String(), phs +} + +func isWordByte(c byte) bool { + return c == '_' || c == '@' || c >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' +} + +// skipQuoted returns the index just past the quoted token starting at i: a +// string, a double-quoted identifier or a bracketed one, whose closing +// delimiter is escaped by doubling it. +func skipQuoted(s string, i int) int { + open := s[i] + close := open + if open == '[' { + close = ']' + } + j := i + 1 + for j < len(s) { + switch { + case s[j] == close && j+1 < len(s) && s[j+1] == close: + j += 2 + case s[j] == close: + return j + 1 + default: + j++ + } + } + return len(s) +} + +// splitStatements splits a script into the statements it is made of, on +// the semicolons outside strings, brackets, comments and BEGIN ... END +// blocks, and on the GO lines a T-SQL script separates batches with. A +// CREATE TYPE has to be its own batch before a table can use the type, so +// a schema is loaded one statement at a time; a trigger or procedure +// body keeps its semicolons, since a BEGIN, or a CASE, opens a block that +// its END closes. +func splitStatements(src string) []string { + var stmts []string + flush := func(s string) { + if s = strings.TrimSpace(s); s != "" && !strings.EqualFold(s, "go") { + stmts = append(stmts, s) + } + } + start := 0 + i := 0 + depth := 0 + if isGoLine(src, 0) { + for i < len(src) && src[i] != '\n' { + i++ + } + start = i + } + for i < len(src) { + c := src[i] + switch { + case c == '\'' || c == '"' || c == '[': + i = skipQuoted(src, i) + case strings.HasPrefix(src[i:], "--"): + end := strings.IndexByte(src[i:], '\n') + if end < 0 { + i = len(src) + } else { + i += end + } + case strings.HasPrefix(src[i:], "/*"): + end := strings.Index(src[i:], "*/") + if end < 0 { + i = len(src) + } else { + i += end + 2 + } + case isWordByte(c): + end := i + for end < len(src) && isWordByte(src[end]) { + end++ + } + switch word := strings.ToLower(src[i:end]); word { + case "begin": + // BEGIN TRAN[SACTION] and BEGIN DISTRIBUTED are statements, + // not blocks. + if !nextWordIn(src, end, "tran", "transaction", "distributed") { + depth++ + } + case "case": + depth++ + case "end": + if depth > 0 { + depth-- + } + } + i = end + case c == ';' && depth == 0: + flush(src[start:i]) + start = i + 1 + i++ + case c == '\n' && isGoLine(src, i+1): + flush(src[start:i]) + i++ + for i < len(src) && src[i] != '\n' { + i++ + } + start = i + depth = 0 + default: + i++ + } + } + flush(src[start:]) + return stmts +} + +// nextWordIn reports whether the word after position i, past spaces and +// comments, is one of the words. +func nextWordIn(src string, i int, words ...string) bool { + for i < len(src) { + switch { + case src[i] == ' ' || src[i] == '\t' || src[i] == '\n' || src[i] == '\r': + i++ + case strings.HasPrefix(src[i:], "--"): + end := strings.IndexByte(src[i:], '\n') + if end < 0 { + return false + } + i += end + case strings.HasPrefix(src[i:], "/*"): + end := strings.Index(src[i:], "*/") + if end < 0 { + return false + } + i += end + 2 + default: + end := i + for end < len(src) && isWordByte(src[end]) { + end++ + } + for _, w := range words { + if strings.EqualFold(src[i:end], w) { + return true + } + } + return false + } + } + return false +} + +// isGoLine reports whether the line starting at i is a GO batch separator. +func isGoLine(src string, i int) bool { + end := strings.IndexByte(src[i:], '\n') + if end < 0 { + end = len(src) + } else { + end += i + } + return strings.EqualFold(strings.TrimSpace(src[i:end]), "go") +} + +// column is what the catalog says about a column of the case's database. +type column struct { + name string + typ *analysis.TypeExpr + nullable bool +} + +// relation is a table or view of the case's database, by schema and name, +// in lower case. +type relation struct { + schema, name string +} + +// analyzer holds the session a case is described in and the catalog of +// the case's database. +type analyzer struct { + conn *sql.Conn + catalog map[relation][]column + // userTypes are the alias types the schema created, by name in lower + // case, which the server reports beside the system type they stand on + // and the dialect reports by their own name. + userTypes map[string]bool + // canonical names the type the dialect reports a spelling as, for each + // alias types.jsonl lists: SQL Server spells numeric and timestamp in + // its catalog, which the dialect names decimal and rowversion. + canonical map[string]string +} + +var dbNameRe = regexp.MustCompile(`[^A-Za-z0-9_]+`) + +// Analyze loads a case's schema and fixture into a database of their own +// on the server, describes its queries there and returns what SQL Server +// reports in the JSON shape sqlc analyze prints. +func Analyze(ctx context.Context, dsn string, c endtoend.Case) ([]byte, error) { + conn, err := open(ctx, dsn) + if err != nil { + return nil, err + } + defer conn.Close() + if err := checkVersion(ctx, conn); err != nil { + return nil, err + } + + schema, err := os.ReadFile(c.Schema) + if err != nil { + return nil, err + } + var fixture []byte + if c.Fixture != "" { + if fixture, err = os.ReadFile(c.Fixture); err != nil { + return nil, err + } + } + queries, err := c.Queries() + if err != nil { + return nil, err + } + + db := quote("goldeneye_" + dbNameRe.ReplaceAllString(c.Name, "_")) + for _, stmt := range []string{ + "USE master", + "DROP DATABASE IF EXISTS " + db, + "CREATE DATABASE " + db, + "USE " + db, + } { + if _, err := conn.ExecContext(ctx, stmt); err != nil { + return nil, err + } + } + defer conn.ExecContext(context.WithoutCancel(ctx), "USE master; DROP DATABASE IF EXISTS "+db) + for _, stmt := range splitStatements(string(schema)) { + if _, err := conn.ExecContext(ctx, stmt); err != nil { + return nil, fmt.Errorf("loading %s: %w", c.Schema, err) + } + } + for _, stmt := range splitStatements(string(fixture)) { + if _, err := conn.ExecContext(ctx, stmt); err != nil { + return nil, fmt.Errorf("loading %s: %w", c.Fixture, err) + } + } + + a := &analyzer{conn: conn} + if a.canonical, err = readAliases(); err != nil { + return nil, err + } + if err := a.readCatalog(ctx); err != nil { + return nil, err + } + out := make([]analysis.Query, 0, len(queries)) + for _, q := range queries { + aq, err := a.analyzeQuery(ctx, q) + if err != nil { + return nil, fmt.Errorf("%s: %w", q.Name, err) + } + out = append(out, aq) + } + return analysis.Encode(out) +} + +// readAliases reads the aliases the hand-written types.jsonl gives each +// type, keyed by alias. +func readAliases() (map[string]string, error) { + dir, err := dialect.Dir(Engine) + if err != nil { + return nil, err + } + types, err := dialect.ReadTypes(dir) + if err != nil { + return nil, err + } + canonical := map[string]string{} + for _, t := range types { + for _, alias := range t.Aliases { + canonical[strings.ToLower(alias)] = strings.ToLower(t.Name) + } + } + return canonical, nil +} + +// Check compares what SQL Server reports for a case with the output the +// case committed, returning a diff when they differ. +func Check(ctx context.Context, dsn string, c endtoend.Case) (string, error) { + got, err := Analyze(ctx, dsn, c) + if err != nil { + return "", err + } + return c.Compare(got) +} + +// tablesQuery lists the tables and views of the current database, and the +// columns of each: the type as the schema declared it, whether that is a +// type the schema created, and the dimensions of a vector, which is all +// the describing function does not say. +const tablesQuery = ` +SELECT s.name, o.name, c.name, t.name, t.is_user_defined, c.vector_dimensions +FROM sys.columns c +JOIN sys.objects o ON o.object_id = c.object_id +JOIN sys.schemas s ON s.schema_id = o.schema_id +JOIN sys.types t ON t.user_type_id = c.user_type_id +WHERE o.type IN ('U', 'V') +ORDER BY s.name, o.name, c.column_id` + +// readCatalog reads the tables the schema created. The server spells each +// column's type by describing a SELECT * from the table, and the catalog +// says which columns that spelling is not the declared type of. +func (a *analyzer) readCatalog(ctx context.Context) error { + a.catalog = map[relation][]column{} + a.userTypes = map[string]bool{} + rows, err := a.conn.QueryContext(ctx, tablesQuery) + if err != nil { + return err + } + type declared struct { + name string + typeName string + userDefined bool + dimensions sql.NullInt64 + } + decls := map[relation][]declared{} + var order []relation + for rows.Next() { + var ( + schema, table, col string + d declared + ) + if err := rows.Scan(&schema, &table, &col, &d.typeName, &d.userDefined, &d.dimensions); err != nil { + rows.Close() + return err + } + d.name = col + rel := relation{strings.ToLower(schema), strings.ToLower(table)} + if _, ok := decls[rel]; !ok { + order = append(order, rel) + } + decls[rel] = append(decls[rel], d) + if d.userDefined { + a.userTypes[strings.ToLower(d.typeName)] = true + } + } + rows.Close() + if err := rows.Err(); err != nil { + return err + } + for _, rel := range order { + described, err := a.describe(ctx, "SELECT * FROM "+quote(rel.schema)+"."+quote(rel.name)) + if err != nil { + return fmt.Errorf("%s.%s: %w", rel.schema, rel.name, err) + } + byName := map[string]declared{} + for _, d := range decls[rel] { + byName[strings.ToLower(d.name)] = d + } + var cols []column + for _, dc := range described { + d, ok := byName[strings.ToLower(dc.name)] + if !ok { + return fmt.Errorf("%s.%s: the server describes a column %q the catalog does not list", rel.schema, rel.name, dc.name) + } + t := dc.typ + switch { + case d.userDefined: + t = &analysis.TypeExpr{Name: strings.ToLower(d.typeName)} + case strings.EqualFold(d.typeName, "json"): + t = &analysis.TypeExpr{Name: "json"} + case strings.EqualFold(d.typeName, "vector") && d.dimensions.Valid: + n := d.dimensions.Int64 + t = &analysis.TypeExpr{Name: "vector", Args: []analysis.TypeArg{{Int: &n}}} + } + cols = append(cols, column{name: strings.ToLower(dc.name), typ: t, nullable: dc.nullable}) + } + a.catalog[rel] = cols + } + return nil +} + +// described is one result column as sys.dm_exec_describe_first_result_set +// reports it. +type described struct { + name string + typ *analysis.TypeExpr + nullable bool + source *columnRef // the table column it is read from, or nil +} + +const describeColumnsQuery = ` +SELECT column_ordinal, name, system_type_name, user_type_name, is_nullable, + source_schema, source_table, source_column, is_computed_column, error_message +FROM sys.dm_exec_describe_first_result_set(@p1, NULL, 1) +WHERE is_hidden = 0 +ORDER BY column_ordinal` + +// describe asks the server what the first result set of a statement +// looks like. A statement that returns no rows describes as no columns; one +// the server cannot compile describes as its error. +func (a *analyzer) describe(ctx context.Context, query string) ([]described, error) { + rows, err := a.conn.QueryContext(ctx, describeColumnsQuery, query) + if err != nil { + return nil, err + } + defer rows.Close() + var out []described + for rows.Next() { + var ( + ordinal int + name, sysType, userType sql.NullString + nullable sql.NullBool + srcSchema, srcTable, srcColumn sql.NullString + computed sql.NullBool + errMsg sql.NullString + ) + if err := rows.Scan(&ordinal, &name, &sysType, &userType, &nullable, &srcSchema, &srcTable, &srcColumn, &computed, &errMsg); err != nil { + return nil, err + } + if errMsg.Valid { + return nil, fmt.Errorf("cannot be described: %s", errMsg.String) + } + d := described{ + name: name.String, + typ: a.typeOf(sysType.String, userType), + nullable: nullable.Bool, + } + // A computed column names the column it is computed from, as the + // one an update through the result set would write; a column is + // read from a table only when it is that column. + if srcTable.Valid && !computed.Bool { + d.source = &columnRef{schema: srcSchema.String, table: srcTable.String, column: srcColumn.String} + } + out = append(out, d) + } + return out, rows.Err() +} + +// typeOf reads a type the server spelled, which is the system type unless +// the server also names a type the schema created, which the dialect +// reports by that name and no argument. +func (a *analyzer) typeOf(systemType string, userType sql.NullString) *analysis.TypeExpr { + if userType.Valid && a.userTypes[strings.ToLower(userType.String)] { + return &analysis.TypeExpr{Name: strings.ToLower(userType.String)} + } + return parseType(systemType, a.canonical) +} + +// parseType reads a type spelled the way a declaration spells it — +// nvarchar(max), decimal(10,2), datetime2(7) — into an expression, named +// the way the dialect names it when the spelling is one of the aliases +// the dialect lists: numeric is decimal, timestamp is rowversion. +func parseType(s string, canonical map[string]string) *analysis.TypeExpr { + s = strings.TrimSpace(strings.ToLower(s)) + name, args := s, "" + if open := strings.IndexByte(s, '('); open >= 0 && strings.HasSuffix(s, ")") { + name, args = strings.TrimSpace(s[:open]), s[open+1:len(s)-1] + } + if c, ok := canonical[name]; ok { + name = c + } + t := &analysis.TypeExpr{Name: name} + if args == "" { + return t + } + for _, arg := range strings.Split(args, ",") { + arg = strings.TrimSpace(arg) + if n, err := strconv.ParseInt(arg, 10, 64); err == nil { + t.Args = append(t.Args, analysis.TypeArg{Int: &n}) + } else { + ident := arg + t.Args = append(t.Args, analysis.TypeArg{Ident: &ident}) + } + } + return t +} + +// withNullable copies a type with its nullability set. +func withNullable(t *analysis.TypeExpr, nullable bool) *analysis.TypeExpr { + if t == nil { + return nil + } + out := *t + out.Nullable = nullable + return &out +} + +// lookup finds a column of the case's database in the catalog. +func (a *analyzer) lookup(ref columnRef) (column, bool) { + cols, ok := a.catalog[relation{strings.ToLower(ref.schema), strings.ToLower(ref.table)}] + if !ok { + return column{}, false + } + for _, col := range cols { + if strings.EqualFold(col.name, ref.column) { + return col, true + } + } + return column{}, false +} + +// parameter is what sp_describe_undeclared_parameters says about one +// variable the statement leaves undeclared. +type parameter struct { + systemType string + userType sql.NullString +} + +// undeclaredParameters asks the server what type it would give each +// parameter, keyed by the variable's name without the @. +func (a *analyzer) undeclaredParameters(ctx context.Context, query string) (map[string]parameter, error) { + rows, err := a.conn.QueryContext(ctx, "EXEC sp_describe_undeclared_parameters @p1", query) + if err != nil { + return nil, err + } + defer rows.Close() + cols, err := rows.Columns() + if err != nil { + return nil, err + } + index := map[string]int{} + for i, c := range cols { + index[c] = i + } + params := map[string]parameter{} + for rows.Next() { + vals := make([]any, len(cols)) + ptrs := make([]any, len(cols)) + for i := range vals { + ptrs[i] = &vals[i] + } + if err := rows.Scan(ptrs...); err != nil { + return nil, err + } + str := func(col string) sql.NullString { + i, ok := index[col] + if !ok || vals[i] == nil { + return sql.NullString{} + } + return sql.NullString{String: fmt.Sprint(vals[i]), Valid: true} + } + name := strings.TrimPrefix(str("name").String, "@") + params[name] = parameter{ + systemType: str("suggested_system_type_name").String, + userType: str("suggested_user_type_name"), + } + } + return params, rows.Err() +} + +// analyzeQuery describes one query. +func (a *analyzer) analyzeQuery(ctx context.Context, q endtoend.Query) (analysis.Query, error) { + sql, phs := bind(q.SQL) + aq := analysis.Query{ + Name: q.Name, + Cmd: q.Cmd, + Columns: []analysis.Column{}, + Params: []analysis.Param{}, + } + + described, err := a.describe(ctx, sql) + if err != nil { + return analysis.Query{}, err + } + for _, d := range described { + ac := analysis.Column{Name: strings.ToLower(d.name), Type: withNullable(d.typ, d.nullable)} + if d.source != nil { + if col, ok := a.lookup(*d.source); ok { + ac.Type = withNullable(col.typ, d.nullable) + } + ac.Table = strings.ToLower(d.source.table) + } + aq.Columns = append(aq.Columns, ac) + } + + if len(phs) == 0 { + return aq, nil + } + params, err := a.undeclaredParameters(ctx, sql) + if err != nil { + return analysis.Query{}, err + } + var decl []string + for _, ph := range phs { + for _, v := range ph.Vars { + p, ok := params[v] + if !ok { + return analysis.Query{}, fmt.Errorf("the server did not describe parameter @%s", v) + } + decl = append(decl, "@"+v+" "+p.systemType) + } + } + partners, err := a.partners(ctx, "DECLARE "+strings.Join(decl, ", ")+";\n"+sql) + if err != nil { + return analysis.Query{}, err + } + for _, ph := range phs { + ac := analysis.Column{} + found := false + for _, v := range ph.Vars { + ref, ok := partners[v] + if !ok { + continue + } + col, ok := a.lookup(ref) + if !ok { + continue + } + ac = analysis.Column{Name: col.name, Type: withNullable(col.typ, col.nullable), Table: strings.ToLower(ref.table)} + found = true + break + } + if !found { + p := params[ph.Vars[0]] + ac.Type = a.typeOf(p.systemType, p.userType) + } + aq.Params = append(aq.Params, analysis.Param{Number: ph.Number, Column: ac}) + } + return aq, nil +} diff --git a/internal/goldeneye/mssql/mssql.go b/internal/goldeneye/mssql/mssql.go new file mode 100644 index 0000000..23c338a --- /dev/null +++ b/internal/goldeneye/mssql/mssql.go @@ -0,0 +1,153 @@ +// Package mssql generates the SQL Server dialect seed under +// internal/engine/mssql/dialect from a live server, and verifies the SQL +// Server analyze cases under internal/endtoend/testdata against the same +// server. +// +// SQL Server keeps no catalog of its built-in functions or operators — the +// intrinsic functions such as GETDATE and LEN are not objects — so +// types.jsonl and functions.jsonl are written by hand and are not this +// package's business. What it does describe is its catalog: relations.jsonl +// is every view of the sys and INFORMATION_SCHEMA schemas, with each view's +// columns as the server itself describes a SELECT * from it. +// +// The package also verifies the SQL Server analyze cases under +// internal/endtoend/testdata against the same server: each case's schema +// and fixture are loaded into a database of their own and its queries +// described there, without being run. Result columns come from +// sys.dm_exec_describe_first_result_set, which says what each column is +// called, what type it has, whether it can be NULL and which table column +// it is read from; parameters from sp_describe_undeclared_parameters, which +// says what type the server would give each, and from the estimated +// showplan, which says which column each is compared with or assigned to. +// The answer is printed in the JSON shape sqlc analyze prints and compared +// with the case's committed stdout.json byte for byte. +// +// The server is named by MSSQL_SERVER_URI, in any form the go-mssqldb +// driver accepts, such as +// sqlserver://sa:password@127.0.0.1:1433?encrypt=disable, and has to be +// the major release in Major, since each release adds to the catalog views. +package mssql + +import ( + "context" + "database/sql" + "errors" + "fmt" + "os" + "strconv" + "strings" + + _ "github.com/microsoft/go-mssqldb" + "github.com/microsoft/go-mssqldb/msdsn" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/dialect" +) + +// Engine is the name sqlc knows the dialect by, and the name of the analyze +// case directories under internal/endtoend/testdata. +const Engine = "mssql" + +// Major is the SQL Server major release the dialect is generated from, as +// SERVERPROPERTY('ProductMajorVersion') reports it: 17 is SQL Server 2025. +// Bumping it is a deliberate change: every release adds views and columns +// to the catalog, so regenerate and review the dialect after changing it. +const Major = 17 + +// Locate returns the server to generate from, named by MSSQL_SERVER_URI. +func Locate() (string, error) { + dsn := os.Getenv("MSSQL_SERVER_URI") + if dsn == "" { + return "", errors.New("MSSQL_SERVER_URI is not set") + } + if _, err := msdsn.Parse(dsn); err != nil { + return "", fmt.Errorf("MSSQL_SERVER_URI: %w", err) + } + return dsn, nil +} + +// open connects to the server and holds one session, since a case's +// database is the session's current database and the showplan is a +// session setting. +func open(ctx context.Context, dsn string) (*sql.Conn, error) { + db, err := sql.Open("sqlserver", dsn) + if err != nil { + return nil, err + } + conn, err := db.Conn(ctx) + if err != nil { + db.Close() + return nil, err + } + return conn, nil +} + +// Version reports the release a server is. +func Version(ctx context.Context, dsn string) (string, error) { + conn, err := open(ctx, dsn) + if err != nil { + return "", err + } + defer conn.Close() + var v string + if err := conn.QueryRowContext(ctx, "SELECT @@VERSION").Scan(&v); err != nil { + return "", err + } + // The first line names the product and build; the rest is the copyright + // and the platform. + v, _, _ = strings.Cut(v, "\n") + return strings.TrimSpace(v), nil +} + +// checkVersion refuses a server of another major release than the dialect +// is generated from, whose catalog would differ from the committed one +// without anything being wrong. +func checkVersion(ctx context.Context, conn *sql.Conn) error { + var v string + if err := conn.QueryRowContext(ctx, "SELECT CAST(SERVERPROPERTY('ProductMajorVersion') AS nvarchar(10))").Scan(&v); err != nil { + return err + } + major, err := strconv.Atoi(v) + if err != nil { + return fmt.Errorf("ProductMajorVersion %q: %w", v, err) + } + if major != Major { + return fmt.Errorf("the dialect is generated from SQL Server major release %d, but the server is release %d", Major, major) + } + return nil +} + +// Generate reads the dialect from the server: relations.jsonl, the views of +// sys and INFORMATION_SCHEMA. They are read from a database of their own, +// since the views a query sees are the ones a user database has, and +// master lists internal views of its own that no query can name. +func Generate(ctx context.Context, dsn string) (dialect.Files, error) { + conn, err := open(ctx, dsn) + if err != nil { + return nil, err + } + defer conn.Close() + if err := checkVersion(ctx, conn); err != nil { + return nil, err + } + db := quote("goldeneye_dialect") + for _, stmt := range []string{ + "USE master", + "DROP DATABASE IF EXISTS " + db, + "CREATE DATABASE " + db, + "USE " + db, + } { + if _, err := conn.ExecContext(ctx, stmt); err != nil { + return nil, err + } + } + defer conn.ExecContext(context.WithoutCancel(ctx), "USE master; DROP DATABASE IF EXISTS "+db) + relations, err := readRelations(ctx, conn) + if err != nil { + return nil, err + } + blob, err := dialect.JSONL(relations) + if err != nil { + return nil, err + } + return dialect.Files{dialect.RelationsFile: blob}, nil +} diff --git a/internal/goldeneye/mssql/mssql_test.go b/internal/goldeneye/mssql/mssql_test.go new file mode 100644 index 0000000..e83b324 --- /dev/null +++ b/internal/goldeneye/mssql/mssql_test.go @@ -0,0 +1,66 @@ +package mssql + +import ( + "context" + "testing" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/dialect" + "github.com/sqlc-dev/sqlc/internal/goldeneye/endtoend" +) + +// TestDialect verifies the committed SQL Server dialect against what the +// server reports. It skips unless MSSQL_SERVER_URI names a server. +func TestDialect(t *testing.T) { + dsn, err := Locate() + if err != nil { + t.Skip(err) + } + ctx := context.Background() + version, err := Version(ctx, dsn) + if err != nil { + t.Fatal(err) + } + files, err := Generate(ctx, dsn) + if err != nil { + t.Fatal(err) + } + dir, err := dialect.Dir(Engine) + if err != nil { + t.Fatal(err) + } + report, err := dialect.Check(dir, files) + if err != nil { + t.Fatal(err) + } + if report != "" { + t.Errorf("%s does not match what %s reports:\n%s", dir, version, report) + } +} + +// TestAnalyzeCases verifies every SQL Server analyze case under +// internal/endtoend/testdata against what the server reports. It skips +// unless MSSQL_SERVER_URI names a server. +func TestAnalyzeCases(t *testing.T) { + dsn, err := Locate() + if err != nil { + t.Skip(err) + } + cases, err := endtoend.Cases(Engine) + if err != nil { + t.Fatal(err) + } + if len(cases) == 0 { + t.Fatal("no mssql analyze cases found") + } + for _, c := range cases { + t.Run(c.Name, func(t *testing.T) { + diff, err := Check(context.Background(), dsn, c) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Errorf("%s does not match what SQL Server reports (-committed +mssql):\n%s", c.Output, diff) + } + }) + } +} diff --git a/internal/goldeneye/mssql/plan.go b/internal/goldeneye/mssql/plan.go new file mode 100644 index 0000000..d11054b --- /dev/null +++ b/internal/goldeneye/mssql/plan.go @@ -0,0 +1,243 @@ +package mssql + +import ( + "context" + "encoding/xml" + "fmt" + "strings" +) + +// The estimated showplan is the one thing that says what a parameter is +// compared with or assigned to. It is compiled, not run, with SET +// SHOWPLAN_XML ON, and prints the plan as XML in which every column is a +// ColumnReference naming its schema, table and column, and every variable +// one naming only @variable. A parameter's partner is the column on the +// other side of the Compare it is an operand of, the column an Assign +// sets to it, or the column of a seek whose range expression it is. An +// expression the plan computes once and refers to by name, Expr1002, is +// followed to its DefinedValue. A parameter the query casts, CAST(@p AS +// T), has no partner: the cast says what it is, as it does to sqlc, and +// the plan shows it as a Convert the query asked for rather than one the +// server added. + +// columnRef names a table column the plan refers to. +type columnRef struct { + schema, table, column string +} + +// node is one element of the showplan XML. +type node struct { + XMLName xml.Name + Attrs []xml.Attr `xml:",any,attr"` + Children []node `xml:",any"` +} + +func (n *node) attr(name string) string { + for _, a := range n.Attrs { + if a.Name.Local == name { + return a.Value + } + } + return "" +} + +// unbracket strips the [brackets] the plan quotes names with. +func unbracket(s string) string { + if strings.HasPrefix(s, "[") && strings.HasSuffix(s, "]") { + return strings.ReplaceAll(s[1:len(s)-1], "]]", "]") + } + return s +} + +// plan is a parsed showplan with the expressions it defines by name. +type plan struct { + root node + defined map[string]*node // Expr1002 -> the ScalarOperator defining it +} + +// partners compiles a batch and returns the column each variable is +// compared with or assigned to, keyed by the variable's name without the +// @. A variable with no such column is absent. +func (a *analyzer) partners(ctx context.Context, batch string) (map[string]columnRef, error) { + if _, err := a.conn.ExecContext(ctx, "SET SHOWPLAN_XML ON"); err != nil { + return nil, err + } + defer a.conn.ExecContext(context.WithoutCancel(ctx), "SET SHOWPLAN_XML OFF") + rows, err := a.conn.QueryContext(ctx, batch) + if err != nil { + return nil, fmt.Errorf("showplan: %w", err) + } + defer rows.Close() + var blob string + for rows.Next() { + var s string + if err := rows.Scan(&s); err != nil { + return nil, err + } + blob += s + } + if err := rows.Err(); err != nil { + return nil, err + } + p := &plan{defined: map[string]*node{}} + if err := xml.Unmarshal([]byte(blob), &p.root); err != nil { + return nil, fmt.Errorf("showplan: %w", err) + } + p.collectDefined(&p.root) + partners := map[string]columnRef{} + p.walk(&p.root, partners) + return partners, nil +} + +// collectDefined records every DefinedValue that names an expression. +func (p *plan) collectDefined(n *node) { + if n.XMLName.Local == "DefinedValue" && len(n.Children) >= 2 { + ref := &n.Children[0] + if ref.XMLName.Local == "ColumnReference" && ref.attr("Table") == "" && !strings.HasPrefix(ref.attr("Column"), "@") { + p.defined[ref.attr("Column")] = &n.Children[1] + } + } + for i := range n.Children { + p.collectDefined(&n.Children[i]) + } +} + +// walk finds the partners in a subtree, keeping the first found for each +// variable. +func (p *plan) walk(n *node, partners map[string]columnRef) { + set := func(vars []string, ref columnRef) { + for _, v := range vars { + if _, ok := partners[v]; !ok { + partners[v] = ref + } + } + } + switch n.XMLName.Local { + case "Compare": + var sides []*node + for i := range n.Children { + if n.Children[i].XMLName.Local == "ScalarOperator" { + sides = append(sides, &n.Children[i]) + } + } + if len(sides) == 2 { + for i, side := range sides { + vars := p.variables(side, nil) + if len(vars) == 0 { + continue + } + if cols := p.columns(sides[1-i], nil); len(cols) > 0 { + set(vars, cols[0]) + } + } + } + case "Assign": + var target *columnRef + for i := range n.Children { + c := &n.Children[i] + switch c.XMLName.Local { + case "ColumnReference": + if ref, ok := refOf(c); ok && target == nil { + target = &ref + } + case "ScalarOperator": + if target != nil { + set(p.variables(c, nil), *target) + } + } + } + case "Prefix", "StartRange", "EndRange": + var cols []columnRef + var exprs []*node + for i := range n.Children { + c := &n.Children[i] + switch c.XMLName.Local { + case "RangeColumns": + for j := range c.Children { + if ref, ok := refOf(&c.Children[j]); ok { + cols = append(cols, ref) + } + } + case "RangeExpressions": + for j := range c.Children { + exprs = append(exprs, &c.Children[j]) + } + } + } + for i, e := range exprs { + if i < len(cols) { + set(p.variables(e, nil), cols[i]) + } + } + } + for i := range n.Children { + p.walk(&n.Children[i], partners) + } +} + +// refOf reads a ColumnReference that names a table column. +func refOf(n *node) (columnRef, bool) { + if n.XMLName.Local != "ColumnReference" || n.attr("Table") == "" { + return columnRef{}, false + } + return columnRef{ + schema: unbracket(n.attr("Schema")), + table: unbracket(n.attr("Table")), + column: n.attr("Column"), + }, true +} + +// variables lists the variables a subtree refers to, following named +// expressions and leaving out the ones under a cast the query wrote. +func (p *plan) variables(n *node, seen map[string]bool) []string { + var out []string + if n.XMLName.Local == "Convert" && n.attr("Implicit") == "0" { + return nil + } + if n.XMLName.Local == "ColumnReference" { + col := n.attr("Column") + switch { + case strings.HasPrefix(col, "@"): + return []string{col[1:]} + case n.attr("Table") == "": + if def, ok := p.defined[col]; ok && !seen[col] { + if seen == nil { + seen = map[string]bool{} + } + seen[col] = true + vars := p.variables(def, seen) + delete(seen, col) + return vars + } + } + } + for i := range n.Children { + out = append(out, p.variables(&n.Children[i], seen)...) + } + return out +} + +// columns lists the table columns a subtree refers to, following named +// expressions. +func (p *plan) columns(n *node, seen map[string]bool) []columnRef { + var out []columnRef + if n.XMLName.Local == "ColumnReference" { + if ref, ok := refOf(n); ok { + return []columnRef{ref} + } + col := n.attr("Column") + if def, ok := p.defined[col]; ok && !seen[col] { + if seen == nil { + seen = map[string]bool{} + } + seen[col] = true + cols := p.columns(def, seen) + delete(seen, col) + return cols + } + } + for i := range n.Children { + out = append(out, p.columns(&n.Children[i], seen)...) + } + return out +} diff --git a/internal/goldeneye/mssql/relations.go b/internal/goldeneye/mssql/relations.go new file mode 100644 index 0000000..1b51c4c --- /dev/null +++ b/internal/goldeneye/mssql/relations.go @@ -0,0 +1,123 @@ +package mssql + +import ( + "context" + "database/sql" + "fmt" + "sort" + "strings" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/dialect" +) + +// systemSchemas are the schemas whose relations are generated: the catalog +// views, which are what a query of the server's catalog reads. Both hold +// nothing but views, so every relation a dialect seeds from them is one +// the analysis core never hands codegen as a model. +var systemSchemas = []string{ + "sys", + "INFORMATION_SCHEMA", +} + +// viewQuery lists a schema's views. They are sorted in Go, by the bytes +// of their lower-cased names, so that the output does not depend on the +// server's collation. +const viewQuery = ` +SELECT o.name +FROM sys.all_objects o +JOIN sys.schemas s ON s.schema_id = o.schema_id +WHERE o.type = 'V' AND s.name = @p1` + +// describeQuery asks the server to describe a SELECT * from a view: each +// column's name, its type spelled the way a declaration spells it — +// nvarchar(128), decimal(10,2), varbinary(max) — and whether it can be +// NULL. A view the server cannot describe reports an error message on a +// row of its own rather than failing the query. +const describeQuery = ` +SELECT column_ordinal, name, system_type_name, is_nullable, error_message +FROM sys.dm_exec_describe_first_result_set(@p1, NULL, 0) +ORDER BY column_ordinal` + +// readRelations reads the views of the system schemas. Their names are +// written in lower case: SQL Server matches them in any case under its +// default collations, INFORMATION_SCHEMA spells its own in upper case, and +// sqlc's SQL Server parser lowercases every identifier, so lower case is +// how a query reaches them. The type of each column is spelled the way the +// server describes it to a driver, which is the way a declaration spells +// it, numeric and timestamp included, since the seed reads the aliases +// types.jsonl lists. +func readRelations(ctx context.Context, conn *sql.Conn) ([]dialect.Relation, error) { + var relations []dialect.Relation + for _, schema := range systemSchemas { + names, err := views(ctx, conn, schema) + if err != nil { + return nil, fmt.Errorf("%s: %w", schema, err) + } + for _, name := range names { + columns, err := describe(ctx, conn, schema, name) + if err != nil { + return nil, fmt.Errorf("%s.%s: %w", schema, name, err) + } + relations = append(relations, dialect.Relation{ + Schema: strings.ToLower(schema), + Name: strings.ToLower(name), + Kind: "v", + Columns: columns, + }) + } + } + return relations, nil +} + +func views(ctx context.Context, conn *sql.Conn, schema string) ([]string, error) { + rows, err := conn.QueryContext(ctx, viewQuery, schema) + if err != nil { + return nil, err + } + defer rows.Close() + var names []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + names = append(names, name) + } + sort.Slice(names, func(i, j int) bool { return strings.ToLower(names[i]) < strings.ToLower(names[j]) }) + return names, rows.Err() +} + +func describe(ctx context.Context, conn *sql.Conn, schema, name string) ([]dialect.Column, error) { + rows, err := conn.QueryContext(ctx, describeQuery, "SELECT * FROM "+quote(schema)+"."+quote(name)) + if err != nil { + return nil, err + } + defer rows.Close() + var columns []dialect.Column + for rows.Next() { + var ( + ordinal int + colName sql.NullString + typeName sql.NullString + nullable sql.NullBool + errMsg sql.NullString + ) + if err := rows.Scan(&ordinal, &colName, &typeName, &nullable, &errMsg); err != nil { + return nil, err + } + if errMsg.Valid { + return nil, fmt.Errorf("cannot be described: %s", errMsg.String) + } + columns = append(columns, dialect.Column{ + Name: strings.ToLower(colName.String), + Type: typeName.String, + NotNull: !nullable.Bool, + }) + } + return columns, rows.Err() +} + +// quote brackets an identifier the way T-SQL does. +func quote(name string) string { + return "[" + strings.ReplaceAll(name, "]", "]]") + "]" +} diff --git a/internal/goldeneye/mysql/analyze.go b/internal/goldeneye/mysql/analyze.go new file mode 100644 index 0000000..a2c4240 --- /dev/null +++ b/internal/goldeneye/mysql/analyze.go @@ -0,0 +1,787 @@ +package mysql + +import ( + "bytes" + "context" + "database/sql" + "encoding/json" + "fmt" + "github.com/sqlc-dev/sqlc/internal/goldeneye/dialect" + "os" + "regexp" + "strconv" + "strings" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/analysis" + "github.com/sqlc-dev/sqlc/internal/goldeneye/endtoend" +) + +// The analyze cases are checked against a live server, which is asked +// three things about each query. What a driver sees: the query is run, +// with every parameter a user variable set to NULL, and each result +// column's name, type and nullability are read from the result set's +// metadata, the way go-sql-driver reports them. What the resolver made of +// it: the optimizer trace prints each query block back after name +// resolution, with every column qualified, every alias kept and every +// SELECT * expanded, which says which table each result column is read +// from and what each parameter is compared with or assigned to. And for a +// statement the trace does not expand — an INSERT ... VALUES, a +// single-table UPDATE or DELETE — the note EXPLAIN leaves, which prints +// the statement the same way. Views and derived tables are kept as the +// query wrote them rather than merged, so that a column read through one +// is reported as its column. MySQL itself reports nothing about a +// parameter but its position, so a parameter is described by its partner: +// a column's type and nullability come from information_schema, a column +// of a derived table from what its block projects, and an expression's +// from running it, over the tables it reads, as a query of its own. + +// placeholder is one parameter of a query as sqlc numbers them: each ? in +// turn, and each sqlc.arg name once, at its first appearance. Each becomes +// a user variable, which MySQL prints back by name, except in a LIMIT or +// OFFSET, where MySQL allows nothing but a number. +type placeholder struct { + Number int + Name string + Limit bool + Sentinel string // the variable's name, or the number +} + +// limitBase is added to a LIMIT parameter's number, so that the count is +// unlike any a query would write. +const limitBase = 4000000000 + +func bind(sql string) (string, []placeholder) { + var phs []placeholder + numbers := map[string]int{} + out := endtoend.Rewrite(sql, func(name, lastWord string) string { + n, ok := numbers[name] + if name == "" || !ok { + n = len(phs) + 1 + ph := placeholder{Number: n, Name: name} + switch strings.ToLower(lastWord) { + case "limit", "offset": + ph.Limit = true + ph.Sentinel = strconv.Itoa(limitBase + n) + default: + ph.Sentinel = "goldeneye_" + strconv.Itoa(n) + } + phs = append(phs, ph) + if name != "" { + numbers[name] = n + } + } + ph := phs[n-1] + if ph.Limit { + return ph.Sentinel + } + return "@" + ph.Sentinel + }) + return out, phs +} + +// column is what information_schema says about a column: its type as +// COLUMN_TYPE spells it, read into an expression. +type column struct { + name string + typ *analysis.TypeExpr + nullable bool +} + +// typeOfColumn is a column's type as it was declared, from COLUMN_TYPE, which +// carries the arguments and the unsigned that DATA_TYPE does not: "decimal(10,2) +// unsigned" is the family "decimal unsigned" applied to 10 and 2, and +// "enum('a','b')" is enum applied to its members. A trailing word such as +// zerofill is part of the family too. +func typeOfColumn(columnType string) *analysis.TypeExpr { + s := strings.TrimSpace(columnType) + open := strings.IndexByte(s, '(') + if open < 0 { + return &analysis.TypeExpr{Name: strings.ToLower(s)} + } + close := strings.LastIndexByte(s, ')') + if close < open { + return &analysis.TypeExpr{Name: strings.ToLower(s)} + } + // The family is spelled in lower case; an enum's members keep theirs, + // since they are values. + name := strings.ToLower(strings.TrimSpace(s[:open])) + if rest := strings.ToLower(strings.TrimSpace(s[close+1:])); rest != "" { + name += " " + rest + } + t := &analysis.TypeExpr{Name: name} + for _, a := range splitArgs(s[open+1 : close]) { + a = strings.TrimSpace(a) + if strings.HasPrefix(a, "'") && strings.HasSuffix(a, "'") && len(a) >= 2 { + v := unquoteMember(a[1 : len(a)-1]) + t.Args = append(t.Args, analysis.TypeArg{String: &v}) + continue + } + if n, err := strconv.ParseInt(a, 10, 64); err == nil { + t.Args = append(t.Args, analysis.TypeArg{Int: &n}) + } + } + return t +} + +// splitArgs splits a type's argument list on the commas outside quotes. A +// backslash inside a quoted member escapes the character after it. +func splitArgs(s string) []string { + var out []string + start, quoted := 0, false + for i := 0; i < len(s); i++ { + switch { + case quoted && s[i] == '\\': + i++ + case s[i] == '\'': + quoted = !quoted + case s[i] == ',' && !quoted: + out = append(out, s[start:i]) + start = i + 1 + } + } + return append(out, s[start:]) +} + +// unquoteMember reads the body of a quoted enum or set member as +// information_schema spells it: a quote is doubled and a backslash escapes +// the character after it. +func unquoteMember(s string) string { + var out strings.Builder + for i := 0; i < len(s); i++ { + switch { + case s[i] == '\\' && i+1 < len(s): + i++ + out.WriteByte(s[i]) + case s[i] == '\'' && i+1 < len(s) && s[i+1] == '\'': + i++ + out.WriteByte('\'') + default: + out.WriteByte(s[i]) + } + } + return out.String() +} + +// withNullable copies a type with its nullability set. +func withNullable(t *analysis.TypeExpr, nullable bool) *analysis.TypeExpr { + out := *t + out.Nullable = nullable + return &out +} + +// relation is a table the catalog knows, by schema and name. +type relation struct { + schema, name string +} + +// analyzer holds the session a case runs in and the catalog: the case's +// own schema, and information_schema, whose names are matched and +// reported in lower case, since MySQL matches them in any case and the +// dialect spells them that way. +type analyzer struct { + conn *sql.Conn + db string // the case's schema + catalog map[relation][]column // columns in order +} + +// table returns the catalog's name for a table of a schema, or "" when +// the catalog has no such table. +func (a *analyzer) table(schema, name string) (relation, bool) { + if schema == "" { + schema = a.db + } + if strings.EqualFold(schema, "information_schema") { + schema, name = "information_schema", strings.ToLower(name) + } + rel := relation{schema, name} + _, ok := a.catalog[rel] + return rel, ok +} + +var dbNameRe = regexp.MustCompile(`[^A-Za-z0-9_]+`) + +// Analyze loads a case's schema and fixture into a database of their own +// on the server, runs its queries there and returns what MySQL reports in +// the JSON shape sqlc analyze prints. +func Analyze(ctx context.Context, dsn string, c endtoend.Case) ([]byte, error) { + conn, err := open(ctx, dsn) + if err != nil { + return nil, err + } + defer conn.Close() + + schema, err := os.ReadFile(c.Schema) + if err != nil { + return nil, err + } + var fixture []byte + if c.Fixture != "" { + if fixture, err = os.ReadFile(c.Fixture); err != nil { + return nil, err + } + } + queries, err := c.Queries() + if err != nil { + return nil, err + } + + name := "goldeneye_" + dbNameRe.ReplaceAllString(c.Name, "_") + db := quote(name) + for _, stmt := range []string{ + "DROP DATABASE IF EXISTS " + db, + "CREATE DATABASE " + db, + "USE " + db, + "SET SESSION optimizer_trace = 'enabled=on'", + "SET SESSION optimizer_trace_max_mem_size = 67108864", + // A view or derived table is kept as the query wrote it rather + // than merged into the block that reads it, so that a column read + // from one is reported as its column, and an information_schema + // view is not resolved away into the data dictionary tables + // behind it. + "SET SESSION optimizer_switch = 'derived_merge=off,derived_condition_pushdown=off'", + } { + if _, err := conn.ExecContext(ctx, stmt); err != nil { + return nil, err + } + } + defer conn.ExecContext(context.WithoutCancel(ctx), "DROP DATABASE IF EXISTS "+db) + if _, err := conn.ExecContext(ctx, string(schema)); err != nil { + return nil, fmt.Errorf("loading %s: %w", c.Schema, err) + } + if strings.TrimSpace(string(fixture)) != "" { + if _, err := conn.ExecContext(ctx, string(fixture)); err != nil { + return nil, fmt.Errorf("loading %s: %w", c.Fixture, err) + } + } + + a := &analyzer{conn: conn, db: name} + if a.catalog, err = readCatalog(ctx, conn, name); err != nil { + return nil, err + } + out := make([]analysis.Query, 0, len(queries)) + for _, q := range queries { + aq, err := a.analyzeQuery(ctx, q) + if err != nil { + return nil, fmt.Errorf("%s: %w", q.Name, err) + } + out = append(out, aq) + } + return analysis.Encode(out) +} + +// Check compares what MySQL reports for a case with the output the case +// committed, returning a diff when they differ. +// Check compares a case's committed output with what MySQL reports. A +// column read from a table is compared in full, since information_schema +// spells its whole type; an expression's type comes from the wire, which +// carries the family and nothing of its arguments, so an expression, and +// a parameter typed by one, is compared by family alone. +func Check(ctx context.Context, dsn string, c endtoend.Case) (string, error) { + got, err := Analyze(ctx, dsn, c) + if err != nil { + return "", err + } + want, err := os.ReadFile(c.Output) + if err != nil { + return "", err + } + var queries []analysis.Query + if err := json.Unmarshal(want, &queries); err != nil { + return "", fmt.Errorf("%s: %w", c.Output, err) + } + for i := range queries { + for j := range queries[i].Columns { + familyOnly(&queries[i].Columns[j]) + } + for j := range queries[i].Params { + familyOnly(&queries[i].Params[j].Column) + } + } + want, err = analysis.Encode(queries) + if err != nil { + return "", err + } + if bytes.Equal(want, got) { + return "", nil + } + return dialect.Diff(string(want), string(got)), nil +} + +// familyOnly drops the arguments of a column's type when the column is not +// read from a table, which is as much as the wire says about it. +func familyOnly(col *analysis.Column) { + if col.Table == "" && col.Type != nil { + col.Type.Args = nil + } +} + +const catalogQuery = ` +SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE, COLUMN_TYPE, IS_NULLABLE +FROM information_schema.COLUMNS +WHERE TABLE_SCHEMA IN (?, 'information_schema') +ORDER BY TABLE_SCHEMA, TABLE_NAME, ORDINAL_POSITION` + +func readCatalog(ctx context.Context, conn *sql.Conn, db string) (map[relation][]column, error) { + rows, err := conn.QueryContext(ctx, catalogQuery, db) + if err != nil { + return nil, err + } + defer rows.Close() + catalog := map[relation][]column{} + for rows.Next() { + var schema, table, name, dataType, columnType, nullable string + if err := rows.Scan(&schema, &table, &name, &dataType, &columnType, &nullable); err != nil { + return nil, err + } + if schema == "information_schema" { + table, name = strings.ToLower(table), strings.ToLower(name) + } + rel := relation{schema, table} + catalog[rel] = append(catalog[rel], column{ + name: name, + typ: typeOfColumn(columnType), + nullable: nullable == "YES", + }) + } + return catalog, rows.Err() +} + +// statement is everything the server said about one query. +type statement struct { + a *analyzer + trace trace + note *text // the statement as EXPLAIN printed it, nil without one + aliases map[string]tableRef + results []*sql.ColumnType // of the executed query, nil for one returning no rows + target *relation // the table an INSERT ... VALUES writes + targets []string // its columns, in row order +} + +func (a *analyzer) analyzeQuery(ctx context.Context, q endtoend.Query) (analysis.Query, error) { + sql, phs := bind(q.SQL) + + var sets []string + for _, ph := range phs { + if !ph.Limit { + sets = append(sets, "@"+ph.Sentinel+" = NULL") + } + } + if len(sets) > 0 { + if _, err := a.conn.ExecContext(ctx, "SET "+strings.Join(sets, ", ")); err != nil { + return analysis.Query{}, err + } + } + + // EXPLAIN resolves and optimises the statement without running it, + // leaving its note and its trace behind. Only the traditional format + // leaves the note, and since MySQL 26 the default format is the tree. + if err := drain(a.conn.QueryContext(ctx, "EXPLAIN FORMAT=TRADITIONAL "+sql)); err != nil { + return analysis.Query{}, err + } + note, err := readNote(ctx, a.conn) + if err != nil { + return analysis.Query{}, err + } + tr, err := readTrace(ctx, a.conn) + if err != nil { + return analysis.Query{}, err + } + + s := &statement{a: a, trace: tr, aliases: map[string]tableRef{}} + if note != "" { + t := tokenize(note) + s.note = &t + t.aliases(s.aliases) + s.target, s.targets = s.insertTargets(t) + } + for _, t := range tr.blocks { + t.aliases(s.aliases) + } + + aq := analysis.Query{ + Name: q.Name, + Cmd: q.Cmd, + Columns: []analysis.Column{}, + Params: []analysis.Param{}, + } + if returnsRows(sql) { + rows, err := a.conn.QueryContext(ctx, sql) + if err != nil { + return analysis.Query{}, err + } + s.results, err = rows.ColumnTypes() + rows.Close() + if err != nil { + return analysis.Query{}, err + } + // Names, types and nullability are the result set's. The top + // block's SELECT list adds which table each column is read from, + // when the two line up. MySQL sends every size of TEXT and BLOB + // as the one wire type and tells them apart by the length beside + // it, which the driver keeps to itself, so a column read from a + // table, directly or through a derived table, is spelled the way + // the table declares it. + var items []item + if top, ok := tr.blocks[1]; ok { + items = top.selectItems() + } + for i, ct := range s.results { + ac := analysis.Column{Name: ct.Name(), Type: typeOf(ct)} + if len(items) == len(s.results) { + top := tr.blocks[1] + if it := items[i]; it.end-it.start == 1 && top.at(it.start).kind == tkIdent { + tok := top.at(it.start) + if rel, ok := s.resolve(tok.parts); ok { + ac.Table = rel.name + } + if col, ok := s.origin(top, tok, 0); ok { + ac.Type = withNullable(col.typ, ac.Type.Nullable) + } + } + } + aq.Columns = append(aq.Columns, ac) + } + } + + for _, ph := range phs { + ac := analysis.Column{} + if t, i, ok := s.locate(ph); ok { + ac = s.describe(ctx, t, t.partner(i), 0) + } + if ph.Name != "" { + ac.Name = ph.Name + } + aq.Params = append(aq.Params, analysis.Param{Number: ph.Number, Column: ac}) + } + return aq, nil +} + +// drain reads a result set to the end and closes it. +func drain(rows *sql.Rows, err error) error { + if err != nil { + return err + } + defer rows.Close() + for rows.Next() { + } + return rows.Err() +} + +// readNote returns the statement EXPLAIN printed back, from the note it +// leaves among the warnings, or "" when it left none. +func readNote(ctx context.Context, conn *sql.Conn) (string, error) { + rows, err := conn.QueryContext(ctx, "SHOW WARNINGS") + if err != nil { + return "", err + } + defer rows.Close() + note := "" + for rows.Next() { + var level, message string + var code int + if err := rows.Scan(&level, &code, &message); err != nil { + return "", err + } + if code == 1003 { + note = message + } + } + return note, rows.Err() +} + +// readTrace returns the optimizer trace of the last statement. +func readTrace(ctx context.Context, conn *sql.Conn) (trace, error) { + rows, err := conn.QueryContext(ctx, "SELECT TRACE, MISSING_BYTES_BEYOND_MAX_MEM_SIZE FROM information_schema.OPTIMIZER_TRACE") + if err != nil { + return trace{}, err + } + defer rows.Close() + blob := "" + for rows.Next() { + var missing int64 + if err := rows.Scan(&blob, &missing); err != nil { + return trace{}, err + } + if missing > 0 { + return trace{}, fmt.Errorf("the optimizer trace was truncated by %d bytes", missing) + } + } + if err := rows.Err(); err != nil { + return trace{}, err + } + return parseTrace(blob) +} + +// returnsRows reports whether a statement produces a result set. +func returnsRows(sql string) bool { + head := strings.ToLower(strings.TrimSpace(sql)) + if strings.HasPrefix(head, "(") { + return true + } + for _, kw := range []string{"select", "with", "show", "describe", "desc", "explain", "table", "values"} { + if strings.HasPrefix(head, kw) && (len(head) == len(kw) || !isWordByte(head[len(kw)])) { + return true + } + } + return false +} + +// typeOf is a result column's type as the driver reports it, spelled the +// way a column declaration does: "bigint unsigned" rather than the +// driver's "UNSIGNED BIGINT". +func typeOf(ct *sql.ColumnType) *analysis.TypeExpr { + name := strings.ToLower(ct.DatabaseTypeName()) + if rest, ok := strings.CutPrefix(name, "unsigned "); ok { + name = rest + " unsigned" + } + nullable, _ := ct.Nullable() + return &analysis.TypeExpr{Name: name, Nullable: nullable} +} + +// resolve returns the catalog table a qualified column name is read from: +// the qualifier is an alias, or a table of the case's schema, or a table +// of the schema the name spells out. +func (s *statement) resolve(parts []string) (relation, bool) { + if len(parts) < 2 { + return relation{}, false + } + qualifier := parts[len(parts)-2] + if ref, ok := s.aliases[qualifier]; ok { + return s.a.table(ref.schema, ref.name) + } + schema := "" + if len(parts) >= 3 { + schema = parts[len(parts)-3] + } + return s.a.table(schema, qualifier) +} + +// locate finds the text a placeholder was printed in and where: the +// innermost query block whose expanded_query has it, or else the note. +func (s *statement) locate(ph placeholder) (text, int, bool) { + find := func(t text) int { + if ph.Limit { + return t.findNumber(ph.Sentinel) + } + return t.findVar(ph.Sentinel) + } + for _, sel := range s.trace.order() { + t := s.trace.blocks[sel] + if i := find(t); i >= 0 { + return t, i, true + } + } + if s.note != nil { + if i := find(*s.note); i >= 0 { + return *s.note, i, true + } + } + return text{}, -1, false +} + +// describe turns a parameter's partner into the column description sqlc +// prints for the parameter. +func (s *statement) describe(ctx context.Context, t text, p partner, depth int) analysis.Column { + switch p.kind { + case partnerOperand: + return s.operand(ctx, t, p.start, p.end, depth) + case partnerProjection: + if s.results != nil { + if top, ok := s.trace.blocks[1]; ok && top.src == t.src && p.index < len(s.results) { + ct := s.results[p.index] + return analysis.Column{Name: ct.Name(), Type: typeOf(ct)} + } + } + if items := t.selectItems(); p.index < len(items) { + return analysis.Column{Name: items[p.index].alias} + } + case partnerInsert: + if s.target != nil && len(s.targets) > 0 { + return s.column(*s.target, s.targets[p.index%len(s.targets)]) + } + case partnerLimit: + // A LIMIT or OFFSET count is an unsigned 64-bit integer to MySQL. + return analysis.Column{Type: &analysis.TypeExpr{Name: "bigint unsigned"}} + } + return analysis.Column{} +} + +// operand describes an operand: a column by what the schema says of it, a +// call by its name and what it returns, anything else by its type. +func (s *statement) operand(ctx context.Context, t text, start, end, depth int) analysis.Column { + tok := t.at(start) + if end-start == 1 && tok.kind == tkIdent { + return s.columnRef(ctx, t, tok, depth) + } + if tok.kind == tkVar { + return analysis.Column{} + } + ac := analysis.Column{} + if tok.kind == tkWord && t.at(start+1).kind == tkLParen && t.isCall(start) && !strings.HasPrefix(tok.text, "<") { + ac.Name = tok.text + } + ac.Type = s.eval(ctx, t, start, end) + return ac +} + +// columnRef describes a column reference: a column of the schema, a column +// of a derived table by the expression its block projects, or a SELECT list +// alias by the expression it names. +func (s *statement) columnRef(ctx context.Context, t text, tok token, depth int) analysis.Column { + parts := tok.parts + if depth > 8 { + return analysis.Column{Name: parts[len(parts)-1]} + } + if len(parts) == 1 { + for _, it := range t.selectItems() { + if it.alias == parts[0] { + ac := s.operand(ctx, t, it.start, it.end, depth+1) + ac.Name = parts[0] + return ac + } + } + return analysis.Column{Name: parts[0]} + } + qualifier, name := parts[len(parts)-2], parts[len(parts)-1] + if rel, ok := s.resolve(parts); ok { + return s.column(rel, name) + } + if sel, ok := s.trace.derived[qualifier]; ok { + if block, ok := s.trace.blocks[sel]; ok { + for _, it := range block.selectItems() { + if it.alias == name { + ac := s.operand(ctx, block, it.start, it.end, depth+1) + ac.Name = name + return ac + } + } + } + } + return analysis.Column{Name: name} +} + +// origin follows a column reference to the catalog column it reads, through +// any derived table or CTE whose block projects that column as it is. +func (s *statement) origin(t text, tok token, depth int) (column, bool) { + parts := tok.parts + if depth > 8 || len(parts) < 2 { + return column{}, false + } + qualifier, name := parts[len(parts)-2], parts[len(parts)-1] + if rel, ok := s.resolve(parts); ok { + if rel.schema == "information_schema" { + name = strings.ToLower(name) + } + for _, col := range s.a.catalog[rel] { + if col.name == name { + return col, true + } + } + return column{}, false + } + sel, ok := s.trace.derived[qualifier] + if !ok { + return column{}, false + } + block, ok := s.trace.blocks[sel] + if !ok { + return column{}, false + } + for _, it := range block.selectItems() { + if it.alias == name && it.end-it.start == 1 && block.at(it.start).kind == tkIdent { + return s.origin(block, block.at(it.start), depth+1) + } + } + return column{}, false +} + +// column describes a column of a catalog table. +func (s *statement) column(rel relation, name string) analysis.Column { + if rel.schema == "information_schema" { + name = strings.ToLower(name) + } + for _, col := range s.a.catalog[rel] { + if col.name == name { + return analysis.Column{ + Name: name, + Type: withNullable(col.typ, col.nullable), + Table: rel.name, + } + } + } + return analysis.Column{Name: name, Table: rel.name} +} + +// eval finds the type of an expression by running it as a query of its +// own, over the tables its columns are read from under the aliases the +// statement gave them. An expression that reads a derived table cannot be +// run that way and gets no type. +func (s *statement) eval(ctx context.Context, t text, start, end int) *analysis.TypeExpr { + var from []string + seen := map[string]bool{} + for _, id := range t.idents(start, end) { + qualifier := id.parts[len(id.parts)-2] + if seen[qualifier] { + continue + } + seen[qualifier] = true + rel, ok := s.resolve(id.parts) + if !ok { + return nil + } + item := quote(rel.schema) + "." + quote(rel.name) + if qualifier != rel.name { + item += " " + quote(qualifier) + } + from = append(from, item) + } + query := "SELECT " + t.slice(start, end) + if len(from) > 0 { + query += " FROM " + strings.Join(from, ", ") + } + rows, err := s.a.conn.QueryContext(ctx, query+" LIMIT 0") + if err != nil { + return nil + } + defer rows.Close() + cts, err := rows.ColumnTypes() + if err != nil || len(cts) != 1 { + return nil + } + return typeOf(cts[0]) +} + +// insertTargets reads the table and columns an INSERT ... VALUES writes, +// as the note prints them: the columns listed, or every column of the +// table in order when none are. +func (s *statement) insertTargets(t text) (*relation, []string) { + for i, tok := range t.toks { + if tok.kind != tkWord || tok.text != "into" || t.at(i+1).kind != tkIdent { + continue + } + parts := t.at(i + 1).parts + schema := "" + if len(parts) >= 2 { + schema = parts[len(parts)-2] + } + rel, ok := s.a.table(schema, parts[len(parts)-1]) + if !ok { + return nil, nil + } + var targets []string + if t.at(i+2).kind == tkLParen { + for _, m := range t.list(i + 2) { + if m[1]-m[0] == 1 && t.at(m[0]).kind == tkIdent { + parts := t.at(m[0]).parts + targets = append(targets, parts[len(parts)-1]) + } + } + } else { + for _, col := range s.a.catalog[rel] { + targets = append(targets, col.name) + } + } + return &rel, targets + } + return nil, nil +} diff --git a/internal/goldeneye/mysql/mysql.go b/internal/goldeneye/mysql/mysql.go new file mode 100644 index 0000000..e925891 --- /dev/null +++ b/internal/goldeneye/mysql/mysql.go @@ -0,0 +1,150 @@ +// Package mysql generates the MySQL dialect seed under +// internal/engine/dolphin/dialect from a live server, and verifies the +// MySQL analyze cases under internal/endtoend/testdata against the same +// server. +// +// MySQL keeps no catalog of its types, functions or operators — the server +// describes a built-in function no further than its name, in the help +// tables — so types.jsonl, functions.jsonl and operators.jsonl are written +// by hand and are not this package's business. What it does describe is +// its data dictionary: relations.jsonl is every view of information_schema, +// read from information_schema itself. +// +// The package also verifies the MySQL analyze cases under +// internal/endtoend/testdata against the same server: each case's schema +// and fixture are loaded into a database of their own and its queries run +// there. Result columns come from the result set's metadata as the driver +// reports it, provenance and parameters from the optimizer trace's +// expanded_query and the note EXPLAIN leaves, since MySQL reports nothing +// about a parameter but its position. The answer is printed in the JSON +// shape sqlc analyze prints and compared with the case's committed +// stdout.json byte for byte. +// +// The server is named by MYSQL_SERVER_URI, in the form the go-sql-driver +// DSN takes, and has to be the major release in Major, since each release +// adds to information_schema. +package mysql + +import ( + "context" + "database/sql" + "errors" + "fmt" + "os" + "strconv" + "strings" + + driver "github.com/go-sql-driver/mysql" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/dialect" +) + +// Engine is the name sqlc knows the dialect by, and the name of the analyze +// case directories under internal/endtoend/testdata. +const Engine = "mysql" + +// Dir is the name of the engine directory the dialect lives under, which +// is named after the parser sqlc reads MySQL with rather than the engine. +const Dir = "dolphin" + +// Major is the MySQL major release the dialect is generated from. Bumping +// it is a deliberate change: every release adds tables and columns to the +// system schemas, so regenerate and review the dialect after changing it. +const Major = 26 + +// Locate returns the server to generate from, named by MYSQL_SERVER_URI. +func Locate() (string, error) { + dsn := os.Getenv("MYSQL_SERVER_URI") + if dsn == "" { + return "", errors.New("MYSQL_SERVER_URI is not set") + } + if _, err := driver.ParseDSN(dsn); err != nil { + return "", fmt.Errorf("MYSQL_SERVER_URI: %w", err) + } + return dsn, nil +} + +// open connects to the server. The connection runs several statements at +// once, so that a case's schema loads as one script, and holds one +// session, since the optimizer trace and the warnings a statement leaves +// are both per session. +func open(ctx context.Context, dsn string) (*sql.Conn, error) { + cfg, err := driver.ParseDSN(dsn) + if err != nil { + return nil, err + } + cfg.MultiStatements = true + db, err := sql.Open("mysql", cfg.FormatDSN()) + if err != nil { + return nil, err + } + conn, err := db.Conn(ctx) + if err != nil { + db.Close() + return nil, err + } + return conn, nil +} + +// Version reports the release a server is. +func Version(ctx context.Context, dsn string) (string, error) { + conn, err := open(ctx, dsn) + if err != nil { + return "", err + } + defer conn.Close() + return version(ctx, conn) +} + +func version(ctx context.Context, conn *sql.Conn) (string, error) { + var v string + if err := conn.QueryRowContext(ctx, "SELECT version()").Scan(&v); err != nil { + return "", err + } + return "MySQL " + v, nil +} + +// checkVersion refuses a server of another major release than the dialect +// is generated from, whose system schemas would differ from the committed +// ones without anything being wrong. +func checkVersion(ctx context.Context, conn *sql.Conn) error { + var v string + if err := conn.QueryRowContext(ctx, "SELECT version()").Scan(&v); err != nil { + return err + } + head, _, _ := strings.Cut(v, ".") + major, err := strconv.Atoi(head) + if err != nil { + return fmt.Errorf("version %q: %w", v, err) + } + if major != Major { + return fmt.Errorf("the dialect is generated from MySQL %d, but the server is MySQL %d", Major, major) + } + return nil +} + +// Generate reads the dialect from the server: relations.jsonl, the views of +// information_schema. +func Generate(ctx context.Context, dsn string) (dialect.Files, error) { + conn, err := open(ctx, dsn) + if err != nil { + return nil, err + } + defer conn.Close() + if err := checkVersion(ctx, conn); err != nil { + return nil, err + } + var relations []dialect.Relation + for _, schema := range systemSchemas { + rels, err := readRelations(ctx, conn, schema) + if err != nil { + return nil, err + } + relations = append(relations, rels...) + } + blob, err := dialect.JSONL(relations) + if err != nil { + return nil, err + } + return dialect.Files{dialect.RelationsFile: blob}, nil +} diff --git a/internal/goldeneye/mysql/mysql_test.go b/internal/goldeneye/mysql/mysql_test.go new file mode 100644 index 0000000..5347394 --- /dev/null +++ b/internal/goldeneye/mysql/mysql_test.go @@ -0,0 +1,66 @@ +package mysql + +import ( + "context" + "testing" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/dialect" + "github.com/sqlc-dev/sqlc/internal/goldeneye/endtoend" +) + +// TestDialect verifies the committed MySQL dialect against what the server +// reports. It skips unless MYSQL_SERVER_URI names a server. +func TestDialect(t *testing.T) { + dsn, err := Locate() + if err != nil { + t.Skip(err) + } + ctx := context.Background() + version, err := Version(ctx, dsn) + if err != nil { + t.Fatal(err) + } + files, err := Generate(ctx, dsn) + if err != nil { + t.Fatal(err) + } + dir, err := dialect.Dir(Dir) + if err != nil { + t.Fatal(err) + } + report, err := dialect.Check(dir, files) + if err != nil { + t.Fatal(err) + } + if report != "" { + t.Errorf("%s does not match what %s reports:\n%s", dir, version, report) + } +} + +// TestAnalyzeCases verifies every MySQL analyze case under +// internal/endtoend/testdata against what the server reports. It skips +// unless MYSQL_SERVER_URI names a server. +func TestAnalyzeCases(t *testing.T) { + dsn, err := Locate() + if err != nil { + t.Skip(err) + } + cases, err := endtoend.Cases(Engine) + if err != nil { + t.Fatal(err) + } + if len(cases) == 0 { + t.Fatal("no mysql analyze cases found") + } + for _, c := range cases { + t.Run(c.Name, func(t *testing.T) { + diff, err := Check(context.Background(), dsn, c) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Errorf("%s does not match what MySQL reports (-committed +mysql):\n%s", c.Output, diff) + } + }) + } +} diff --git a/internal/goldeneye/mysql/relations.go b/internal/goldeneye/mysql/relations.go new file mode 100644 index 0000000..63e422c --- /dev/null +++ b/internal/goldeneye/mysql/relations.go @@ -0,0 +1,99 @@ +package mysql + +import ( + "context" + "database/sql" + "fmt" + "strings" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/dialect" +) + +// systemSchemas are the schemas whose relations are generated: the data +// dictionary's views, which are what a query of the server's catalog +// reads. The other schemas mysqld --initialize creates — mysql, +// performance_schema and sys — are tables rather than views, and every +// table a dialect seeds is one the analysis core hands codegen as a model, +// so they wait until codegen knows a system schema when it sees one. +var systemSchemas = []string{ + "information_schema", +} + +// relationQuery lists a schema's relations and their columns, in the order +// the columns were declared, so that the output is stable. +const relationQuery = ` +SELECT t.TABLE_NAME, t.TABLE_TYPE, + c.COLUMN_NAME, c.DATA_TYPE, c.COLUMN_TYPE, c.IS_NULLABLE +FROM information_schema.TABLES t +JOIN information_schema.COLUMNS c + ON c.TABLE_SCHEMA = t.TABLE_SCHEMA AND c.TABLE_NAME = t.TABLE_NAME +WHERE t.TABLE_SCHEMA = ? +ORDER BY t.TABLE_NAME, c.ORDINAL_POSITION` + +// readRelations reads a schema's tables and views. Their names are written +// in lower case: information_schema names its views in upper case and +// matches them in any case, MySQL matches every column name in any case, +// and sqlc's MySQL parser lowercases every identifier, so lower case is +// how a query reaches them. A column's type is spelled the way a +// declaration does, as COLUMN_TYPE reports it, arguments and UNSIGNED +// included: varchar(64), bigint unsigned. +func readRelations(ctx context.Context, conn *sql.Conn, schema string) ([]dialect.Relation, error) { + rows, err := conn.QueryContext(ctx, relationQuery, schema) + if err != nil { + return nil, fmt.Errorf("%s: %w", schema, err) + } + defer rows.Close() + var relations []dialect.Relation + var cur *dialect.Relation + for rows.Next() { + var name, kind, colName, dataType, columnType, nullable string + if err := rows.Scan(&name, &kind, &colName, &dataType, &columnType, &nullable); err != nil { + return nil, err + } + name = strings.ToLower(name) + if cur == nil || cur.Name != name { + rel := dialect.Relation{Catalog: "def", Schema: schema, Name: name} + if kind != "BASE TABLE" { + rel.Kind = "v" + } + relations = append(relations, rel) + cur = &relations[len(relations)-1] + } + cur.Columns = append(cur.Columns, dialect.Column{ + Name: strings.ToLower(colName), + Type: typeName(dataType, columnType), + NotNull: nullable == "NO", + }) + } + return relations, rows.Err() +} + +// typeName spells a column's type the way a declaration does, which is +// COLUMN_TYPE as information_schema reports it: "varchar(64)", "bigint +// unsigned", "enum('a','b')". The family is spelled in lower case; the +// members of an enum or set are values and keep theirs. +func typeName(dataType, columnType string) string { + if columnType == "" { + return strings.ToLower(dataType) + } + var out strings.Builder + quoted := false + for i := 0; i < len(columnType); i++ { + c := columnType[i] + switch { + case quoted && c == '\\' && i+1 < len(columnType): + out.WriteByte(c) + i++ + out.WriteByte(columnType[i]) + continue + case c == '\'': + quoted = !quoted + } + if quoted { + out.WriteByte(c) + } else { + out.WriteString(strings.ToLower(string(c))) + } + } + return out.String() +} diff --git a/internal/goldeneye/mysql/text.go b/internal/goldeneye/mysql/text.go new file mode 100644 index 0000000..98831b6 --- /dev/null +++ b/internal/goldeneye/mysql/text.go @@ -0,0 +1,678 @@ +package mysql + +import ( + "strings" +) + +// MySQL prints a statement back with every name resolved, every table +// alias kept, every SELECT * expanded and every binary operation +// parenthesised — in the optimizer trace's expanded_query, once per query +// block, and in the note EXPLAIN leaves. Such a text is tokenised here and +// read for three things: the tables it names and their aliases, the +// columns each query block projects, and the operand a parameter is +// compared with or assigned to. + +type tokKind int + +const ( + tkIdent tokKind = iota // `a`.`b`.`c` + tkVar // @`name` + tkNumber // 42, 1.5 + tkString // 'text' + tkWord // a keyword, a function name or a + tkOp // =, <=>, +, like is a word + tkLParen + tkRParen + tkComma +) + +type token struct { + kind tokKind + text string // the token as printed; a word is lower-cased + parts []string // an identifier's parts, unquoted; a variable's name + start int // offsets into the source + end int +} + +// text is a tokenised statement. +type text struct { + src string + toks []token + match []int // the index of each parenthesis's partner, or -1 +} + +func tokenize(src string) text { + var toks []token + i := 0 + emit := func(kind tokKind, start, end int, parts []string) { + toks = append(toks, token{kind: kind, text: src[start:end], parts: parts, start: start, end: end}) + } + for i < len(src) { + c := src[i] + switch { + case c == ' ' || c == '\t' || c == '\n' || c == '\r': + i++ + case strings.HasPrefix(src[i:], "/*"): + end := strings.Index(src[i:], "*/") + if end < 0 { + i = len(src) + } else { + i += end + 2 + } + case c == '`': + start := i + var parts []string + for { + part, end := readQuoted(src, i) + parts = append(parts, part) + i = end + if i+1 < len(src) && src[i] == '.' && src[i+1] == '`' { + i++ + continue + } + break + } + emit(tkIdent, start, i, parts) + case c == '@': + start := i + i++ + for i < len(src) && src[i] == '@' { + i++ + } + if i < len(src) && src[i] == '`' { + name, end := readQuoted(src, i) + i = end + emit(tkVar, start, i, []string{name}) + } else { + for i < len(src) && isWordByte(src[i]) { + i++ + } + emit(tkVar, start, i, []string{src[start+1 : i]}) + } + case c == '\'' || c == '"': + start := i + i = skipString(src, i) + emit(tkString, start, i, nil) + case c >= '0' && c <= '9' || c == '.' && i+1 < len(src) && src[i+1] >= '0' && src[i+1] <= '9': + start := i + for i < len(src) && (src[i] >= '0' && src[i] <= '9' || src[i] == '.') { + i++ + } + if i < len(src) && (src[i] == 'e' || src[i] == 'E') { + i++ + if i < len(src) && (src[i] == '+' || src[i] == '-') { + i++ + } + for i < len(src) && src[i] >= '0' && src[i] <= '9' { + i++ + } + } + emit(tkNumber, start, i, nil) + case c == '<' && i+1 < len(src) && isWordByte(src[i+1]) && strings.IndexByte(src[i:], '>') > 0 && isMarker(src[i:i+strings.IndexByte(src[i:], '>')+1]): + // , , : what the optimizer wrapped + // an expression in. says nothing about the expression + // and is dropped; the others are read as calls. + end := i + strings.IndexByte(src[i:], '>') + 1 + if src[i:end] != "" { + emit(tkWord, i, end, nil) + toks[len(toks)-1].text = src[i+1 : end-1] + } + i = end + case c == '(': + emit(tkLParen, i, i+1, nil) + i++ + case c == ')': + emit(tkRParen, i, i+1, nil) + i++ + case c == ',': + emit(tkComma, i, i+1, nil) + i++ + case isWordByte(c): + start := i + for i < len(src) && isWordByte(src[i]) { + i++ + } + emit(tkWord, start, i, nil) + toks[len(toks)-1].text = strings.ToLower(src[start:i]) + default: + n := 1 + for _, op := range operators { + if strings.HasPrefix(src[i:], op) { + n = len(op) + break + } + } + emit(tkOp, i, i+n, nil) + i += n + } + } + t := text{src: src, toks: toks, match: make([]int, len(toks))} + var open []int + for i, tok := range toks { + t.match[i] = -1 + switch tok.kind { + case tkLParen: + open = append(open, i) + case tkRParen: + if len(open) > 0 { + j := open[len(open)-1] + open = open[:len(open)-1] + t.match[i] = j + t.match[j] = i + } + } + } + return t +} + +// operators is every symbolic operator MySQL prints, longest first. +var operators = []string{ + "<=>", "->>", "<>", "!=", ">=", "<=", "->", "<<", ">>", "||", "&&", ":=", + "=", "<", ">", "+", "-", "*", "/", "%", "!", "^", "&", "|", "~", ".", +} + +func isMarker(s string) bool { + for _, c := range []byte(s[1 : len(s)-1]) { + if !isWordByte(c) { + return false + } + } + return true +} + +func isWordByte(c byte) bool { + return c == '_' || c == '$' || c >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' +} + +// readQuoted reads the backticked identifier at i, unescaping a doubled +// backtick, and returns it with the index just past its closing quote. +func readQuoted(s string, i int) (string, int) { + var b strings.Builder + j := i + 1 + for j < len(s) { + if s[j] == '`' { + if j+1 < len(s) && s[j+1] == '`' { + b.WriteByte('`') + j += 2 + continue + } + return b.String(), j + 1 + } + b.WriteByte(s[j]) + j++ + } + return b.String(), j +} + +// skipString returns the index just past the string literal starting at i, +// honouring backslash escapes and doubled quotes. +func skipString(s string, i int) int { + q := s[i] + j := i + 1 + for j < len(s) { + switch { + case s[j] == '\\' && j+1 < len(s): + j += 2 + case s[j] == q && j+1 < len(s) && s[j+1] == q: + j += 2 + case s[j] == q: + return j + 1 + default: + j++ + } + } + return len(s) +} + +// wordOperators are the operators MySQL spells as words. and/or/not/is +// are left out: MySQL parenthesises each predicate, so a parameter that +// is a whole predicate has nothing to be compared with. +var wordOperators = map[string]bool{ + "like": true, "in": true, "regexp": true, "rlike": true, "div": true, "mod": true, + "xor": true, "sounds": true, "escape": true, "between": true, "collate": true, + "member": true, +} + +// keywords are the words that can precede a parenthesis without naming a +// function, so that "(a, b)" after one is a list rather than a call. +var keywords = map[string]bool{ + "in": true, "values": true, "value": true, "and": true, "or": true, "not": true, + "where": true, "on": true, "from": true, "select": true, "having": true, + "set": true, "when": true, "then": true, "else": true, "case": true, "end": true, + "like": true, "between": true, "by": true, "group": true, "order": true, + "limit": true, "offset": true, "using": true, "join": true, "as": true, "is": true, + "xor": true, "div": true, "mod": true, "interval": true, "distinct": true, + "all": true, "any": true, "some": true, "escape": true, "regexp": true, + "rlike": true, "sounds": true, "collate": true, "union": true, "except": true, + "intersect": true, "with": true, "insert": true, "into": true, "update": true, + "delete": true, "replace": true, "key": true, "duplicate": true, "do": true, + "partition": true, "over": true, "window": true, "rows": true, "range": true, + "straight_join": true, "cross": true, "inner": true, "left": true, "right": true, + "natural": true, "lateral": true, "of": true, "for": true, "lock": true, + "share": true, "null": true, "true": true, "false": true, "unknown": true, + "binary": true, "row": true, "asc": true, "desc": true, "sql_calc_found_rows": true, + "high_priority": true, "low_priority": true, "ignore": true, "table": true, + "member": true, "exists": true, +} + +// literalWords are the words that are operands on their own. +var literalWords = map[string]bool{ + "null": true, "true": true, "false": true, "unknown": true, + "current_timestamp": true, "current_date": true, "current_time": true, + "current_user": true, "localtime": true, "localtimestamp": true, "utc_timestamp": true, +} + +func (t text) at(i int) token { + if i < 0 || i >= len(t.toks) { + return token{kind: -1} + } + return t.toks[i] +} + +func (t text) isWord(i int, word string) bool { + tok := t.at(i) + return tok.kind == tkWord && tok.text == word +} + +// isCall reports whether the word at i names a function, given that a +// parenthesis follows it. +func (t text) isCall(i int) bool { + tok := t.at(i) + return tok.kind == tkWord && !keywords[tok.text] || tok.kind == tkWord && tok.text == "exists" +} + +// isOperator reports whether the token at i joins two operands. +func (t text) isOperator(i int) bool { + tok := t.at(i) + switch tok.kind { + case tkOp: + return tok.text != "." && tok.text != "~" && tok.text != "!" + case tkWord: + return wordOperators[tok.text] + } + return false +} + +// operandEnd returns the index just past the operand starting at i, or -1 +// when no operand starts there: a name, a literal, a call with its +// arguments, or a parenthesised group. +func (t text) operandEnd(i int) int { + tok := t.at(i) + switch tok.kind { + case tkIdent, tkVar, tkNumber, tkString: + return i + 1 + case tkLParen: + if t.match[i] < 0 { + return -1 + } + return t.match[i] + 1 + case tkWord: + if literalWords[tok.text] { + return i + 1 + } + if t.at(i+1).kind == tkLParen && t.isCall(i) { + return t.operandEnd(i + 1) + } + if tok.text == "not" || tok.text == "binary" || tok.text == "interval" { + return t.operandEnd(i + 1) + } + case tkOp: + if tok.text == "-" || tok.text == "+" || tok.text == "~" || tok.text == "!" { + return t.operandEnd(i + 1) + } + } + return -1 +} + +// operandStart returns the index of the operand ending just before j, or +// -1 when none ends there. +func (t text) operandStart(j int) int { + k := j - 1 + tok := t.at(k) + switch tok.kind { + case tkIdent, tkVar, tkNumber, tkString: + return k + case tkRParen: + open := t.match[k] + if open < 0 { + return -1 + } + if t.at(open-1).kind == tkWord && t.isCall(open-1) { + return open - 1 + } + return open + case tkWord: + if literalWords[tok.text] { + return k + } + } + return -1 +} + +// group returns the index of the parenthesis enclosing token i, or -1. +func (t text) group(i int) int { + depth := 0 + for k := i - 1; k >= 0; k-- { + switch t.toks[k].kind { + case tkRParen: + depth++ + case tkLParen: + if depth == 0 { + return k + } + depth-- + } + } + return -1 +} + +// list splits the tokens strictly inside the group opened at open into its +// comma-separated members, each a token range. +func (t text) list(open int) [][2]int { + close := t.match[open] + if close < 0 { + return nil + } + var members [][2]int + start := open + 1 + for i := open + 1; i < close; i++ { + switch t.toks[i].kind { + case tkLParen: + i = t.match[i] + case tkComma: + members = append(members, [2]int{start, i}) + start = i + 1 + } + } + if start < close { + members = append(members, [2]int{start, close}) + } + return members +} + +// item is one entry of a SELECT list: the expression and the name it is +// projected as. +type item struct { + start, end int + alias string +} + +// selectItems reads the list of the first SELECT at the top level of the +// text, which is the statement's own for a query block's expanded_query +// and for a statement whose CTEs come first. +func (t text) selectItems() []item { + depth := 0 + start := -1 + for i, tok := range t.toks { + switch tok.kind { + case tkLParen: + depth++ + case tkRParen: + depth-- + case tkWord: + if depth == 0 && tok.text == "select" { + start = i + 1 + } + } + if start >= 0 { + break + } + } + if start < 0 { + return nil + } + for t.at(start).kind == tkWord && (t.at(start).text == "distinct" || t.at(start).text == "all" || t.at(start).text == "sql_calc_found_rows" || t.at(start).text == "straight_join" || t.at(start).text == "high_priority") { + start++ + } + end := len(t.toks) + for i := start; i < len(t.toks); i++ { + switch tok := t.toks[i]; tok.kind { + case tkLParen: + i = t.match[i] + if i < 0 { + return nil + } + case tkWord: + switch tok.text { + case "from", "where", "group", "having", "order", "limit", "union", "into", "window", "for", "lock", "except", "intersect": + end = i + } + } + if end != len(t.toks) { + break + } + } + var items []item + itemStart := start + flush := func(itemEnd int) { + it := item{start: itemStart, end: itemEnd} + if itemEnd-itemStart >= 3 && t.isWord(itemEnd-2, "as") && t.at(itemEnd-1).kind == tkIdent { + it.alias = t.toks[itemEnd-1].parts[0] + it.end = itemEnd - 2 + } + items = append(items, it) + } + for i := start; i < end; i++ { + switch t.toks[i].kind { + case tkLParen: + i = t.match[i] + case tkComma: + flush(i) + itemStart = i + 1 + } + } + if itemStart < end { + flush(end) + } + return items +} + +// tableRef is a table as a FROM clause names it, with the schema when it +// spells one out. +type tableRef struct { + schema, name string +} + +// aliases reads the table aliases the text declares: a table name followed +// by a bare identifier, as `users` `u` in a FROM clause. A SELECT list +// alias is always introduced by AS, so the shape means nothing else. +func (t text) aliases(into map[string]tableRef) { + for i := 0; i+1 < len(t.toks); i++ { + tok, next := t.toks[i], t.toks[i+1] + if tok.kind != tkIdent || next.kind != tkIdent || len(next.parts) != 1 || len(tok.parts) > 2 { + continue + } + if t.at(i-1).kind == tkOp && t.at(i-1).text == "." { + continue + } + ref := tableRef{name: tok.parts[len(tok.parts)-1]} + if len(tok.parts) == 2 { + ref.schema = tok.parts[0] + } + into[next.parts[0]] = ref + } +} + +// find returns the index of the variable named name, or -1. +func (t text) findVar(name string) int { + for i, tok := range t.toks { + if tok.kind == tkVar && len(tok.parts) == 1 && tok.parts[0] == name { + return i + } + } + return -1 +} + +// findNumber returns the index of the number printed as lit, or -1. +func (t text) findNumber(lit string) int { + for i, tok := range t.toks { + if tok.kind == tkNumber && tok.text == lit { + return i + } + } + return -1 +} + +// A partner is what a parameter stands against in a statement. +type partnerKind int + +const ( + partnerNone partnerKind = iota + partnerOperand // the operand it is compared with, or the argument beside it + partnerProjection // the SELECT list item it is projected as + partnerInsert // the column of an INSERT ... VALUES row it is written to + partnerLimit // the count of a LIMIT or OFFSET +) + +type partner struct { + kind partnerKind + start, end int // partnerOperand: the operand's tokens + index int // partnerProjection: the item; partnerInsert: the position in the row +} + +// partner finds what the parameter at token index s stands against. +func (t text) partner(s int) partner { + lo, hi := s, s+1 + if t.at(lo-1).kind == tkLParen && t.at(hi).kind == tkRParen { + lo, hi = lo-1, hi+1 + } + if t.at(hi).kind == tkWord && t.at(hi).text == "as" { + for i, it := range t.selectItems() { + if it.start <= lo && hi <= it.end { + return partner{kind: partnerProjection, index: i} + } + } + } + // The count of a LIMIT or OFFSET, which is a number rather than a + // variable since MySQL allows nothing else there. + if t.at(lo-1).kind == tkWord && (t.at(lo-1).text == "limit" || t.at(lo-1).text == "offset") || + t.at(lo-1).kind == tkComma && t.at(lo-2).kind == tkNumber && t.isWord(lo-3, "limit") { + return partner{kind: partnerLimit} + } + // Compared: the operand on the other side of the operator. + if t.isOperator(lo - 1) { + q := lo - 2 + if t.isWord(q, "not") { + q-- + } + if st := t.operandStart(q + 1); st >= 0 { + // The second bound of BETWEEN ... AND: the operand before BETWEEN. + if t.isWord(lo-1, "and") { + if t.isWord(st-1, "between") || t.isWord(st-1, "not") && t.isWord(st-2, "between") { + q = st - 2 + if t.isWord(q, "not") { + q-- + } + if st2 := t.operandStart(q + 1); st2 >= 0 { + return partner{kind: partnerOperand, start: st2, end: q + 1} + } + } + } + return partner{kind: partnerOperand, start: st, end: q + 1} + } + } + if t.isWord(lo-1, "and") { + if st := t.operandStart(lo - 1); st >= 0 && (t.isWord(st-1, "between") || t.isWord(st-1, "not") && t.isWord(st-2, "between")) { + q := st - 2 + if t.isWord(q, "not") { + q-- + } + if st2 := t.operandStart(q + 1); st2 >= 0 { + return partner{kind: partnerOperand, start: st2, end: q + 1} + } + } + } + if t.isOperator(hi) { + n := hi + 1 + if t.isWord(n, "not") { + n++ + } + if end := t.operandEnd(n); end >= 0 { + return partner{kind: partnerOperand, start: n, end: end} + } + } + // A member of a list: the row of an INSERT ... VALUES, the values of an + // IN, or the arguments of a call, where the argument beside it says + // what it is, a column above an expression above a constant. + if t.at(lo-1).kind == tkComma || t.at(lo-1).kind == tkLParen { + open := t.group(lo) + if open < 0 { + return partner{} + } + members := t.list(open) + index := -1 + for i, m := range members { + if m[0] <= lo && hi <= m[1] { + index = i + } + } + head := open - 1 + for t.at(head).kind == tkComma && t.at(head-1).kind == tkRParen { + head = t.match[head-1] - 1 + } + switch { + case t.isWord(head, "values") || t.isWord(head, "value"): + return partner{kind: partnerInsert, index: index} + case t.isWord(head, "in"): + q := head - 1 + if t.isWord(q, "not") { + q-- + } + if st := t.operandStart(q + 1); st >= 0 { + return partner{kind: partnerOperand, start: st, end: q + 1} + } + case t.at(head).kind == tkWord && t.isCall(head): + best, bestRank := -1, 3 + for i, m := range members { + if i == index { + continue + } + if r := t.rank(m[0], m[1]); r < bestRank { + best, bestRank = i, r + } + } + if best >= 0 { + return partner{kind: partnerOperand, start: members[best][0], end: members[best][1]} + } + } + } + return partner{} +} + +// rank orders operands by how much they say about a parameter beside them. +func (t text) rank(start, end int) int { + switch tok := t.at(start); { + case end-start == 1 && tok.kind == tkIdent: + return 0 + case tok.kind == tkVar: + return 3 + case end-start == 1: + return 2 + } + return 1 +} + +// idents lists the qualified identifiers in a token range: the columns an +// expression reads. +func (t text) idents(start, end int) []token { + var out []token + for i := start; i < end; i++ { + if tok := t.toks[i]; tok.kind == tkIdent && len(tok.parts) >= 2 { + out = append(out, tok) + } + } + return out +} + +// slice is the source text of a token range. +func (t text) slice(start, end int) string { + if start >= end { + return "" + } + return t.src[t.toks[start].start:t.toks[end-1].end] +} + +// quote backticks an identifier. +func quote(name string) string { + return "`" + strings.ReplaceAll(name, "`", "``") + "`" +} diff --git a/internal/goldeneye/mysql/trace.go b/internal/goldeneye/mysql/trace.go new file mode 100644 index 0000000..c7f040f --- /dev/null +++ b/internal/goldeneye/mysql/trace.go @@ -0,0 +1,87 @@ +package mysql + +import ( + "encoding/json" + "fmt" + "sort" + "strings" +) + +// trace is what the optimizer trace says about a statement: the text of +// each query block after name resolution and before optimisation, by the +// number MySQL gives the block, and the block each derived table or CTE is +// materialised from. +// +// The trace is the one place MySQL prints a query block as it was resolved +// rather than as it was optimised. The note EXPLAIN leaves is printed +// after optimisation, and a lookup on a unique key against an empty table +// folds to `NULL = (@x)` there, losing the column the parameter was +// compared with; the expanded_query of the block still has it. +type trace struct { + blocks map[int]text + derived map[string]int +} + +// parseTrace reads the JSON of the OPTIMIZER_TRACE table's TRACE column. +func parseTrace(blob string) (trace, error) { + tr := trace{blocks: map[int]text{}, derived: map[string]int{}} + if strings.TrimSpace(blob) == "" { + return tr, nil + } + var v any + if err := json.Unmarshal([]byte(blob), &v); err != nil { + return tr, fmt.Errorf("reading the optimizer trace: %w", err) + } + tr.walk(v, 0) + return tr, nil +} + +// walk collects the first expanded_query printed for each block — the one +// join_preparation prints, before join_optimization prints its rewrite — +// and the derived tables. Lists are walked in order and objects in key +// order, so the result does not depend on map iteration. +func (tr *trace) walk(v any, sel int) { + switch v := v.(type) { + case map[string]any: + if n, ok := v["select#"].(float64); ok { + sel = int(n) + } + if d, ok := v["derived"].(map[string]any); ok { + if table, ok := d["table"].(string); ok { + if n, ok := d["select#"].(float64); ok { + tr.derived[strings.Trim(table, "` ")] = int(n) + } + } + } + if q, ok := v["expanded_query"].(string); ok { + if _, seen := tr.blocks[sel]; !seen { + tr.blocks[sel] = tokenize(q) + } + } + keys := make([]string, 0, len(v)) + for k := range v { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + tr.walk(v[k], sel) + } + case []any: + for _, c := range v { + tr.walk(c, sel) + } + } +} + +// order lists the block numbers innermost first: a block's text includes +// its subqueries' text, and a subquery is numbered after the block it is +// in, so the block a parameter belongs to is the highest-numbered block +// whose text has it. +func (tr *trace) order() []int { + sels := make([]int, 0, len(tr.blocks)) + for sel := range tr.blocks { + sels = append(sels, sel) + } + sort.Sort(sort.Reverse(sort.IntSlice(sels))) + return sels +} diff --git a/internal/goldeneye/postgresql/postgresql.go b/internal/goldeneye/postgresql/postgresql.go new file mode 100644 index 0000000..b94ff5e --- /dev/null +++ b/internal/goldeneye/postgresql/postgresql.go @@ -0,0 +1,364 @@ +// Package postgresql generates the PostgreSQL dialect seed under +// internal/engine/postgresql/dialect from a live server: pg_catalog's +// functions, the relations of pg_catalog and information_schema, and one +// directory per contrib extension holding the types and functions CREATE +// EXTENSION adds. types.jsonl and operators.jsonl at the top of the dialect +// are written by hand and are not this package's business. +// +// The server is named by POSTGRESQL_SERVER_URI and has to be the major +// release in Major, since each release adds to its catalogs. +package postgresql + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "os" + "path" + "sort" + "strconv" + "strings" + + "github.com/jackc/pgx/v5" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/dialect" +) + +// Engine is the name of the engine directory the dialect lives under. +const Engine = "postgresql" + +// Major is the PostgreSQL major release the dialect is generated from. +// Bumping it is a deliberate change: every release adds functions and +// catalog columns, so regenerate and review the dialect after changing it. +const Major = 16 + +// https://dba.stackexchange.com/questions/255412/how-to-select-functions-that-belong-in-a-given-extension-in-postgresql +// +// Extension functions are added to the public schema +const extensionFuncs = ` +WITH extension_funcs AS ( + SELECT p.oid + FROM pg_catalog.pg_extension AS e + INNER JOIN pg_catalog.pg_depend AS d ON (d.refobjid = e.oid) + INNER JOIN pg_catalog.pg_proc AS p ON (p.oid = d.objid) + INNER JOIN pg_catalog.pg_namespace AS ne ON (ne.oid = e.extnamespace) + INNER JOIN pg_catalog.pg_namespace AS np ON (np.oid = p.pronamespace) + WHERE d.deptype = 'e' AND e.extname = $1 +) +SELECT p.proname as name, + format_type(p.prorettype, NULL), + array(select format_type(unnest(p.proargtypes), NULL)), + p.proargnames, + p.proargnames[p.pronargs-p.pronargdefaults+1:p.pronargs], + p.proargmodes::text[] +FROM pg_catalog.pg_proc p +JOIN extension_funcs ef ON ef.oid = p.oid +WHERE pg_function_is_visible(p.oid) +-- simply order all columns to keep subsequent runs stable +ORDER BY 1, 2, 3, 4, 5; +` + +// The types an extension defines, in the order they were declared so that a +// type appears after the types it is built on. Array types are created +// implicitly rather than by the extension's script, so they carry an internal +// dependency and never show up here. +const extensionTypes = ` +SELECT t.typname, t.typcategory +FROM pg_catalog.pg_extension AS e + INNER JOIN pg_catalog.pg_depend AS d ON (d.refobjid = e.oid) + INNER JOIN pg_catalog.pg_type AS t ON (t.oid = d.objid) +WHERE d.deptype = 'e' + AND d.classid = 'pg_catalog.pg_type'::regclass + AND e.extname = $1 + AND t.typtype <> 'p' +ORDER BY t.oid; +` + +// Locate returns the server to generate from, named by POSTGRESQL_SERVER_URI. +func Locate() (string, error) { + if url := os.Getenv("POSTGRESQL_SERVER_URI"); url != "" { + return url, nil + } + return "", errors.New("POSTGRESQL_SERVER_URI is not set") +} + +// Version reports the release a server is. +func Version(ctx context.Context, url string) (string, error) { + conn, err := pgx.Connect(ctx, url) + if err != nil { + return "", err + } + defer conn.Close(ctx) + var version string + if err := conn.QueryRow(ctx, "SELECT version()").Scan(&version); err != nil { + return "", err + } + return version, nil +} + +// checkVersion refuses a server of another major release than the dialect +// is generated from, whose catalogs would differ from the committed ones +// without anything being wrong. +func checkVersion(ctx context.Context, conn *pgx.Conn) error { + var num string + if err := conn.QueryRow(ctx, "SELECT current_setting('server_version_num')").Scan(&num); err != nil { + return err + } + n, err := strconv.Atoi(num) + if err != nil { + return fmt.Errorf("server_version_num %q: %w", num, err) + } + if major := n / 10000; major != Major { + return fmt.Errorf("the dialect is generated from PostgreSQL %d, but the server is PostgreSQL %d", Major, major) + } + return nil +} + +func clean(arg string) string { + arg = strings.TrimSpace(arg) + arg = strings.Replace(arg, "\"any\"", "any", -1) + arg = strings.Replace(arg, "\"char\"", "char", -1) + arg = strings.Replace(arg, "\"timestamp\"", "char", -1) + return arg +} + +// encodeFunctions encodes procs as JSONL, one function per line, in the form +// the seed package reads. Both the analysis core and the catalog the legacy +// compiler builds load the result. +func encodeFunctions(procs []Proc) ([]byte, error) { + funcs := make([]dialect.Function, 0, len(procs)) + for _, proc := range procs { + fn := dialect.Function{Name: proc.Name, Returns: proc.ReturnTypeName()} + for _, arg := range proc.Args() { + a := dialect.Arg{Name: arg.Name, Type: arg.TypeName(), HasDefault: arg.HasDefault} + if arg.Mode != "" && arg.Mode != "i" { + a.Mode = arg.Mode + } + fn.Args = append(fn.Args, a) + } + funcs = append(funcs, fn) + } + return dialect.JSONL(funcs) +} + +// readExtensionTypes reads the types an extension defines. +func readExtensionTypes(ctx context.Context, conn *pgx.Conn, extension string) ([]dialect.Type, error) { + rows, err := conn.Query(ctx, extensionTypes, extension) + if err != nil { + return nil, err + } + defer rows.Close() + var types []dialect.Type + for rows.Next() { + var t dialect.Type + if err := rows.Scan(&t.Name, &t.Category); err != nil { + return nil, err + } + types = append(types, t) + } + return types, rows.Err() +} + +// writeRelations appends a schema's relations to out as JSONL, one relation +// per line, in the form the seed package reads. +func writeRelations(out *bytes.Buffer, schemaName string, relations []Relation) error { + enc := json.NewEncoder(out) + for _, relation := range relations { + rec := dialect.Relation{ + Catalog: relation.Catalog, + Schema: schemaName, + Name: relation.Name, + } + for _, col := range relation.Columns { + c := dialect.Column{ + Name: col.Name, + Type: col.Type, + NotNull: col.IsNotNull, + Array: col.IsArray, + } + if col.Length != nil { + c.Length = *col.Length + } + rec.Columns = append(rec.Columns, c) + } + if err := enc.Encode(rec); err != nil { + return err + } + } + return nil +} + +// preserveLegacyCatalogBehavior maintain previous ordering and filtering +// that was manually done to the generated file pg_catalog.go. +// Some of the test depend on this ordering - in particular, function lookups +// where there might be multiple matching functions (due to type overloads) +// Until sqlc supports "smarter" looking up of these functions, +// preserveLegacyCatalogBehavior ensures there are no accidental test breakages +func preserveLegacyCatalogBehavior(allProcs []Proc) []Proc { + // Preserve the legacy sort order of the end-to-end tests + sort.SliceStable(allProcs, func(i, j int) bool { + fnA := allProcs[i] + fnB := allProcs[j] + + if fnA.Name == "lower" && fnB.Name == "lower" && len(fnA.ArgTypes) == 1 && fnA.ArgTypes[0] == "text" { + return true + } + + if fnA.Name == "generate_series" && fnB.Name == "generate_series" && len(fnA.ArgTypes) == 2 && fnA.ArgTypes[0] == "numeric" { + return true + } + + return false + }) + + procs := make([]Proc, 0, len(allProcs)) + for _, p := range allProcs { + // Skip generating pg_catalog.concat to preserve legacy behavior + if p.Name == "concat" { + continue + } + + procs = append(procs, p) + } + + return procs +} + +// Generate reads the dialect from the server. It creates every contrib +// extension it describes, so the server's contrib package has to be +// installed. +func Generate(ctx context.Context, url string) (dialect.Files, error) { + conn, err := pgx.Connect(ctx, url) + if err != nil { + return nil, err + } + defer conn.Close(ctx) + if err := checkVersion(ctx, conn); err != nil { + return nil, err + } + + files := dialect.Files{} + + // The two schemas sqlc knows PostgreSQL by. pg_catalog's functions are + // the dialect's standard library; the relations of both share one file, + // keyed by schema. + procs, err := readProcs(ctx, conn, "pg_catalog", extensions) + if err != nil { + return nil, err + } + if files[dialect.FunctionsFile], err = encodeFunctions(preserveLegacyCatalogBehavior(procs)); err != nil { + return nil, err + } + var relations bytes.Buffer + for _, schema := range []string{"pg_catalog", "information_schema"} { + rels, err := readRelations(ctx, conn, schema) + if err != nil { + return nil, err + } + if err := writeRelations(&relations, schema, rels); err != nil { + return nil, err + } + } + files[dialect.RelationsFile] = relations.Bytes() + + // Each extension is a directory of its own under the dialect, holding the + // functions CREATE EXTENSION adds to the catalog. + for _, extension := range extensions { + if _, err := conn.Exec(ctx, fmt.Sprintf("CREATE EXTENSION IF NOT EXISTS %q", extension)); err != nil { + return nil, fmt.Errorf("error creating %s: %s", extension, err) + } + + rows, err := conn.Query(ctx, extensionFuncs, extension) + if err != nil { + return nil, err + } + procs, err := scanProcs(rows) + if err != nil { + return nil, err + } + types, err := readExtensionTypes(ctx, conn, extension) + if err != nil { + return nil, err + } + if len(procs) == 0 && len(types) == 0 { + continue + } + + // Preserve the legacy sort order of the end-to-end tests + sort.SliceStable(procs, func(i, j int) bool { + fnA := procs[i] + fnB := procs[j] + + if extension == "pgcrypto" { + if fnA.Name == "digest" && fnB.Name == "digest" && len(fnA.ArgTypes) == 2 && fnA.ArgTypes[0] == "text" { + return true + } + } + + return false + }) + + extensionDir := path.Join(dialect.ExtensionsDir, extension) + if len(types) > 0 { + if files[path.Join(extensionDir, dialect.TypesFile)], err = dialect.JSONL(types); err != nil { + return nil, fmt.Errorf("error generating extension %s: %w", extension, err) + } + } + if files[path.Join(extensionDir, dialect.FunctionsFile)], err = encodeFunctions(procs); err != nil { + return nil, fmt.Errorf("error generating extension %s: %w", extension, err) + } + } + + return files, nil +} + +// https://www.postgresql.org/docs/current/contrib.html +var extensions = []string{ + "adminpack", + "amcheck", + // "auth_delay", + // "auto_explain", + // "bloom", + "btree_gin", + "btree_gist", + "citext", + "cube", + "dblink", + // "dict_int", + // "dict_xsyn", + "earthdistance", + "file_fdw", + "fuzzystrmatch", + "hstore", + "intagg", + "intarray", + "isn", + "lo", + "ltree", + "pageinspect", + // "passwordcheck", + "pg_buffercache", + "pg_freespacemap", + "pg_prewarm", + "pg_stat_statements", + "pg_trgm", + "pg_visibility", + "pgcrypto", + "pgrowlocks", + "pgstattuple", + "postgres_fdw", + "seg", + // "sepgsql", + // "spi", + "sslinfo", + "tablefunc", + "tcn", + // "test_decoding", + // "tsm_system_rows", + // "tsm_system_time", + "unaccent", + "uuid-ossp", + "xml2", +} diff --git a/internal/goldeneye/postgresql/postgresql_test.go b/internal/goldeneye/postgresql/postgresql_test.go new file mode 100644 index 0000000..e892b12 --- /dev/null +++ b/internal/goldeneye/postgresql/postgresql_test.go @@ -0,0 +1,37 @@ +package postgresql + +import ( + "context" + "testing" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/dialect" +) + +// TestDialect verifies the committed PostgreSQL dialect against what the +// server reports. It skips unless POSTGRESQL_SERVER_URI names a server. +func TestDialect(t *testing.T) { + url, err := Locate() + if err != nil { + t.Skip(err) + } + ctx := context.Background() + version, err := Version(ctx, url) + if err != nil { + t.Fatal(err) + } + files, err := Generate(ctx, url) + if err != nil { + t.Fatal(err) + } + dir, err := dialect.Dir(Engine) + if err != nil { + t.Fatal(err) + } + report, err := dialect.Check(dir, files) + if err != nil { + t.Fatal(err) + } + if report != "" { + t.Errorf("%s does not match what %s reports:\n%s", dir, version, report) + } +} diff --git a/internal/goldeneye/postgresql/proc.go b/internal/goldeneye/postgresql/proc.go new file mode 100644 index 0000000..31933c7 --- /dev/null +++ b/internal/goldeneye/postgresql/proc.go @@ -0,0 +1,163 @@ +package postgresql + +import ( + "context" + "strings" + + pgx "github.com/jackc/pgx/v5" +) + +// https://stackoverflow.com/questions/25308765/postgresql-how-can-i-inspect-which-arguments-to-a-procedure-have-a-default-valu +const catalogFuncs = ` +SELECT p.proname as name, + format_type(p.prorettype, NULL), + array(select format_type(unnest(p.proargtypes), NULL)), + p.proargnames, + p.proargnames[p.pronargs-p.pronargdefaults+1:p.pronargs], + p.proargmodes::text[] +FROM pg_catalog.pg_proc p +LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace +WHERE n.nspname::text = $1 + AND pg_function_is_visible(p.oid) + -- A function that one of the extensions the dialect describes separately + -- put in the schema, as adminpack puts its own in pg_catalog, belongs to + -- that extension's directory: leaving it out here keeps the output the + -- same whether or not the extension is installed. + AND NOT EXISTS ( + SELECT 1 + FROM pg_catalog.pg_depend d + INNER JOIN pg_catalog.pg_extension e ON e.oid = d.refobjid + WHERE d.classid = 'pg_catalog.pg_proc'::regclass + AND d.objid = p.oid + AND d.deptype = 'e' + AND e.extname = ANY($2)) +-- simply order all columns to keep subsequent runs stable +ORDER BY 1, 2, 3, 4, 5; +` + +type Proc struct { + Name string + ReturnType string + ArgTypes []string + ArgNames []string + HasDefault []string + ArgModes []string +} + +func (p *Proc) ReturnTypeName() string { + return clean(p.ReturnType) +} + +func (p *Proc) Args() []Arg { + var args []Arg + defaults := map[string]bool{} + for _, name := range p.HasDefault { + defaults[name] = true + } + + for i, argType := range p.ArgTypes { + mode := "i" + name := "" + if i < len(p.ArgModes) { + mode = p.ArgModes[i] + } + if i < len(p.ArgNames) { + name = p.ArgNames[i] + } + + args = append(args, Arg{ + Name: name, + Type: argType, + Mode: mode, + HasDefault: defaults[name], + }) + } + + // Some manual changes until https://github.com/sqlc-dev/sqlc/pull/1748 + // can be completely implmented + if p.Name == "mode" { + return nil + } + + if p.Name == "percentile_cont" && len(args) == 2 { + args = args[:1] + } + + if p.Name == "percentile_disc" && len(args) == 2 { + args = args[:1] + } + + return args +} + +type Arg struct { + Name string + Mode string + Type string + HasDefault bool +} + +func (a *Arg) TypeName() string { + return clean(a.Type) +} + +func scanProcs(rows pgx.Rows) ([]Proc, error) { + defer rows.Close() + // Iterate through the result set + var procs []Proc + for rows.Next() { + var p Proc + err := rows.Scan( + &p.Name, + &p.ReturnType, + &p.ArgTypes, + &p.ArgNames, + &p.HasDefault, + &p.ArgModes, + ) + if err != nil { + return nil, err + } + + // TODO: Filter these out in SQL + if strings.HasPrefix(p.ReturnType, "SETOF") { + continue + } + + // The internal pseudo-type is used to declare functions that are meant + // only to be called internally by the database system, and not by + // direct invocation in an SQL query. If a function has at least one + // internal-type argument then it cannot be called from SQL. To + // preserve the type safety of this restriction it is important to + // follow this coding rule: do not create any function that is declared + // to return internal unless it has at least one internal argument + // + // https://www.postgresql.org/docs/current/datatype-pseudo.html + var skip bool + for i := range p.ArgTypes { + if p.ArgTypes[i] == "internal" { + skip = true + } + } + if skip { + continue + } + if p.ReturnType == "internal" { + continue + } + + procs = append(procs, p) + } + return procs, rows.Err() +} + +// readProcs reads the functions of a schema, leaving out the ones that +// belong to any of the named extensions. +func readProcs(ctx context.Context, conn *pgx.Conn, schemaName string, extensions []string) ([]Proc, error) { + rows, err := conn.Query(ctx, catalogFuncs, schemaName, extensions) + if err != nil { + return nil, err + } + + return scanProcs(rows) +} diff --git a/internal/goldeneye/postgresql/relation.go b/internal/goldeneye/postgresql/relation.go new file mode 100644 index 0000000..7e036a0 --- /dev/null +++ b/internal/goldeneye/postgresql/relation.go @@ -0,0 +1,118 @@ +package postgresql + +import ( + "context" + + pgx "github.com/jackc/pgx/v5" +) + +// Relations are the relations available in pg_tables and pg_views +// such as pg_catalog.pg_timezone_names +const relationQuery = ` +with relations as ( + select schemaname, tablename as name from pg_catalog.pg_tables + UNION ALL + select schemaname, viewname as name from pg_catalog.pg_views +) +select + relations.schemaname, + relations.name as tablename, + pg_attribute.attname as column_name, + attnotnull as column_notnull, + -- An array column's type is its element's, with the array flag set, + -- rather than pg_type's own _text spelling of the array type. Only the + -- _-prefixed array types count: int2vector and oidvector are in the + -- array category and carry an element, but are types of their own. + coalesce(element_type.typname, column_type.typname) as column_type, + nullif(coalesce(element_type.typlen, column_type.typlen), -1) as column_length, + element_type.oid is not null as column_isarray +from relations +inner join pg_catalog.pg_class on pg_class.relname = relations.name +left join pg_catalog.pg_attribute on pg_attribute.attrelid = pg_class.oid +inner join pg_catalog.pg_type column_type on pg_attribute.atttypid = column_type.oid +left join pg_catalog.pg_type element_type + on column_type.typcategory = 'A' and column_type.typname like '\_%' + and element_type.oid = column_type.typelem +where relations.schemaname = $1 +-- Make sure these columns are always generated in the same order +-- so that the output is stable +order by + relations.schemaname ASC, + relations.name ASC, + pg_attribute.attnum ASC +` + +type Relation struct { + Catalog string + SchemaName string + Name string + Columns []RelationColumn +} + +type RelationColumn struct { + Name string + Type string + IsNotNull bool + IsArray bool + Length *int +} + +func scanRelations(rows pgx.Rows) ([]Relation, error) { + defer rows.Close() + // Iterate through the result set + var relations []Relation + var prevRel *Relation + + for rows.Next() { + var schemaName string + var tableName string + var columnName string + var columnNotNull bool + var columnType string + var columnLength *int + var columnIsArray bool + err := rows.Scan( + &schemaName, + &tableName, + &columnName, + &columnNotNull, + &columnType, + &columnLength, + &columnIsArray, + ) + if err != nil { + return nil, err + } + + if prevRel == nil || tableName != prevRel.Name { + // We are on the same table, just keep adding columns + r := Relation{ + Catalog: "pg_catalog", + SchemaName: schemaName, + Name: tableName, + } + + relations = append(relations, r) + prevRel = &relations[len(relations)-1] + } + + prevRel.Columns = append(prevRel.Columns, RelationColumn{ + Name: columnName, + Type: columnType, + IsNotNull: columnNotNull, + IsArray: columnIsArray, + Length: columnLength, + }) + } + + return relations, rows.Err() +} + +func readRelations(ctx context.Context, conn *pgx.Conn, schemaName string) ([]Relation, error) { + rows, err := conn.Query(ctx, relationQuery, schemaName) + if err != nil { + return nil, err + } + + return scanRelations(rows) +} diff --git a/internal/goldeneye/spanner/analyze.go b/internal/goldeneye/spanner/analyze.go new file mode 100644 index 0000000..813ec3f --- /dev/null +++ b/internal/goldeneye/spanner/analyze.go @@ -0,0 +1,673 @@ +package spanner + +import ( + "context" + "fmt" + "hash/crc32" + "os" + "regexp" + "strconv" + "strings" + + "cloud.google.com/go/spanner/apiv1/spannerpb" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/analysis" + "github.com/sqlc-dev/sqlc/internal/goldeneye/endtoend" +) + +// The analyze cases are checked against a live server, which compiles +// each query in PLAN mode: nothing runs, and the server reports the name +// and type of each result column, the type of each parameter the query +// leaves undeclared, and the query plan. The metadata types a value the +// way the wire does — STRING, ARRAY — without the length a +// declaration gives a STRING(10) or whether the column can be NULL, so a +// result column the plan reads from a table column is described from the +// case's INFORMATION_SCHEMA instead, and a parameter the plan compares +// with or assigns to a table column is described as that column. + +// placeholder is one parameter of a query as sqlc numbers them: each +// @name or sqlc.arg name once, at its first appearance, which is how +// Spanner numbers its named parameters too. +type placeholder struct { + Number int + Name string +} + +var identRe = regexp.MustCompile(`^@([A-Za-z_][A-Za-z0-9_]*)`) + +// bind rewrites the query so that every parameter is a Spanner @name, and +// lists the parameters in sqlc's order. The query's own @name references +// are kept, since that is how sqlc's GoogleSQL queries name their +// parameters; a sqlc.arg becomes one, and each ? in turn becomes one +// named after its position. A @@system_variable is not a parameter. +func bind(query string) (string, []placeholder) { + positional := 0 + sql := endtoend.Rewrite(query, func(name, _ string) string { + if name == "" { + positional++ + name = "p" + strconv.Itoa(positional) + } + return "@" + name + }) + var phs []placeholder + numbers := map[string]int{} + i := 0 + for i < len(sql) { + c := sql[i] + switch { + case c == '\'' || c == '"' || c == '`': + i = skipQuoted(sql, i) + case strings.HasPrefix(sql[i:], "--") || strings.HasPrefix(sql[i:], "#"): + end := strings.IndexByte(sql[i:], '\n') + if end < 0 { + i = len(sql) + } else { + i += end + } + case strings.HasPrefix(sql[i:], "/*"): + end := strings.Index(sql[i:], "*/") + if end < 0 { + i = len(sql) + } else { + i += end + 2 + } + case c == '@' && i+1 < len(sql) && sql[i+1] == '@': + i += 2 + for i < len(sql) && (isWordByte(sql[i])) { + i++ + } + case c == '@' && identRe.MatchString(sql[i:]): + m := identRe.FindStringSubmatch(sql[i:]) + if _, ok := numbers[m[1]]; !ok { + numbers[m[1]] = len(phs) + 1 + phs = append(phs, placeholder{Number: len(phs) + 1, Name: m[1]}) + } + i += len(m[0]) + default: + i++ + } + } + return sql, phs +} + +func isWordByte(c byte) bool { + return c == '_' || c >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' +} + +// skipQuoted returns the index just past the quoted token starting at i, +// honouring backslash escapes. +func skipQuoted(s string, i int) int { + q := s[i] + j := i + 1 + for j < len(s) { + switch { + case s[j] == '\\' && j+1 < len(s): + j += 2 + case s[j] == q: + return j + 1 + default: + j++ + } + } + return len(s) +} + +// splitStatements splits a script on the semicolons outside strings and +// comments, which is how a schema's DDL is handed to CREATE DATABASE and a +// fixture's DML to a transaction. +func splitStatements(src string) []string { + var stmts []string + flush := func(s string) { + if s = strings.TrimSpace(s); s != "" { + stmts = append(stmts, s) + } + } + start, i := 0, 0 + for i < len(src) { + c := src[i] + switch { + case c == '\'' || c == '"' || c == '`': + i = skipQuoted(src, i) + case strings.HasPrefix(src[i:], "--") || strings.HasPrefix(src[i:], "#"): + end := strings.IndexByte(src[i:], '\n') + if end < 0 { + i = len(src) + } else { + i += end + } + case strings.HasPrefix(src[i:], "/*"): + end := strings.Index(src[i:], "*/") + if end < 0 { + i = len(src) + } else { + i += end + 2 + } + case c == ';': + flush(src[start:i]) + start = i + 1 + i++ + default: + i++ + } + } + flush(src[start:]) + return stmts +} + +// column is what INFORMATION_SCHEMA says about a column of the case's +// database: its type as the schema declared it, and whether it can be +// NULL. +type column struct { + name string + typ *analysis.TypeExpr + nullable bool +} + +// analyzer holds the session a case is compiled in and the catalog of the +// case's database, keyed by table name in the database's own schema. +type analyzer struct { + s *server + session string + catalog map[string][]column + keys map[string][]string // the primary key columns of each table +} + +var dbNameRe = regexp.MustCompile(`[^a-z0-9_]+`) + +// Analyze creates a database of the case's own from its schema, writes its +// fixture there, compiles its queries and returns what Spanner reports in +// the JSON shape sqlc analyze prints. +func Analyze(ctx context.Context, endpoint string, c endtoend.Case) ([]byte, error) { + s, err := open(ctx, endpoint) + if err != nil { + return nil, err + } + defer s.Close() + + schema, err := os.ReadFile(c.Schema) + if err != nil { + return nil, err + } + var fixture []byte + if c.Fixture != "" { + if fixture, err = os.ReadFile(c.Fixture); err != nil { + return nil, err + } + } + queries, err := c.Queries() + if err != nil { + return nil, err + } + + // A database id is lower-case letters, digits and underscores, at + // most 30 characters: the case's name, cut to fit, and a hash of the + // whole of it, so that two cases with the same head stay apart. + hash := fmt.Sprintf("%08x", crc32.ChecksumIEEE([]byte(c.Name))) + name := "goldeneye_" + dbNameRe.ReplaceAllString(strings.ToLower(c.Name), "_") + if max := 30 - 1 - len(hash); len(name) > max { + name = name[:max] + } + name = strings.TrimRight(name, "_") + "_" + hash + db := Instance + "/databases/" + name + if err := s.dropDatabase(ctx, db); err != nil { + return nil, err + } + if _, err := s.createDatabase(ctx, name, splitStatements(string(schema))); err != nil { + return nil, fmt.Errorf("loading %s: %w", c.Schema, err) + } + defer s.dropDatabase(context.WithoutCancel(ctx), db) + session, err := s.session(ctx, db) + if err != nil { + return nil, err + } + if stmts := splitStatements(string(fixture)); len(stmts) > 0 { + if err := s.write(ctx, session, stmts); err != nil { + return nil, fmt.Errorf("loading %s: %w", c.Fixture, err) + } + } + + a := &analyzer{s: s, session: session} + if err := a.readCatalog(ctx); err != nil { + return nil, err + } + out := make([]analysis.Query, 0, len(queries)) + for _, q := range queries { + aq, err := a.analyzeQuery(ctx, q) + if err != nil { + return nil, fmt.Errorf("%s: %w", q.Name, err) + } + out = append(out, aq) + } + return analysis.Encode(out) +} + +// Check compares what Spanner reports for a case with the output the +// case committed, returning a diff when they differ. +func Check(ctx context.Context, endpoint string, c endtoend.Case) (string, error) { + got, err := Analyze(ctx, endpoint, c) + if err != nil { + return "", err + } + return c.Compare(got) +} + +// write runs DML statements in a read-write transaction and commits it. +func (s *server) write(ctx context.Context, session string, stmts []string) error { + tx, err := s.data.BeginTransaction(ctx, &spannerpb.BeginTransactionRequest{ + Session: session, + Options: &spannerpb.TransactionOptions{Mode: &spannerpb.TransactionOptions_ReadWrite_{ReadWrite: &spannerpb.TransactionOptions_ReadWrite{}}}, + }) + if err != nil { + return err + } + req := &spannerpb.ExecuteBatchDmlRequest{ + Session: session, + Transaction: &spannerpb.TransactionSelector{Selector: &spannerpb.TransactionSelector_Id{Id: tx.Id}}, + Seqno: 1, + } + for _, stmt := range stmts { + req.Statements = append(req.Statements, &spannerpb.ExecuteBatchDmlRequest_Statement{Sql: stmt}) + } + resp, err := s.data.ExecuteBatchDml(ctx, req) + if err == nil && resp.Status != nil && resp.Status.Code != 0 { + err = fmt.Errorf("%s", resp.Status.Message) + } + if err != nil { + s.data.Rollback(context.WithoutCancel(ctx), &spannerpb.RollbackRequest{Session: session, TransactionId: tx.Id}) + return err + } + _, err = s.data.Commit(ctx, &spannerpb.CommitRequest{ + Session: session, + Transaction: &spannerpb.CommitRequest_TransactionId{TransactionId: tx.Id}, + }) + return err +} + +const catalogQuery = ` +SELECT TABLE_NAME, COLUMN_NAME, SPANNER_TYPE, IS_NULLABLE +FROM INFORMATION_SCHEMA.COLUMNS +WHERE TABLE_SCHEMA = '' +ORDER BY TABLE_NAME, ORDINAL_POSITION` + +const keysQuery = ` +SELECT TABLE_NAME, COLUMN_NAME +FROM INFORMATION_SCHEMA.INDEX_COLUMNS +WHERE TABLE_SCHEMA = '' AND INDEX_TYPE = 'PRIMARY_KEY' +ORDER BY TABLE_NAME, ORDINAL_POSITION` + +// readCatalog reads the tables the schema created, and their keys. +func (a *analyzer) readCatalog(ctx context.Context) error { + rows, err := a.s.query(ctx, a.session, catalogQuery) + if err != nil { + return err + } + a.catalog = map[string][]column{} + for _, row := range rows { + table := row[0].GetStringValue() + a.catalog[table] = append(a.catalog[table], column{ + name: row[1].GetStringValue(), + typ: parseType(row[2].GetStringValue()), + nullable: row[3].GetStringValue() == "YES", + }) + } + rows, err = a.s.query(ctx, a.session, keysQuery) + if err != nil { + return err + } + a.keys = map[string][]string{} + for _, row := range rows { + table := row[0].GetStringValue() + a.keys[table] = append(a.keys[table], row[1].GetStringValue()) + } + return nil +} + +// tableName returns the catalog's spelling of a table's name, which +// Spanner matches in any case. +func (a *analyzer) tableName(table string) string { + for t := range a.catalog { + if strings.EqualFold(t, table) { + return t + } + } + return table +} + +// lookup finds a column of a table of the case's database. Spanner +// matches table and column names in any case. +func (a *analyzer) lookup(table, name string) (column, bool) { + for t, cols := range a.catalog { + if !strings.EqualFold(t, table) { + continue + } + for _, col := range cols { + if strings.EqualFold(col.name, name) { + return col, true + } + } + } + return column{}, false +} + +// parseType reads a type spelled the way SPANNER_TYPE and a declaration +// spell it — STRING(10), ARRAY, STRUCT — +// into an expression, in lower case, with MAX an identifier. +func parseType(s string) *analysis.TypeExpr { + s = strings.TrimSpace(s) + lower := strings.ToLower(s) + if element, ok := strings.CutPrefix(lower, "array<"); ok && strings.HasSuffix(element, ">") { + return &analysis.TypeExpr{Name: "array", Args: []analysis.TypeArg{{Type: parseType(s[6 : len(s)-1])}}} + } + for _, kind := range []string{"proto", "enum"} { + if message, ok := strings.CutPrefix(lower, kind+"<"); ok && strings.HasSuffix(message, ">") { + m := s[len(kind)+1 : len(s)-1] + return &analysis.TypeExpr{Name: kind, Args: []analysis.TypeArg{{String: &m}}} + } + } + if fields, ok := strings.CutPrefix(lower, "struct<"); ok && strings.HasSuffix(fields, ">") { + t := &analysis.TypeExpr{Name: "struct"} + for _, f := range splitTop(s[7:len(s)-1], ',') { + f = strings.TrimSpace(f) + label, typ := "", f + if i := strings.IndexAny(f, " \t"); i > 0 && !strings.ContainsAny(f[:i], "<(") { + label, typ = f[:i], strings.TrimSpace(f[i+1:]) + } + t.Args = append(t.Args, analysis.TypeArg{Label: label, Type: parseType(typ)}) + } + return t + } + name, args := lower, "" + if open := strings.IndexByte(lower, '('); open >= 0 && strings.HasSuffix(lower, ")") { + name, args = strings.TrimSpace(lower[:open]), lower[open+1:len(lower)-1] + } + t := &analysis.TypeExpr{Name: name} + if args == "" { + return t + } + for _, arg := range strings.Split(args, ",") { + arg = strings.TrimSpace(arg) + if n, err := strconv.ParseInt(arg, 10, 64); err == nil { + t.Args = append(t.Args, analysis.TypeArg{Int: &n}) + } else { + ident := arg + t.Args = append(t.Args, analysis.TypeArg{Ident: &ident}) + } + } + return t +} + +// splitTop splits on a separator outside angle brackets and parentheses. +func splitTop(s string, sep byte) []string { + var out []string + depth, start := 0, 0 + for i := 0; i < len(s); i++ { + switch s[i] { + case '<', '(': + depth++ + case '>', ')': + depth-- + case sep: + if depth == 0 { + out = append(out, s[start:i]) + start = i + 1 + } + } + } + return append(out, s[start:]) +} + +// typeOf reads a type the way the wire spells it, which names the family +// and, for an array or a struct, what it holds, and nothing of a length. +func typeOf(t *spannerpb.Type) *analysis.TypeExpr { + if t == nil { + return nil + } + switch t.Code { + case spannerpb.TypeCode_ARRAY: + return &analysis.TypeExpr{Name: "array", Args: []analysis.TypeArg{{Type: typeOf(t.ArrayElementType)}}} + case spannerpb.TypeCode_STRUCT: + out := &analysis.TypeExpr{Name: "struct"} + if t.StructType != nil { + for _, f := range t.StructType.Fields { + out.Args = append(out.Args, analysis.TypeArg{Label: f.Name, Type: typeOf(f.Type)}) + } + } + return out + case spannerpb.TypeCode_PROTO, spannerpb.TypeCode_ENUM: + // A proto or enum is named by its message, the way a declaration + // spells PROTO. + fqn := t.ProtoTypeFqn + return &analysis.TypeExpr{Name: strings.ToLower(t.Code.String()), Args: []analysis.TypeArg{{String: &fqn}}} + } + return &analysis.TypeExpr{Name: strings.ToLower(t.Code.String())} +} + +// withNullable copies a type with its nullability set. +func withNullable(t *analysis.TypeExpr, nullable bool) *analysis.TypeExpr { + if t == nil { + return nil + } + out := *t + out.Nullable = nullable + return &out +} + +// isDML reports whether a statement writes, and so has to be compiled in a +// read-write transaction, which is begun for it and never committed. The +// statement's first word decides, past any comment it opens with. +func isDML(sql string) bool { + i := 0 + for i < len(sql) { + switch { + case sql[i] == ' ' || sql[i] == '\t' || sql[i] == '\n' || sql[i] == '\r': + i++ + case strings.HasPrefix(sql[i:], "--") || strings.HasPrefix(sql[i:], "#"): + end := strings.IndexByte(sql[i:], '\n') + if end < 0 { + return false + } + i += end + case strings.HasPrefix(sql[i:], "/*"): + end := strings.Index(sql[i:], "*/") + if end < 0 { + return false + } + i += end + 2 + default: + head := strings.ToLower(sql[i:]) + for _, kw := range []string{"insert", "update", "delete"} { + if strings.HasPrefix(head, kw) { + return true + } + } + return false + } + } + return false +} + +// compile compiles a statement in PLAN mode and returns what the server +// reports about it. +func (a *analyzer) compile(ctx context.Context, sql string) (*spannerpb.ResultSet, error) { + req := &spannerpb.ExecuteSqlRequest{ + Session: a.session, + Sql: sql, + QueryMode: spannerpb.ExecuteSqlRequest_PLAN, + } + if isDML(sql) { + req.Transaction = &spannerpb.TransactionSelector{Selector: &spannerpb.TransactionSelector_Begin{ + Begin: &spannerpb.TransactionOptions{Mode: &spannerpb.TransactionOptions_ReadWrite_{ReadWrite: &spannerpb.TransactionOptions_ReadWrite{}}}, + }} + req.Seqno = 1 + } + rs, err := a.s.data.ExecuteSql(ctx, req) + if err != nil { + return nil, err + } + if rs.Metadata != nil && rs.Metadata.Transaction != nil && len(rs.Metadata.Transaction.Id) > 0 { + a.s.data.Rollback(context.WithoutCancel(ctx), &spannerpb.RollbackRequest{Session: a.session, TransactionId: rs.Metadata.Transaction.Id}) + } + return rs, nil +} + +// analyzeQuery compiles one query. +func (a *analyzer) analyzeQuery(ctx context.Context, q endtoend.Query) (analysis.Query, error) { + sql, phs := bind(q.SQL) + aq := analysis.Query{ + Name: q.Name, + Cmd: q.Cmd, + Columns: []analysis.Column{}, + Params: []analysis.Param{}, + } + rs, err := a.compile(ctx, sql) + if err != nil { + return analysis.Query{}, err + } + p := newPlan(rs.Stats.GetQueryPlan()) + partners := p.partners() + describe := func(o origin) (analysis.Column, bool) { + if o.param != "" { + o = partners[o.param] + } + if o.table == "" { + return analysis.Column{}, false + } + col, ok := a.lookup(o.table, o.column) + if !ok { + return analysis.Column{}, false + } + return analysis.Column{Name: col.name, Type: withNullable(col.typ, col.nullable), Table: a.tableName(o.table)}, true + } + + var fields []*spannerpb.StructType_Field + if rs.Metadata != nil && rs.Metadata.RowType != nil { + fields = rs.Metadata.RowType.Fields + } + outputs := p.outputs() + table, operation := p.mutation() + if table != "" { + // A DML plan lists the columns it returns, then the values it + // writes: each of those is a parameter standing for the column + // it is written to. + written := a.written(sql, table, operation) + writes := outputs[min(len(fields), len(outputs)):] + for i, w := range written { + if i >= len(writes) { + break + } + if o := p.resolve(writes[i], map[int32]bool{}); o.param != "" { + if _, ok := partners[o.param]; !ok { + partners[o.param] = origin{table: table, column: w} + } + } + } + outputs = outputs[:min(len(fields), len(outputs))] + } + for i, f := range fields { + ac := analysis.Column{Name: f.Name, Type: typeOf(f.Type)} + var out *spannerpb.PlanNode + if i < len(outputs) { + out = outputs[i] + } + if col, ok := describe(p.resolve(out, map[int32]bool{})); ok { + ac.Type, ac.Table = col.Type, col.Table + } else if table != "" && (out == nil || out.DisplayName != "Function") { + // A THEN RETURN column the plan reads as a constant, such + // as the default a column not inserted takes, is the table's + // column of that name. + if col, ok := a.lookup(table, f.Name); ok { + ac.Type = withNullable(col.typ, col.nullable) + ac.Table = a.tableName(table) + } + } + aq.Columns = append(aq.Columns, ac) + } + + declared := map[string]*spannerpb.Type{} + if rs.Metadata != nil && rs.Metadata.UndeclaredParameters != nil { + for _, f := range rs.Metadata.UndeclaredParameters.Fields { + declared[f.Name] = f.Type + } + } + for _, ph := range phs { + ac, ok := describe(origin{param: ph.Name}) + if !ok { + ac = analysis.Column{Type: typeOf(declared[ph.Name])} + } + aq.Params = append(aq.Params, analysis.Param{Number: ph.Number, Column: ac}) + } + return aq, nil +} + +var ( + insertRe = regexp.MustCompile("(?is)^insert\\s+(?:or\\s+\\w+\\s+)?into\\s+[\\w.`]+\\s*(?:\\(([^)]*)\\))?") + setRe = regexp.MustCompile("(?is)^update\\s+[\\w.`]+(?:\\s+(?:as\\s+)?\\w+)?\\s+set\\s+") +) + +// written lists the columns a DML statement writes, in the order the plan +// lists their values: for an INSERT the columns it inserts, which are the +// statement's column list or every column of the table, and for an +// UPDATE or DELETE the table's key columns, then the columns an UPDATE +// sets. +func (a *analyzer) written(sql, table, operation string) []string { + switch operation { + case "INSERT": + m := insertRe.FindStringSubmatch(sql) + if m == nil { + return nil + } + if strings.TrimSpace(m[1]) == "" { + var cols []string + for _, col := range a.catalog[a.tableName(table)] { + cols = append(cols, col.name) + } + return cols + } + var cols []string + for _, c := range strings.Split(m[1], ",") { + cols = append(cols, strings.Trim(strings.TrimSpace(c), "`")) + } + return cols + case "UPDATE": + cols := append([]string(nil), a.keys[a.tableName(table)]...) + if m := setRe.FindStringIndex(sql); m != nil { + for _, assignment := range setList(sql[m[1]:]) { + target, _, _ := strings.Cut(assignment, "=") + target = strings.TrimSpace(target) + if i := strings.LastIndexByte(target, '.'); i >= 0 { + target = target[i+1:] + } + cols = append(cols, strings.Trim(target, "`")) + } + } + return cols + case "DELETE": + return a.keys[a.tableName(table)] + } + return nil +} + +// setList splits an UPDATE's SET list into its assignments: the text up +// to the WHERE outside strings and parentheses, split on the commas +// outside them. +func setList(s string) []string { + var out []string + depth, start := 0, 0 + for i := 0; i < len(s); i++ { + c := s[i] + switch { + case c == '\'' || c == '"' || c == '`': + i = skipQuoted(s, i) - 1 + case c == '(': + depth++ + case c == ')': + depth-- + case c == ',' && depth == 0: + out = append(out, s[start:i]) + start = i + 1 + case depth == 0 && (i == 0 || !isWordByte(s[i-1])) && len(s)-i >= 5 && strings.EqualFold(s[i:i+5], "where") && (len(s) == i+5 || !isWordByte(s[i+5])): + return append(out, s[start:i]) + } + } + return append(out, s[start:]) +} diff --git a/internal/goldeneye/spanner/plan.go b/internal/goldeneye/spanner/plan.go new file mode 100644 index 0000000..c0d91d0 --- /dev/null +++ b/internal/goldeneye/spanner/plan.go @@ -0,0 +1,220 @@ +package spanner + +import ( + "regexp" + "strings" + + "cloud.google.com/go/spanner/apiv1/spannerpb" +) + +// The query plan is the one thing that says where a result column comes +// from and what a parameter stands for. It is a list of nodes: relational +// ones, such as a Scan of a table or the Serialize Result that produces the +// rows, and scalar ones, such as a Reference to a column or a variable, a +// Parameter, a Function. A relational node defines variables through its +// child links: a Scan of a table defines one per column it reads, named +// after the column, and any node may define one as another scalar, which +// a Reference names with a $. The children of Serialize Result after the +// relation it serializes are the result columns, in order; a DML plan +// lists its THEN RETURN columns first and the values it writes after +// them: for an INSERT the columns it inserts, in the statement's order, +// and for an UPDATE or DELETE the key columns of the table, then the +// columns an UPDATE sets. A comparison is a Function whose description +// reads ($col = @param). + +// origin is what a scalar of the plan resolves to: a table column, a +// parameter, or nothing. +type origin struct { + table, column string + param string +} + +// plan is a parsed query plan. +type plan struct { + nodes []*spannerpb.PlanNode + // vars maps a variable to the node that defines it and the scalar it + // is defined as. + vars map[string]definition +} + +type definition struct { + owner *spannerpb.PlanNode + child *spannerpb.PlanNode +} + +func newPlan(qp *spannerpb.QueryPlan) *plan { + p := &plan{vars: map[string]definition{}} + if qp == nil { + return p + } + p.nodes = qp.PlanNodes + for _, n := range p.nodes { + for _, l := range n.ChildLinks { + if l.Variable != "" { + p.vars[l.Variable] = definition{owner: n, child: p.node(l.ChildIndex)} + } + } + } + return p +} + +func (p *plan) node(index int32) *spannerpb.PlanNode { + for _, n := range p.nodes { + if n.Index == index { + return n + } + } + return nil +} + +func (p *plan) root() *spannerpb.PlanNode { + return p.node(0) +} + +func meta(n *spannerpb.PlanNode, key string) string { + if n == nil || n.Metadata == nil { + return "" + } + if v, ok := n.Metadata.Fields[key]; ok { + return v.GetStringValue() + } + return "" +} + +func description(n *spannerpb.PlanNode) string { + if n == nil || n.ShortRepresentation == nil { + return "" + } + return n.ShortRepresentation.Description +} + +// serializeResult finds the node that produces the rows, the first +// Serialize Result reached from the root. +func (p *plan) serializeResult() *spannerpb.PlanNode { + var found *spannerpb.PlanNode + seen := map[int32]bool{} + var walk func(n *spannerpb.PlanNode) + walk = func(n *spannerpb.PlanNode) { + if n == nil || found != nil || seen[n.Index] { + return + } + seen[n.Index] = true + if n.DisplayName == "Serialize Result" { + found = n + return + } + for _, l := range n.ChildLinks { + walk(p.node(l.ChildIndex)) + } + } + walk(p.root()) + return found +} + +// outputs lists the scalars Serialize Result produces, in order: every +// child after the relation it serializes. +func (p *plan) outputs() []*spannerpb.PlanNode { + sr := p.serializeResult() + if sr == nil { + return nil + } + var out []*spannerpb.PlanNode + for _, l := range sr.ChildLinks { + if c := p.node(l.ChildIndex); c != nil && c.Kind == spannerpb.PlanNode_SCALAR { + out = append(out, c) + } + } + return out +} + +// mutation names the table a DML plan writes, or "" for a query. +func (p *plan) mutation() (table, operation string) { + for _, n := range p.nodes { + if n.DisplayName == "Apply Mutations" { + return meta(n, "table"), meta(n, "operation_type") + } + } + return "", "" +} + +// resolve follows a scalar to what it stands for. +func (p *plan) resolve(n *spannerpb.PlanNode, seen map[int32]bool) origin { + if n == nil || seen[n.Index] { + return origin{} + } + seen[n.Index] = true + switch n.DisplayName { + case "Parameter": + return origin{param: meta(n, "name")} + case "Reference": + desc := description(n) + if name, ok := strings.CutPrefix(desc, "$"); ok { + return p.resolveVar(name, seen) + } + // A bare name is a column of the scan it is read by, or an input + // of a union, which names it in the link's type. + for _, m := range p.nodes { + for _, l := range m.ChildLinks { + if l.ChildIndex != n.Index { + continue + } + switch { + case m.DisplayName == "Scan" && meta(m, "scan_type") == "TableScan": + return origin{table: meta(m, "scan_target"), column: desc} + case m.DisplayName == "Scan": + // A batch scan reads the batch variable of that name. + target := strings.TrimPrefix(meta(m, "scan_target"), "$") + return p.resolveVar(target+".Batch."+desc, seen) + } + } + } + for _, m := range p.nodes { + if m.DisplayName != "Union Input" { + continue + } + for _, l := range m.ChildLinks { + if l.Type == desc { + return p.resolve(p.node(l.ChildIndex), seen) + } + } + } + } + return origin{} +} + +// resolveVar follows a variable to what it is defined as. +func (p *plan) resolveVar(name string, seen map[int32]bool) origin { + d, ok := p.vars[name] + if !ok { + return origin{} + } + return p.resolve(d.child, seen) +} + +var compareRe = regexp.MustCompile(`^\((.+) (=|!=|<>|<|<=|>|>=) (.+)\)$`) + +// partners finds the table column each parameter is compared with, keyed +// by parameter name: the other operand of a comparison Function the +// parameter is an operand of. The first found wins. +func (p *plan) partners() map[string]origin { + out := map[string]origin{} + for _, n := range p.nodes { + if n.DisplayName != "Function" || len(n.ChildLinks) != 2 || !compareRe.MatchString(description(n)) { + continue + } + sides := []*spannerpb.PlanNode{p.node(n.ChildLinks[0].ChildIndex), p.node(n.ChildLinks[1].ChildIndex)} + for i, side := range sides { + o := p.resolve(side, map[int32]bool{}) + if o.param == "" { + continue + } + other := p.resolve(sides[1-i], map[int32]bool{}) + if other.table != "" { + if _, ok := out[o.param]; !ok { + out[o.param] = other + } + } + } + } + return out +} diff --git a/internal/goldeneye/spanner/relations.go b/internal/goldeneye/spanner/relations.go new file mode 100644 index 0000000..4899e8b --- /dev/null +++ b/internal/goldeneye/spanner/relations.go @@ -0,0 +1,96 @@ +package spanner + +import ( + "context" + "fmt" + "strings" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/dialect" +) + +// relationQuery lists the relations of every schema but the database's +// own, unnamed one — INFORMATION_SCHEMA and SPANNER_SYS — with their +// columns in declared order, so that the output is stable. A column's +// type is spelled the way SPANNER_TYPE spells a declaration: STRING(MAX), +// ARRAY. +const relationQuery = ` +SELECT t.TABLE_SCHEMA, t.TABLE_NAME, t.TABLE_TYPE, + c.COLUMN_NAME, c.SPANNER_TYPE, c.IS_NULLABLE +FROM INFORMATION_SCHEMA.TABLES AS t +JOIN INFORMATION_SCHEMA.COLUMNS AS c + ON c.TABLE_SCHEMA = t.TABLE_SCHEMA AND c.TABLE_NAME = t.TABLE_NAME +WHERE t.TABLE_SCHEMA != '' +ORDER BY t.TABLE_SCHEMA, t.TABLE_NAME, c.ORDINAL_POSITION` + +// readRelations reads the views of the system schemas. Their names are +// kept as the catalog spells them, in upper case, which is how a query +// names them; a column's type is spelled in lower case, the way the +// dialect's types.jsonl spells its types, with an ARRAY written as T +// with the array flag, since that is how a seed spells an array. +func readRelations(ctx context.Context, s *server, session string) ([]dialect.Relation, error) { + rows, err := s.query(ctx, session, relationQuery) + if err != nil { + return nil, err + } + var relations []dialect.Relation + var cur *dialect.Relation + for _, row := range rows { + if len(row) != 6 { + return nil, fmt.Errorf("expected 6 columns, got %d", len(row)) + } + schema, name, kind := row[0].GetStringValue(), row[1].GetStringValue(), row[2].GetStringValue() + if cur == nil || cur.Schema != schema || cur.Name != name { + rel := dialect.Relation{Schema: schema, Name: name} + if kind == "VIEW" { + rel.Kind = "v" + } + relations = append(relations, rel) + cur = &relations[len(relations)-1] + } + col := dialect.Column{ + Name: row[3].GetStringValue(), + NotNull: row[5].GetStringValue() == "NO", + } + col.Type, col.Array = typeName(row[4].GetStringValue()) + cur.Columns = append(cur.Columns, col) + } + return relations, nil +} + +// typeName spells a SPANNER_TYPE the way a seed spells a column's type: +// in lower case, with an ARRAY as its element and the array flag, a +// STRUCT as struct(a: t, b: u) and a PROTO or ENUM as +// proto('p.M') or enum('p.E'), since a seed spells a type's arguments in +// parentheses. +func typeName(spannerType string) (string, bool) { + t := strings.TrimSpace(spannerType) + if element, ok := strings.CutPrefix(t, "ARRAY<"); ok && strings.HasSuffix(element, ">") { + name, _ := typeName(strings.TrimSuffix(element, ">")) + return name, true + } + if fields, ok := strings.CutPrefix(t, "STRUCT<"); ok && strings.HasSuffix(fields, ">") { + var args []string + for _, f := range splitTop(strings.TrimSuffix(fields, ">"), ',') { + f = strings.TrimSpace(f) + label, typ := "", f + if i := strings.IndexAny(f, " \t"); i > 0 && !strings.ContainsAny(f[:i], "<(") { + label, typ = f[:i], strings.TrimSpace(f[i+1:]) + } + name, array := typeName(typ) + if array { + name += "[]" + } + if label != "" { + name = label + ": " + name + } + args = append(args, name) + } + return "struct(" + strings.Join(args, ", ") + ")", false + } + for _, kind := range []string{"PROTO<", "ENUM<"} { + if message, ok := strings.CutPrefix(t, kind); ok && strings.HasSuffix(message, ">") { + return strings.ToLower(strings.TrimSuffix(kind, "<")) + "('" + strings.TrimSuffix(message, ">") + "')", false + } + } + return strings.ToLower(t), false +} diff --git a/internal/goldeneye/spanner/spanner.go b/internal/goldeneye/spanner/spanner.go new file mode 100644 index 0000000..90d82a1 --- /dev/null +++ b/internal/goldeneye/spanner/spanner.go @@ -0,0 +1,224 @@ +// Package spanner generates the GoogleSQL dialect seed under +// internal/engine/googlesql/dialect from a live Spanner server, and +// verifies the GoogleSQL analyze cases under internal/endtoend/testdata +// against the same server. The server is Spanner Omni, the downloadable +// Spanner, run from its container image; the package writes into the +// googlesql directory, since sqlc's engine is named after the language +// Spanner speaks rather than the database. +// +// Spanner keeps no catalog of its types, functions or operators, so +// types.jsonl, functions.jsonl and operators.jsonl are written by hand and +// are not this package's business. What it does describe is its +// information schema: relations.jsonl is every view of INFORMATION_SCHEMA +// and SPANNER_SYS, read from INFORMATION_SCHEMA itself. +// +// The package also verifies the GoogleSQL analyze cases against the same +// server: each case's schema becomes a database of its own, its fixture is +// written there, and each query is compiled in PLAN mode, which runs +// nothing and reports the type of each result column and of each +// parameter the query leaves undeclared, and the query plan, which says +// which table column each result column and parameter stands for. The +// answer is printed in the JSON shape sqlc analyze prints and compared +// with the case's committed stdout.json byte for byte. +// +// The server is named by SPANNER_SERVER_URI, the gRPC endpoint of a +// Spanner Omni server such as localhost:15000, which is reached without +// TLS or credentials, as Omni is. Databases are created in the instance +// Omni's single server provides, projects/default/instances/default. +package spanner + +import ( + "context" + "errors" + "fmt" + "os" + "strings" + + database "cloud.google.com/go/spanner/admin/database/apiv1" + "cloud.google.com/go/spanner/admin/database/apiv1/databasepb" + instance "cloud.google.com/go/spanner/admin/instance/apiv1" + "cloud.google.com/go/spanner/admin/instance/apiv1/instancepb" + spannerapi "cloud.google.com/go/spanner/apiv1" + "cloud.google.com/go/spanner/apiv1/spannerpb" + "google.golang.org/api/option" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/structpb" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/dialect" +) + +// Engine is the name goldeneye knows the database by. +const Engine = "spanner" + +// Dir is the name of the engine directory the dialect lives under, and +// Cases the name of the analyze case directories under +// internal/endtoend/testdata: both are named after the language, GoogleSQL, +// which is how sqlc knows the dialect. +const ( + Dir = "googlesql" + Cases = "googlesql" +) + +// Instance is the instance a Spanner Omni single server provides, which +// every database is created in. +const Instance = "projects/default/instances/default" + +// Locate returns the server to generate from, named by SPANNER_SERVER_URI. +func Locate() (string, error) { + endpoint := os.Getenv("SPANNER_SERVER_URI") + if endpoint == "" { + return "", errors.New("SPANNER_SERVER_URI is not set") + } + if strings.Contains(endpoint, "://") { + return "", fmt.Errorf("SPANNER_SERVER_URI: %q should be a host:port, the gRPC endpoint of a Spanner Omni server", endpoint) + } + return endpoint, nil +} + +// server holds the clients a run talks to the server through. +type server struct { + endpoint string + instances *instance.InstanceAdminClient + databases *database.DatabaseAdminClient + data *spannerapi.Client +} + +// open connects to the server. Omni serves plaintext gRPC and asks for no +// credentials. +func open(ctx context.Context, endpoint string) (*server, error) { + opts := []option.ClientOption{ + option.WithEndpoint(endpoint), + option.WithoutAuthentication(), + option.WithGRPCDialOption(grpc.WithTransportCredentials(insecure.NewCredentials())), + } + s := &server{endpoint: endpoint} + var err error + if s.instances, err = instance.NewInstanceAdminClient(ctx, opts...); err != nil { + return nil, err + } + if s.databases, err = database.NewDatabaseAdminClient(ctx, opts...); err != nil { + s.Close() + return nil, err + } + if s.data, err = spannerapi.NewClient(ctx, opts...); err != nil { + s.Close() + return nil, err + } + return s, nil +} + +func (s *server) Close() { + if s.instances != nil { + s.instances.Close() + } + if s.databases != nil { + s.databases.Close() + } + if s.data != nil { + s.data.Close() + } +} + +// Version describes the server: Spanner Omni reports no release of its +// own through the API, so the instance the databases are created in is +// described instead. +func Version(ctx context.Context, endpoint string) (string, error) { + s, err := open(ctx, endpoint) + if err != nil { + return "", err + } + defer s.Close() + inst, err := s.instances.GetInstance(ctx, &instancepb.GetInstanceRequest{Name: Instance}) + if err != nil { + return "", fmt.Errorf("%s: %w", Instance, err) + } + return fmt.Sprintf("Spanner Omni at %s, instance %s (%s)", endpoint, inst.Name, inst.State), nil +} + +// createDatabase creates a database in the instance, running the DDL +// statements in it, and returns its full name. +func (s *server) createDatabase(ctx context.Context, name string, ddl []string) (string, error) { + op, err := s.databases.CreateDatabase(ctx, &databasepb.CreateDatabaseRequest{ + Parent: Instance, + CreateStatement: "CREATE DATABASE `" + name + "`", + ExtraStatements: ddl, + }) + if err != nil { + return "", err + } + db, err := op.Wait(ctx) + if err != nil { + return "", err + } + return db.Name, nil +} + +// dropDatabase drops a database by its full name. A database that does +// not exist is not an error, so that a run can clear the way for itself. +func (s *server) dropDatabase(ctx context.Context, db string) error { + err := s.databases.DropDatabase(ctx, &databasepb.DropDatabaseRequest{Database: db}) + if status.Code(err) == codes.NotFound && strings.Contains(err.Error(), "Database") { + return nil + } + return err +} + +// session opens a session on a database, multiplexed as Omni requires. +func (s *server) session(ctx context.Context, db string) (string, error) { + sess, err := s.data.CreateSession(ctx, &spannerpb.CreateSessionRequest{ + Database: db, + Session: &spannerpb.Session{Multiplexed: true}, + }) + if err != nil { + return "", err + } + return sess.Name, nil +} + +// query runs a statement and returns its rows as lists of values. +func (s *server) query(ctx context.Context, session, sql string) ([][]*structpb.Value, error) { + rs, err := s.data.ExecuteSql(ctx, &spannerpb.ExecuteSqlRequest{Session: session, Sql: sql}) + if err != nil { + return nil, err + } + var rows [][]*structpb.Value + for _, row := range rs.Rows { + rows = append(rows, row.Values) + } + return rows, nil +} + +// Generate reads the dialect from the server: relations.jsonl, the views of +// INFORMATION_SCHEMA and SPANNER_SYS, read from a database of their own, +// since every database has the same ones. +func Generate(ctx context.Context, endpoint string) (dialect.Files, error) { + s, err := open(ctx, endpoint) + if err != nil { + return nil, err + } + defer s.Close() + db := Instance + "/databases/goldeneye_dialect" + if err := s.dropDatabase(ctx, db); err != nil { + return nil, err + } + if _, err := s.createDatabase(ctx, "goldeneye_dialect", nil); err != nil { + return nil, err + } + defer s.dropDatabase(context.WithoutCancel(ctx), db) + session, err := s.session(ctx, db) + if err != nil { + return nil, err + } + relations, err := readRelations(ctx, s, session) + if err != nil { + return nil, err + } + blob, err := dialect.JSONL(relations) + if err != nil { + return nil, err + } + return dialect.Files{dialect.RelationsFile: blob}, nil +} diff --git a/internal/goldeneye/spanner/spanner_test.go b/internal/goldeneye/spanner/spanner_test.go new file mode 100644 index 0000000..3b5bf48 --- /dev/null +++ b/internal/goldeneye/spanner/spanner_test.go @@ -0,0 +1,66 @@ +package spanner + +import ( + "context" + "testing" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/dialect" + "github.com/sqlc-dev/sqlc/internal/goldeneye/endtoend" +) + +// TestDialect verifies the committed GoogleSQL dialect against what a +// Spanner server reports. It skips unless SPANNER_SERVER_URI names one. +func TestDialect(t *testing.T) { + endpoint, err := Locate() + if err != nil { + t.Skip(err) + } + ctx := context.Background() + version, err := Version(ctx, endpoint) + if err != nil { + t.Fatal(err) + } + files, err := Generate(ctx, endpoint) + if err != nil { + t.Fatal(err) + } + dir, err := dialect.Dir(Dir) + if err != nil { + t.Fatal(err) + } + report, err := dialect.Check(dir, files) + if err != nil { + t.Fatal(err) + } + if report != "" { + t.Errorf("%s does not match what %s reports:\n%s", dir, version, report) + } +} + +// TestAnalyzeCases verifies every GoogleSQL analyze case under +// internal/endtoend/testdata against what a Spanner server reports. It +// skips unless SPANNER_SERVER_URI names one. +func TestAnalyzeCases(t *testing.T) { + endpoint, err := Locate() + if err != nil { + t.Skip(err) + } + cases, err := endtoend.Cases(Cases) + if err != nil { + t.Fatal(err) + } + if len(cases) == 0 { + t.Fatal("no googlesql analyze cases found") + } + for _, c := range cases { + t.Run(c.Name, func(t *testing.T) { + diff, err := Check(context.Background(), endpoint, c) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Errorf("%s does not match what Spanner reports (-committed +spanner):\n%s", c.Output, diff) + } + }) + } +} diff --git a/internal/goldeneye/sqlite/analyze.go b/internal/goldeneye/sqlite/analyze.go new file mode 100644 index 0000000..b1a8003 --- /dev/null +++ b/internal/goldeneye/sqlite/analyze.go @@ -0,0 +1,269 @@ +package sqlite + +import ( + "context" + "errors" + "fmt" + "os" + "strings" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/analysis" + "github.com/sqlc-dev/sqlc/internal/goldeneye/endtoend" +) + +// The analyze cases are checked against the analysis shell, which is asked +// three things about each query. What the library reports about the +// prepared statement, through `.stats stmt`: each result column's name and, +// for one read straight from a table, its declared type and which table +// column it is, with the column's NOT NULL looked up in the catalog. What +// the query returns, over the case's fixture and again over no rows, for +// the columns the library has no answer for: an expression's type is the +// storage class of its value, since SQLite types values rather than +// expressions, and any column is nullable when a NULL comes back — an +// aggregate over no rows, the far side of an outer join. And the bytecode +// the statement compiles to, which is where the parameters are found, +// since the library reports nothing about them but their number. + +// placeholder is one parameter of a query as sqlc numbers them: each ? in +// turn, and each sqlc.arg name once, at its first appearance. SQLite +// numbers ?NNN the same way, so the query is rewritten with those. +type placeholder struct { + Number int + Name string +} + +func bind(sql string) (string, []placeholder) { + var phs []placeholder + numbers := map[string]int{} + out := endtoend.Rewrite(sql, func(name, _ string) string { + n, ok := numbers[name] + if name == "" || !ok { + n = len(phs) + 1 + phs = append(phs, placeholder{Number: n, Name: name}) + if name != "" { + numbers[name] = n + } + } + return fmt.Sprintf("?%d", n) + }) + return out, phs +} + +// Analyze runs a case's queries through the analysis shell and returns what +// SQLite reports in the JSON shape sqlc analyze prints. +func Analyze(ctx context.Context, dir string, c endtoend.Case) ([]byte, error) { + if err := checkOptions(ctx, dir, analysisShell); err != nil { + return nil, err + } + binary := analysisShell.binary(dir) + schema, err := os.ReadFile(c.Schema) + if err != nil { + return nil, err + } + var fixture []byte + if c.Fixture != "" { + if fixture, err = os.ReadFile(c.Fixture); err != nil { + return nil, err + } + } + queries, err := c.Queries() + if err != nil { + return nil, err + } + out := make([]analysis.Query, 0, len(queries)) + for _, q := range queries { + aq, err := analyzeQuery(ctx, binary, string(schema), string(fixture), q) + if err != nil { + return nil, fmt.Errorf("%s: %w", q.Name, err) + } + out = append(out, aq) + } + return analysis.Encode(out) +} + +// Check compares what SQLite reports for a case with the output the case +// committed, returning a diff when they differ. +func Check(ctx context.Context, dir string, c endtoend.Case) (string, error) { + got, err := Analyze(ctx, dir, c) + if err != nil { + return "", err + } + return c.Compare(got) +} + +func analyzeQuery(ctx context.Context, binary, schema, fixture string, q endtoend.Query) (analysis.Query, error) { + sql, phs := bind(q.SQL) + + // What the library says: the catalog, the bytecode, and the statement + // prepared, with nothing bound to its parameters. + s := newScript() + s.sql(schema) + s.sql(fixture) + s.add(".mode json") + s.add(".explain off") + for _, cq := range catalogQueries { + s.section(cq.section) + s.sql(cq.sql) + } + s.section("explain") + s.sql("EXPLAIN " + sql) + s.section("query") + s.add(".stats stmt") + line := s.sql(sql) + s.section("end") + out, err := run(ctx, binary, s) + if err != nil { + return analysis.Query{}, err + } + if errs := out.errorsBefore(line); len(errs) > 0 { + return analysis.Query{}, errors.New(strings.Join(errs, "\n")) + } + query := out.sections["query"] + if query == nil || !query.prepared { + msg := strings.TrimSpace(out.stderr) + if msg == "" { + msg = "the statement was not prepared" + } + return analysis.Query{}, errors.New(msg) + } + cat, err := readCatalog(out) + if err != nil { + return analysis.Query{}, err + } + var prog []instr + if explain := out.sections["explain"]; explain != nil && len(explain.blocks) > 0 { + if err := explain.decode(0, &prog); err != nil { + return analysis.Query{}, fmt.Errorf("reading the bytecode: %w", err) + } + } + var names []string + for _, m := range query.columns { + names = append(names, m.Name) + } + t := newTracer(cat, names) + t.run(prog) + params := make([]analysis.Column, len(phs)) + for i, ph := range phs { + params[i] = t.param(ph.Number) + } + + // What the statement returns: over the fixture, with each parameter + // bound to a value of the column it stands in for, so that the rows + // come through the WHERE clause, and over no rows. + s = newScript() + s.sql(schema) + s.sql(fixture) + s.add(".parameter init") + for i, ph := range phs { + if v := sample(params[i]); v != "" { + s.sql(fmt.Sprintf("REPLACE INTO temp.sqlite_parameters(key, value) VALUES ('?%d', %s)", ph.Number, v)) + } + } + s.add(".mode quote") + s.section("query") + s.sql(sql) + s.section("end") + bound, err := run(ctx, binary, s) + if err != nil { + return analysis.Query{}, err + } + s = newScript() + s.sql(schema) + s.add(".mode quote") + s.section("query") + s.sql(sql) + s.section("end") + empty, err := run(ctx, binary, s) + if err != nil { + return analysis.Query{}, err + } + var rows []string + for _, o := range []*output{bound, empty} { + if q := o.sections["query"]; q != nil { + rows = append(rows, q.rows...) + } + } + + aq := analysis.Query{ + Name: q.Name, + Cmd: q.Cmd, + Columns: []analysis.Column{}, + Params: []analysis.Param{}, + } + for i, m := range query.columns { + aq.Columns = append(aq.Columns, describeColumn(cat, m, classes(rows, i))) + } + for i, ph := range phs { + ac := params[i] + if ph.Name != "" { + ac.Name = ph.Name + } + aq.Params = append(aq.Params, analysis.Param{Number: ph.Number, Column: ac}) + } + return aq, nil +} + +// sample is an expression for a value to bind to a parameter: one of its +// column's values in the fixture, or a value of its type when all that is +// known is the type. Empty when nothing is known. +func sample(ac analysis.Column) string { + if ac.Table != "" && ac.Name != "" { + col, tbl := quoteIdent(ac.Name), quoteIdent(ac.Table) + return fmt.Sprintf("(SELECT %s FROM %s WHERE %s IS NOT NULL LIMIT 1)", col, tbl, col) + } + if ac.Type == nil { + return "" + } + switch ac.Type.Name { + case "integer", "numeric": + return "1" + case "real": + return "1.0" + case "text": + return "'a'" + case "blob": + return "x'00'" + } + return "" +} + +func quoteIdent(s string) string { + return `"` + strings.ReplaceAll(s, `"`, `""`) + `"` +} + +// classes lists the storage classes of a column's values across rows. +func classes(rows []string, i int) []string { + var out []string + for _, row := range rows { + if c := cells(row); i < len(c) { + out = append(out, storageClass(c[i])) + } + } + return out +} + +// describeColumn describes a result column: as the table column it is read +// from when it is one, otherwise by the storage class of its values, and +// nullable when any of its values was NULL. +func describeColumn(cat *catalog, m columnMeta, classes []string) analysis.Column { + ac := analysis.Column{Name: m.Name} + if col := cat.lookup(m.Table, m.Origin); col != nil { + d := col.describe() + ac.Type, ac.Table = d.Type, d.Table + } else { + for _, class := range classes { + if class != "null" { + ac.Type = &analysis.TypeExpr{Name: class} + break + } + } + } + if ac.Type != nil { + for _, class := range classes { + if class == "null" { + ac.Type.Nullable = true + } + } + } + return ac +} diff --git a/internal/goldeneye/sqlite/bytecode.go b/internal/goldeneye/sqlite/bytecode.go new file mode 100644 index 0000000..2a0e0dd --- /dev/null +++ b/internal/goldeneye/sqlite/bytecode.go @@ -0,0 +1,456 @@ +package sqlite + +import ( + "strconv" + "strings" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/analysis" +) + +// SQLite has nothing to say about a parameter's type: a bound value is +// whatever it is, and the column a parameter stands in for appears nowhere +// in what the library reports about a prepared statement. What it does +// report is the program it compiled the statement into. EXPLAIN prints the +// bytecode, in which a parameter is a Variable loading a register, and the +// column it stands in for is the other operand of the comparison the +// register reaches, the row the seek it drives lands on, or the position +// in the record that Insert writes. So each parameter is followed from the +// register it loads, through copies and through the expressions it is an +// argument of, to the first opcode that uses it against something the +// catalog can name, the way the ClickHouse check follows a placeholder +// through the query tree to the column it is compared with. +// +// Registers hold what the last opcode to write them wrote, and remember +// which parameters have been loaded into them, which a later constant does +// not clear: coalesce(?, 'x') overwrites the parameter's register with the +// fallback on the branch where the parameter is NULL, and the comparison +// that follows is still the parameter's. A parameter with no such use is +// described by what the program does to it before using it, when it does +// anything: MustBeInt says it has to be an integer, as LIMIT's does, and +// Affinity says which affinity it is coerced to. + +// instr is one line of EXPLAIN output. +type instr struct { + Addr int `json:"addr"` + Opcode string `json:"opcode"` + P1 int `json:"p1"` + P2 int `json:"p2"` + P3 int `json:"p3"` + P4 *string `json:"p4"` + P5 int `json:"p5"` +} + +func (in instr) p4() string { + if in.P4 == nil { + return "" + } + return *in.P4 +} + +type valueKind int + +const ( + vNone valueKind = iota + vParam // a Variable + vColumn // Column: a stored column of a cursor + vRowid // Rowid, IdxRowid: the rowid of a cursor + vConstant // a literal, with its storage class + vFunction // the result of a function call, with its name + vExpr // the result of an operator + vRecord // MakeRecord: the registers packed into a record +) + +// value is what a register holds. +type value struct { + kind valueKind + cursor int + index int + class string // vConstant + fn string // vFunction + regs []int // vRecord +} + +type register struct { + desc value + params []int // every parameter loaded into the register +} + +// tracer follows the parameters of one statement through its bytecode. +type tracer struct { + cat *catalog + names []string // the statement's result columns + // cursors is what each open cursor is on; ephemeral holds, for the + // cursors on ephemeral tables and sorters, the parameters stored in + // each column, so that a parameter put into an IN list's table comes + // back out with the Column that reads it. + cursors map[int]object + ephemeral map[int]map[int][]int + regs map[int]*register + // found is the column each parameter was found to stand in for, and + // hint what the program said about a parameter's type. + found map[int]analysis.Column + hint map[int]string +} + +func newTracer(cat *catalog, names []string) *tracer { + return &tracer{ + cat: cat, + names: names, + cursors: map[int]object{}, + ephemeral: map[int]map[int][]int{}, + regs: map[int]*register{}, + found: map[int]analysis.Column{}, + hint: map[int]string{}, + } +} + +// run walks the program in the order it runs: the prologue Init jumps to, +// where the Variables of a query are loaded, and then the body. +func (t *tracer) run(prog []instr) { + order := prog + if len(prog) > 0 && prog[0].Opcode == "Init" && prog[0].P2 > 0 && prog[0].P2 < len(prog) { + order = append(append([]instr{}, prog[prog[0].P2:]...), prog[1:prog[0].P2]...) + } + for _, in := range order { + t.step(in) + } +} + +// param describes what the parameter was found to stand in for. +func (t *tracer) param(number int) analysis.Column { + if ac, ok := t.found[number]; ok { + return ac + } + if typ := t.hint[number]; typ != "" { + return analysis.Column{Type: &analysis.TypeExpr{Name: typ}} + } + return analysis.Column{} +} + +func (t *tracer) reg(n int) *register { + r := t.regs[n] + if r == nil { + r = ®ister{} + t.regs[n] = r + } + return r +} + +func (t *tracer) params(n int) []int { + if r := t.regs[n]; r != nil { + return r.params + } + return nil +} + +// set records a write to a register. A Variable is the parameter and +// nothing else; a column read replaces whatever the register held, since +// the compiler reuses registers for the columns it reads; a constant keeps +// the parameters, for the coalesce case above; anything else carries the +// parameters it was computed from. +func (t *tracer) set(n int, v value, params []int) { + r := t.reg(n) + r.desc = v + switch v.kind { + case vConstant: + default: + r.params = params + } +} + +func (t *tracer) copy(from, to int) { + src := t.reg(from) + dst := t.reg(to) + dst.desc = src.desc + dst.params = append([]int{}, src.params...) +} + +// assoc records the column the parameters in a register stand in for, +// keeping the first found for each. +func (t *tracer) assoc(params []int, ac analysis.Column) { + for _, p := range params { + if _, ok := t.found[p]; !ok { + t.found[p] = ac + } + } +} + +// typeHint records what the program requires of a register's parameters. +func (t *tracer) typeHint(n int, typ string) { + if typ == "" { + return + } + for _, p := range t.params(n) { + if _, ok := t.hint[p]; !ok { + t.hint[p] = typ + } + } +} + +// describe turns what a register holds into the column a parameter +// compared with it stands in for, when it can be named: a stored column +// or rowid, a constant's storage class, or a function's name. +func (t *tracer) describe(v value) (analysis.Column, bool) { + switch v.kind { + case vColumn: + return t.stored(v.cursor, v.index) + case vRowid: + if owner := t.cursors[v.cursor].owner(); owner != nil { + return owner.rowid(), true + } + case vConstant: + if v.class != "null" && v.class != "" { + return analysis.Column{Type: &analysis.TypeExpr{Name: v.class}}, true + } + case vFunction: + return analysis.Column{Name: v.fn}, true + } + return analysis.Column{}, false +} + +// stored describes the ith stored column of a cursor. +func (t *tracer) stored(cursor, i int) (analysis.Column, bool) { + col, owner, ok := t.cursors[cursor].column(i) + switch { + case !ok: + return analysis.Column{}, false + case col != nil: + return col.describe(), true + default: + return owner.rowid(), true + } +} + +// rank orders what a parameter's fellow operands may be described by: a +// column first, then a function, then a constant. +func rank(v value) int { + switch v.kind { + case vColumn, vRowid: + return 0 + case vFunction: + return 1 + case vConstant: + if v.class != "null" && v.class != "" { + return 2 + } + } + return -1 +} + +// expression handles an opcode computing a result from operand registers: +// each parameter among the operands is described by the best other +// operand, and one with no other operand to be described by is carried +// into the result, for whatever the result is then compared with. +func (t *tracer) expression(args []int, dest int, result value) { + var carried []int + for _, a := range args { + params := t.params(a) + if len(params) == 0 { + continue + } + best := -1 + for _, b := range args { + if b == a { + continue + } + if r := rank(t.reg(b).desc); r >= 0 && (best < 0 || r < rank(t.reg(best).desc)) { + best = b + } + } + if best >= 0 { + if ac, ok := t.describe(t.reg(best).desc); ok { + t.assoc(params, ac) + continue + } + } + carried = append(carried, params...) + } + t.set(dest, result, carried) +} + +// compare handles a comparison of two registers: the parameters of each +// stand in for what the other holds. +func (t *tracer) compare(a, b int) { + if ac, ok := t.describe(t.reg(b).desc); ok { + t.assoc(t.params(a), ac) + } + if ac, ok := t.describe(t.reg(a).desc); ok { + t.assoc(t.params(b), ac) + } +} + +// store handles a register written as the ith column of a cursor's row: +// an ephemeral table remembers the parameters for the reads to come, and +// a real one is the column the parameters stand in for. +func (t *tracer) store(cursor, i, reg int) { + params := t.params(reg) + if len(params) == 0 { + return + } + if cols, ok := t.ephemeral[cursor]; ok { + cols[i] = append(cols[i], params...) + return + } + if ac, ok := t.stored(cursor, i); ok { + t.assoc(params, ac) + } +} + +// key handles registers used as a key into a cursor: n registers from +// start, or the record in start when n is zero. +func (t *tracer) key(cursor, start, n int) { + regs := t.span(start, n) + if n == 0 { + if r := t.reg(start); r.desc.kind == vRecord { + regs = r.desc.regs + } + } + for i, reg := range regs { + t.store(cursor, i, reg) + } +} + +func (t *tracer) span(start, n int) []int { + regs := make([]int, 0, max(n, 0)) + for i := 0; i < n; i++ { + regs = append(regs, start+i) + } + return regs +} + +// affinity names the type an affinity character coerces to. +func affinity(c byte) string { + switch c { + case 'A': + return "blob" + case 'B': + return "text" + case 'C': + return "numeric" + case 'D': + return "integer" + case 'E': + return "real" + } + return "" +} + +func (t *tracer) step(in instr) { + switch in.Opcode { + case "OpenRead", "OpenWrite", "ReopenIdx": + t.cursors[in.P1] = t.cat.root(in.P3, in.P2) + case "OpenDup": + t.cursors[in.P1] = t.cursors[in.P2] + if cols, ok := t.ephemeral[in.P2]; ok { + t.ephemeral[in.P1] = cols + } + case "OpenEphemeral", "OpenAutoindex", "SorterOpen", "OpenPseudo": + t.cursors[in.P1] = object{} + t.ephemeral[in.P1] = map[int][]int{} + case "Variable": + t.set(in.P2, value{kind: vParam}, []int{in.P1}) + case "Column", "VColumn": + t.set(in.P3, value{kind: vColumn, cursor: in.P1, index: in.P2}, t.ephemeral[in.P1][in.P2]) + case "Rowid", "IdxRowid": + t.set(in.P2, value{kind: vRowid, cursor: in.P1}, nil) + case "Copy": + for i := 0; i <= in.P3; i++ { + t.copy(in.P1+i, in.P2+i) + } + case "SCopy", "IntCopy": + t.copy(in.P1, in.P2) + case "Null", "SoftNull": + end := max(in.P2, in.P3) + if in.Opcode == "SoftNull" { + end = in.P1 + in.P2 = in.P1 + } + for r := in.P2; r <= end; r++ { + t.set(r, value{kind: vConstant, class: "null"}, nil) + } + case "Integer", "Int64": + t.set(in.P2, value{kind: vConstant, class: "integer"}, nil) + case "Real": + t.set(in.P2, value{kind: vConstant, class: "real"}, nil) + case "String8", "String": + t.set(in.P2, value{kind: vConstant, class: "text"}, nil) + case "Blob": + t.set(in.P2, value{kind: vConstant, class: "blob"}, nil) + case "Function", "PureFunc": + // P4 prints the function's arity, which for a variadic function + // is negative and says nothing about this call. Its arguments + // are the registers from P2 written so far, allocated together + // for the call. + name, n := parseCall(in.p4()) + if n < 0 { + n = 0 + for t.regs[in.P2+n] != nil { + n++ + } + } + t.expression(t.span(in.P2, n), in.P3, value{kind: vFunction, fn: name}) + case "Add", "Subtract", "Multiply", "Divide", "Remainder", "Concat", "BitAnd", "BitOr", "ShiftLeft", "ShiftRight": + t.expression([]int{in.P2, in.P1}, in.P3, value{kind: vExpr}) + case "MakeRecord": + t.set(in.P3, value{kind: vRecord, regs: t.span(in.P1, in.P2)}, nil) + case "Insert": + if r := t.reg(in.P2); r.desc.kind == vRecord { + for i, reg := range r.desc.regs { + t.store(in.P1, i, reg) + } + } + if owner := t.cursors[in.P1].owner(); owner != nil { + t.assoc(t.params(in.P3), owner.rowid()) + } + case "IdxInsert", "SorterInsert": + n, _ := strconv.Atoi(in.p4()) + if n > 0 { + t.key(in.P1, in.P3, n) + } else { + t.key(in.P1, in.P2, 0) + } + case "Eq", "Ne", "Lt", "Le", "Gt", "Ge": + t.compare(in.P1, in.P3) + case "SeekRowid", "NotExists": + if owner := t.cursors[in.P1].owner(); owner != nil { + t.assoc(t.params(in.P3), owner.rowid()) + } + case "SeekGE", "SeekGT", "SeekLE", "SeekLT": + // On a table with a rowid the seek is by the rowid in P3; on an + // index it is by the P4 registers from P3. + if o := t.cursors[in.P1]; o.table != nil && !o.table.withoutRowid { + t.assoc(t.params(in.P3), o.table.rowid()) + break + } + n, _ := strconv.Atoi(in.p4()) + t.key(in.P1, in.P3, n) + case "IdxGE", "IdxGT", "IdxLE", "IdxLT", "Found", "NotFound", "NoConflict": + n, _ := strconv.Atoi(in.p4()) + t.key(in.P1, in.P3, n) + case "MustBeInt": + t.typeHint(in.P1, "integer") + case "Affinity": + for i, c := range []byte(in.p4()) { + if i < in.P2 { + t.typeHint(in.P1+i, affinity(c)) + } + } + case "ResultRow": + for i := 0; i < in.P2; i++ { + if i < len(t.names) { + t.assoc(t.params(in.P1+i), analysis.Column{Name: t.names[i]}) + } + } + } +} + +// parseCall splits the `name(n)` a Function's P4 prints into the function's +// name and the number of arguments it is called with. +func parseCall(p4 string) (string, int) { + open := strings.LastIndexByte(p4, '(') + if open < 0 || !strings.HasSuffix(p4, ")") { + return p4, 0 + } + n, _ := strconv.Atoi(p4[open+1 : len(p4)-1]) + return p4[:open], n +} diff --git a/internal/goldeneye/sqlite/catalog.go b/internal/goldeneye/sqlite/catalog.go new file mode 100644 index 0000000..8077543 --- /dev/null +++ b/internal/goldeneye/sqlite/catalog.go @@ -0,0 +1,294 @@ +package sqlite + +import ( + "fmt" + "strconv" + "strings" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/analysis" +) + +// catalog is what the database says about a schema: its tables and their +// columns, its indexes, and the b-tree each is stored in, which is how the +// bytecode names them. +type catalog struct { + tables map[string]*table + roots map[int]object // by root page +} + +type table struct { + name string + withoutRowid bool + cols []*tableColumn // by cid + // stored lists the columns in the order a row's record holds them, + // which is cid order less the generated columns that are not stored. + stored []*tableColumn + // pk is the PRIMARY KEY index of a WITHOUT ROWID table, whose order is + // the order the table's own b-tree stores a row in. + pk *index +} + +type tableColumn struct { + table *table + cid int + name string + declType string + notNull bool + pk int // position in the primary key, 0 for none +} + +type index struct { + name string + table *table + cids []int // by seqno: -1 for the rowid, -2 for an expression +} + +// object is what a cursor is open on: a table, an index, or, with neither +// set, something the catalog does not describe — an ephemeral table, a +// sorter, a virtual table. +type object struct { + table *table + index *index +} + +// The catalog is read with these, each in a section of its own, in json +// mode. A query that finds nothing prints nothing, so a section may be +// empty. +var catalogQueries = []struct{ section, sql string }{ + {"tables", `SELECT name, type, wr FROM pragma_table_list WHERE schema = 'main' ORDER BY name`}, + {"columns", `SELECT t.name AS tbl, c.cid, c.name, c.type, c."notnull" AS "notnull", c.pk, c.hidden + FROM pragma_table_list t, pragma_table_xinfo(t.name) c + WHERE t.schema = 'main' AND t.type IN ('table', 'virtual') ORDER BY t.name, c.cid`}, + {"indexes", `SELECT t.name AS tbl, i.name AS idx, i.origin, x.seqno, x.cid + FROM pragma_table_list t, pragma_index_list(t.name) i, pragma_index_xinfo(i.name) x + WHERE t.schema = 'main' ORDER BY t.name, i.name, x.seqno`}, + {"roots", `SELECT type, name, tbl_name, rootpage FROM sqlite_schema WHERE rootpage > 0`}, +} + +// readCatalog builds the catalog from the sections catalogQueries printed. +func readCatalog(out *output) (*catalog, error) { + var tables []struct { + Name string `json:"name"` + Type string `json:"type"` + WR int `json:"wr"` + } + var columns []struct { + Table string `json:"tbl"` + CID int `json:"cid"` + Name string `json:"name"` + Type string `json:"type"` + NotNull int `json:"notnull"` + PK int `json:"pk"` + Hidden int `json:"hidden"` + } + var indexes []struct { + Table string `json:"tbl"` + Index string `json:"idx"` + Origin string `json:"origin"` + Seqno int `json:"seqno"` + CID int `json:"cid"` + } + var roots []struct { + Type string `json:"type"` + Name string `json:"name"` + Table string `json:"tbl_name"` + Rootpage int `json:"rootpage"` + } + for name, v := range map[string]any{"tables": &tables, "columns": &columns, "indexes": &indexes, "roots": &roots} { + s := out.sections[name] + if s == nil { + return nil, fmt.Errorf("reading the catalog: no %s section in the output", name) + } + if len(s.blocks) > 0 { + if err := s.decode(0, v); err != nil { + return nil, fmt.Errorf("reading the catalog's %s: %w", name, err) + } + } + } + + c := &catalog{tables: map[string]*table{}, roots: map[int]object{}} + for _, t := range tables { + if t.Type == "table" || t.Type == "virtual" { + c.tables[t.Name] = &table{name: t.Name, withoutRowid: t.WR == 1} + } + } + for _, col := range columns { + t := c.tables[col.Table] + if t == nil { + continue + } + tc := &tableColumn{table: t, cid: col.CID, name: col.Name, declType: col.Type, notNull: col.NotNull == 1, pk: col.PK} + for len(t.cols) <= col.CID { + t.cols = append(t.cols, nil) + } + t.cols[col.CID] = tc + // A generated column that is not stored — hidden is 2 — has no + // place in the record. + if col.Hidden != 2 { + t.stored = append(t.stored, tc) + } + } + byName := map[string]*index{} + for _, ic := range indexes { + t := c.tables[ic.Table] + if t == nil { + continue + } + ix := byName[ic.Index] + if ix == nil { + ix = &index{name: ic.Index, table: t} + byName[ic.Index] = ix + if ic.Origin == "pk" && t.withoutRowid { + t.pk = ix + } + } + for len(ix.cids) <= ic.Seqno { + ix.cids = append(ix.cids, -2) + } + ix.cids[ic.Seqno] = ic.CID + } + for _, r := range roots { + switch r.Type { + case "table": + if t := c.tables[r.Name]; t != nil { + c.roots[r.Rootpage] = object{table: t} + } + case "index": + if ix := byName[r.Name]; ix != nil { + c.roots[r.Rootpage] = object{index: ix} + } + } + } + return c, nil +} + +// root returns what is stored in a b-tree of the main database. +func (c *catalog) root(db, page int) object { + if db != 0 { + return object{} + } + return c.roots[page] +} + +// lookup finds a table column by the names `.stats stmt` prints. +func (c *catalog) lookup(tbl, col string) *tableColumn { + t := c.tables[tbl] + if t == nil { + return nil + } + for _, tc := range t.cols { + if tc != nil && tc.name == col { + return tc + } + } + return nil +} + +// rowidAlias returns the column that is another name for the rowid: the +// lone INTEGER PRIMARY KEY of a table that has a rowid. +func (t *table) rowidAlias() *tableColumn { + if t.withoutRowid { + return nil + } + var alias *tableColumn + for _, tc := range t.cols { + if tc == nil || tc.pk == 0 { + continue + } + if alias != nil || !strings.EqualFold(tc.declType, "INTEGER") { + return nil + } + alias = tc + } + return alias +} + +// describe is the column as sqlc analyze describes one: its declared type, +// nullable unless declared NOT NULL or the rowid, which is never NULL. +func (tc *tableColumn) describe() analysis.Column { + typ := parseType(tc.declType) + typ.Nullable = !tc.notNull && tc.table.rowidAlias() != tc + return analysis.Column{Name: tc.name, Type: typ, Table: tc.table.name} +} + +// rowid describes the table's rowid: the column that aliases it, or the +// rowid itself. +func (t *table) rowid() analysis.Column { + if alias := t.rowidAlias(); alias != nil { + return alias.describe() + } + return analysis.Column{Name: "rowid", Type: &analysis.TypeExpr{Name: "integer"}, Table: t.name} +} + +// column returns what the object's ith stored column is: a table column, +// or the rowid of a table. An index stores the columns it is on and then +// the rowid; a WITHOUT ROWID table is stored in the order of its primary +// key; any other table is stored in column order. +func (o object) column(i int) (*tableColumn, *table, bool) { + ix := o.index + if o.table != nil && o.table.withoutRowid { + ix = o.table.pk + } + switch { + case ix != nil: + if i < 0 || i >= len(ix.cids) { + return nil, nil, false + } + cid := ix.cids[i] + switch { + case cid == -1: + return nil, ix.table, true + case cid >= 0 && cid < len(ix.table.cols) && ix.table.cols[cid] != nil: + return ix.table.cols[cid], nil, true + } + case o.table != nil: + if i >= 0 && i < len(o.table.stored) { + return o.table.stored[i], nil, true + } + } + return nil, nil, false +} + +// owner is the table the object stores rows of. +func (o object) owner() *table { + if o.index != nil { + return o.index.table + } + return o.table +} + +// parseType reads a declared type the way sqlc's catalog does: the name +// lowercased, with whatever is in parentheses after it as arguments. A +// column declared with no type at all can hold anything. +func parseType(decl string) *analysis.TypeExpr { + decl = strings.TrimSpace(decl) + if decl == "" { + return &analysis.TypeExpr{Name: "any"} + } + name, args := decl, "" + if open := strings.IndexByte(decl, '('); open >= 0 && strings.HasSuffix(decl, ")") { + name, args = decl[:open], decl[open+1:len(decl)-1] + } + t := &analysis.TypeExpr{Name: strings.ToLower(strings.TrimSpace(name))} + if strings.TrimSpace(args) == "" { + return t + } + for _, a := range strings.Split(args, ",") { + a = strings.TrimSpace(a) + switch { + case strings.HasPrefix(a, "'") && strings.HasSuffix(a, "'") && len(a) >= 2: + s := strings.ReplaceAll(a[1:len(a)-1], "''", "'") + t.Args = append(t.Args, analysis.TypeArg{String: &s}) + case strings.EqualFold(a, "true") || strings.EqualFold(a, "false"): + b := strings.EqualFold(a, "true") + t.Args = append(t.Args, analysis.TypeArg{Bool: &b}) + default: + if n, err := strconv.ParseInt(a, 10, 64); err == nil { + t.Args = append(t.Args, analysis.TypeArg{Int: &n}) + } else { + t.Args = append(t.Args, analysis.TypeArg{Type: &analysis.TypeExpr{Name: strings.ToLower(a)}}) + } + } + } + return t +} diff --git a/internal/goldeneye/sqlite/install.go b/internal/goldeneye/sqlite/install.go new file mode 100644 index 0000000..d09a380 --- /dev/null +++ b/internal/goldeneye/sqlite/install.go @@ -0,0 +1,347 @@ +package sqlite + +import ( + "archive/zip" + "context" + "crypto/sha3" + "encoding/hex" + "errors" + "fmt" + "io" + "net/http" + "os" + "os/exec" + "path/filepath" + "runtime" + "slices" + "strings" + "sync" +) + +// DefaultVersion is the SQLite release the dialect is generated from. It is +// the release the ncruces/go-sqlite3 driver in the main module embeds, so +// the functions the dialect knows are the ones the tests run against. +// Bumping it is a deliberate change: releases add functions and overloads, +// so regenerate and review the dialect after changing it, and add the new +// release's amalgamation to the table below. +const DefaultVersion = "3.53.4" + +// defaultOptions are the compile options the base dialect is built with: +// the ones sqlite.org's own configure turns on by default, and so the ones +// a stock sqlite3 has. JSON is part of the library unless omitted, so only +// the math functions need naming. +var defaultOptions = []string{"SQLITE_ENABLE_MATH_FUNCTIONS"} + +// extensions are the compile options that each become a directory under +// the dialect's extensions/, holding the functions a build with the option +// adds over the default build — the way each PostgreSQL contrib extension +// holds what CREATE EXTENSION adds. Each is named after its option as +// pragma compile_options spells it, in lower case, and lists the options +// its build needs: GEOPOLY lives inside the RTREE module, so enabling it +// alone adds nothing. Options that add virtual tables but no functions, +// such as SESSION and DBSTAT, are not listed, since the dialect has nothing +// to say about them, and ENABLE_FTS4 is the same module as ENABLE_FTS3. +var extensions = []build{ + {"soundex", []string{"SQLITE_SOUNDEX"}}, + {"enable_fts3", []string{"SQLITE_ENABLE_FTS3"}}, + {"enable_fts5", []string{"SQLITE_ENABLE_FTS5"}}, + {"enable_geopoly", []string{"SQLITE_ENABLE_RTREE", "SQLITE_ENABLE_GEOPOLY"}}, + {"enable_offset_sql_func", []string{"SQLITE_ENABLE_OFFSET_SQL_FUNC"}}, + {"enable_percentile", []string{"SQLITE_ENABLE_PERCENTILE"}}, + {"enable_rtree", []string{"SQLITE_ENABLE_RTREE"}}, +} + +// analysisShell is the shell the analyze cases run through, which is no +// dialect build: nothing is generated from it. It is built with column +// metadata, so that `.stats stmt` can say which table column each result +// column of a statement comes from, and with every extension option at +// once, so that whatever a case's schema asks for is there. +var analysisShell = build{"analysis", append([]string{"SQLITE_ENABLE_COLUMN_METADATA"}, extensionOptions()...)} + +// extensionOptions is every option an extension build turns on, once each. +func extensionOptions() []string { + var opts []string + for _, b := range extensions { + for _, opt := range b.options { + if !slices.Contains(opts, opt) { + opts = append(opts, opt) + } + } + } + return opts +} + +// asset is one downloadable amalgamation of SQLite: the zip published on +// sqlite.org holding sqlite3.c, sqlite3.h and the shell's shell.c. +type asset struct { + Version string + // Path is the download's address under https://sqlite.org/, the + // release year included, as the download page's index lists it. + Path string + // SHA3 is the SHA3-256 of the zip, as the download page lists it. + SHA3 string +} + +// assets lists every amalgamation Install knows how to fetch, with the +// SHA3-256 of the download. A version that is not in this table cannot be +// installed: verifying the download is the point of the table. The +// checksums are the ones in the index at the foot of +// https://sqlite.org/download.html. +var assets = []asset{ + {"3.53.4", "2026/sqlite-amalgamation-3530400.zip", "628a44cfe82c66aed1ccbbe85a562d2e33ebe64b3288981ed76285612227934e"}, +} + +// sources are the files taken out of the amalgamation. +var sources = []string{"sqlite3.c", "sqlite3.h", "shell.c"} + +func releaseAsset(version string) (asset, error) { + for _, a := range assets { + if a.Version == version { + return a, nil + } + } + return asset{}, fmt.Errorf("SQLite %s is not in the asset table; add its amalgamation and checksum to install.go", version) +} + +func (a asset) url() string { + return "https://sqlite.org/" + a.Path +} + +// cacheDir is where Install puts a version: the sources under src/, and one +// shell per build under default/, under each option's extension name and +// under analysis/. +func cacheDir(version string) (string, error) { + dir, err := os.UserCacheDir() + if err != nil { + return "", err + } + return filepath.Join(dir, "sqlc-sqlite", version), nil +} + +// build is one compiled shell: its name, which is the directory it is +// under in the version's cache directory and, for an extension, under the +// dialect's extensions/, and the options it is built with beyond the +// default ones. +type build struct { + name string + options []string +} + +// builds lists the dialect builds: the default build first, then one per +// extension. +func builds() []build { + return append([]build{{"default", nil}}, extensions...) +} + +// shells lists every build Install makes: the dialect builds and the +// analysis shell. +func shells() []build { + return append(builds(), analysisShell) +} + +// flags are every option a build is compiled with. +func (b build) flags() []string { + return append(append([]string{}, defaultOptions...), b.options...) +} + +func (b build) binary(dir string) string { + return filepath.Join(dir, b.name, "sqlite3") +} + +// Locate finds the directory of shells Install made for DefaultVersion. +func Locate() (string, error) { + dir, err := cacheDir(DefaultVersion) + if err != nil { + return "", err + } + for _, b := range shells() { + if _, err := os.Stat(b.binary(dir)); err != nil { + return "", fmt.Errorf("sqlite %s is not built with %s: run `go run ./cmd/goldeneye install sqlite` in internal/goldeneye", DefaultVersion, strings.Join(b.flags(), " ")) + } + } + return dir, nil +} + +// Install downloads the amalgamation for a version into the cache and +// compiles the shell from it once per build, returning the directory the +// shells are under. Builds already there are kept, so adding an option +// compiles only its shell. The download is checked against the table's +// SHA3-256 before it is unpacked. Compiling takes the compiler CC names, or +// cc, and a few seconds per build without optimisation, which a shell that +// only reads catalogs does not need. +// +// goos and goarch are what every installer is handed; the sources build the +// same everywhere a C compiler is, but no default compiler or link line is +// known for Windows. +func Install(ctx context.Context, version, goos, goarch string, progress io.Writer) (string, error) { + if goos == "windows" { + return "", errors.New("building SQLite from source is not supported on Windows") + } + dir, err := cacheDir(version) + if err != nil { + return "", err + } + var missing []build + for _, b := range shells() { + if _, err := os.Stat(b.binary(dir)); err != nil { + missing = append(missing, b) + } + } + if len(missing) == 0 { + return dir, nil + } + if err := download(ctx, version, dir, progress); err != nil { + return "", err + } + if err := compile(ctx, dir, missing, progress); err != nil { + return "", err + } + return dir, nil +} + +// download fetches the amalgamation and unpacks the sources into src/, +// unless they are already there. +func download(ctx context.Context, version, dir string, progress io.Writer) error { + src := filepath.Join(dir, "src") + have := true + for _, name := range sources { + if _, err := os.Stat(filepath.Join(src, name)); err != nil { + have = false + } + } + if have { + return nil + } + a, err := releaseAsset(version) + if err != nil { + return err + } + if err := os.MkdirAll(src, 0o755); err != nil { + return err + } + + url := a.url() + fmt.Fprintf(progress, "downloading %s\n", url) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + return err + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("downloading %s: %s", url, resp.Status) + } + + // The zip has to land on disk before it can be read — its directory is + // at the end — so download it whole and hash every byte on the way. + archive, err := os.CreateTemp(dir, "sqlite-amalgamation-*.partial") + if err != nil { + return err + } + defer os.Remove(archive.Name()) + sum := sha3.New256() + if _, err := io.Copy(io.MultiWriter(archive, sum), resp.Body); err != nil { + archive.Close() + return err + } + if err := archive.Close(); err != nil { + return err + } + if got := hex.EncodeToString(sum.Sum(nil)); got != a.SHA3 { + return fmt.Errorf("downloading %s: SHA3-256 mismatch: got %s, want %s", url, got, a.SHA3) + } + + zr, err := zip.OpenReader(archive.Name()) + if err != nil { + return err + } + defer zr.Close() + for _, name := range sources { + if err := extract(zr, name, filepath.Join(src, name)); err != nil { + return fmt.Errorf("downloading %s: %w", url, err) + } + } + return nil +} + +// extract copies the named file out of the zip. The amalgamation's files +// sit in one directory named after the release, so the name is matched on +// its base. +func extract(zr *zip.ReadCloser, name, dest string) error { + for _, f := range zr.File { + if filepath.Base(f.Name) != name || f.FileInfo().IsDir() { + continue + } + rc, err := f.Open() + if err != nil { + return err + } + defer rc.Close() + tmp, err := os.CreateTemp(filepath.Dir(dest), name+"-*.partial") + if err != nil { + return err + } + defer os.Remove(tmp.Name()) + if _, err := io.Copy(tmp, rc); err != nil { + tmp.Close() + return err + } + if err := tmp.Close(); err != nil { + return err + } + return os.Rename(tmp.Name(), dest) + } + return fmt.Errorf("zip does not contain %s", name) +} + +// compile builds the shells, as many at a time as there are CPUs. +func compile(ctx context.Context, dir string, todo []build, progress io.Writer) error { + cc := os.Getenv("CC") + if cc == "" { + cc = "cc" + } + if _, err := exec.LookPath(cc); err != nil { + return fmt.Errorf("no C compiler found: put cc on PATH or set CC to one") + } + var wg sync.WaitGroup + slots := make(chan struct{}, max(1, runtime.NumCPU())) + errs := make([]error, len(todo)) + for i, b := range todo { + wg.Add(1) + go func() { + defer wg.Done() + slots <- struct{}{} + defer func() { <-slots }() + errs[i] = b.compile(ctx, cc, dir, progress) + }() + } + wg.Wait() + return errors.Join(errs...) +} + +// compile builds one shell from the sources in src/, writing it beside its +// destination and renaming so a failed build never masquerades as one. +func (b build) compile(ctx context.Context, cc, dir string, progress io.Writer) error { + dest := b.binary(dir) + if err := os.MkdirAll(filepath.Dir(dest), 0o755); err != nil { + return err + } + tmp := dest + ".partial" + defer os.Remove(tmp) + args := []string{"-O0"} + for _, opt := range b.flags() { + args = append(args, "-D"+opt) + } + src := filepath.Join(dir, "src") + args = append(args, filepath.Join(src, "shell.c"), filepath.Join(src, "sqlite3.c"), "-o", tmp, "-lm", "-ldl", "-lpthread") + fmt.Fprintf(progress, "building %s: %s %s\n", b.name, cc, strings.Join(args, " ")) + cmd := exec.CommandContext(ctx, cc, args...) + out, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("building %s: %w\n%s", b.name, err, strings.TrimSpace(string(out))) + } + return os.Rename(tmp, dest) +} diff --git a/internal/goldeneye/sqlite/shell.go b/internal/goldeneye/sqlite/shell.go new file mode 100644 index 0000000..f17b933 --- /dev/null +++ b/internal/goldeneye/sqlite/shell.go @@ -0,0 +1,254 @@ +package sqlite + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "os/exec" + "regexp" + "strconv" + "strings" +) + +// The analysis shell is driven with a script on its standard input, made +// of SQL and of the shell's own dot-commands: `.print` labels the sections +// of the output so that each statement's results can be found again, +// `.mode` chooses how rows print — json for the catalog and the bytecode, +// quote for a query's own rows, since quote mode is the one that tells a +// blob from a string and a real from an integer — and `.stats stmt` makes +// the shell print what it knows about each result column of the statement +// it has just run, which with column metadata compiled in is the column's +// name, declared type, database, table and origin column. + +// script is a shell script under construction, counting its lines so that +// an error the shell reports "near line N" can be placed. +type script struct { + buf strings.Builder + line int // the number of the next line written +} + +func newScript() *script { + return &script{line: 1} +} + +// add writes text on lines of its own, and returns the line it starts on. +func (s *script) add(text string) int { + start := s.line + text = strings.TrimSpace(text) + if text == "" { + return start + } + s.buf.WriteString(text) + s.buf.WriteByte('\n') + s.line += strings.Count(text, "\n") + 1 + return start +} + +// sql writes statements, ending them with a semicolon when they lack one. +func (s *script) sql(text string) int { + text = strings.TrimRight(strings.TrimSpace(text), "; \t\r\n") + if text == "" { + return s.line + } + return s.add(text + ";") +} + +// section labels what follows, up to the next label. +func (s *script) section(name string) { + s.add(".print @@" + name) +} + +// columnMeta is what `.stats stmt` prints about one result column. Table +// and Origin name the table column a result column is read from, and are +// empty for an expression. +type columnMeta struct { + Name string + DeclType string + Database string + Table string + Origin string +} + +// section is the output between two labels. +type section struct { + // blocks holds every JSON result set printed in the section. + blocks []json.RawMessage + // rows holds every other line printed before the statement's + // statistics: in quote mode, one row each. + rows []string + // prepared says a statement's statistics were printed, which the shell + // does only for a statement it could prepare. + prepared bool + columns []columnMeta +} + +// decode reads the section's nth JSON result set. +func (s *section) decode(n int, v any) error { + if n >= len(s.blocks) { + return fmt.Errorf("expected at least %d result set(s), got %d", n+1, len(s.blocks)) + } + return json.Unmarshal(s.blocks[n], v) +} + +// output is what one run of the shell printed, by section. +type output struct { + sections map[string]*section + stderr string +} + +var errLineRe = regexp.MustCompile(`near line (\d+):`) + +// errorsBefore returns the errors the shell reported for statements before +// the given line: the ones that are not the statement under analysis +// failing to run, which it may, with nothing bound to its parameters. +func (o *output) errorsBefore(line int) []string { + var errs []string + for _, l := range strings.Split(o.stderr, "\n") { + if m := errLineRe.FindStringSubmatch(l); m != nil { + if n, _ := strconv.Atoi(m[1]); n < line { + errs = append(errs, strings.TrimSpace(l)) + } + } + } + return errs +} + +// run feeds a script to the shell over a fresh in-memory database and +// parses what it printed. A statement that fails does not stop the shell, +// so a failure is read from the output: a section whose statement has no +// statistics was not prepared, and stderr says why. +func run(ctx context.Context, binary string, s *script) (*output, error) { + cmd := exec.CommandContext(ctx, binary, ":memory:") + cmd.Stdin = strings.NewReader(s.buf.String()) + var stdout, stderr bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = &stderr + if err := cmd.Run(); err != nil { + var exit *exec.ExitError + if !errors.As(err, &exit) { + return nil, fmt.Errorf("sqlite3: %w", err) + } + } + out := &output{sections: map[string]*section{}, stderr: stderr.String()} + var ( + cur *section + block []string // lines of the JSON result set being read + row []string // lines of the quote-mode row being read + ) + for _, line := range strings.Split(stdout.String(), "\n") { + switch { + case block != nil: + block = append(block, line) + if strings.HasSuffix(line, "]") { + cur.blocks = append(cur.blocks, json.RawMessage(strings.Join(block, "\n"))) + block = nil + } + case row != nil: + row = append(row, line) + if joined := strings.Join(row, "\n"); strings.Count(joined, "'")%2 == 0 { + cur.rows = append(cur.rows, joined) + row = nil + } + case strings.HasPrefix(line, "@@"): + cur = §ion{} + out.sections[line[2:]] = cur + case cur == nil || line == "": + case strings.HasPrefix(line, "["): + if strings.HasSuffix(line, "]") { + cur.blocks = append(cur.blocks, json.RawMessage(line)) + } else { + block = []string{line} + } + case strings.HasPrefix(line, "Number of output columns:"): + cur.prepared = true + case cur.prepared: + if i, field, value, ok := statLine(line); ok { + for len(cur.columns) <= i { + cur.columns = append(cur.columns, columnMeta{}) + } + c := &cur.columns[i] + switch field { + case "name": + c.Name = value + case "declared type": + c.DeclType = value + case "database name": + c.Database = value + case "table name": + c.Table = value + case "origin name": + c.Origin = value + } + } + default: + // A quote-mode row, complete unless a string in it spans lines. + if strings.Count(line, "'")%2 == 0 { + cur.rows = append(cur.rows, line) + } else { + row = []string{line} + } + } + } + return out, nil +} + +var statLineRe = regexp.MustCompile(`^Column (\d+) ([a-z ]+):`) + +// statLine reads one line of `.stats stmt` column output, which the shell +// prints as the label padded to 36 columns, a space and the value; a value +// the library has no answer for prints as the C library prints a null +// string. +func statLine(line string) (int, string, string, bool) { + m := statLineRe.FindStringSubmatch(line) + if m == nil { + return 0, "", "", false + } + i, _ := strconv.Atoi(m[1]) + label := m[0] + value := "" + if start := max(len(label), 36) + 1; start < len(line) { + value = line[start:] + } + if value == "(null)" { + value = "" + } + return i, m[2], value, true +} + +// cells splits a quote-mode row into its values as printed. +func cells(row string) []string { + var out []string + start := 0 + quoted := false + for i := 0; i < len(row); i++ { + switch { + case row[i] == '\'': + quoted = !quoted + case row[i] == ',' && !quoted: + out = append(out, row[start:i]) + start = i + 1 + } + } + return append(out, row[start:]) +} + +// storageClass reads the storage class of a value as quote mode prints +// it: a string is quoted, a blob is quoted with an X, NULL is spelled +// out, and a real has a point, an exponent or is infinite or not a number +// where an integer is digits. +func storageClass(cell string) string { + switch { + case cell == "NULL": + return "null" + case strings.HasPrefix(cell, "'"): + return "text" + case strings.HasPrefix(cell, "x'") || strings.HasPrefix(cell, "X'"): + return "blob" + case strings.ContainsAny(cell, ".eEIN"): + return "real" + default: + return "integer" + } +} diff --git a/internal/goldeneye/sqlite/signatures.go b/internal/goldeneye/sqlite/signatures.go new file mode 100644 index 0000000..5551061 --- /dev/null +++ b/internal/goldeneye/sqlite/signatures.go @@ -0,0 +1,136 @@ +package sqlite + +import "github.com/sqlc-dev/sqlc/internal/goldeneye/dialect" + +// signature is what a function returns and what its arguments hold, read +// from the amalgamation by source.signature. Args types the leading +// arguments in order; a position it does not cover is "any", which the +// analyzer resolves to the argument's own type. Variadic types the +// arguments an overload of variable arity repeats, "any" when empty. How +// many arguments an overload takes, and how many of them it requires, +// comes from the shell. Nullable is decided afterwards: for an aggregate by +// running it over no rows, for a scalar by the nullable list below. +// Numeric says the function returns an integer for an integer argument +// and a real for a real one, and Returns what it returns for anything +// else. +type signature struct { + Args []string + Variadic string + Returns string + Numeric bool + Nullable bool +} + +// args builds an overload's parameters from the shell's argument count. A +// fixed count is that many parameters; a negative count is the required +// leading parameters, any further ones the signature types marked as +// having a default, and a variadic tail. +func (s signature) args(narg int) []dialect.Arg { + if narg >= 0 { + args := make([]dialect.Arg, narg) + for i := range args { + args[i] = dialect.Arg{Type: s.argType(i)} + } + return args + } + required := minArgs(narg) + n := max(required, len(s.Args)) + args := make([]dialect.Arg, 0, n+1) + for i := 0; i < n; i++ { + args = append(args, dialect.Arg{Type: s.argType(i), HasDefault: i >= required}) + } + tail := s.Variadic + if tail == "" { + tail = "any" + } + return append(args, dialect.Arg{Type: tail, Mode: "v"}) +} + +func (s signature) argType(i int) string { + if i < len(s.Args) { + return s.Args[i] + } + return "any" +} + +// inlineReturns is what the functions the VDBE implements in bytecode +// return, by the INLINEFUNC_* constant their registration carries. All but +// one hand back one of their arguments, which is what the default of "any" +// says; sqlite_offset is a byte offset. +var inlineReturns = map[string]string{ + "INLINEFUNC_sqlite_offset": "integer", +} + +// realResults are the functions that return an integer or a real on +// something other than which their argument is, and so are typed real +// alone: unixepoch takes a time string and returns a real only with the +// 'subsec' modifier. +var realResults = map[string]bool{ + "unixepoch": true, +} + +// omitted are functions the dialect leaves out: ones that exist for their +// side effect and return nothing a query can use, and ones an extension +// uses to pass pointers to itself. +var omitted = map[string]bool{ + // Loads a shared library and returns NULL. + "load_extension": true, + // Writes to the error log and returns NULL. + "sqlite_log": true, + // FTS3's and FTS5's ways of passing pointers to their virtual tables, + // not functions a query calls. + "fts3_tokenizer": true, + "fts5": true, + // A debugging aid of GEOPOLY's. + "geopoly_debug": true, +} + +// nullable are the scalar functions that return NULL for arguments that +// are not: a lookup that finds nothing, an input that does not parse, a +// value with no sign. The source cannot say this — a SQLite function +// returns NULL as often by setting no result as by calling +// sqlite3_result_null — so it is listed by the documentation of each. +// Aggregates are not listed: whether one returns NULL over no rows is +// found by running it over none. +var nullable = map[string]bool{ + // Core functions. + "nullif": true, + "sign": true, + "sqlite_compileoption_get": true, + "sqlite_offset": true, + "unhex": true, + // Date and time functions, for a time value they cannot parse. + "date": true, + "datetime": true, + "julianday": true, + "strftime": true, + "time": true, + "timediff": true, + "unixepoch": true, + // JSON functions, for a path that leads nowhere. + "->": true, + "->>": true, + "json_array_length": true, + "json_extract": true, + "json_type": true, + "jsonb_extract": true, + // Window functions, for a row outside the frame. + "first_value": true, + "lag": true, + "last_value": true, + "lead": true, + "nth_value": true, + // FTS5, for a table with no locale. + "fts5_get_locale": true, + // GEOPOLY functions, for an argument that is not a polygon. + "geopoly_area": true, + "geopoly_bbox": true, + "geopoly_blob": true, + "geopoly_ccw": true, + "geopoly_contains_point": true, + "geopoly_json": true, + "geopoly_overlap": true, + "geopoly_svg": true, + "geopoly_within": true, + "geopoly_xform": true, +} diff --git a/internal/goldeneye/sqlite/source.go b/internal/goldeneye/sqlite/source.go new file mode 100644 index 0000000..d7c5518 --- /dev/null +++ b/internal/goldeneye/sqlite/source.go @@ -0,0 +1,521 @@ +package sqlite + +import ( + "fmt" + "os" + "regexp" + "sort" + "strings" +) + +// source is what the amalgamation says about how SQLite's functions answer. +// A function is registered in one of a few shapes — the FuncDef macros of +// the built-in tables, a sqlite3_create_function call, or a struct table an +// extension walks — each naming the C functions that implement it. Those +// implementations set their result through sqlite3_result_* and read their +// arguments through sqlite3_value_*, which is as close as SQLite comes to +// declaring a signature. +type source struct { + funcs map[string]cfunc + aliases map[string]string + regs map[string]*registration +} + +// cfunc is one C function definition: its parameter list and its body. +type cfunc struct { + params string + body string +} + +// registration is the union of everything the source registers under one +// SQL function name. +type registration struct { + // scalar implements a scalar overload: its results and its arguments. + scalar []string + // step and final implement an aggregate or window overload: step reads + // the arguments, final and value set the result. + step []string + final []string + // inline names the INLINEFUNC_* constant of a function the VDBE + // implements in bytecode, which has no C body to read. + inline string + // json records what a JSON function's registration says it returns, + // "text" or "blob", since the json_ and jsonb_ forms share an + // implementation; jsonAlways says the registration promises JSON text + // whatever the implementation might otherwise return, as -> does. + json string + jsonAlways bool + // table marks a registration found only in a struct table, which is + // consulted when nothing more direct registered the name. + table bool +} + +// The FuncDef macros, with the positions of the C functions in each. +var macroEntry = regexp.MustCompile(`\b(FUNCTION2|FUNCTION|VFUNCTION|SFUNCTION|MFUNCTION|JFUNCTION|INLINE_FUNC|DFUNCTION|PURE_DATE|STR_FUNCTION|LIKEFUNC|WAGGREGATE|WINDOWFUNCX|WINDOWFUNCALL|WINDOWFUNCNOOP)\(`) + +var ( + createFunction = regexp.MustCompile(`\bsqlite3_create_(window_)?function\(`) + defineAlias = regexp.MustCompile(`(?m)^#define\s+(\w+)\s+(\w+)\s*$`) + definition = regexp.MustCompile(`(?m)^(?:static\s+|SQLITE_PRIVATE\s+)?(?:const\s+)?(?:unsigned\s+)?[A-Za-z_]\w*(?:\s*\*+\s*|\s+)([A-Za-z_]\w*)\(`) + initializer = regexp.MustCompile(`\{[^{}]*"([a-z_0-9>-]+)"[^{}]*\}`) + identifier = regexp.MustCompile(`\b([A-Za-z_]\w*)\b`) + resultCall = regexp.MustCompile(`\bsqlite3_result_(\w+)\(`) + valueCall = regexp.MustCompile(`\bsqlite3_value_(\w+)\(\s*(?:argv|apVal|apArg)\[(\w+)\]`) + callee = regexp.MustCompile(`\b([A-Za-z_]\w*)\s*\(`) +) + +// readSource reads the amalgamation. +func readSource(path string) (*source, error) { + data, err := os.ReadFile(path) + if err != nil { + return nil, err + } + text := string(data) + s := &source{ + funcs: map[string]cfunc{}, + aliases: map[string]string{}, + regs: map[string]*registration{}, + } + for _, m := range defineAlias.FindAllStringSubmatch(text, -1) { + s.aliases[m[1]] = m[2] + } + s.readDefinitions(text) + s.readMacros(text) + s.readCreateFunctions(text) + s.readTables(text) + return s, nil +} + +// readDefinitions indexes every function defined at the left margin. +func (s *source) readDefinitions(text string) { + for _, m := range definition.FindAllStringSubmatchIndex(text, -1) { + name := text[m[2]:m[3]] + params, end, ok := balanced(text, m[1]-1, '(', ')') + if !ok { + continue + } + i := end + for i < len(text) && (text[i] == ' ' || text[i] == '\n' || text[i] == '\r' || text[i] == '\t') { + i++ + } + if i >= len(text) || text[i] != '{' { + continue + } + body, _, ok := balanced(text, i, '{', '}') + if !ok { + continue + } + if _, dup := s.funcs[name]; !dup { + s.funcs[name] = cfunc{params: params, body: body} + } + } +} + +// balanced returns the text between the bracket at open and its match, +// skipping string and character literals and comments, and the index after +// the closing bracket. +func balanced(text string, open int, lb, rb byte) (string, int, bool) { + depth := 0 + for i := open; i < len(text); i++ { + switch c := text[i]; { + case c == '"' || c == '\'': + for i++; i < len(text) && text[i] != c; i++ { + if text[i] == '\\' { + i++ + } + } + case c == '/' && i+1 < len(text) && text[i+1] == '*': + end := strings.Index(text[i+2:], "*/") + if end < 0 { + return "", 0, false + } + i += end + 3 + case c == '/' && i+1 < len(text) && text[i+1] == '/': + end := strings.IndexByte(text[i:], '\n') + if end < 0 { + return "", 0, false + } + i += end + case c == lb: + depth++ + case c == rb: + depth-- + if depth == 0 { + return text[open+1 : i], i + 1, true + } + } + } + return "", 0, false +} + +// arguments splits a bracketed argument list at the commas of its own +// level, and reports the index after the closing bracket. +func arguments(text string, open int) ([]string, int, bool) { + inner, end, ok := balanced(text, open, '(', ')') + if !ok { + return nil, 0, false + } + var args []string + depth, start := 0, 0 + for i := 0; i < len(inner); i++ { + switch inner[i] { + case '(', '[', '{': + depth++ + case ')', ']', '}': + depth-- + case '"': + for i++; i < len(inner) && inner[i] != '"'; i++ { + if inner[i] == '\\' { + i++ + } + } + case ',': + if depth == 0 { + args = append(args, strings.TrimSpace(inner[start:i])) + start = i + 1 + } + } + } + args = append(args, strings.TrimSpace(inner[start:])) + return args, end, true +} + +func (s *source) reg(name string) *registration { + name = strings.ToLower(name) + r, ok := s.regs[name] + if !ok { + r = ®istration{} + s.regs[name] = r + } + return r +} + +// readMacros reads the FuncDef tables. The macro definitions themselves +// match too, and are told apart by their formal parameter names. +func (s *source) readMacros(text string) { + for _, m := range macroEntry.FindAllStringSubmatchIndex(text, -1) { + macro := text[m[2]:m[3]] + args, _, ok := arguments(text, m[1]-1) + if !ok || len(args) < 2 || args[0] == "zName" || args[0] == "name" { + continue + } + name := args[0] + switch macro { + case "FUNCTION", "FUNCTION2", "VFUNCTION", "SFUNCTION", "DFUNCTION", "PURE_DATE", "STR_FUNCTION": + if len(args) > 4 { + r := s.reg(name) + r.scalar = append(r.scalar, args[4]) + } + case "MFUNCTION": + if len(args) > 3 { + r := s.reg(name) + r.scalar = append(r.scalar, args[3]) + } + case "JFUNCTION": + // JFUNCTION(zName, nArg, bUseCache, bWS, bRS, bJsonB, iArg, xFunc) + if len(args) > 7 { + r := s.reg(name) + r.scalar = append(r.scalar, args[7]) + r.json = "text" + if args[5] == "1" { + r.json = "blob" + } + r.jsonAlways = strings.Contains(args[6], "JSON_JSON") + } + case "INLINE_FUNC": + if len(args) > 2 { + s.reg(name).inline = args[2] + } + case "LIKEFUNC": + r := s.reg(name) + r.scalar = append(r.scalar, "likeFunc") + case "WAGGREGATE": + // WAGGREGATE(zName, nArg, arg, nc, xStep, xFinal, xValue, xInverse, f) + // The JSON aggregates use it too, told by their implementation, + // with JSON_BLOB as the user data of the jsonb_ forms. + if len(args) > 6 { + r := s.reg(name) + r.step = append(r.step, args[4]) + r.final = append(r.final, args[5], args[6]) + if strings.HasPrefix(args[4], "json") { + r.json = "text" + if strings.Contains(args[2], "JSON_BLOB") { + r.json = "blob" + } + } + } + case "WINDOWFUNCX", "WINDOWFUNCALL": + r := s.reg(name) + r.step = append(r.step, name+"StepFunc") + r.final = append(r.final, name+"ValueFunc") + case "WINDOWFUNCNOOP": + s.reg(name).inline = "bytecode" + } + } +} + +// readCreateFunctions reads the functions extensions register by calling +// sqlite3_create_function or sqlite3_create_window_function with a literal +// name. +func (s *source) readCreateFunctions(text string) { + for _, m := range createFunction.FindAllStringSubmatchIndex(text, -1) { + window := m[2] != -1 + args, _, ok := arguments(text, m[1]-1) + if !ok || len(args) < 8 || !strings.HasPrefix(args[1], `"`) { + continue + } + r := s.reg(strings.Trim(args[1], `"`)) + if window { + // (db, zName, nArg, eTextRep, pApp, xStep, xFinal, xValue, xInverse, xDestroy) + r.step = given(r.step, args[5]) + r.final = given(r.final, args[6], args[7]) + } else { + // (db, zName, nArg, eTextRep, pApp, xFunc, xStep, xFinal) + r.scalar = given(r.scalar, args[5]) + r.step = given(r.step, args[6]) + r.final = given(r.final, args[7]) + } + } +} + +// given appends the implementations a registration names, leaving out the +// methods it passes as 0 or NULL. +func given(impls []string, names ...string) []string { + for _, name := range names { + if name != "0" && name != "NULL" { + impls = append(impls, name) + } + } + return impls +} + +// readTables reads the struct tables extensions walk to register their +// functions — geopoly's aFunc, FTS5's aBuiltin, FTS3's aOverload — each row +// an initializer holding the function's name and the C functions that +// implement it. Any C function in the row counts as an implementation; +// which reads arguments and which sets the result comes out in the +// reading. A row is consulted only for a name nothing else registered. +func (s *source) readTables(text string) { + for _, m := range initializer.FindAllStringSubmatch(text, -1) { + var impls []string + for _, id := range identifier.FindAllStringSubmatch(m[0], -1) { + if _, ok := s.funcs[s.resolve(id[1])]; ok { + impls = append(impls, id[1]) + } + } + if len(impls) == 0 { + continue + } + name := strings.ToLower(m[1]) + r, ok := s.regs[name] + if ok && !r.table { + continue + } + r = s.reg(name) + r.table = true + r.scalar = append(r.scalar, impls...) + } +} + +// resolve follows #define aliases from a C function name to the one that +// is defined. +func (s *source) resolve(name string) string { + for i := 0; i < 8; i++ { + alias, ok := s.aliases[name] + if !ok { + return name + } + name = alias + } + return name +} + +// noop reports a C function that does nothing: the stand-in for a function +// the VDBE implements in bytecode, whose result is one of its arguments. +func noop(name string) bool { + return strings.HasPrefix(name, "noop") +} + +// The kinds a result or argument call names, by the sqlite3_result_* or +// sqlite3_value_* suffix with any 64 dropped. Suffixes not listed — error, +// subtype, type, bytes, dup — say nothing about a type. +var ( + resultKinds = map[string]string{ + "int": "integer", "double": "real", + "text": "text", "text16": "text", "text16le": "text", "text16be": "text", + "blob": "blob", "zeroblob": "blob", + "value": "any", "pointer": "any", + } + valueKinds = map[string]string{ + "int": "integer", "double": "real", + "text": "text", "text16": "text", "text16le": "text", "text16be": "text", + "blob": "blob", + } +) + +func kindOf(kinds map[string]string, suffix string) (string, bool) { + k, ok := kinds[strings.TrimSuffix(suffix, "64")] + return k, ok +} + +// results collects the kinds a C function sets its result to, following +// the helpers it calls a few levels down, since many functions hand their +// result to one. +func (s *source) results(name string, depth int, seen map[string]bool) map[string]bool { + kinds := map[string]bool{} + name = s.resolve(name) + if noop(name) { + kinds["any"] = true + return kinds + } + fn, ok := s.funcs[name] + if !ok || seen[name] || depth > 3 { + return kinds + } + seen[name] = true + for _, m := range resultCall.FindAllStringSubmatch(fn.body, -1) { + if k, ok := kindOf(resultKinds, m[1]); ok { + kinds[k] = true + } + } + for _, m := range callee.FindAllStringSubmatch(fn.body, -1) { + c := m[1] + if c == name || strings.HasPrefix(c, "sqlite3_") || strings.HasPrefix(c, "sqlite3Vdbe") { + continue + } + if _, ok := s.funcs[c]; ok { + for k := range s.results(c, depth+1, seen) { + kinds[k] = true + } + } + } + return kinds +} + +// args collects the kinds a C function reads each of its arguments as, by +// position, and the kind it reads a run of arguments as under a loop +// index. An implementation called through the FTS5 extension API is handed +// the table as an implicit first argument, so its positions shift by one. +func (s *source) args(name string, positions map[int]map[string]bool, variadic map[string]bool) { + fn, ok := s.funcs[s.resolve(name)] + if !ok { + return + } + shift := 0 + if strings.Contains(fn.params, "Fts5ExtensionApi") { + shift = 1 + if positions[0] == nil { + positions[0] = map[string]bool{} + } + positions[0]["any"] = true + } + for _, m := range valueCall.FindAllStringSubmatch(fn.body, -1) { + k, ok := kindOf(valueKinds, m[1]) + if !ok { + continue + } + var pos int + if _, err := fmt.Sscanf(m[2], "%d", &pos); err != nil { + variadic[k] = true + continue + } + pos += shift + if positions[pos] == nil { + positions[pos] = map[string]bool{} + } + positions[pos][k] = true + } +} + +// single reduces the kinds seen at one position to a type: the one kind +// seen, or "any" for a mixture or nothing. +func single(kinds map[string]bool) string { + if len(kinds) == 1 { + for k := range kinds { + return k + } + } + return "any" +} + +// signature derives what the source says a SQL function returns and takes. +// A result of one kind is that type. A function that returns one of its +// arguments, or a mixture of kinds, takes the type of its first argument, +// which the seed spells "any" — except that integer and real together are +// real, and Numeric, since abs, ceil and sum hand back an integer for an +// integer and a real for a real, and a real for the text or blob they +// convert, unless the function is one of the few whose choice turns on +// something else; and text and blob together are text, since a function +// that returns either is handing back the bytes it was given, and the +// legacy compiler cannot follow "any" to an argument. +func (s *source) signature(name string) (signature, error) { + r, ok := s.regs[strings.ToLower(name)] + if !ok { + return signature{}, fmt.Errorf("the amalgamation registers no function named %s", name) + } + var sig signature + switch { + case r.inline != "": + sig.Returns = inlineReturns[r.inline] + if sig.Returns == "" { + sig.Returns = "any" + } + default: + kinds := map[string]bool{} + for _, fn := range append(append([]string{}, r.scalar...), r.final...) { + for k := range s.results(fn, 0, map[string]bool{}) { + kinds[k] = true + } + } + jsonOnly := r.json != "" && len(kinds) <= 2 && !kinds["integer"] && !kinds["real"] && !kinds["any"] + switch { + case len(kinds) == 0: + return signature{}, fmt.Errorf("cannot tell what %s returns: no sqlite3_result call in %s", name, strings.Join(append(append([]string{}, r.scalar...), r.final...), ", ")) + case r.jsonAlways: + sig.Returns = "text" + case kinds["any"]: + sig.Returns = "any" + case len(kinds) == 1: + for k := range kinds { + sig.Returns = k + } + case jsonOnly: + // The shared implementation writes JSON text or JSONB; the + // registration says which this form gets. + sig.Returns = r.json + case len(kinds) == 2 && kinds["integer"] && kinds["real"]: + sig.Returns = "real" + sig.Numeric = !realResults[strings.ToLower(name)] + case len(kinds) == 2 && kinds["text"] && kinds["blob"]: + sig.Returns = "text" + default: + sig.Returns = "any" + } + } + + positions := map[int]map[string]bool{} + variadic := map[string]bool{} + for _, fn := range append(append([]string{}, r.scalar...), r.step...) { + s.args(fn, positions, variadic) + } + if len(positions) > 0 { + var order []int + for pos := range positions { + order = append(order, pos) + } + sort.Ints(order) + sig.Args = make([]string, order[len(order)-1]+1) + for i := range sig.Args { + sig.Args[i] = single(positions[i]) + } + // Trailing positions nothing typed say nothing, unless a variadic + // tail follows them, when they keep it from starting early. + for len(variadic) == 0 && len(sig.Args) > 0 && sig.Args[len(sig.Args)-1] == "any" { + sig.Args = sig.Args[:len(sig.Args)-1] + } + } + if len(variadic) == 1 { + sig.Variadic = single(variadic) + } + return sig, nil +} diff --git a/internal/goldeneye/sqlite/sqlite.go b/internal/goldeneye/sqlite/sqlite.go new file mode 100644 index 0000000..c176a55 --- /dev/null +++ b/internal/goldeneye/sqlite/sqlite.go @@ -0,0 +1,444 @@ +// Package sqlite generates the SQLite dialect seed under +// internal/engine/sqlite/dialect from sqlite3 shells built from the +// amalgamation sqlite.org publishes, run against in-memory databases that +// need no server, and from the amalgamation itself. +// +// SQLite describes its functions as far as their names, their kinds and the +// number of arguments each takes — pragma_function_list — and no further: +// it types values rather than columns or functions, so nothing in the +// database says what a function returns or what it expects. The source +// does, in its way. Every function is registered with the C functions that +// implement it, and those set their result through sqlite3_result_* and +// read their arguments through sqlite3_value_*, which is as close as SQLite +// comes to declaring a signature. So functions.jsonl is built from both: +// the shell says which functions exist, how many arguments each overload +// takes and whether it aggregates, and the amalgamation says what each +// returns and what its arguments hold. A function the shell reports that +// the source does not register, or whose implementation sets no result, +// fails generation rather than being guessed at. What neither can say — +// which scalar functions return NULL for arguments that are not — is a +// short list in signatures.go; for aggregates it is found by running each +// over no rows. +// +// Which functions a SQLite has is decided when it is compiled, so the +// dialect treats compile options the way the PostgreSQL dialect treats +// contrib extensions. functions.jsonl is what a build with the default +// options has, and each further option gets a directory under extensions/ +// holding the functions a build with that option adds — found the way +// CREATE EXTENSION's additions are, by comparing the catalog with and +// without. SQLite has no catalog of types or operators, so types.jsonl and +// operators.jsonl are hand-written. +// +// The shells are built once per pinned version by Install. +package sqlite + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "maps" + "os/exec" + "path" + "path/filepath" + "slices" + "sort" + "strconv" + "strings" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/dialect" +) + +// Engine is the name of the engine directory the dialect lives under. +const Engine = "sqlite" + +// functionList is every function the connection knows, one row per +// overload: name, whether the library builds it in or the shell or an +// extension registered it, 's', 'a' or 'w' for how it is called, and how +// many arguments it takes. Fixed arities come before the variable one so +// that an exact match is found first by anything reading the file in +// order. +const functionList = ` +SELECT name, builtin, type, narg +FROM pragma_function_list +ORDER BY name, narg < 0, narg` + +type functionRow struct { + Name string `json:"name"` + Builtin int `json:"builtin"` + Type string `json:"type"` + NArg int `json:"narg"` +} + +// key tells one overload from another. +func (r functionRow) key() string { + return r.Name + "/" + strconv.Itoa(r.NArg) +} + +// Version reports the release the default shell is. +func Version(ctx context.Context, dir string) (string, error) { + out, err := exec.CommandContext(ctx, builds()[0].binary(dir), "--version").Output() + if err != nil { + return "", fmt.Errorf("sqlite3 --version: %w", err) + } + return "SQLite " + strings.TrimSpace(string(out)), nil +} + +// query runs a SQL statement against an in-memory database and decodes the +// shell's JSON output into rows. +func query(ctx context.Context, binary, sql string, rows any) error { + cmd := exec.CommandContext(ctx, binary, "-json", "-bail", ":memory:", sql) + out, err := cmd.Output() + if err != nil { + var exit *exec.ExitError + if errors.As(err, &exit) { + return fmt.Errorf("sqlite3: %s: %s", err, bytes.TrimSpace(exit.Stderr)) + } + return fmt.Errorf("sqlite3: %w", err) + } + // An empty result set prints nothing rather than []. + if len(bytes.TrimSpace(out)) == 0 { + return nil + } + return json.Unmarshal(out, rows) +} + +// minArgs decodes a negative argument count from pragma_function_list, +// which prints the count SQLite keeps for the function as it is: -1 for any +// number of arguments, and the two values reserved for built-ins, -3 for +// one or more and -4 for two or more — see matchQuality in the SQLite +// source. No function is counted as -2. +func minArgs(narg int) int { + if narg < -2 { + return -2 - narg + } + return 0 +} + +// functionKind maps the type the shell reports onto the seed's letters. +// The shell says 's' for a scalar function, 'a' for an aggregate and 'w' +// for one with a window implementation — but every one of SQLite's +// aggregates has one, so 'w' covers avg and count as well as row_number. +// The two are told apart by calling the function without an OVER clause, +// which only a window function refuses. +func functionKind(ctx context.Context, binary string, row functionRow) (string, error) { + switch row.Type { + case "s": + return "", nil + case "a": + return "a", nil + case "w": + window, err := isWindowFunction(ctx, binary, row) + if err != nil { + return "", err + } + if window { + return "w", nil + } + return "a", nil + } + return "", fmt.Errorf("sqlite: function %s has unknown type %q", row.Name, row.Type) +} + +// isWindowFunction reports whether the shell refuses to call a function +// without an OVER clause. Any other complaint — an aggregate objecting to +// the NULLs it is handed — means the call was accepted as an aggregate. +func isWindowFunction(ctx context.Context, binary string, row functionRow) (bool, error) { + n := row.NArg + if n < 0 { + n = minArgs(n) + } + args := strings.TrimSuffix(strings.Repeat("NULL, ", n), ", ") + cmd := exec.CommandContext(ctx, binary, ":memory:", fmt.Sprintf("SELECT %s(%s)", row.Name, args)) + var stderr bytes.Buffer + cmd.Stdout = io.Discard + cmd.Stderr = &stderr + err := cmd.Run() + if err == nil { + return false, nil + } + if strings.Contains(stderr.String(), "misuse of window function") { + return true, nil + } + var exit *exec.ExitError + if errors.As(err, &exit) { + return false, nil + } + return false, fmt.Errorf("sqlite3: %w", err) +} + +// shell is one built sqlite3 and the functions it reports. +type shell struct { + build build + binary string + rows []functionRow +} + +// readShell lists a build's functions, after checking that the shell was +// built with the options the build says — a cached shell from before the +// option lists changed would otherwise describe the wrong dialect. +func readShell(ctx context.Context, dir string, b build) (*shell, error) { + s := &shell{build: b, binary: b.binary(dir)} + if err := checkOptions(ctx, dir, b); err != nil { + return nil, err + } + if err := query(ctx, s.binary, functionList, &s.rows); err != nil { + return nil, err + } + return s, nil +} + +// checkOptions asks a build's shell whether it was compiled with every +// option any build turns on, and fails when the answers do not match the +// build's own list. +func checkOptions(ctx context.Context, dir string, b build) error { + var used []struct { + Option string `json:"option"` + Used int `json:"used"` + } + known := map[string]bool{} + for _, b := range shells() { + for _, opt := range b.flags() { + known[opt] = true + } + } + var clauses []string + for _, opt := range slices.Sorted(maps.Keys(known)) { + clauses = append(clauses, fmt.Sprintf("SELECT '%s' AS option, sqlite_compileoption_used('%s') AS used", opt, opt)) + } + if err := query(ctx, b.binary(dir), strings.Join(clauses, " UNION ALL "), &used); err != nil { + return err + } + for _, u := range used { + want := 0 + if slices.Contains(b.flags(), u.Option) { + want = 1 + } + if u.Used != want { + return fmt.Errorf("sqlite: the %s shell was not built with the options it should have been (%s is %d): remove %s and run `go run ./cmd/goldeneye install sqlite` again", b.name, u.Option, u.Used, filepath.Join(dir, b.name)) + } + } + return nil +} + +// generator accumulates the functions of every build, reading their +// signatures from the amalgamation, and remembers which names were +// reported so that the lists in signatures.go can be checked against the +// shells at the end. +type generator struct { + ctx context.Context + src *source + reported map[string]bool + // numeric holds every spelling types.jsonl gives integer and real, in + // its order, for the functions written once per spelling. + numeric map[string][]string +} + +// overload is one row of a shell's list with what was found out about it. +type overload struct { + row functionRow + kind string + sig signature +} + +// functions turns rows into records, one per overload. Every row has to be +// a function the amalgamation registers unless omitted. In the default +// build only what the library builds in counts: the rest is what the shell +// registers on top — edit, sha3, the extensions it bundles — which is not +// the dialect's business, and which a comparison with the default build has +// already removed from an option's rows. +func (g *generator) functions(s *shell, base bool) ([]dialect.Function, error) { + var overloads []overload + seen := map[string]bool{} + var missing []string + for _, row := range s.rows { + g.reported[row.Name] = true + if omitted[row.Name] || seen[row.key()] || base && row.Builtin == 0 { + continue + } + seen[row.key()] = true + sig, err := g.src.signature(row.Name) + if err != nil { + if !seen[row.Name] { + seen[row.Name] = true + missing = append(missing, err.Error()) + } + continue + } + kind, err := functionKind(g.ctx, s.binary, row) + if err != nil { + return nil, err + } + overloads = append(overloads, overload{row: row, kind: kind, sig: sig}) + } + if len(missing) > 0 { + return nil, fmt.Errorf("sqlite: %s build: %s", s.build.name, strings.Join(missing, "; ")) + } + empty, err := overNoRows(g.ctx, s.binary, overloads) + if err != nil { + return nil, err + } + funcs := make([]dialect.Function, 0, len(overloads)) + for _, o := range overloads { + isNullable := nullable[o.row.Name] + if o.kind == "a" { + isNullable = empty[o.row.key()] == "null" + } + fn := dialect.Function{ + Name: o.row.Name, + Kind: o.kind, + Args: o.sig.args(o.row.NArg), + Returns: o.sig.Returns, + Nullable: isNullable, + } + funcs = append(funcs, fn) + // A function that returns an integer for an integer and a real for + // a real is written once more per spelling of each, the way + // PostgreSQL's catalog has a sum per numeric type. The overload over + // any comes first: the analysis core picks the overload whose + // parameter is the argument's type, but the legacy compiler takes + // the first of the right arity, and keeps what it had. + if o.sig.Numeric && len(fn.Args) > 0 { + for _, typ := range []string{"integer", "real"} { + for _, spelling := range g.numeric[typ] { + typed := fn + typed.Args = append([]dialect.Arg{{Type: spelling}}, fn.Args[1:]...) + typed.Returns = typ + funcs = append(funcs, typed) + } + } + } + } + return funcs, nil +} + +// overNoRows runs every aggregate over no rows and reports the type of +// what each returns, "null" for the ones — avg, max, group_concat — that +// return NULL when there is nothing to aggregate, and not count or total. +// The probes go through one shell process, each statement labelled with +// its overload so that the answers can be told apart. +func overNoRows(ctx context.Context, binary string, overloads []overload) (map[string]string, error) { + var script strings.Builder + for _, o := range overloads { + if o.kind != "a" { + continue + } + n := o.row.NArg + if n < 0 { + n = minArgs(n) + } + args := strings.TrimSuffix(strings.Repeat("x, ", n), ", ") + fmt.Fprintf(&script, "SELECT '%s', typeof(%s(%s)) FROM (SELECT NULL AS x) WHERE 0;\n", o.row.key(), o.row.Name, args) + } + results := map[string]string{} + if script.Len() == 0 { + return results, nil + } + cmd := exec.CommandContext(ctx, binary, "-list", ":memory:", script.String()) + var stdout, stderr bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = &stderr + if err := cmd.Run(); err != nil { + var exit *exec.ExitError + if !errors.As(err, &exit) { + return nil, fmt.Errorf("sqlite3: %w", err) + } + } + for _, line := range strings.Split(strings.TrimSpace(stdout.String()), "\n") { + key, typ, ok := strings.Cut(line, "|") + if ok { + results[key] = typ + } + } + for _, o := range overloads { + if o.kind == "a" { + if _, ok := results[o.row.key()]; !ok { + return nil, fmt.Errorf("sqlite: cannot run %s over no rows: %s", o.row.Name, strings.TrimSpace(stderr.String())) + } + } + } + return results, nil +} + +// added returns the rows of an option's shell that the default shell does +// not have: what the option adds. +func added(opt, base *shell) *shell { + have := map[string]bool{} + for _, row := range base.rows { + have[row.key()] = true + } + diff := &shell{build: opt.build, binary: opt.binary} + for _, row := range opt.rows { + if !have[row.key()] { + diff.rows = append(diff.rows, row) + } + } + return diff +} + +// Generate reads the dialect from the shells under dir and the +// amalgamation they were built from. +func Generate(ctx context.Context, dir string) (dialect.Files, error) { + src, err := readSource(filepath.Join(dir, "src", "sqlite3.c")) + if err != nil { + return nil, err + } + g := &generator{ctx: ctx, src: src, reported: map[string]bool{}, numeric: map[string][]string{}} + dialectDir, err := dialect.Dir(Engine) + if err != nil { + return nil, err + } + types, err := dialect.ReadTypes(dialectDir) + if err != nil { + return nil, err + } + for _, t := range types { + if t.Name == "integer" || t.Name == "real" { + g.numeric[t.Name] = append([]string{t.Name}, t.Aliases...) + } + } + all := builds() + base, err := readShell(ctx, dir, all[0]) + if err != nil { + return nil, err + } + funcs, err := g.functions(base, true) + if err != nil { + return nil, err + } + files := dialect.Files{} + if files[dialect.FunctionsFile], err = dialect.JSONL(funcs); err != nil { + return nil, err + } + for _, b := range all[1:] { + s, err := readShell(ctx, dir, b) + if err != nil { + return nil, err + } + funcs, err := g.functions(added(s, base), false) + if err != nil { + return nil, err + } + if len(funcs) == 0 { + return nil, fmt.Errorf("sqlite: %s adds no functions over the default build; drop it from the extensions in install.go", strings.Join(b.options, " ")) + } + if files[path.Join(dialect.ExtensionsDir, b.name, dialect.FunctionsFile)], err = dialect.JSONL(funcs); err != nil { + return nil, err + } + } + var stale []string + for _, list := range []map[string]bool{omitted, nullable, realResults} { + for name := range list { + if !g.reported[name] { + stale = append(stale, name) + } + } + } + if len(stale) > 0 { + sort.Strings(stale) + return nil, fmt.Errorf("sqlite: signatures.go lists function(s) no shell reports: %s", strings.Join(stale, ", ")) + } + return files, nil +} diff --git a/internal/goldeneye/sqlite/sqlite_test.go b/internal/goldeneye/sqlite/sqlite_test.go new file mode 100644 index 0000000..8327090 --- /dev/null +++ b/internal/goldeneye/sqlite/sqlite_test.go @@ -0,0 +1,66 @@ +package sqlite + +import ( + "context" + "testing" + + "github.com/sqlc-dev/sqlc/internal/goldeneye/dialect" + "github.com/sqlc-dev/sqlc/internal/goldeneye/endtoend" +) + +// TestDialect verifies the committed SQLite dialect against what the pinned +// sqlite3 shell reports. It skips unless the shell is installed. +func TestDialect(t *testing.T) { + binary, err := Locate() + if err != nil { + t.Skip(err) + } + ctx := context.Background() + version, err := Version(ctx, binary) + if err != nil { + t.Fatal(err) + } + files, err := Generate(ctx, binary) + if err != nil { + t.Fatal(err) + } + dir, err := dialect.Dir(Engine) + if err != nil { + t.Fatal(err) + } + report, err := dialect.Check(dir, files) + if err != nil { + t.Fatal(err) + } + if report != "" { + t.Errorf("%s does not match what %s reports:\n%s", dir, version, report) + } +} + +// TestAnalyzeCases verifies every SQLite analyze case under +// internal/endtoend/testdata against what SQLite reports. It skips unless +// the shells are installed. +func TestAnalyzeCases(t *testing.T) { + dir, err := Locate() + if err != nil { + t.Skip(err) + } + cases, err := endtoend.Cases(Engine) + if err != nil { + t.Fatal(err) + } + if len(cases) == 0 { + t.Fatal("no sqlite analyze cases found") + } + for _, c := range cases { + t.Run(c.Name, func(t *testing.T) { + diff, err := Check(context.Background(), dir, c) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Errorf("%s does not match what SQLite reports (-committed +sqlite):\n%s", c.Output, diff) + } + }) + } +} diff --git a/internal/inflection/singular.go b/internal/inflection/singular.go new file mode 100644 index 0000000..64e042a --- /dev/null +++ b/internal/inflection/singular.go @@ -0,0 +1,52 @@ +package inflection + +import ( + "strings" + + upstream "github.com/jinzhu/inflection" +) + +type SingularParams struct { + Name string + Exclusions []string +} + +func Singular(s SingularParams) string { + for _, exclusion := range s.Exclusions { + if strings.EqualFold(s.Name, exclusion) { + return s.Name + } + } + + // Manual fix for incorrect handling of "campus" + // + // https://github.com/sqlc-dev/sqlc/issues/430 + // https://github.com/jinzhu/inflection/issues/13 + if strings.ToLower(s.Name) == "campus" { + return s.Name + } + // Manual fix for incorrect handling of "meta" + // + // https://github.com/sqlc-dev/sqlc/issues/1217 + // https://github.com/jinzhu/inflection/issues/21 + if strings.ToLower(s.Name) == "meta" { + return s.Name + } + // Manual fix for incorrect handling of "calories" + // + // https://github.com/sqlc-dev/sqlc/issues/2017 + // https://github.com/jinzhu/inflection/issues/23 + if strings.ToLower(s.Name) == "calories" { + return "calorie" + } + // Manual fix for incorrect handling of "-ves" suffix + if strings.ToLower(s.Name) == "waves" { + return "wave" + } + + if strings.ToLower(s.Name) == "metadata" { + return "metadata" + } + + return upstream.Singular(s.Name) +} diff --git a/internal/info/facts.go b/internal/info/facts.go new file mode 100644 index 0000000..934814e --- /dev/null +++ b/internal/info/facts.go @@ -0,0 +1,5 @@ +package info + +// When no version is set, return the next bug fix version +// after the most recent tag +const Version = "v1.31.1" diff --git a/internal/metadata/meta.go b/internal/metadata/meta.go new file mode 100644 index 0000000..76ee992 --- /dev/null +++ b/internal/metadata/meta.go @@ -0,0 +1,172 @@ +package metadata + +import ( + "bufio" + "fmt" + "github.com/sqlc-dev/sqlc/internal/constants" + "strings" + "unicode" + + "github.com/sqlc-dev/sqlc/internal/source" +) + +type CommentSyntax source.CommentSyntax + +type Metadata struct { + Name string + Cmd string + Comments []string + Params map[string]string + Flags map[string]bool + + // RuleSkiplist contains the names of rules to disable vetting for. + // If the map is empty, but the disable vet flag is specified, then all rules are ignored. + RuleSkiplist map[string]struct{} + + Filename string +} + +const ( + CmdExec = ":exec" + CmdExecResult = ":execresult" + CmdExecRows = ":execrows" + CmdExecLastId = ":execlastid" + CmdMany = ":many" + CmdOne = ":one" + CmdCopyFrom = ":copyfrom" + CmdBatchExec = ":batchexec" + CmdBatchMany = ":batchmany" + CmdBatchOne = ":batchone" +) + +// A query name must be a valid Go identifier +// +// https://golang.org/ref/spec#Identifiers +func validateQueryName(name string) error { + if len(name) == 0 { + return fmt.Errorf("invalid query name: %q", name) + } + for i, c := range name { + isLetter := unicode.IsLetter(c) || c == '_' + isDigit := unicode.IsDigit(c) + if i == 0 && !isLetter { + return fmt.Errorf("invalid query name %q", name) + } else if !(isLetter || isDigit) { + return fmt.Errorf("invalid query name %q", name) + } + } + return nil +} + +func ParseQueryNameAndType(t string, commentStyle CommentSyntax) (string, string, error) { + for line := range strings.SplitSeq(t, "\n") { + var prefix string + if strings.HasPrefix(line, "--") { + if !commentStyle.Dash { + continue + } + prefix = "--" + } + if strings.HasPrefix(line, "/*") { + if !commentStyle.SlashStar { + continue + } + prefix = "/*" + } + if strings.HasPrefix(line, "#") { + if !commentStyle.Hash { + continue + } + prefix = "#" + } + if prefix == "" { + continue + } + rest := line[len(prefix):] + if !strings.HasPrefix(strings.TrimSpace(rest), "name") { + continue + } + if !strings.Contains(rest, ":") { + continue + } + if !strings.HasPrefix(rest, " name: ") { + return "", "", fmt.Errorf("invalid metadata: %s", line) + } + + part := strings.Split(strings.TrimSpace(line), " ") + if prefix == "/*" { + part = part[:len(part)-1] // removes the trailing "*/" element + } + if len(part) == 3 { + return "", "", fmt.Errorf("missing query type [':one', ':many', ':exec', ':execrows', ':execlastid', ':execresult', ':copyfrom', 'batchexec', 'batchmany', 'batchone']: %s", line) + } + if len(part) != 4 { + return "", "", fmt.Errorf("invalid query comment: %s", line) + } + queryName := part[2] + queryType := strings.TrimSpace(part[3]) + switch queryType { + case CmdOne, CmdMany, CmdExec, CmdExecResult, CmdExecRows, CmdExecLastId, CmdCopyFrom, CmdBatchExec, CmdBatchMany, CmdBatchOne: + default: + return "", "", fmt.Errorf("invalid query type: %s", queryType) + } + if err := validateQueryName(queryName); err != nil { + return "", "", err + } + return queryName, queryType, nil + } + return "", "", nil +} + +// ParseCommentFlags processes the comments provided with queries to determine the metadata params, flags and rules to skip. +// All flags in query comments are prefixed with `@`, e.g. @param, @@sqlc-vet-disable. +func ParseCommentFlags(comments []string) (map[string]string, map[string]bool, map[string]struct{}, error) { + params := make(map[string]string) + flags := make(map[string]bool) + ruleSkiplist := make(map[string]struct{}) + + for _, line := range comments { + s := bufio.NewScanner(strings.NewReader(line)) + s.Split(bufio.ScanWords) + + s.Scan() + token := s.Text() + + if !strings.HasPrefix(token, "@") { + continue + } + + switch token { + case constants.QueryFlagParam: + s.Scan() + name := s.Text() + var rest []string + for s.Scan() { + paramToken := s.Text() + rest = append(rest, paramToken) + } + params[name] = strings.Join(rest, " ") + + case constants.QueryFlagSqlcVetDisable: + flags[token] = true + + // Vet rules can all be disabled in the same line or split across lines .i.e. + // /* @sqlc-vet-disable sqlc/db-prepare delete-without-where */ + // is equivalent to: + // /* @sqlc-vet-disable sqlc/db-prepare */ + // /* @sqlc-vet-disable delete-without-where */ + for s.Scan() { + ruleSkiplist[s.Text()] = struct{}{} + } + + default: + flags[token] = true + } + + if s.Err() != nil { + return params, flags, ruleSkiplist, s.Err() + } + } + + return params, flags, ruleSkiplist, nil +} diff --git a/internal/metadata/meta_test.go b/internal/metadata/meta_test.go new file mode 100644 index 0000000..e9ef545 --- /dev/null +++ b/internal/metadata/meta_test.go @@ -0,0 +1,182 @@ +package metadata + +import ( + "testing" +) + +func TestParseQueryNameAndType(t *testing.T) { + + for _, query := range []string{ + `-- name: CreateFoo, :one`, + `-- name: 9Foo_, :one`, + `-- name: CreateFoo :two`, + `-- name: CreateFoo`, + `-- name: CreateFoo :one something`, + `-- name: `, + `--name: CreateFoo :one`, + `--name CreateFoo :one`, + `--name: CreateFoo :two`, + "-- name:CreateFoo", + `--name:CreateFoo :two`, + } { + if _, _, err := ParseQueryNameAndType(query, CommentSyntax{Dash: true}); err == nil { + t.Errorf("expected invalid metadata: %q", query) + } + } + + for _, query := range []string{ + `-- some comment`, + `-- name comment`, + `--name comment`, + } { + if _, _, err := ParseQueryNameAndType(query, CommentSyntax{Dash: true}); err != nil { + t.Errorf("expected valid comment: %q", query) + } + } + + for query, cs := range map[string]CommentSyntax{ + `-- name: CreateFoo :one`: {Dash: true}, + `# name: CreateFoo :one`: {Hash: true}, + `/* name: CreateFoo :one */`: {SlashStar: true}, + } { + queryName, queryCmd, err := ParseQueryNameAndType(query, cs) + if err != nil { + t.Errorf("expected valid metadata: %q", query) + } + if queryName != "CreateFoo" { + t.Errorf("incorrect queryName parsed: (%q) %q", queryName, query) + } + if queryCmd != CmdOne { + t.Errorf("incorrect queryCmd parsed: (%q) %q", queryCmd, query) + } + } + +} + +func TestParseQueryParams(t *testing.T) { + for _, comments := range [][]string{ + { + " name: CreateFoo :one", + " @param foo_id UUID", + }, + { + " name: CreateFoo :one ", + " @param foo_id UUID ", + }, + { + " name: CreateFoo :one", + "@param foo_id UUID", + " invalid", + }, + { + " name: CreateFoo :one", + " @invalid", + " @param foo_id UUID", + }, + { + " name: GetFoos :many ", + " @param foo_id UUID ", + " @param @invalid UUID ", + }, + } { + params, _, _, err := ParseCommentFlags(comments) + if err != nil { + t.Errorf("expected comments to parse, got err: %s", err) + } + + pt, ok := params["foo_id"] + if !ok { + t.Errorf("expected param not found") + } + + if pt != "UUID" { + t.Error("unexpected param metadata:", pt) + } + + _, ok = params["invalid"] + if ok { + t.Errorf("unexpected param found") + } + } +} + +func TestParseQueryFlags(t *testing.T) { + for _, comments := range [][]string{ + { + " name: CreateFoo :one", + " @flag-foo", + }, + { + " name: CreateFoo :one ", + "@flag-foo ", + }, + { + " name: CreateFoo :one", + " @flag-foo @flag-bar", + }, + { + " name: GetFoos :many", + " @param @flag-bar UUID", + " @flag-foo", + }, + { + " name: GetFoos :many", + " @flag-foo", + " @param @flag-bar UUID", + }, + } { + _, flags, _, err := ParseCommentFlags(comments) + if err != nil { + t.Errorf("expected comments to parse, got err: %s", err) + } + + if !flags["@flag-foo"] { + t.Errorf("expected flag not found") + } + + if flags["@flag-bar"] { + t.Errorf("unexpected flag found") + } + } +} + +func TestParseQueryRuleSkiplist(t *testing.T) { + for _, comments := range [][]string{ + { + " name: CreateFoo :one", + " @sqlc-vet-disable sqlc/db-prepare delete-without-where ", + }, + { + " name: CreateFoo :one ", + " @sqlc-vet-disable sqlc/db-prepare ", + " @sqlc-vet-disable delete-without-where ", + }, + { + " name: CreateFoo :one", + " @sqlc-vet-disable sqlc/db-prepare ", + " update-without where", + " @sqlc-vet-disable delete-without-where ", + }, + } { + _, flags, ruleSkiplist, err := ParseCommentFlags(comments) + if err != nil { + t.Errorf("expected comments to parse, got err: %s", err) + } + + if !flags["@sqlc-vet-disable"] { + t.Errorf("expected @sqlc-vet-disable flag not found") + } + + if _, ok := ruleSkiplist["sqlc/db-prepare"]; !ok { + t.Errorf("expected rule not found in skiplist") + } + + if _, ok := ruleSkiplist["delete-without-where"]; !ok { + t.Errorf("expected rule not found in skiplist") + } + + if _, ok := ruleSkiplist["update-without-where"]; ok { + t.Errorf("unexpected rule found in skiplist") + } + } +} diff --git a/internal/migrations/migrations.go b/internal/migrations/migrations.go new file mode 100644 index 0000000..bd5da61 --- /dev/null +++ b/internal/migrations/migrations.go @@ -0,0 +1,62 @@ +package migrations + +import ( + "bufio" + "regexp" + "strings" +) + +// psqlMetaCommand matches a psql meta-command (a line that begins with a +// backslash followed by a command name). pg_dump emits these starting with +// PostgreSQL 17.6 / 16.10 / 15.14 / 14.19 / 13.22 (e.g. `\restrict KEY` and +// `\unrestrict KEY`), and sqlc's SQL parsers cannot handle them. +var psqlMetaCommand = regexp.MustCompile(`^\\[A-Za-z!?;][^\n]*$`) + +// Remove all lines after a rollback comment. +// +// goose: -- +goose Down +// sql-migrate: -- +migrate Down +// tern: ---- create above / drop below ---- +// dbmate: -- migrate:down +func RemoveRollbackStatements(contents string) string { + s := bufio.NewScanner(strings.NewReader(contents)) + var lines []string + for s.Scan() { + statement := strings.ToLower(s.Text()) + if strings.HasPrefix(statement, "-- +goose down") { + break + } + if strings.HasPrefix(statement, "-- +migrate down") { + break + } + if strings.HasPrefix(statement, "---- create above / drop below ----") { + break + } + if strings.HasPrefix(statement, "-- migrate:down") { + break + } + lines = append(lines, s.Text()) + } + return strings.Join(lines, "\n") +} + +// RemovePsqlMetaCommands strips psql meta-command lines (e.g. `\restrict KEY`, +// `\unrestrict KEY`, `\connect foo`) from SQL input. These are emitted by +// pg_dump but are not valid SQL, so they must be removed before parsing. +func RemovePsqlMetaCommands(contents string) string { + s := bufio.NewScanner(strings.NewReader(contents)) + var lines []string + for s.Scan() { + line := s.Text() + if psqlMetaCommand.MatchString(line) { + continue + } + lines = append(lines, line) + } + return strings.Join(lines, "\n") +} + +func IsDown(filename string) bool { + // Remove golang-migrate rollback files. + return strings.HasSuffix(filename, ".down.sql") +} diff --git a/internal/migrations/migrations_test.go b/internal/migrations/migrations_test.go new file mode 100644 index 0000000..1217674 --- /dev/null +++ b/internal/migrations/migrations_test.go @@ -0,0 +1,107 @@ +package migrations + +import ( + "testing" + + "github.com/google/go-cmp/cmp" +) + +const inputGoose = ` +-- +goose Up +ALTER TABLE archived_jobs ADD COLUMN expires_at TIMESTAMP WITH TIME ZONE; + +-- +goose Down +ALTER TABLE archived_jobs DROP COLUMN expires_at; +` + +const outputGoose = ` +-- +goose Up +ALTER TABLE archived_jobs ADD COLUMN expires_at TIMESTAMP WITH TIME ZONE; +` + +const inputMigrate = ` +-- +migrate Up +-- SQL in section 'Up' is executed when this migration is applied +CREATE TABLE people (id int); + +-- +migrate Down +-- SQL section 'Down' is executed when this migration is rolled back +DROP TABLE people; +` + +const outputMigrate = ` +-- +migrate Up +-- SQL in section 'Up' is executed when this migration is applied +CREATE TABLE people (id int); +` + +const inputTern = ` +-- Write your migrate up statements here +ALTER TABLE todo RENAME COLUMN done TO is_done; +---- create above / drop below ---- +ALTER TABLE todo RENAME COLUMN is_done TO done; +` + +const outputTern = ` +-- Write your migrate up statements here +ALTER TABLE todo RENAME COLUMN done TO is_done;` + +const inputDbmate = ` +-- migrate:up +CREATE TABLE foo (bar int); +-- migrate:down +DROP TABLE foo;` + +const outputDbmate = ` +-- migrate:up +CREATE TABLE foo (bar int);` + +const inputPsqlMeta = `\restrict auwherpfqaiuwrhgp + +CREATE TABLE foo (id int); + +\unrestrict auwherpfqaiuwrhgp +` + +const outputPsqlMeta = ` +CREATE TABLE foo (id int); +` + +func TestRemoveRollback(t *testing.T) { + if diff := cmp.Diff(outputGoose, RemoveRollbackStatements(inputGoose)); diff != "" { + t.Errorf("goose migration mismatch:\n%s", diff) + } + if diff := cmp.Diff(outputMigrate, RemoveRollbackStatements(inputMigrate)); diff != "" { + t.Errorf("sql-migrate migration mismatch:\n%s", diff) + } + if diff := cmp.Diff(outputTern, RemoveRollbackStatements(inputTern)); diff != "" { + t.Errorf("tern migration mismatch:\n%s", diff) + } + if diff := cmp.Diff(outputDbmate, RemoveRollbackStatements(inputDbmate)); diff != "" { + t.Errorf("dbmate migration mismatch:\n%s", diff) + } +} + +func TestRemovePsqlMetaCommands(t *testing.T) { + if diff := cmp.Diff(outputPsqlMeta, RemovePsqlMetaCommands(inputPsqlMeta)); diff != "" { + t.Errorf("psql meta-command mismatch:\n%s", diff) + } +} + +func TestRemoveGolangMigrateRollback(t *testing.T) { + filenames := map[string]bool{ + // make sure we let through golang-migrate files that aren't rollbacks + "migrations/1.up.sql": false, + // make sure we let through other sql files + "migrations/2.sql": false, + "migrations/foo.sql": false, + "migrations/1.down.sql": true, + } + + for filename, want := range filenames { + got := IsDown(filename) + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("IsDown mismatch: %s\n %s", filename, diff) + } + } +} diff --git a/internal/multierr/error.go b/internal/multierr/error.go new file mode 100644 index 0000000..433a24b --- /dev/null +++ b/internal/multierr/error.go @@ -0,0 +1,52 @@ +package multierr + +import ( + "fmt" + + "github.com/sqlc-dev/sqlc/internal/source" + "github.com/sqlc-dev/sqlc/internal/sql/sqlerr" +) + +type FileError struct { + Filename string + Line int + Column int + Err error +} + +func (e *FileError) Unwrap() error { + return e.Err +} + +type Error struct { + errs []*FileError +} + +func (e *Error) Add(filename, in string, loc int, err error) { + line := 1 + column := 1 + if lerr, ok := err.(*sqlerr.Error); ok { + if lerr.Location != 0 { + loc = lerr.Location + } else if lerr.Line != 0 && lerr.Column != 0 { + line = lerr.Line + column = lerr.Column + } + } + if in != "" && loc != 0 { + line, column = source.LineNumber(in, loc) + } + e.errs = append(e.errs, &FileError{filename, line, column, err}) +} + +func (e *Error) Errs() []*FileError { + return e.errs +} + +func (e *Error) Error() string { + return fmt.Sprintf("multiple errors: %d errors", len(e.errs)) +} + +func New() *Error { + return &Error{} +} diff --git a/internal/opts/experiment.go b/internal/opts/experiment.go new file mode 100644 index 0000000..8d4b1c1 --- /dev/null +++ b/internal/opts/experiment.go @@ -0,0 +1,105 @@ +package opts + +import ( + "os" + "strings" +) + +// The SQLCEXPERIMENT variable controls experimental features within sqlc. It +// is a comma-separated list of experiment names. Experiment names can be +// prefixed with "no" to explicitly disable them. +// +// This is modeled after Go's GOEXPERIMENT environment variable. For more +// information, see https://pkg.go.dev/internal/goexperiment +// +// Available experiments: +// +// coreanalyzer - routes generate through the core catalog and analyzer +// +// Example usage: +// +// SQLCEXPERIMENT=foo,bar # enable foo and bar experiments +// SQLCEXPERIMENT=nofoo # explicitly disable foo experiment +// SQLCEXPERIMENT=foo,nobar # enable foo, disable bar + +// Experiment holds the state of all experimental features. +// Add new experiments as boolean fields to this struct. +type Experiment struct { + // CoreAnalyzer routes generate through the core catalog and analyzer + // instead of each engine's own analysis path. + CoreAnalyzer bool +} + +// ExperimentFromEnv returns an Experiment initialized from the SQLCEXPERIMENT +// environment variable. +func ExperimentFromEnv() Experiment { + return ExperimentFromString(os.Getenv("SQLCEXPERIMENT")) +} + +// ExperimentFromString parses a comma-separated list of experiment names +// and returns an Experiment with the appropriate flags set. +// +// Experiment names can be prefixed with "no" to explicitly disable them. +// Unknown experiment names are silently ignored. +func ExperimentFromString(val string) Experiment { + e := Experiment{} + if val == "" { + return e + } + + for name := range strings.SplitSeq(val, ",") { + name = strings.TrimSpace(name) + if name == "" { + continue + } + + // Check if this is a negation (noFoo) + enabled := true + if strings.HasPrefix(strings.ToLower(name), "no") && len(name) > 2 { + // Could be a negation, check if the rest is a valid experiment + possibleExp := name[2:] + if isKnownExperiment(possibleExp) { + name = possibleExp + enabled = false + } + // If not a known experiment, treat "no..." as a potential experiment name itself + } + + setExperiment(&e, name, enabled) + } + + return e +} + +// isKnownExperiment returns true if the given name (case-insensitive) is a +// known experiment. +func isKnownExperiment(name string) bool { + switch strings.ToLower(name) { + case "coreanalyzer": + return true + default: + return false + } +} + +// setExperiment sets the experiment flag with the given name to the given value. +func setExperiment(e *Experiment, name string, enabled bool) { + switch strings.ToLower(name) { + case "coreanalyzer": + e.CoreAnalyzer = enabled + } +} + +// Enabled returns a slice of all enabled experiment names. +func (e Experiment) Enabled() []string { + var enabled []string + if e.CoreAnalyzer { + enabled = append(enabled, "coreanalyzer") + } + return enabled +} + +// String returns a comma-separated list of enabled experiments. +func (e Experiment) String() string { + return strings.Join(e.Enabled(), ",") +} diff --git a/internal/opts/experiment_test.go b/internal/opts/experiment_test.go new file mode 100644 index 0000000..b64204b --- /dev/null +++ b/internal/opts/experiment_test.go @@ -0,0 +1,155 @@ +package opts + +import "testing" + +func TestExperimentFromString(t *testing.T) { + tests := []struct { + name string + input string + want Experiment + }{ + { + name: "empty string", + input: "", + want: Experiment{}, + }, + { + name: "whitespace only", + input: " ", + want: Experiment{}, + }, + { + name: "unknown experiment", + input: "unknownexperiment", + want: Experiment{}, + }, + { + name: "multiple unknown experiments", + input: "foo,bar,baz", + want: Experiment{}, + }, + { + name: "unknown with no prefix", + input: "nounknown", + want: Experiment{}, + }, + { + name: "whitespace around experiments", + input: " foo , bar , baz ", + want: Experiment{}, + }, + { + name: "empty items in list", + input: "foo,,bar", + want: Experiment{}, + }, + { + name: "enable coreanalyzer", + input: "coreanalyzer", + want: Experiment{CoreAnalyzer: true}, + }, + { + name: "disable coreanalyzer", + input: "nocoreanalyzer", + want: Experiment{CoreAnalyzer: false}, + }, + { + name: "enable then disable coreanalyzer", + input: "coreanalyzer,nocoreanalyzer", + want: Experiment{CoreAnalyzer: false}, + }, + { + name: "coreanalyzer case insensitive", + input: "CoreAnalyzer", + want: Experiment{CoreAnalyzer: true}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := ExperimentFromString(tt.input) + if got != tt.want { + t.Errorf("ExperimentFromString(%q) = %+v, want %+v", tt.input, got, tt.want) + } + }) + } +} + +func TestExperimentEnabled(t *testing.T) { + tests := []struct { + name string + exp Experiment + want []string + }{ + { + name: "no experiments enabled", + exp: Experiment{}, + want: nil, + }, + { + name: "coreanalyzer enabled", + exp: Experiment{CoreAnalyzer: true}, + want: []string{"coreanalyzer"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := tt.exp.Enabled() + if len(got) != len(tt.want) { + t.Errorf("Experiment.Enabled() = %v, want %v", got, tt.want) + return + } + for i := range got { + if got[i] != tt.want[i] { + t.Errorf("Experiment.Enabled()[%d] = %q, want %q", i, got[i], tt.want[i]) + } + } + }) + } +} + +func TestExperimentString(t *testing.T) { + exp := Experiment{} + if got := exp.String(); got != "" { + t.Errorf("Experiment.String() = %q, want %q", got, "") + } +} + +func TestIsKnownExperiment(t *testing.T) { + tests := []struct { + name string + input string + want bool + }{ + { + name: "unknown experiment", + input: "unknown", + want: false, + }, + { + name: "empty string", + input: "", + want: false, + }, + { + name: "coreanalyzer lowercase", + input: "coreanalyzer", + want: true, + }, + { + name: "coreanalyzer mixed case", + input: "CoreAnalyzer", + want: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := isKnownExperiment(tt.input) + if got != tt.want { + t.Errorf("isKnownExperiment(%q) = %v, want %v", tt.input, got, tt.want) + } + }) + } +} diff --git a/internal/opts/parser.go b/internal/opts/parser.go new file mode 100644 index 0000000..69112dc --- /dev/null +++ b/internal/opts/parser.go @@ -0,0 +1,5 @@ +package opts + +type Parser struct { + Experiment Experiment +} diff --git a/internal/pattern/match.go b/internal/pattern/match.go new file mode 100644 index 0000000..c72663d --- /dev/null +++ b/internal/pattern/match.go @@ -0,0 +1,86 @@ +package pattern + +import ( + "fmt" + "regexp" + "strings" + "sync" +) + +// Match is a wrapper of *regexp.Regexp. +// It contains the match pattern compiled into a regular expression. +type Match struct { + *regexp.Regexp +} + +var ( + matchCache = make(map[string]*Match) + matchCacheLock sync.RWMutex +) + +// Compile takes our match expression as a string, and compiles it into a *Match object. +// Will return an error on an invalid pattern. +func MatchCompile(pattern string) (*Match, error) { + // check for pattern in cache + matchCacheLock.RLock() + matcher, ok := matchCache[pattern] + matchCacheLock.RUnlock() + if ok { + return matcher, nil + } + + // pattern isn't in cache, compile it + matcher, err := matchCompile(pattern) + if err != nil { + return nil, err + } + // add it to the cache + matchCacheLock.Lock() + matchCache[pattern] = matcher + matchCacheLock.Unlock() + + return matcher, nil +} + +func matchCompile(pattern string) (match *Match, err error) { + var regex strings.Builder + escaped := false + arr := []byte(pattern) + + for i := range arr { + if escaped { + escaped = false + switch arr[i] { + case '*', '?', '\\': + regex.WriteString("\\" + string(arr[i])) + default: + return nil, fmt.Errorf("Invalid escaped character '%c'", arr[i]) + } + } else { + switch arr[i] { + case '\\': + escaped = true + case '*': + regex.WriteString(".*") + case '?': + regex.WriteString(".") + case '.', '(', ')', '+', '|', '^', '$', '[', ']', '{', '}': + regex.WriteString("\\" + string(arr[i])) + default: + regex.WriteString(string(arr[i])) + } + } + } + + if escaped { + return nil, fmt.Errorf("Unterminated escape at end of pattern") + } + + var r *regexp.Regexp + + if r, err = regexp.Compile("^" + regex.String() + "$"); err != nil { + return nil, err + } + + return &Match{r}, nil +} diff --git a/internal/pgx/poolcache/poolcache.go b/internal/pgx/poolcache/poolcache.go new file mode 100644 index 0000000..3fce3cb --- /dev/null +++ b/internal/pgx/poolcache/poolcache.go @@ -0,0 +1,61 @@ +package poolcache + +import ( + "context" + "fmt" + "sync" + + "github.com/jackc/pgx/v5/pgxpool" +) + +type Cache struct { + lock sync.RWMutex + closed bool + pools map[string]*pgxpool.Pool +} + +func New() *Cache { + return &Cache{ + pools: map[string]*pgxpool.Pool{}, + } +} + +func (c *Cache) Open(ctx context.Context, uri string) (*pgxpool.Pool, error) { + if c.closed { + return nil, fmt.Errorf("poolcache is closed") + } + + c.lock.RLock() + existing, found := c.pools[uri] + c.lock.RUnlock() + + if found { + return existing, nil + } + + pool, err := pgxpool.New(ctx, uri) + if err != nil { + return nil, err + } + + c.lock.Lock() + c.pools[uri] = pool + c.lock.Unlock() + + return pool, nil +} + +func (c *Cache) Close() error { + c.lock.Lock() + defer c.lock.Unlock() + + var closeErr error + for _, pool := range c.pools { + pool.Close() + } + + c.closed = true + clear(c.pools) + + return closeErr +} diff --git a/internal/plugin/codegen.pb.go b/internal/plugin/codegen.pb.go new file mode 100644 index 0000000..525ffc7 --- /dev/null +++ b/internal/plugin/codegen.pb.go @@ -0,0 +1,1648 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.30.0 +// protoc (unknown) +// source: plugin/codegen.proto + +package plugin + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type File struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Contents []byte `protobuf:"bytes,2,opt,name=contents,proto3" json:"contents,omitempty"` +} + +func (x *File) Reset() { + *x = File{} + if protoimpl.UnsafeEnabled { + mi := &file_plugin_codegen_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *File) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*File) ProtoMessage() {} + +func (x *File) ProtoReflect() protoreflect.Message { + mi := &file_plugin_codegen_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use File.ProtoReflect.Descriptor instead. +func (*File) Descriptor() ([]byte, []int) { + return file_plugin_codegen_proto_rawDescGZIP(), []int{0} +} + +func (x *File) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *File) GetContents() []byte { + if x != nil { + return x.Contents + } + return nil +} + +type Settings struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` + Engine string `protobuf:"bytes,2,opt,name=engine,proto3" json:"engine,omitempty"` + Schema []string `protobuf:"bytes,3,rep,name=schema,proto3" json:"schema,omitempty"` + Queries []string `protobuf:"bytes,4,rep,name=queries,proto3" json:"queries,omitempty"` + Codegen *Codegen `protobuf:"bytes,12,opt,name=codegen,proto3" json:"codegen,omitempty"` +} + +func (x *Settings) Reset() { + *x = Settings{} + if protoimpl.UnsafeEnabled { + mi := &file_plugin_codegen_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Settings) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Settings) ProtoMessage() {} + +func (x *Settings) ProtoReflect() protoreflect.Message { + mi := &file_plugin_codegen_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Settings.ProtoReflect.Descriptor instead. +func (*Settings) Descriptor() ([]byte, []int) { + return file_plugin_codegen_proto_rawDescGZIP(), []int{1} +} + +func (x *Settings) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *Settings) GetEngine() string { + if x != nil { + return x.Engine + } + return "" +} + +func (x *Settings) GetSchema() []string { + if x != nil { + return x.Schema + } + return nil +} + +func (x *Settings) GetQueries() []string { + if x != nil { + return x.Queries + } + return nil +} + +func (x *Settings) GetCodegen() *Codegen { + if x != nil { + return x.Codegen + } + return nil +} + +type Codegen struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Out string `protobuf:"bytes,1,opt,name=out,proto3" json:"out,omitempty"` + Plugin string `protobuf:"bytes,2,opt,name=plugin,proto3" json:"plugin,omitempty"` + Options []byte `protobuf:"bytes,3,opt,name=options,proto3" json:"options,omitempty"` + Env []string `protobuf:"bytes,4,rep,name=env,proto3" json:"env,omitempty"` + Process *Codegen_Process `protobuf:"bytes,5,opt,name=process,proto3" json:"process,omitempty"` + Wasm *Codegen_WASM `protobuf:"bytes,6,opt,name=wasm,proto3" json:"wasm,omitempty"` +} + +func (x *Codegen) Reset() { + *x = Codegen{} + if protoimpl.UnsafeEnabled { + mi := &file_plugin_codegen_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Codegen) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Codegen) ProtoMessage() {} + +func (x *Codegen) ProtoReflect() protoreflect.Message { + mi := &file_plugin_codegen_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Codegen.ProtoReflect.Descriptor instead. +func (*Codegen) Descriptor() ([]byte, []int) { + return file_plugin_codegen_proto_rawDescGZIP(), []int{2} +} + +func (x *Codegen) GetOut() string { + if x != nil { + return x.Out + } + return "" +} + +func (x *Codegen) GetPlugin() string { + if x != nil { + return x.Plugin + } + return "" +} + +func (x *Codegen) GetOptions() []byte { + if x != nil { + return x.Options + } + return nil +} + +func (x *Codegen) GetEnv() []string { + if x != nil { + return x.Env + } + return nil +} + +func (x *Codegen) GetProcess() *Codegen_Process { + if x != nil { + return x.Process + } + return nil +} + +func (x *Codegen) GetWasm() *Codegen_WASM { + if x != nil { + return x.Wasm + } + return nil +} + +type Catalog struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Comment string `protobuf:"bytes,1,opt,name=comment,proto3" json:"comment,omitempty"` + DefaultSchema string `protobuf:"bytes,2,opt,name=default_schema,json=defaultSchema,proto3" json:"default_schema,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + Schemas []*Schema `protobuf:"bytes,4,rep,name=schemas,proto3" json:"schemas,omitempty"` +} + +func (x *Catalog) Reset() { + *x = Catalog{} + if protoimpl.UnsafeEnabled { + mi := &file_plugin_codegen_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Catalog) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Catalog) ProtoMessage() {} + +func (x *Catalog) ProtoReflect() protoreflect.Message { + mi := &file_plugin_codegen_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Catalog.ProtoReflect.Descriptor instead. +func (*Catalog) Descriptor() ([]byte, []int) { + return file_plugin_codegen_proto_rawDescGZIP(), []int{3} +} + +func (x *Catalog) GetComment() string { + if x != nil { + return x.Comment + } + return "" +} + +func (x *Catalog) GetDefaultSchema() string { + if x != nil { + return x.DefaultSchema + } + return "" +} + +func (x *Catalog) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Catalog) GetSchemas() []*Schema { + if x != nil { + return x.Schemas + } + return nil +} + +type Schema struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Comment string `protobuf:"bytes,1,opt,name=comment,proto3" json:"comment,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Tables []*Table `protobuf:"bytes,3,rep,name=tables,proto3" json:"tables,omitempty"` + Enums []*Enum `protobuf:"bytes,4,rep,name=enums,proto3" json:"enums,omitempty"` + CompositeTypes []*CompositeType `protobuf:"bytes,5,rep,name=composite_types,json=compositeTypes,proto3" json:"composite_types,omitempty"` +} + +func (x *Schema) Reset() { + *x = Schema{} + if protoimpl.UnsafeEnabled { + mi := &file_plugin_codegen_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Schema) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Schema) ProtoMessage() {} + +func (x *Schema) ProtoReflect() protoreflect.Message { + mi := &file_plugin_codegen_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Schema.ProtoReflect.Descriptor instead. +func (*Schema) Descriptor() ([]byte, []int) { + return file_plugin_codegen_proto_rawDescGZIP(), []int{4} +} + +func (x *Schema) GetComment() string { + if x != nil { + return x.Comment + } + return "" +} + +func (x *Schema) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Schema) GetTables() []*Table { + if x != nil { + return x.Tables + } + return nil +} + +func (x *Schema) GetEnums() []*Enum { + if x != nil { + return x.Enums + } + return nil +} + +func (x *Schema) GetCompositeTypes() []*CompositeType { + if x != nil { + return x.CompositeTypes + } + return nil +} + +type CompositeType struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Comment string `protobuf:"bytes,2,opt,name=comment,proto3" json:"comment,omitempty"` +} + +func (x *CompositeType) Reset() { + *x = CompositeType{} + if protoimpl.UnsafeEnabled { + mi := &file_plugin_codegen_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CompositeType) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CompositeType) ProtoMessage() {} + +func (x *CompositeType) ProtoReflect() protoreflect.Message { + mi := &file_plugin_codegen_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CompositeType.ProtoReflect.Descriptor instead. +func (*CompositeType) Descriptor() ([]byte, []int) { + return file_plugin_codegen_proto_rawDescGZIP(), []int{5} +} + +func (x *CompositeType) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *CompositeType) GetComment() string { + if x != nil { + return x.Comment + } + return "" +} + +type Enum struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Vals []string `protobuf:"bytes,2,rep,name=vals,proto3" json:"vals,omitempty"` + Comment string `protobuf:"bytes,3,opt,name=comment,proto3" json:"comment,omitempty"` +} + +func (x *Enum) Reset() { + *x = Enum{} + if protoimpl.UnsafeEnabled { + mi := &file_plugin_codegen_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Enum) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Enum) ProtoMessage() {} + +func (x *Enum) ProtoReflect() protoreflect.Message { + mi := &file_plugin_codegen_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Enum.ProtoReflect.Descriptor instead. +func (*Enum) Descriptor() ([]byte, []int) { + return file_plugin_codegen_proto_rawDescGZIP(), []int{6} +} + +func (x *Enum) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Enum) GetVals() []string { + if x != nil { + return x.Vals + } + return nil +} + +func (x *Enum) GetComment() string { + if x != nil { + return x.Comment + } + return "" +} + +type Table struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Rel *Identifier `protobuf:"bytes,1,opt,name=rel,proto3" json:"rel,omitempty"` + Columns []*Column `protobuf:"bytes,2,rep,name=columns,proto3" json:"columns,omitempty"` + Comment string `protobuf:"bytes,3,opt,name=comment,proto3" json:"comment,omitempty"` +} + +func (x *Table) Reset() { + *x = Table{} + if protoimpl.UnsafeEnabled { + mi := &file_plugin_codegen_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Table) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Table) ProtoMessage() {} + +func (x *Table) ProtoReflect() protoreflect.Message { + mi := &file_plugin_codegen_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Table.ProtoReflect.Descriptor instead. +func (*Table) Descriptor() ([]byte, []int) { + return file_plugin_codegen_proto_rawDescGZIP(), []int{7} +} + +func (x *Table) GetRel() *Identifier { + if x != nil { + return x.Rel + } + return nil +} + +func (x *Table) GetColumns() []*Column { + if x != nil { + return x.Columns + } + return nil +} + +func (x *Table) GetComment() string { + if x != nil { + return x.Comment + } + return "" +} + +type Identifier struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Catalog string `protobuf:"bytes,1,opt,name=catalog,proto3" json:"catalog,omitempty"` + Schema string `protobuf:"bytes,2,opt,name=schema,proto3" json:"schema,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *Identifier) Reset() { + *x = Identifier{} + if protoimpl.UnsafeEnabled { + mi := &file_plugin_codegen_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Identifier) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Identifier) ProtoMessage() {} + +func (x *Identifier) ProtoReflect() protoreflect.Message { + mi := &file_plugin_codegen_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Identifier.ProtoReflect.Descriptor instead. +func (*Identifier) Descriptor() ([]byte, []int) { + return file_plugin_codegen_proto_rawDescGZIP(), []int{8} +} + +func (x *Identifier) GetCatalog() string { + if x != nil { + return x.Catalog + } + return "" +} + +func (x *Identifier) GetSchema() string { + if x != nil { + return x.Schema + } + return "" +} + +func (x *Identifier) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type Column struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + NotNull bool `protobuf:"varint,3,opt,name=not_null,json=notNull,proto3" json:"not_null,omitempty"` + IsArray bool `protobuf:"varint,4,opt,name=is_array,json=isArray,proto3" json:"is_array,omitempty"` + Comment string `protobuf:"bytes,5,opt,name=comment,proto3" json:"comment,omitempty"` + Length int32 `protobuf:"varint,6,opt,name=length,proto3" json:"length,omitempty"` + IsNamedParam bool `protobuf:"varint,7,opt,name=is_named_param,json=isNamedParam,proto3" json:"is_named_param,omitempty"` + IsFuncCall bool `protobuf:"varint,8,opt,name=is_func_call,json=isFuncCall,proto3" json:"is_func_call,omitempty"` + // XXX: Figure out what PostgreSQL calls `foo.id` + Scope string `protobuf:"bytes,9,opt,name=scope,proto3" json:"scope,omitempty"` + Table *Identifier `protobuf:"bytes,10,opt,name=table,proto3" json:"table,omitempty"` + TableAlias string `protobuf:"bytes,11,opt,name=table_alias,json=tableAlias,proto3" json:"table_alias,omitempty"` + Type *Identifier `protobuf:"bytes,12,opt,name=type,proto3" json:"type,omitempty"` + IsSqlcSlice bool `protobuf:"varint,13,opt,name=is_sqlc_slice,json=isSqlcSlice,proto3" json:"is_sqlc_slice,omitempty"` + EmbedTable *Identifier `protobuf:"bytes,14,opt,name=embed_table,json=embedTable,proto3" json:"embed_table,omitempty"` + OriginalName string `protobuf:"bytes,15,opt,name=original_name,json=originalName,proto3" json:"original_name,omitempty"` + Unsigned bool `protobuf:"varint,16,opt,name=unsigned,proto3" json:"unsigned,omitempty"` + ArrayDims int32 `protobuf:"varint,17,opt,name=array_dims,json=arrayDims,proto3" json:"array_dims,omitempty"` +} + +func (x *Column) Reset() { + *x = Column{} + if protoimpl.UnsafeEnabled { + mi := &file_plugin_codegen_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Column) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Column) ProtoMessage() {} + +func (x *Column) ProtoReflect() protoreflect.Message { + mi := &file_plugin_codegen_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Column.ProtoReflect.Descriptor instead. +func (*Column) Descriptor() ([]byte, []int) { + return file_plugin_codegen_proto_rawDescGZIP(), []int{9} +} + +func (x *Column) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Column) GetNotNull() bool { + if x != nil { + return x.NotNull + } + return false +} + +func (x *Column) GetIsArray() bool { + if x != nil { + return x.IsArray + } + return false +} + +func (x *Column) GetComment() string { + if x != nil { + return x.Comment + } + return "" +} + +func (x *Column) GetLength() int32 { + if x != nil { + return x.Length + } + return 0 +} + +func (x *Column) GetIsNamedParam() bool { + if x != nil { + return x.IsNamedParam + } + return false +} + +func (x *Column) GetIsFuncCall() bool { + if x != nil { + return x.IsFuncCall + } + return false +} + +func (x *Column) GetScope() string { + if x != nil { + return x.Scope + } + return "" +} + +func (x *Column) GetTable() *Identifier { + if x != nil { + return x.Table + } + return nil +} + +func (x *Column) GetTableAlias() string { + if x != nil { + return x.TableAlias + } + return "" +} + +func (x *Column) GetType() *Identifier { + if x != nil { + return x.Type + } + return nil +} + +func (x *Column) GetIsSqlcSlice() bool { + if x != nil { + return x.IsSqlcSlice + } + return false +} + +func (x *Column) GetEmbedTable() *Identifier { + if x != nil { + return x.EmbedTable + } + return nil +} + +func (x *Column) GetOriginalName() string { + if x != nil { + return x.OriginalName + } + return "" +} + +func (x *Column) GetUnsigned() bool { + if x != nil { + return x.Unsigned + } + return false +} + +func (x *Column) GetArrayDims() int32 { + if x != nil { + return x.ArrayDims + } + return 0 +} + +type Query struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Cmd string `protobuf:"bytes,3,opt,name=cmd,proto3" json:"cmd,omitempty"` + Columns []*Column `protobuf:"bytes,4,rep,name=columns,proto3" json:"columns,omitempty"` + Params []*Parameter `protobuf:"bytes,5,rep,name=params,json=parameters,proto3" json:"params,omitempty"` + Comments []string `protobuf:"bytes,6,rep,name=comments,proto3" json:"comments,omitempty"` + Filename string `protobuf:"bytes,7,opt,name=filename,proto3" json:"filename,omitempty"` + InsertIntoTable *Identifier `protobuf:"bytes,8,opt,name=insert_into_table,proto3" json:"insert_into_table,omitempty"` +} + +func (x *Query) Reset() { + *x = Query{} + if protoimpl.UnsafeEnabled { + mi := &file_plugin_codegen_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Query) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Query) ProtoMessage() {} + +func (x *Query) ProtoReflect() protoreflect.Message { + mi := &file_plugin_codegen_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Query.ProtoReflect.Descriptor instead. +func (*Query) Descriptor() ([]byte, []int) { + return file_plugin_codegen_proto_rawDescGZIP(), []int{10} +} + +func (x *Query) GetText() string { + if x != nil { + return x.Text + } + return "" +} + +func (x *Query) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Query) GetCmd() string { + if x != nil { + return x.Cmd + } + return "" +} + +func (x *Query) GetColumns() []*Column { + if x != nil { + return x.Columns + } + return nil +} + +func (x *Query) GetParams() []*Parameter { + if x != nil { + return x.Params + } + return nil +} + +func (x *Query) GetComments() []string { + if x != nil { + return x.Comments + } + return nil +} + +func (x *Query) GetFilename() string { + if x != nil { + return x.Filename + } + return "" +} + +func (x *Query) GetInsertIntoTable() *Identifier { + if x != nil { + return x.InsertIntoTable + } + return nil +} + +type Parameter struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Number int32 `protobuf:"varint,1,opt,name=number,proto3" json:"number,omitempty"` + Column *Column `protobuf:"bytes,2,opt,name=column,proto3" json:"column,omitempty"` +} + +func (x *Parameter) Reset() { + *x = Parameter{} + if protoimpl.UnsafeEnabled { + mi := &file_plugin_codegen_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Parameter) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Parameter) ProtoMessage() {} + +func (x *Parameter) ProtoReflect() protoreflect.Message { + mi := &file_plugin_codegen_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Parameter.ProtoReflect.Descriptor instead. +func (*Parameter) Descriptor() ([]byte, []int) { + return file_plugin_codegen_proto_rawDescGZIP(), []int{11} +} + +func (x *Parameter) GetNumber() int32 { + if x != nil { + return x.Number + } + return 0 +} + +func (x *Parameter) GetColumn() *Column { + if x != nil { + return x.Column + } + return nil +} + +type GenerateRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Settings *Settings `protobuf:"bytes,1,opt,name=settings,proto3" json:"settings,omitempty"` + Catalog *Catalog `protobuf:"bytes,2,opt,name=catalog,proto3" json:"catalog,omitempty"` + Queries []*Query `protobuf:"bytes,3,rep,name=queries,proto3" json:"queries,omitempty"` + SqlcVersion string `protobuf:"bytes,4,opt,name=sqlc_version,proto3" json:"sqlc_version,omitempty"` + PluginOptions []byte `protobuf:"bytes,5,opt,name=plugin_options,proto3" json:"plugin_options,omitempty"` + GlobalOptions []byte `protobuf:"bytes,6,opt,name=global_options,proto3" json:"global_options,omitempty"` +} + +func (x *GenerateRequest) Reset() { + *x = GenerateRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_plugin_codegen_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GenerateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GenerateRequest) ProtoMessage() {} + +func (x *GenerateRequest) ProtoReflect() protoreflect.Message { + mi := &file_plugin_codegen_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GenerateRequest.ProtoReflect.Descriptor instead. +func (*GenerateRequest) Descriptor() ([]byte, []int) { + return file_plugin_codegen_proto_rawDescGZIP(), []int{12} +} + +func (x *GenerateRequest) GetSettings() *Settings { + if x != nil { + return x.Settings + } + return nil +} + +func (x *GenerateRequest) GetCatalog() *Catalog { + if x != nil { + return x.Catalog + } + return nil +} + +func (x *GenerateRequest) GetQueries() []*Query { + if x != nil { + return x.Queries + } + return nil +} + +func (x *GenerateRequest) GetSqlcVersion() string { + if x != nil { + return x.SqlcVersion + } + return "" +} + +func (x *GenerateRequest) GetPluginOptions() []byte { + if x != nil { + return x.PluginOptions + } + return nil +} + +func (x *GenerateRequest) GetGlobalOptions() []byte { + if x != nil { + return x.GlobalOptions + } + return nil +} + +type GenerateResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Files []*File `protobuf:"bytes,1,rep,name=files,proto3" json:"files,omitempty"` +} + +func (x *GenerateResponse) Reset() { + *x = GenerateResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_plugin_codegen_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GenerateResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GenerateResponse) ProtoMessage() {} + +func (x *GenerateResponse) ProtoReflect() protoreflect.Message { + mi := &file_plugin_codegen_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GenerateResponse.ProtoReflect.Descriptor instead. +func (*GenerateResponse) Descriptor() ([]byte, []int) { + return file_plugin_codegen_proto_rawDescGZIP(), []int{13} +} + +func (x *GenerateResponse) GetFiles() []*File { + if x != nil { + return x.Files + } + return nil +} + +type Codegen_Process struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Cmd string `protobuf:"bytes,1,opt,name=cmd,proto3" json:"cmd,omitempty"` +} + +func (x *Codegen_Process) Reset() { + *x = Codegen_Process{} + if protoimpl.UnsafeEnabled { + mi := &file_plugin_codegen_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Codegen_Process) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Codegen_Process) ProtoMessage() {} + +func (x *Codegen_Process) ProtoReflect() protoreflect.Message { + mi := &file_plugin_codegen_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Codegen_Process.ProtoReflect.Descriptor instead. +func (*Codegen_Process) Descriptor() ([]byte, []int) { + return file_plugin_codegen_proto_rawDescGZIP(), []int{2, 0} +} + +func (x *Codegen_Process) GetCmd() string { + if x != nil { + return x.Cmd + } + return "" +} + +type Codegen_WASM struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` + Sha256 string `protobuf:"bytes,2,opt,name=sha256,proto3" json:"sha256,omitempty"` +} + +func (x *Codegen_WASM) Reset() { + *x = Codegen_WASM{} + if protoimpl.UnsafeEnabled { + mi := &file_plugin_codegen_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Codegen_WASM) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Codegen_WASM) ProtoMessage() {} + +func (x *Codegen_WASM) ProtoReflect() protoreflect.Message { + mi := &file_plugin_codegen_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Codegen_WASM.ProtoReflect.Descriptor instead. +func (*Codegen_WASM) Descriptor() ([]byte, []int) { + return file_plugin_codegen_proto_rawDescGZIP(), []int{2, 1} +} + +func (x *Codegen_WASM) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *Codegen_WASM) GetSha256() string { + if x != nil { + return x.Sha256 + } + return "" +} + +var File_plugin_codegen_proto protoreflect.FileDescriptor + +var file_plugin_codegen_proto_rawDesc = []byte{ + 0x0a, 0x14, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x67, 0x65, 0x6e, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x22, 0x36, + 0x0a, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xb7, 0x01, 0x0a, 0x08, 0x53, 0x65, 0x74, 0x74, 0x69, + 0x6e, 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, + 0x06, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, + 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x18, 0x0a, + 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, + 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0x29, 0x0a, 0x07, 0x63, 0x6f, 0x64, 0x65, 0x67, + 0x65, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, + 0x6e, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x67, 0x65, 0x6e, 0x52, 0x07, 0x63, 0x6f, 0x64, 0x65, 0x67, + 0x65, 0x6e, 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x4a, 0x04, + 0x08, 0x09, 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x0a, 0x10, 0x0b, 0x4a, 0x04, 0x08, 0x0b, 0x10, 0x0c, + 0x22, 0x8b, 0x02, 0x0a, 0x07, 0x43, 0x6f, 0x64, 0x65, 0x67, 0x65, 0x6e, 0x12, 0x10, 0x0a, 0x03, + 0x6f, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6f, 0x75, 0x74, 0x12, 0x16, + 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x65, + 0x6e, 0x76, 0x12, 0x31, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x43, 0x6f, 0x64, + 0x65, 0x67, 0x65, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x07, 0x70, 0x72, + 0x6f, 0x63, 0x65, 0x73, 0x73, 0x12, 0x28, 0x0a, 0x04, 0x77, 0x61, 0x73, 0x6d, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x43, 0x6f, 0x64, + 0x65, 0x67, 0x65, 0x6e, 0x2e, 0x57, 0x41, 0x53, 0x4d, 0x52, 0x04, 0x77, 0x61, 0x73, 0x6d, 0x1a, + 0x1b, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x6d, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, 0x6d, 0x64, 0x1a, 0x30, 0x0a, 0x04, + 0x57, 0x41, 0x53, 0x4d, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x22, 0x88, + 0x01, 0x0a, 0x07, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, + 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, + 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, + 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x28, 0x0a, 0x07, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x0e, 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, + 0x52, 0x07, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x22, 0xc1, 0x01, 0x0a, 0x06, 0x53, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x06, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x54, 0x61, 0x62, 0x6c, + 0x65, 0x52, 0x06, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x05, 0x65, 0x6e, 0x75, + 0x6d, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, + 0x6e, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x05, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x12, 0x3e, 0x0a, + 0x0f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, + 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0e, 0x63, + 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x22, 0x3d, 0x0a, + 0x0d, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x48, 0x0a, 0x04, + 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x76, 0x61, 0x6c, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x76, 0x61, 0x6c, 0x73, 0x12, 0x18, 0x0a, 0x07, + 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, + 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x71, 0x0a, 0x05, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, + 0x24, 0x0a, 0x03, 0x72, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x70, + 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, + 0x52, 0x03, 0x72, 0x65, 0x6c, 0x12, 0x28, 0x0a, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, + 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x12, + 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x52, 0x0a, 0x0a, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x61, 0x74, 0x61, 0x6c, + 0x6f, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, + 0x67, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x8e, 0x04, + 0x0a, 0x06, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, + 0x6e, 0x6f, 0x74, 0x5f, 0x6e, 0x75, 0x6c, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, + 0x6e, 0x6f, 0x74, 0x4e, 0x75, 0x6c, 0x6c, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x61, 0x72, + 0x72, 0x61, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x41, 0x72, 0x72, + 0x61, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, + 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x6c, 0x65, + 0x6e, 0x67, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0e, 0x69, 0x73, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x64, + 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x73, + 0x4e, 0x61, 0x6d, 0x65, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x12, 0x20, 0x0a, 0x0c, 0x69, 0x73, + 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0a, 0x69, 0x73, 0x46, 0x75, 0x6e, 0x63, 0x43, 0x61, 0x6c, 0x6c, 0x12, 0x14, 0x0a, 0x05, + 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x63, 0x6f, + 0x70, 0x65, 0x12, 0x28, 0x0a, 0x05, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x05, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x1f, 0x0a, 0x0b, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x26, 0x0a, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x6c, + 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x69, 0x73, 0x5f, 0x73, 0x71, 0x6c, 0x63, + 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, + 0x53, 0x71, 0x6c, 0x63, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x12, 0x33, 0x0a, 0x0b, 0x65, 0x6d, 0x62, + 0x65, 0x64, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, + 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x52, 0x0a, 0x65, 0x6d, 0x62, 0x65, 0x64, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x23, + 0x0a, 0x0d, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x18, + 0x10, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x12, + 0x1d, 0x0a, 0x0a, 0x61, 0x72, 0x72, 0x61, 0x79, 0x5f, 0x64, 0x69, 0x6d, 0x73, 0x18, 0x11, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x09, 0x61, 0x72, 0x72, 0x61, 0x79, 0x44, 0x69, 0x6d, 0x73, 0x22, 0x94, + 0x02, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x10, 0x0a, 0x03, 0x63, 0x6d, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, + 0x6d, 0x64, 0x12, 0x28, 0x0a, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x04, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x43, 0x6f, 0x6c, + 0x75, 0x6d, 0x6e, 0x52, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x12, 0x2d, 0x0a, 0x06, + 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, + 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x52, + 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x63, + 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, + 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x40, 0x0a, 0x11, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x5f, 0x69, 0x6e, + 0x74, 0x6f, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, + 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x52, 0x11, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x6f, 0x5f, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x4b, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, + 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x26, 0x0a, 0x06, 0x63, 0x6f, + 0x6c, 0x75, 0x6d, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x6c, 0x75, + 0x67, 0x69, 0x6e, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x06, 0x63, 0x6f, 0x6c, 0x75, + 0x6d, 0x6e, 0x22, 0x87, 0x02, 0x0a, 0x0f, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, + 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, + 0x69, 0x6e, 0x67, 0x73, 0x12, 0x29, 0x0a, 0x07, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x43, + 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x07, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x12, + 0x27, 0x0a, 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x0d, 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, + 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x71, 0x6c, 0x63, + 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, + 0x73, 0x71, 0x6c, 0x63, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x0e, + 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x5f, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x67, 0x6c, + 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x36, 0x0a, 0x10, + 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x22, 0x0a, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x0c, 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x05, 0x66, + 0x69, 0x6c, 0x65, 0x73, 0x32, 0x4f, 0x0a, 0x0e, 0x43, 0x6f, 0x64, 0x65, 0x67, 0x65, 0x6e, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3d, 0x0a, 0x08, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x65, 0x12, 0x17, 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x6e, 0x65, + 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x70, 0x6c, + 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x7c, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6c, 0x75, + 0x67, 0x69, 0x6e, 0x42, 0x0c, 0x43, 0x6f, 0x64, 0x65, 0x67, 0x65, 0x6e, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x50, 0x01, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x73, 0x71, 0x6c, 0x63, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x73, 0x71, 0x6c, 0x63, 0x2f, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0xa2, 0x02, 0x03, + 0x50, 0x58, 0x58, 0xaa, 0x02, 0x06, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0xca, 0x02, 0x06, 0x50, + 0x6c, 0x75, 0x67, 0x69, 0x6e, 0xe2, 0x02, 0x12, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x5c, 0x47, + 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x06, 0x50, 0x6c, 0x75, + 0x67, 0x69, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_plugin_codegen_proto_rawDescOnce sync.Once + file_plugin_codegen_proto_rawDescData = file_plugin_codegen_proto_rawDesc +) + +func file_plugin_codegen_proto_rawDescGZIP() []byte { + file_plugin_codegen_proto_rawDescOnce.Do(func() { + file_plugin_codegen_proto_rawDescData = protoimpl.X.CompressGZIP(file_plugin_codegen_proto_rawDescData) + }) + return file_plugin_codegen_proto_rawDescData +} + +var file_plugin_codegen_proto_msgTypes = make([]protoimpl.MessageInfo, 16) +var file_plugin_codegen_proto_goTypes = []interface{}{ + (*File)(nil), // 0: plugin.File + (*Settings)(nil), // 1: plugin.Settings + (*Codegen)(nil), // 2: plugin.Codegen + (*Catalog)(nil), // 3: plugin.Catalog + (*Schema)(nil), // 4: plugin.Schema + (*CompositeType)(nil), // 5: plugin.CompositeType + (*Enum)(nil), // 6: plugin.Enum + (*Table)(nil), // 7: plugin.Table + (*Identifier)(nil), // 8: plugin.Identifier + (*Column)(nil), // 9: plugin.Column + (*Query)(nil), // 10: plugin.Query + (*Parameter)(nil), // 11: plugin.Parameter + (*GenerateRequest)(nil), // 12: plugin.GenerateRequest + (*GenerateResponse)(nil), // 13: plugin.GenerateResponse + (*Codegen_Process)(nil), // 14: plugin.Codegen.Process + (*Codegen_WASM)(nil), // 15: plugin.Codegen.WASM +} +var file_plugin_codegen_proto_depIdxs = []int32{ + 2, // 0: plugin.Settings.codegen:type_name -> plugin.Codegen + 14, // 1: plugin.Codegen.process:type_name -> plugin.Codegen.Process + 15, // 2: plugin.Codegen.wasm:type_name -> plugin.Codegen.WASM + 4, // 3: plugin.Catalog.schemas:type_name -> plugin.Schema + 7, // 4: plugin.Schema.tables:type_name -> plugin.Table + 6, // 5: plugin.Schema.enums:type_name -> plugin.Enum + 5, // 6: plugin.Schema.composite_types:type_name -> plugin.CompositeType + 8, // 7: plugin.Table.rel:type_name -> plugin.Identifier + 9, // 8: plugin.Table.columns:type_name -> plugin.Column + 8, // 9: plugin.Column.table:type_name -> plugin.Identifier + 8, // 10: plugin.Column.type:type_name -> plugin.Identifier + 8, // 11: plugin.Column.embed_table:type_name -> plugin.Identifier + 9, // 12: plugin.Query.columns:type_name -> plugin.Column + 11, // 13: plugin.Query.params:type_name -> plugin.Parameter + 8, // 14: plugin.Query.insert_into_table:type_name -> plugin.Identifier + 9, // 15: plugin.Parameter.column:type_name -> plugin.Column + 1, // 16: plugin.GenerateRequest.settings:type_name -> plugin.Settings + 3, // 17: plugin.GenerateRequest.catalog:type_name -> plugin.Catalog + 10, // 18: plugin.GenerateRequest.queries:type_name -> plugin.Query + 0, // 19: plugin.GenerateResponse.files:type_name -> plugin.File + 12, // 20: plugin.CodegenService.Generate:input_type -> plugin.GenerateRequest + 13, // 21: plugin.CodegenService.Generate:output_type -> plugin.GenerateResponse + 21, // [21:22] is the sub-list for method output_type + 20, // [20:21] is the sub-list for method input_type + 20, // [20:20] is the sub-list for extension type_name + 20, // [20:20] is the sub-list for extension extendee + 0, // [0:20] is the sub-list for field type_name +} + +func init() { file_plugin_codegen_proto_init() } +func file_plugin_codegen_proto_init() { + if File_plugin_codegen_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_plugin_codegen_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*File); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_plugin_codegen_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Settings); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_plugin_codegen_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Codegen); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_plugin_codegen_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Catalog); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_plugin_codegen_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Schema); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_plugin_codegen_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CompositeType); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_plugin_codegen_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Enum); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_plugin_codegen_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Table); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_plugin_codegen_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Identifier); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_plugin_codegen_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Column); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_plugin_codegen_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Query); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_plugin_codegen_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Parameter); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_plugin_codegen_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GenerateRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_plugin_codegen_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GenerateResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_plugin_codegen_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Codegen_Process); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_plugin_codegen_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Codegen_WASM); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_plugin_codegen_proto_rawDesc, + NumEnums: 0, + NumMessages: 16, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_plugin_codegen_proto_goTypes, + DependencyIndexes: file_plugin_codegen_proto_depIdxs, + MessageInfos: file_plugin_codegen_proto_msgTypes, + }.Build() + File_plugin_codegen_proto = out.File + file_plugin_codegen_proto_rawDesc = nil + file_plugin_codegen_proto_goTypes = nil + file_plugin_codegen_proto_depIdxs = nil +} diff --git a/internal/plugin/codegen_grpc.pb.go b/internal/plugin/codegen_grpc.pb.go new file mode 100644 index 0000000..30287ac --- /dev/null +++ b/internal/plugin/codegen_grpc.pb.go @@ -0,0 +1,109 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc (unknown) +// source: plugin/codegen.proto + +package plugin + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + CodegenService_Generate_FullMethodName = "/plugin.CodegenService/Generate" +) + +// CodegenServiceClient is the client API for CodegenService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type CodegenServiceClient interface { + Generate(ctx context.Context, in *GenerateRequest, opts ...grpc.CallOption) (*GenerateResponse, error) +} + +type codegenServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewCodegenServiceClient(cc grpc.ClientConnInterface) CodegenServiceClient { + return &codegenServiceClient{cc} +} + +func (c *codegenServiceClient) Generate(ctx context.Context, in *GenerateRequest, opts ...grpc.CallOption) (*GenerateResponse, error) { + out := new(GenerateResponse) + err := c.cc.Invoke(ctx, CodegenService_Generate_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// CodegenServiceServer is the server API for CodegenService service. +// All implementations must embed UnimplementedCodegenServiceServer +// for forward compatibility +type CodegenServiceServer interface { + Generate(context.Context, *GenerateRequest) (*GenerateResponse, error) + mustEmbedUnimplementedCodegenServiceServer() +} + +// UnimplementedCodegenServiceServer must be embedded to have forward compatible implementations. +type UnimplementedCodegenServiceServer struct { +} + +func (UnimplementedCodegenServiceServer) Generate(context.Context, *GenerateRequest) (*GenerateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Generate not implemented") +} +func (UnimplementedCodegenServiceServer) mustEmbedUnimplementedCodegenServiceServer() {} + +// UnsafeCodegenServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to CodegenServiceServer will +// result in compilation errors. +type UnsafeCodegenServiceServer interface { + mustEmbedUnimplementedCodegenServiceServer() +} + +func RegisterCodegenServiceServer(s grpc.ServiceRegistrar, srv CodegenServiceServer) { + s.RegisterService(&CodegenService_ServiceDesc, srv) +} + +func _CodegenService_Generate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GenerateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CodegenServiceServer).Generate(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: CodegenService_Generate_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CodegenServiceServer).Generate(ctx, req.(*GenerateRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// CodegenService_ServiceDesc is the grpc.ServiceDesc for CodegenService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var CodegenService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "plugin.CodegenService", + HandlerType: (*CodegenServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Generate", + Handler: _CodegenService_Generate_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "plugin/codegen.proto", +} diff --git a/internal/quickdb/mysql.go b/internal/quickdb/mysql.go new file mode 100644 index 0000000..628b08c --- /dev/null +++ b/internal/quickdb/mysql.go @@ -0,0 +1,16 @@ +package quickdb + +import ( + "fmt" + "net/url" +) + +// The database URI returned by the QuickDB service isn't understood by the +// go-mysql-driver +func MySQLReformatURI(original string) (string, error) { + u, err := url.Parse(original) + if err != nil { + return "", err + } + return fmt.Sprintf("%s@tcp(%s)%s?multiStatements=true&parseTime=true&tls=true", u.User, u.Host, u.Path), nil +} diff --git a/internal/quickdb/rpc.go b/internal/quickdb/rpc.go new file mode 100644 index 0000000..9d9649d --- /dev/null +++ b/internal/quickdb/rpc.go @@ -0,0 +1,57 @@ +package quickdb + +import ( + "crypto/tls" + + "github.com/riza-io/grpc-go/credentials/basic" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + + "github.com/sqlc-dev/sqlc/internal/config" + pb "github.com/sqlc-dev/sqlc/internal/quickdb/v1" + "github.com/sqlc-dev/sqlc/internal/rpc" +) + +const defaultHostname = "grpc.sqlc.dev" + +func NewClientFromConfig(cloudConfig config.Cloud) (pb.QuickClient, error) { + projectID := cloudConfig.Project + return NewClient(projectID, cloudConfig.AuthToken, WithHost(cloudConfig.Hostname)) +} + +type options struct { + hostname string +} + +type Option func(*options) + +func WithHost(host string) Option { + return func(o *options) { + o.hostname = host + } +} + +func NewClient(project, token string, opts ...Option) (pb.QuickClient, error) { + var o options + for _, apply := range opts { + apply(&o) + } + + dialOpts := []grpc.DialOption{ + grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})), + grpc.WithPerRPCCredentials(basic.NewPerRPCCredentials(project, token)), + grpc.WithUnaryInterceptor(rpc.UnaryInterceptor), + } + + hostname := o.hostname + if hostname == "" { + hostname = defaultHostname + } + + conn, err := grpc.Dial(hostname+":443", dialOpts...) + if err != nil { + return nil, err + } + + return pb.NewQuickClient(conn), nil +} diff --git a/internal/quickdb/v1/quickdb.pb.go b/internal/quickdb/v1/quickdb.pb.go new file mode 100755 index 0000000..690dfc1 --- /dev/null +++ b/internal/quickdb/v1/quickdb.pb.go @@ -0,0 +1,1142 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.30.0 +// protoc (unknown) +// source: v1/quickdb.proto + +package quickdbv1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type CreateEphemeralDatabaseRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Region string `protobuf:"bytes,1,opt,name=region,proto3" json:"region,omitempty"` + Engine string `protobuf:"bytes,2,opt,name=engine,proto3" json:"engine,omitempty"` + ServerId string `protobuf:"bytes,3,opt,name=server_id,json=serverId,proto3" json:"server_id,omitempty"` + Migrations []string `protobuf:"bytes,4,rep,name=migrations,proto3" json:"migrations,omitempty"` +} + +func (x *CreateEphemeralDatabaseRequest) Reset() { + *x = CreateEphemeralDatabaseRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_v1_quickdb_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateEphemeralDatabaseRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateEphemeralDatabaseRequest) ProtoMessage() {} + +func (x *CreateEphemeralDatabaseRequest) ProtoReflect() protoreflect.Message { + mi := &file_v1_quickdb_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateEphemeralDatabaseRequest.ProtoReflect.Descriptor instead. +func (*CreateEphemeralDatabaseRequest) Descriptor() ([]byte, []int) { + return file_v1_quickdb_proto_rawDescGZIP(), []int{0} +} + +func (x *CreateEphemeralDatabaseRequest) GetRegion() string { + if x != nil { + return x.Region + } + return "" +} + +func (x *CreateEphemeralDatabaseRequest) GetEngine() string { + if x != nil { + return x.Engine + } + return "" +} + +func (x *CreateEphemeralDatabaseRequest) GetServerId() string { + if x != nil { + return x.ServerId + } + return "" +} + +func (x *CreateEphemeralDatabaseRequest) GetMigrations() []string { + if x != nil { + return x.Migrations + } + return nil +} + +type CreateEphemeralDatabaseResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DatabaseId string `protobuf:"bytes,1,opt,name=database_id,json=databaseId,proto3" json:"database_id,omitempty"` + Uri string `protobuf:"bytes,2,opt,name=uri,proto3" json:"uri,omitempty"` +} + +func (x *CreateEphemeralDatabaseResponse) Reset() { + *x = CreateEphemeralDatabaseResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_v1_quickdb_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateEphemeralDatabaseResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateEphemeralDatabaseResponse) ProtoMessage() {} + +func (x *CreateEphemeralDatabaseResponse) ProtoReflect() protoreflect.Message { + mi := &file_v1_quickdb_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateEphemeralDatabaseResponse.ProtoReflect.Descriptor instead. +func (*CreateEphemeralDatabaseResponse) Descriptor() ([]byte, []int) { + return file_v1_quickdb_proto_rawDescGZIP(), []int{1} +} + +func (x *CreateEphemeralDatabaseResponse) GetDatabaseId() string { + if x != nil { + return x.DatabaseId + } + return "" +} + +func (x *CreateEphemeralDatabaseResponse) GetUri() string { + if x != nil { + return x.Uri + } + return "" +} + +type DropEphemeralDatabaseRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DatabaseId string `protobuf:"bytes,1,opt,name=database_id,json=databaseId,proto3" json:"database_id,omitempty"` +} + +func (x *DropEphemeralDatabaseRequest) Reset() { + *x = DropEphemeralDatabaseRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_v1_quickdb_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DropEphemeralDatabaseRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DropEphemeralDatabaseRequest) ProtoMessage() {} + +func (x *DropEphemeralDatabaseRequest) ProtoReflect() protoreflect.Message { + mi := &file_v1_quickdb_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DropEphemeralDatabaseRequest.ProtoReflect.Descriptor instead. +func (*DropEphemeralDatabaseRequest) Descriptor() ([]byte, []int) { + return file_v1_quickdb_proto_rawDescGZIP(), []int{2} +} + +func (x *DropEphemeralDatabaseRequest) GetDatabaseId() string { + if x != nil { + return x.DatabaseId + } + return "" +} + +type DropEphemeralDatabaseResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DropEphemeralDatabaseResponse) Reset() { + *x = DropEphemeralDatabaseResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_v1_quickdb_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DropEphemeralDatabaseResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DropEphemeralDatabaseResponse) ProtoMessage() {} + +func (x *DropEphemeralDatabaseResponse) ProtoReflect() protoreflect.Message { + mi := &file_v1_quickdb_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DropEphemeralDatabaseResponse.ProtoReflect.Descriptor instead. +func (*DropEphemeralDatabaseResponse) Descriptor() ([]byte, []int) { + return file_v1_quickdb_proto_rawDescGZIP(), []int{3} +} + +type File struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Contents []byte `protobuf:"bytes,2,opt,name=contents,proto3" json:"contents,omitempty"` +} + +func (x *File) Reset() { + *x = File{} + if protoimpl.UnsafeEnabled { + mi := &file_v1_quickdb_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *File) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*File) ProtoMessage() {} + +func (x *File) ProtoReflect() protoreflect.Message { + mi := &file_v1_quickdb_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use File.ProtoReflect.Descriptor instead. +func (*File) Descriptor() ([]byte, []int) { + return file_v1_quickdb_proto_rawDescGZIP(), []int{4} +} + +func (x *File) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *File) GetContents() []byte { + if x != nil { + return x.Contents + } + return nil +} + +type QuerySet struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Schema []*File `protobuf:"bytes,2,rep,name=schema,proto3" json:"schema,omitempty"` + Queries []*File `protobuf:"bytes,3,rep,name=queries,proto3" json:"queries,omitempty"` + CodegenRequest *File `protobuf:"bytes,4,opt,name=codegen_request,json=codegenRequest,proto3" json:"codegen_request,omitempty"` +} + +func (x *QuerySet) Reset() { + *x = QuerySet{} + if protoimpl.UnsafeEnabled { + mi := &file_v1_quickdb_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QuerySet) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QuerySet) ProtoMessage() {} + +func (x *QuerySet) ProtoReflect() protoreflect.Message { + mi := &file_v1_quickdb_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use QuerySet.ProtoReflect.Descriptor instead. +func (*QuerySet) Descriptor() ([]byte, []int) { + return file_v1_quickdb_proto_rawDescGZIP(), []int{5} +} + +func (x *QuerySet) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *QuerySet) GetSchema() []*File { + if x != nil { + return x.Schema + } + return nil +} + +func (x *QuerySet) GetQueries() []*File { + if x != nil { + return x.Queries + } + return nil +} + +func (x *QuerySet) GetCodegenRequest() *File { + if x != nil { + return x.CodegenRequest + } + return nil +} + +type UploadArchiveRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SqlcVersion string `protobuf:"bytes,1,opt,name=sqlc_version,json=sqlcVersion,proto3" json:"sqlc_version,omitempty"` + Inputs []*File `protobuf:"bytes,2,rep,name=inputs,proto3" json:"inputs,omitempty"` // deprecated + Outputs []*File `protobuf:"bytes,3,rep,name=outputs,proto3" json:"outputs,omitempty"` // deprecated + Annotations map[string]string `protobuf:"bytes,4,rep,name=annotations,proto3" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + QuerySets []*QuerySet `protobuf:"bytes,5,rep,name=query_sets,json=querySets,proto3" json:"query_sets,omitempty"` + Config *File `protobuf:"bytes,6,opt,name=config,proto3" json:"config,omitempty"` + Tags []string `protobuf:"bytes,7,rep,name=tags,proto3" json:"tags,omitempty"` +} + +func (x *UploadArchiveRequest) Reset() { + *x = UploadArchiveRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_v1_quickdb_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UploadArchiveRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UploadArchiveRequest) ProtoMessage() {} + +func (x *UploadArchiveRequest) ProtoReflect() protoreflect.Message { + mi := &file_v1_quickdb_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UploadArchiveRequest.ProtoReflect.Descriptor instead. +func (*UploadArchiveRequest) Descriptor() ([]byte, []int) { + return file_v1_quickdb_proto_rawDescGZIP(), []int{6} +} + +func (x *UploadArchiveRequest) GetSqlcVersion() string { + if x != nil { + return x.SqlcVersion + } + return "" +} + +func (x *UploadArchiveRequest) GetInputs() []*File { + if x != nil { + return x.Inputs + } + return nil +} + +func (x *UploadArchiveRequest) GetOutputs() []*File { + if x != nil { + return x.Outputs + } + return nil +} + +func (x *UploadArchiveRequest) GetAnnotations() map[string]string { + if x != nil { + return x.Annotations + } + return nil +} + +func (x *UploadArchiveRequest) GetQuerySets() []*QuerySet { + if x != nil { + return x.QuerySets + } + return nil +} + +func (x *UploadArchiveRequest) GetConfig() *File { + if x != nil { + return x.Config + } + return nil +} + +func (x *UploadArchiveRequest) GetTags() []string { + if x != nil { + return x.Tags + } + return nil +} + +type UploadArchiveResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Checksum []byte `protobuf:"bytes,1,opt,name=checksum,proto3" json:"checksum,omitempty"` +} + +func (x *UploadArchiveResponse) Reset() { + *x = UploadArchiveResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_v1_quickdb_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UploadArchiveResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UploadArchiveResponse) ProtoMessage() {} + +func (x *UploadArchiveResponse) ProtoReflect() protoreflect.Message { + mi := &file_v1_quickdb_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UploadArchiveResponse.ProtoReflect.Descriptor instead. +func (*UploadArchiveResponse) Descriptor() ([]byte, []int) { + return file_v1_quickdb_proto_rawDescGZIP(), []int{7} +} + +func (x *UploadArchiveResponse) GetChecksum() []byte { + if x != nil { + return x.Checksum + } + return nil +} + +type VerifyQuerySetsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SqlcVersion string `protobuf:"bytes,1,opt,name=sqlc_version,json=sqlcVersion,proto3" json:"sqlc_version,omitempty"` + QuerySets []*QuerySet `protobuf:"bytes,2,rep,name=query_sets,json=querySets,proto3" json:"query_sets,omitempty"` + Config *File `protobuf:"bytes,3,opt,name=config,proto3" json:"config,omitempty"` + Annotations map[string]string `protobuf:"bytes,4,rep,name=annotations,proto3" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Against string `protobuf:"bytes,5,opt,name=against,proto3" json:"against,omitempty"` +} + +func (x *VerifyQuerySetsRequest) Reset() { + *x = VerifyQuerySetsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_v1_quickdb_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VerifyQuerySetsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerifyQuerySetsRequest) ProtoMessage() {} + +func (x *VerifyQuerySetsRequest) ProtoReflect() protoreflect.Message { + mi := &file_v1_quickdb_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VerifyQuerySetsRequest.ProtoReflect.Descriptor instead. +func (*VerifyQuerySetsRequest) Descriptor() ([]byte, []int) { + return file_v1_quickdb_proto_rawDescGZIP(), []int{8} +} + +func (x *VerifyQuerySetsRequest) GetSqlcVersion() string { + if x != nil { + return x.SqlcVersion + } + return "" +} + +func (x *VerifyQuerySetsRequest) GetQuerySets() []*QuerySet { + if x != nil { + return x.QuerySets + } + return nil +} + +func (x *VerifyQuerySetsRequest) GetConfig() *File { + if x != nil { + return x.Config + } + return nil +} + +func (x *VerifyQuerySetsRequest) GetAnnotations() map[string]string { + if x != nil { + return x.Annotations + } + return nil +} + +func (x *VerifyQuerySetsRequest) GetAgainst() string { + if x != nil { + return x.Against + } + return "" +} + +type VerifyQuerySetsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Errored bool `protobuf:"varint,1,opt,name=errored,proto3" json:"errored,omitempty"` + Output string `protobuf:"bytes,2,opt,name=output,proto3" json:"output,omitempty"` + Summary string `protobuf:"bytes,3,opt,name=summary,proto3" json:"summary,omitempty"` +} + +func (x *VerifyQuerySetsResponse) Reset() { + *x = VerifyQuerySetsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_v1_quickdb_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VerifyQuerySetsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerifyQuerySetsResponse) ProtoMessage() {} + +func (x *VerifyQuerySetsResponse) ProtoReflect() protoreflect.Message { + mi := &file_v1_quickdb_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VerifyQuerySetsResponse.ProtoReflect.Descriptor instead. +func (*VerifyQuerySetsResponse) Descriptor() ([]byte, []int) { + return file_v1_quickdb_proto_rawDescGZIP(), []int{9} +} + +func (x *VerifyQuerySetsResponse) GetErrored() bool { + if x != nil { + return x.Errored + } + return false +} + +func (x *VerifyQuerySetsResponse) GetOutput() string { + if x != nil { + return x.Output + } + return "" +} + +func (x *VerifyQuerySetsResponse) GetSummary() string { + if x != nil { + return x.Summary + } + return "" +} + +type GetQuerySetsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"` +} + +func (x *GetQuerySetsRequest) Reset() { + *x = GetQuerySetsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_v1_quickdb_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetQuerySetsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetQuerySetsRequest) ProtoMessage() {} + +func (x *GetQuerySetsRequest) ProtoReflect() protoreflect.Message { + mi := &file_v1_quickdb_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetQuerySetsRequest.ProtoReflect.Descriptor instead. +func (*GetQuerySetsRequest) Descriptor() ([]byte, []int) { + return file_v1_quickdb_proto_rawDescGZIP(), []int{10} +} + +func (x *GetQuerySetsRequest) GetTag() string { + if x != nil { + return x.Tag + } + return "" +} + +type GetQuerySetsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + QuerySets []*QuerySet `protobuf:"bytes,1,rep,name=query_sets,json=querySets,proto3" json:"query_sets,omitempty"` +} + +func (x *GetQuerySetsResponse) Reset() { + *x = GetQuerySetsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_v1_quickdb_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetQuerySetsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetQuerySetsResponse) ProtoMessage() {} + +func (x *GetQuerySetsResponse) ProtoReflect() protoreflect.Message { + mi := &file_v1_quickdb_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetQuerySetsResponse.ProtoReflect.Descriptor instead. +func (*GetQuerySetsResponse) Descriptor() ([]byte, []int) { + return file_v1_quickdb_proto_rawDescGZIP(), []int{11} +} + +func (x *GetQuerySetsResponse) GetQuerySets() []*QuerySet { + if x != nil { + return x.QuerySets + } + return nil +} + +var File_v1_quickdb_proto protoreflect.FileDescriptor + +var file_v1_quickdb_proto_rawDesc = []byte{ + 0x0a, 0x10, 0x76, 0x31, 0x2f, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x64, 0x62, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x12, 0x1a, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x73, 0x71, 0x6c, 0x63, 0x2e, + 0x64, 0x65, 0x76, 0x2e, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x64, 0x62, 0x2e, 0x76, 0x31, 0x22, 0x8d, + 0x01, 0x0a, 0x1e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, + 0x61, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x6e, 0x67, + 0x69, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x6e, 0x67, 0x69, 0x6e, + 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1e, + 0x0a, 0x0a, 0x6d, 0x69, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x69, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x54, + 0x0a, 0x1f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, + 0x6c, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, + 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x75, 0x72, 0x69, 0x22, 0x3f, 0x0a, 0x1c, 0x44, 0x72, 0x6f, 0x70, 0x45, 0x70, 0x68, 0x65, + 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x62, + 0x61, 0x73, 0x65, 0x49, 0x64, 0x22, 0x1f, 0x0a, 0x1d, 0x44, 0x72, 0x6f, 0x70, 0x45, 0x70, 0x68, + 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x36, 0x0a, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xdf, + 0x01, 0x0a, 0x08, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x38, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x20, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x73, 0x71, 0x6c, 0x63, 0x2e, 0x64, 0x65, + 0x76, 0x2e, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x64, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, + 0x65, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x3a, 0x0a, 0x07, 0x71, 0x75, 0x65, + 0x72, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x6d, + 0x6f, 0x74, 0x65, 0x2e, 0x73, 0x71, 0x6c, 0x63, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x71, 0x75, 0x69, + 0x63, 0x6b, 0x64, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x07, 0x71, 0x75, + 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0x49, 0x0a, 0x0f, 0x63, 0x6f, 0x64, 0x65, 0x67, 0x65, 0x6e, + 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, + 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x73, 0x71, 0x6c, 0x63, 0x2e, 0x64, 0x65, 0x76, + 0x2e, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x64, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x65, + 0x52, 0x0e, 0x63, 0x6f, 0x64, 0x65, 0x67, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x22, 0xe7, 0x03, 0x0a, 0x14, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x41, 0x72, 0x63, 0x68, 0x69, + 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x71, 0x6c, + 0x63, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x73, 0x71, 0x6c, 0x63, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x06, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, + 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x73, 0x71, 0x6c, 0x63, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x71, + 0x75, 0x69, 0x63, 0x6b, 0x64, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x06, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x3a, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, + 0x2e, 0x73, 0x71, 0x6c, 0x63, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x64, + 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, + 0x74, 0x73, 0x12, 0x63, 0x0a, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, + 0x2e, 0x73, 0x71, 0x6c, 0x63, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x64, + 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x41, 0x72, 0x63, 0x68, 0x69, + 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x43, 0x0a, 0x0a, 0x71, 0x75, 0x65, 0x72, 0x79, + 0x5f, 0x73, 0x65, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x72, 0x65, + 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x73, 0x71, 0x6c, 0x63, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x71, 0x75, + 0x69, 0x63, 0x6b, 0x64, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, + 0x74, 0x52, 0x09, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x74, 0x73, 0x12, 0x38, 0x0a, 0x06, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, + 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x73, 0x71, 0x6c, 0x63, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x71, + 0x75, 0x69, 0x63, 0x6b, 0x64, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x06, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x07, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x1a, 0x3e, 0x0a, 0x10, 0x41, 0x6e, + 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x33, 0x0a, 0x15, 0x55, 0x70, + 0x6c, 0x6f, 0x61, 0x64, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x22, + 0xfb, 0x02, 0x0a, 0x16, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, + 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x71, + 0x6c, 0x63, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x73, 0x71, 0x6c, 0x63, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x43, 0x0a, + 0x0a, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x24, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x73, 0x71, 0x6c, 0x63, 0x2e, + 0x64, 0x65, 0x76, 0x2e, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x64, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x51, + 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x74, 0x52, 0x09, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, + 0x74, 0x73, 0x12, 0x38, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x73, 0x71, 0x6c, 0x63, + 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x64, 0x62, 0x2e, 0x76, 0x31, 0x2e, + 0x46, 0x69, 0x6c, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x65, 0x0a, 0x0b, + 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x43, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x73, 0x71, 0x6c, 0x63, 0x2e, + 0x64, 0x65, 0x76, 0x2e, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x64, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x56, + 0x65, 0x72, 0x69, 0x66, 0x79, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x74, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x67, 0x61, 0x69, 0x6e, 0x73, 0x74, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x67, 0x61, 0x69, 0x6e, 0x73, 0x74, 0x1a, 0x3e, 0x0a, + 0x10, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x65, 0x0a, + 0x17, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x74, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, + 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x6d, + 0x6d, 0x61, 0x72, 0x79, 0x22, 0x27, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x53, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, + 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0x5b, 0x0a, + 0x14, 0x47, 0x65, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x74, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x0a, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, + 0x65, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x72, 0x65, 0x6d, 0x6f, + 0x74, 0x65, 0x2e, 0x73, 0x71, 0x6c, 0x63, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x71, 0x75, 0x69, 0x63, + 0x6b, 0x64, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x74, 0x52, + 0x09, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x74, 0x73, 0x32, 0x90, 0x05, 0x0a, 0x05, 0x51, + 0x75, 0x69, 0x63, 0x6b, 0x12, 0x92, 0x01, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, + 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, + 0x12, 0x3a, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x73, 0x71, 0x6c, 0x63, 0x2e, 0x64, + 0x65, 0x76, 0x2e, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x64, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x45, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x44, 0x61, 0x74, + 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x72, + 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x73, 0x71, 0x6c, 0x63, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x71, + 0x75, 0x69, 0x63, 0x6b, 0x64, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x45, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x8c, 0x01, 0x0a, 0x15, 0x44, 0x72, + 0x6f, 0x70, 0x45, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x62, + 0x61, 0x73, 0x65, 0x12, 0x38, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x73, 0x71, 0x6c, + 0x63, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x64, 0x62, 0x2e, 0x76, 0x31, + 0x2e, 0x44, 0x72, 0x6f, 0x70, 0x45, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x44, 0x61, + 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x39, 0x2e, + 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x73, 0x71, 0x6c, 0x63, 0x2e, 0x64, 0x65, 0x76, 0x2e, + 0x71, 0x75, 0x69, 0x63, 0x6b, 0x64, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x72, 0x6f, 0x70, 0x45, + 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x74, 0x0a, 0x0d, 0x55, 0x70, 0x6c, 0x6f, + 0x61, 0x64, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x12, 0x30, 0x2e, 0x72, 0x65, 0x6d, 0x6f, + 0x74, 0x65, 0x2e, 0x73, 0x71, 0x6c, 0x63, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x71, 0x75, 0x69, 0x63, + 0x6b, 0x64, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x41, 0x72, 0x63, + 0x68, 0x69, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x72, 0x65, + 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x73, 0x71, 0x6c, 0x63, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x71, 0x75, + 0x69, 0x63, 0x6b, 0x64, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x41, + 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7a, + 0x0a, 0x0f, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x74, + 0x73, 0x12, 0x32, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x73, 0x71, 0x6c, 0x63, 0x2e, + 0x64, 0x65, 0x76, 0x2e, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x64, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x56, + 0x65, 0x72, 0x69, 0x66, 0x79, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x74, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x73, + 0x71, 0x6c, 0x63, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x64, 0x62, 0x2e, + 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, + 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x71, 0x0a, 0x0c, 0x47, 0x65, + 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x74, 0x73, 0x12, 0x2f, 0x2e, 0x72, 0x65, 0x6d, + 0x6f, 0x74, 0x65, 0x2e, 0x73, 0x71, 0x6c, 0x63, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x71, 0x75, 0x69, + 0x63, 0x6b, 0x64, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x53, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x72, 0x65, + 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x73, 0x71, 0x6c, 0x63, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x71, 0x75, + 0x69, 0x63, 0x6b, 0x64, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x53, 0x65, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0xeb, 0x01, + 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x73, 0x71, 0x6c, + 0x63, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x64, 0x62, 0x2e, 0x76, 0x31, + 0x42, 0x0c, 0x51, 0x75, 0x69, 0x63, 0x6b, 0x64, 0x62, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, + 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x71, 0x6c, + 0x63, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x73, 0x71, 0x6c, 0x63, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2f, 0x76, 0x31, 0x3b, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x64, 0x62, 0x76, 0x31, + 0xa2, 0x02, 0x04, 0x52, 0x53, 0x44, 0x51, 0xaa, 0x02, 0x1a, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, + 0x2e, 0x53, 0x71, 0x6c, 0x63, 0x2e, 0x44, 0x65, 0x76, 0x2e, 0x51, 0x75, 0x69, 0x63, 0x6b, 0x64, + 0x62, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x1a, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5c, 0x53, 0x71, + 0x6c, 0x63, 0x5c, 0x44, 0x65, 0x76, 0x5c, 0x51, 0x75, 0x69, 0x63, 0x6b, 0x64, 0x62, 0x5c, 0x56, + 0x31, 0xe2, 0x02, 0x26, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5c, 0x53, 0x71, 0x6c, 0x63, 0x5c, + 0x44, 0x65, 0x76, 0x5c, 0x51, 0x75, 0x69, 0x63, 0x6b, 0x64, 0x62, 0x5c, 0x56, 0x31, 0x5c, 0x47, + 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1e, 0x52, 0x65, 0x6d, + 0x6f, 0x74, 0x65, 0x3a, 0x3a, 0x53, 0x71, 0x6c, 0x63, 0x3a, 0x3a, 0x44, 0x65, 0x76, 0x3a, 0x3a, + 0x51, 0x75, 0x69, 0x63, 0x6b, 0x64, 0x62, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, +} + +var ( + file_v1_quickdb_proto_rawDescOnce sync.Once + file_v1_quickdb_proto_rawDescData = file_v1_quickdb_proto_rawDesc +) + +func file_v1_quickdb_proto_rawDescGZIP() []byte { + file_v1_quickdb_proto_rawDescOnce.Do(func() { + file_v1_quickdb_proto_rawDescData = protoimpl.X.CompressGZIP(file_v1_quickdb_proto_rawDescData) + }) + return file_v1_quickdb_proto_rawDescData +} + +var file_v1_quickdb_proto_msgTypes = make([]protoimpl.MessageInfo, 14) +var file_v1_quickdb_proto_goTypes = []interface{}{ + (*CreateEphemeralDatabaseRequest)(nil), // 0: remote.sqlc.dev.quickdb.v1.CreateEphemeralDatabaseRequest + (*CreateEphemeralDatabaseResponse)(nil), // 1: remote.sqlc.dev.quickdb.v1.CreateEphemeralDatabaseResponse + (*DropEphemeralDatabaseRequest)(nil), // 2: remote.sqlc.dev.quickdb.v1.DropEphemeralDatabaseRequest + (*DropEphemeralDatabaseResponse)(nil), // 3: remote.sqlc.dev.quickdb.v1.DropEphemeralDatabaseResponse + (*File)(nil), // 4: remote.sqlc.dev.quickdb.v1.File + (*QuerySet)(nil), // 5: remote.sqlc.dev.quickdb.v1.QuerySet + (*UploadArchiveRequest)(nil), // 6: remote.sqlc.dev.quickdb.v1.UploadArchiveRequest + (*UploadArchiveResponse)(nil), // 7: remote.sqlc.dev.quickdb.v1.UploadArchiveResponse + (*VerifyQuerySetsRequest)(nil), // 8: remote.sqlc.dev.quickdb.v1.VerifyQuerySetsRequest + (*VerifyQuerySetsResponse)(nil), // 9: remote.sqlc.dev.quickdb.v1.VerifyQuerySetsResponse + (*GetQuerySetsRequest)(nil), // 10: remote.sqlc.dev.quickdb.v1.GetQuerySetsRequest + (*GetQuerySetsResponse)(nil), // 11: remote.sqlc.dev.quickdb.v1.GetQuerySetsResponse + nil, // 12: remote.sqlc.dev.quickdb.v1.UploadArchiveRequest.AnnotationsEntry + nil, // 13: remote.sqlc.dev.quickdb.v1.VerifyQuerySetsRequest.AnnotationsEntry +} +var file_v1_quickdb_proto_depIdxs = []int32{ + 4, // 0: remote.sqlc.dev.quickdb.v1.QuerySet.schema:type_name -> remote.sqlc.dev.quickdb.v1.File + 4, // 1: remote.sqlc.dev.quickdb.v1.QuerySet.queries:type_name -> remote.sqlc.dev.quickdb.v1.File + 4, // 2: remote.sqlc.dev.quickdb.v1.QuerySet.codegen_request:type_name -> remote.sqlc.dev.quickdb.v1.File + 4, // 3: remote.sqlc.dev.quickdb.v1.UploadArchiveRequest.inputs:type_name -> remote.sqlc.dev.quickdb.v1.File + 4, // 4: remote.sqlc.dev.quickdb.v1.UploadArchiveRequest.outputs:type_name -> remote.sqlc.dev.quickdb.v1.File + 12, // 5: remote.sqlc.dev.quickdb.v1.UploadArchiveRequest.annotations:type_name -> remote.sqlc.dev.quickdb.v1.UploadArchiveRequest.AnnotationsEntry + 5, // 6: remote.sqlc.dev.quickdb.v1.UploadArchiveRequest.query_sets:type_name -> remote.sqlc.dev.quickdb.v1.QuerySet + 4, // 7: remote.sqlc.dev.quickdb.v1.UploadArchiveRequest.config:type_name -> remote.sqlc.dev.quickdb.v1.File + 5, // 8: remote.sqlc.dev.quickdb.v1.VerifyQuerySetsRequest.query_sets:type_name -> remote.sqlc.dev.quickdb.v1.QuerySet + 4, // 9: remote.sqlc.dev.quickdb.v1.VerifyQuerySetsRequest.config:type_name -> remote.sqlc.dev.quickdb.v1.File + 13, // 10: remote.sqlc.dev.quickdb.v1.VerifyQuerySetsRequest.annotations:type_name -> remote.sqlc.dev.quickdb.v1.VerifyQuerySetsRequest.AnnotationsEntry + 5, // 11: remote.sqlc.dev.quickdb.v1.GetQuerySetsResponse.query_sets:type_name -> remote.sqlc.dev.quickdb.v1.QuerySet + 0, // 12: remote.sqlc.dev.quickdb.v1.Quick.CreateEphemeralDatabase:input_type -> remote.sqlc.dev.quickdb.v1.CreateEphemeralDatabaseRequest + 2, // 13: remote.sqlc.dev.quickdb.v1.Quick.DropEphemeralDatabase:input_type -> remote.sqlc.dev.quickdb.v1.DropEphemeralDatabaseRequest + 6, // 14: remote.sqlc.dev.quickdb.v1.Quick.UploadArchive:input_type -> remote.sqlc.dev.quickdb.v1.UploadArchiveRequest + 8, // 15: remote.sqlc.dev.quickdb.v1.Quick.VerifyQuerySets:input_type -> remote.sqlc.dev.quickdb.v1.VerifyQuerySetsRequest + 10, // 16: remote.sqlc.dev.quickdb.v1.Quick.GetQuerySets:input_type -> remote.sqlc.dev.quickdb.v1.GetQuerySetsRequest + 1, // 17: remote.sqlc.dev.quickdb.v1.Quick.CreateEphemeralDatabase:output_type -> remote.sqlc.dev.quickdb.v1.CreateEphemeralDatabaseResponse + 3, // 18: remote.sqlc.dev.quickdb.v1.Quick.DropEphemeralDatabase:output_type -> remote.sqlc.dev.quickdb.v1.DropEphemeralDatabaseResponse + 7, // 19: remote.sqlc.dev.quickdb.v1.Quick.UploadArchive:output_type -> remote.sqlc.dev.quickdb.v1.UploadArchiveResponse + 9, // 20: remote.sqlc.dev.quickdb.v1.Quick.VerifyQuerySets:output_type -> remote.sqlc.dev.quickdb.v1.VerifyQuerySetsResponse + 11, // 21: remote.sqlc.dev.quickdb.v1.Quick.GetQuerySets:output_type -> remote.sqlc.dev.quickdb.v1.GetQuerySetsResponse + 17, // [17:22] is the sub-list for method output_type + 12, // [12:17] is the sub-list for method input_type + 12, // [12:12] is the sub-list for extension type_name + 12, // [12:12] is the sub-list for extension extendee + 0, // [0:12] is the sub-list for field type_name +} + +func init() { file_v1_quickdb_proto_init() } +func file_v1_quickdb_proto_init() { + if File_v1_quickdb_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_v1_quickdb_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateEphemeralDatabaseRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_v1_quickdb_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateEphemeralDatabaseResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_v1_quickdb_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DropEphemeralDatabaseRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_v1_quickdb_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DropEphemeralDatabaseResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_v1_quickdb_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*File); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_v1_quickdb_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QuerySet); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_v1_quickdb_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UploadArchiveRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_v1_quickdb_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UploadArchiveResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_v1_quickdb_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VerifyQuerySetsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_v1_quickdb_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VerifyQuerySetsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_v1_quickdb_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetQuerySetsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_v1_quickdb_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetQuerySetsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_v1_quickdb_proto_rawDesc, + NumEnums: 0, + NumMessages: 14, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_v1_quickdb_proto_goTypes, + DependencyIndexes: file_v1_quickdb_proto_depIdxs, + MessageInfos: file_v1_quickdb_proto_msgTypes, + }.Build() + File_v1_quickdb_proto = out.File + file_v1_quickdb_proto_rawDesc = nil + file_v1_quickdb_proto_goTypes = nil + file_v1_quickdb_proto_depIdxs = nil +} diff --git a/internal/quickdb/v1/quickdb_grpc.pb.go b/internal/quickdb/v1/quickdb_grpc.pb.go new file mode 100644 index 0000000..f8f4a13 --- /dev/null +++ b/internal/quickdb/v1/quickdb_grpc.pb.go @@ -0,0 +1,257 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc (unknown) +// source: v1/quickdb.proto + +package quickdbv1 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + Quick_CreateEphemeralDatabase_FullMethodName = "/remote.sqlc.dev.quickdb.v1.Quick/CreateEphemeralDatabase" + Quick_DropEphemeralDatabase_FullMethodName = "/remote.sqlc.dev.quickdb.v1.Quick/DropEphemeralDatabase" + Quick_UploadArchive_FullMethodName = "/remote.sqlc.dev.quickdb.v1.Quick/UploadArchive" + Quick_VerifyQuerySets_FullMethodName = "/remote.sqlc.dev.quickdb.v1.Quick/VerifyQuerySets" + Quick_GetQuerySets_FullMethodName = "/remote.sqlc.dev.quickdb.v1.Quick/GetQuerySets" +) + +// QuickClient is the client API for Quick service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type QuickClient interface { + CreateEphemeralDatabase(ctx context.Context, in *CreateEphemeralDatabaseRequest, opts ...grpc.CallOption) (*CreateEphemeralDatabaseResponse, error) + DropEphemeralDatabase(ctx context.Context, in *DropEphemeralDatabaseRequest, opts ...grpc.CallOption) (*DropEphemeralDatabaseResponse, error) + UploadArchive(ctx context.Context, in *UploadArchiveRequest, opts ...grpc.CallOption) (*UploadArchiveResponse, error) + VerifyQuerySets(ctx context.Context, in *VerifyQuerySetsRequest, opts ...grpc.CallOption) (*VerifyQuerySetsResponse, error) + GetQuerySets(ctx context.Context, in *GetQuerySetsRequest, opts ...grpc.CallOption) (*GetQuerySetsResponse, error) +} + +type quickClient struct { + cc grpc.ClientConnInterface +} + +func NewQuickClient(cc grpc.ClientConnInterface) QuickClient { + return &quickClient{cc} +} + +func (c *quickClient) CreateEphemeralDatabase(ctx context.Context, in *CreateEphemeralDatabaseRequest, opts ...grpc.CallOption) (*CreateEphemeralDatabaseResponse, error) { + out := new(CreateEphemeralDatabaseResponse) + err := c.cc.Invoke(ctx, Quick_CreateEphemeralDatabase_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *quickClient) DropEphemeralDatabase(ctx context.Context, in *DropEphemeralDatabaseRequest, opts ...grpc.CallOption) (*DropEphemeralDatabaseResponse, error) { + out := new(DropEphemeralDatabaseResponse) + err := c.cc.Invoke(ctx, Quick_DropEphemeralDatabase_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *quickClient) UploadArchive(ctx context.Context, in *UploadArchiveRequest, opts ...grpc.CallOption) (*UploadArchiveResponse, error) { + out := new(UploadArchiveResponse) + err := c.cc.Invoke(ctx, Quick_UploadArchive_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *quickClient) VerifyQuerySets(ctx context.Context, in *VerifyQuerySetsRequest, opts ...grpc.CallOption) (*VerifyQuerySetsResponse, error) { + out := new(VerifyQuerySetsResponse) + err := c.cc.Invoke(ctx, Quick_VerifyQuerySets_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *quickClient) GetQuerySets(ctx context.Context, in *GetQuerySetsRequest, opts ...grpc.CallOption) (*GetQuerySetsResponse, error) { + out := new(GetQuerySetsResponse) + err := c.cc.Invoke(ctx, Quick_GetQuerySets_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QuickServer is the server API for Quick service. +// All implementations must embed UnimplementedQuickServer +// for forward compatibility +type QuickServer interface { + CreateEphemeralDatabase(context.Context, *CreateEphemeralDatabaseRequest) (*CreateEphemeralDatabaseResponse, error) + DropEphemeralDatabase(context.Context, *DropEphemeralDatabaseRequest) (*DropEphemeralDatabaseResponse, error) + UploadArchive(context.Context, *UploadArchiveRequest) (*UploadArchiveResponse, error) + VerifyQuerySets(context.Context, *VerifyQuerySetsRequest) (*VerifyQuerySetsResponse, error) + GetQuerySets(context.Context, *GetQuerySetsRequest) (*GetQuerySetsResponse, error) + mustEmbedUnimplementedQuickServer() +} + +// UnimplementedQuickServer must be embedded to have forward compatible implementations. +type UnimplementedQuickServer struct { +} + +func (UnimplementedQuickServer) CreateEphemeralDatabase(context.Context, *CreateEphemeralDatabaseRequest) (*CreateEphemeralDatabaseResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateEphemeralDatabase not implemented") +} +func (UnimplementedQuickServer) DropEphemeralDatabase(context.Context, *DropEphemeralDatabaseRequest) (*DropEphemeralDatabaseResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DropEphemeralDatabase not implemented") +} +func (UnimplementedQuickServer) UploadArchive(context.Context, *UploadArchiveRequest) (*UploadArchiveResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UploadArchive not implemented") +} +func (UnimplementedQuickServer) VerifyQuerySets(context.Context, *VerifyQuerySetsRequest) (*VerifyQuerySetsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method VerifyQuerySets not implemented") +} +func (UnimplementedQuickServer) GetQuerySets(context.Context, *GetQuerySetsRequest) (*GetQuerySetsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetQuerySets not implemented") +} +func (UnimplementedQuickServer) mustEmbedUnimplementedQuickServer() {} + +// UnsafeQuickServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to QuickServer will +// result in compilation errors. +type UnsafeQuickServer interface { + mustEmbedUnimplementedQuickServer() +} + +func RegisterQuickServer(s grpc.ServiceRegistrar, srv QuickServer) { + s.RegisterService(&Quick_ServiceDesc, srv) +} + +func _Quick_CreateEphemeralDatabase_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateEphemeralDatabaseRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QuickServer).CreateEphemeralDatabase(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Quick_CreateEphemeralDatabase_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QuickServer).CreateEphemeralDatabase(ctx, req.(*CreateEphemeralDatabaseRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Quick_DropEphemeralDatabase_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DropEphemeralDatabaseRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QuickServer).DropEphemeralDatabase(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Quick_DropEphemeralDatabase_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QuickServer).DropEphemeralDatabase(ctx, req.(*DropEphemeralDatabaseRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Quick_UploadArchive_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UploadArchiveRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QuickServer).UploadArchive(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Quick_UploadArchive_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QuickServer).UploadArchive(ctx, req.(*UploadArchiveRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Quick_VerifyQuerySets_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(VerifyQuerySetsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QuickServer).VerifyQuerySets(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Quick_VerifyQuerySets_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QuickServer).VerifyQuerySets(ctx, req.(*VerifyQuerySetsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Quick_GetQuerySets_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetQuerySetsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QuickServer).GetQuerySets(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Quick_GetQuerySets_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QuickServer).GetQuerySets(ctx, req.(*GetQuerySetsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// Quick_ServiceDesc is the grpc.ServiceDesc for Quick service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Quick_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "remote.sqlc.dev.quickdb.v1.Quick", + HandlerType: (*QuickServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "CreateEphemeralDatabase", + Handler: _Quick_CreateEphemeralDatabase_Handler, + }, + { + MethodName: "DropEphemeralDatabase", + Handler: _Quick_DropEphemeralDatabase_Handler, + }, + { + MethodName: "UploadArchive", + Handler: _Quick_UploadArchive_Handler, + }, + { + MethodName: "VerifyQuerySets", + Handler: _Quick_VerifyQuerySets_Handler, + }, + { + MethodName: "GetQuerySets", + Handler: _Quick_GetQuerySets_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "v1/quickdb.proto", +} diff --git a/internal/rpc/errors.go b/internal/rpc/errors.go new file mode 100644 index 0000000..8095334 --- /dev/null +++ b/internal/rpc/errors.go @@ -0,0 +1,13 @@ +package rpc + +import ( + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +const errMessageUnauthenticated = `rpc authentication failed + +You may be using a sqlc auth token that was created for a different project, +or your auth token may have expired.` + +var ErrUnauthenticated = status.New(codes.Unauthenticated, errMessageUnauthenticated).Err() diff --git a/internal/rpc/interceptor.go b/internal/rpc/interceptor.go new file mode 100644 index 0000000..6d8dc79 --- /dev/null +++ b/internal/rpc/interceptor.go @@ -0,0 +1,22 @@ +package rpc + +import ( + "context" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func UnaryInterceptor(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + err := invoker(ctx, method, req, reply, cc, opts...) + + switch status.Convert(err).Code() { + case codes.OK: + return nil + case codes.Unauthenticated: + return ErrUnauthenticated + default: + return err + } +} diff --git a/internal/shfmt/shfmt.go b/internal/shfmt/shfmt.go new file mode 100644 index 0000000..88f3074 --- /dev/null +++ b/internal/shfmt/shfmt.go @@ -0,0 +1,38 @@ +package shfmt + +import ( + "os" + "regexp" + "strings" +) + +var pat = regexp.MustCompile(`\$\{[A-Z_]+\}`) + +type Replacer struct { + envmap map[string]string +} + +func (r *Replacer) Replace(f string) string { + return pat.ReplaceAllStringFunc(f, func(s string) string { + s = strings.TrimPrefix(s, "${") + s = strings.TrimSuffix(s, "}") + return r.envmap[s] + }) +} + +func NewReplacer(env []string) *Replacer { + r := Replacer{ + envmap: map[string]string{}, + } + if env == nil { + env = os.Environ() + } + for _, e := range env { + k, v, _ := strings.Cut(e, "=") + if k == "SQLC_AUTH_TOKEN" { + continue + } + r.envmap[k] = v + } + return &r +} diff --git a/internal/shfmt/shfmt_test.go b/internal/shfmt/shfmt_test.go new file mode 100644 index 0000000..cf99ed2 --- /dev/null +++ b/internal/shfmt/shfmt_test.go @@ -0,0 +1,17 @@ +package shfmt + +import "testing" + +func TestReplace(t *testing.T) { + s := "POSTGRES_SQL://${PG_USER}:${PG_PASSWORD}@${PG_HOST}:${PG_PORT}/AUTHORS" + r := NewReplacer([]string{ + "PG_USER=user", + "PG_PASSWORD=password", + "PG_HOST=host", + "PG_PORT=port", + }) + e := "POSTGRES_SQL://user:password@host:port/AUTHORS" + if v := r.Replace(s); v != e { + t.Errorf("%s != %s", v, e) + } +} diff --git a/internal/source/code.go b/internal/source/code.go new file mode 100644 index 0000000..4ad14f0 --- /dev/null +++ b/internal/source/code.go @@ -0,0 +1,171 @@ +package source + +import ( + "bufio" + "fmt" + "sort" + "strings" + "unicode" +) + +type Edit struct { + Location int + Old string + New string + OldFunc func(string) int +} + +type CommentSyntax struct { + Dash bool + Hash bool + SlashStar bool +} + +func LineNumber(source string, head int) (int, int) { + // Calculate the true line and column number for a query, ignoring spaces + var comment bool + var loc, line, col int + for i, char := range source { + loc += 1 + col += 1 + // TODO: Check bounds + if char == '-' && source[i+1] == '-' { + comment = true + } + if char == '\n' { + comment = false + line += 1 + col = 0 + } + if loc <= head { + continue + } + if unicode.IsSpace(char) { + continue + } + if comment { + continue + } + break + } + return line + 1, col +} + +func Pluck(source string, location, length int) (string, error) { + head := location + tail := location + length + return source[head:tail], nil +} + +func Mutate(raw string, a []Edit) (string, error) { + if len(a) == 0 { + return raw, nil + } + + sort.Slice(a, func(i, j int) bool { return a[i].Location > a[j].Location }) + + s := raw + for idx, edit := range a { + start := edit.Location + 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 + oldLen + if stop > len(s) { + return "", fmt.Errorf("edit stop location is out of bounds") + } + + // If this is not the first edit, (applied backwards), check if + // this edit overlaps the previous one (and is therefore a developer error) + if idx != 0 { + prevEdit := a[idx-1] + if prevEdit.Location < edit.Location+oldLen { + return "", fmt.Errorf("2 edits overlap") + } + } + + s = s[:start] + edit.New + s[stop:] + } + return s, nil +} + +func StripComments(sql string) (string, []string, error) { + s := bufio.NewScanner(strings.NewReader(strings.TrimSpace(sql))) + var lines, comments []string + for s.Scan() { + t := s.Text() + if strings.HasPrefix(t, "-- name:") { + continue + } + if strings.HasPrefix(t, "/* name:") && strings.HasSuffix(t, "*/") { + continue + } + if strings.HasPrefix(t, "# name:") { + continue + } + if after, ok := strings.CutPrefix(t, "--"); ok { + comments = append(comments, after) + continue + } + if strings.HasPrefix(t, "/*") && strings.HasSuffix(t, "*/") { + // Preserve MySQL optimizer hints, which share block-comment + // syntax but are semantically part of the query. + if strings.HasPrefix(t, "/*+") { + lines = append(lines, t) + continue + } + t = strings.TrimPrefix(t, "/*") + t = strings.TrimSuffix(t, "*/") + comments = append(comments, t) + continue + } + if after, ok := strings.CutPrefix(t, "#"); ok { + comments = append(comments, after) + continue + } + lines = append(lines, t) + } + return strings.Join(lines, "\n"), comments, s.Err() +} + +func CleanedComments(rawSQL string, cs CommentSyntax) ([]string, error) { + s := bufio.NewScanner(strings.NewReader(strings.TrimSpace(rawSQL))) + var comments []string + for s.Scan() { + line := s.Text() + var prefix string + if strings.HasPrefix(line, "--") { + if !cs.Dash { + continue + } + prefix = "--" + } + if strings.HasPrefix(line, "/*") { + if !cs.SlashStar { + continue + } + prefix = "/*" + } + if strings.HasPrefix(line, "#") { + if !cs.Hash { + continue + } + prefix = "#" + } + if prefix == "" { + continue + } + + rest := line[len(prefix):] + rest = strings.TrimSuffix(rest, "*/") + comments = append(comments, rest) + } + return comments, s.Err() +} diff --git a/internal/source/mutate_test.go b/internal/source/mutate_test.go new file mode 100644 index 0000000..dd76888 --- /dev/null +++ b/internal/source/mutate_test.go @@ -0,0 +1,210 @@ +package source + +import ( + "fmt" + "testing" +) + +// newEdit is a testing helper for quickly generating Edits +func newEdit(loc int, old, new string) Edit { + return Edit{Location: loc, Old: old, New: new} +} + +// TestMutateSingle tests almost every possibility of a single edit +func TestMutateSingle(t *testing.T) { + type test struct { + input string + edit Edit + expected string + } + + tests := []test{ + // Simple edits that replace everything + {"", newEdit(0, "", ""), ""}, + {"a", newEdit(0, "a", "A"), "A"}, + {"abcde", newEdit(0, "abcde", "fghij"), "fghij"}, + {"", newEdit(0, "", "fghij"), "fghij"}, + {"abcde", newEdit(0, "abcde", ""), ""}, + + // Edits that start at the very beginning (But don't cover the whole range) + {"abcde", newEdit(0, "a", "A"), "Abcde"}, + {"abcde", newEdit(0, "ab", "AB"), "ABcde"}, + {"abcde", newEdit(0, "abc", "ABC"), "ABCde"}, + {"abcde", newEdit(0, "abcd", "ABCD"), "ABCDe"}, + + // The above repeated, but with different lengths + {"abcde", newEdit(0, "a", ""), "bcde"}, + {"abcde", newEdit(0, "ab", "A"), "Acde"}, + {"abcde", newEdit(0, "abc", "AB"), "ABde"}, + {"abcde", newEdit(0, "abcd", "AB"), "ABe"}, + + // Edits that touch the end (but don't cover the whole range) + {"abcde", newEdit(4, "e", "E"), "abcdE"}, + {"abcde", newEdit(3, "de", "DE"), "abcDE"}, + {"abcde", newEdit(2, "cde", "CDE"), "abCDE"}, + {"abcde", newEdit(1, "bcde", "BCDE"), "aBCDE"}, + + // The above repeated, but with different lengths + {"abcde", newEdit(4, "e", ""), "abcd"}, + {"abcde", newEdit(3, "de", "D"), "abcD"}, + {"abcde", newEdit(2, "cde", "CD"), "abCD"}, + {"abcde", newEdit(1, "bcde", "BC"), "aBC"}, + + // Raw insertions / deletions + {"abcde", newEdit(0, "", "_"), "_abcde"}, + {"abcde", newEdit(1, "", "_"), "a_bcde"}, + {"abcde", newEdit(2, "", "_"), "ab_cde"}, + {"abcde", newEdit(3, "", "_"), "abc_de"}, + {"abcde", newEdit(4, "", "_"), "abcd_e"}, + {"abcde", newEdit(5, "", "_"), "abcde_"}, + } + + origTests := tests + // Generate the reverse mutations, for every edit - the opposite edit that makes it "undo" + for _, spec := range origTests { + tests = append(tests, test{ + input: spec.expected, + edit: newEdit(spec.edit.Location, spec.edit.New, spec.edit.Old), + expected: spec.input, + }) + } + + for _, spec := range tests { + expected := spec.expected + + actual, err := Mutate(spec.input, []Edit{spec.edit}) + testName := fmt.Sprintf("Mutate(%s, Edit{%v, %v -> %v})", spec.input, spec.edit.Location, spec.edit.Old, spec.edit.New) + if err != nil { + t.Errorf("%s should not error (%v)", testName, err) + continue + } + + if actual != expected { + t.Errorf("%s expected %v; got %v", testName, expected, actual) + } + } +} + +// TestMutateMulti tests combinations of edits +func TestMutateMulti(t *testing.T) { + type test struct { + input string + edit1 Edit + edit2 Edit + expected string + } + + tests := []test{ + // Edits that are >1 character from each other + {"abcde", newEdit(0, "a", "A"), newEdit(2, "c", "C"), "AbCde"}, + {"abcde", newEdit(0, "a", "A"), newEdit(2, "c", "C"), "AbCde"}, + + // 2 edits bump right up next to each other + {"abcde", newEdit(0, "abc", ""), newEdit(3, "de", "DE"), "DE"}, + {"abcde", newEdit(0, "abc", "ABC"), newEdit(3, "de", ""), "ABC"}, + {"abcde", newEdit(0, "abc", "ABC"), newEdit(3, "de", "DE"), "ABCDE"}, + {"abcde", newEdit(1, "b", "BB"), newEdit(2, "c", "CC"), "aBBCCde"}, + + // 2 edits bump next to each other, but don't cover the whole string + {"abcdef", newEdit(1, "bc", "C"), newEdit(3, "de", "D"), "aCDf"}, + {"abcde", newEdit(1, "bc", "CCCC"), newEdit(3, "d", "DDD"), "aCCCCDDDe"}, + + // lengthening edits + {"abcde", newEdit(1, "b", "BBBB"), newEdit(2, "c", "CCCC"), "aBBBBCCCCde"}, + } + + origTests := tests + // Generate the edits in opposite order mutations, source edits should be independent of + // the order the edits are specified + for _, spec := range origTests { + tests = append(tests, test{ + input: spec.input, + edit1: spec.edit2, + edit2: spec.edit1, + expected: spec.expected, + }) + } + + for _, spec := range tests { + expected := spec.expected + + actual, err := Mutate(spec.input, []Edit{spec.edit1, spec.edit2}) + testName := fmt.Sprintf("Mutate(%s, Edits{(%v, %v -> %v), (%v, %v -> %v)})", spec.input, + spec.edit1.Location, spec.edit1.Old, spec.edit1.New, + spec.edit2.Location, spec.edit2.Old, spec.edit2.New) + + if err != nil { + t.Errorf("%s should not error (%v)", testName, err) + continue + } + + if actual != expected { + t.Errorf("%s expected %v; got %v", testName, expected, actual) + } + } +} + +// TestMutateErrorSingle test errors are generated for trivially incorrect single edits +func TestMutateErrorSingle(t *testing.T) { + type test struct { + input string + edit Edit + } + + tests := []test{ + // old text is longer than input text + {"", newEdit(0, "a", "A")}, + {"a", newEdit(0, "aa", "A")}, + {"hello", newEdit(0, "hello!", "A")}, + + // negative indexes + {"aaa", newEdit(-1, "aa", "A")}, + {"aaa", newEdit(-2, "aa", "A")}, + {"aaa", newEdit(-100, "aa", "A")}, + } + + for _, spec := range tests { + edit := spec.edit + + _, err := Mutate(spec.input, []Edit{edit}) + testName := fmt.Sprintf("Mutate(%s, Edit{%v, %v -> %v})", spec.input, edit.Location, edit.Old, edit.New) + if err == nil { + t.Errorf("%s should error (%v)", testName, err) + continue + } + } +} + +// TestMutateErrorMulti tests error that can only happen across multiple errors +func TestMutateErrorMulti(t *testing.T) { + type test struct { + input string + edit1 Edit + edit2 Edit + } + + tests := []test{ + // These edits overlap each other, and are therefore undefined + {"abcdef", newEdit(0, "a", ""), newEdit(0, "a", "A")}, + {"abcdef", newEdit(0, "ab", ""), newEdit(1, "ab", "AB")}, + {"abcdef", newEdit(0, "abc", ""), newEdit(2, "abc", "ABC")}, + + // the last edit is longer than the string itself + {"abcdef", newEdit(0, "abcdefghi", ""), newEdit(2, "abc", "ABC")}, + + // negative indexes + {"abcdef", newEdit(-1, "abc", ""), newEdit(3, "abc", "ABC")}, + {"abcdef", newEdit(0, "abc", ""), newEdit(-1, "abc", "ABC")}, + } + + for _, spec := range tests { + actual, err := Mutate(spec.input, []Edit{spec.edit1, spec.edit2}) + testName := fmt.Sprintf("Mutate(%s, Edits{(%v, %v -> %v), (%v, %v -> %v)})", spec.input, + spec.edit1.Location, spec.edit1.Old, spec.edit1.New, + spec.edit2.Location, spec.edit2.Old, spec.edit2.New) + + if err == nil { + t.Errorf("%s should error, but got (%v)", testName, actual) + } + } +} diff --git a/internal/sql/ast/CLAUDE.md b/internal/sql/ast/CLAUDE.md new file mode 100644 index 0000000..3c5d338 --- /dev/null +++ b/internal/sql/ast/CLAUDE.md @@ -0,0 +1,169 @@ +# AST Package - Claude Code Guide + +This package defines the Abstract Syntax Tree (AST) nodes used by sqlc to represent SQL statements across all supported databases (PostgreSQL, MySQL, SQLite). + +## Key Concepts + +### Node Interface +All AST nodes implement the `Node` interface with: +- `Pos() int` - returns the source position +- `Format(buf *TrackedBuffer, d format.Dialect)` - formats the node back to SQL + +### TrackedBuffer +The `TrackedBuffer` type (`print.go`) handles SQL formatting with dialect-specific behavior: +- `astFormat(node Node)` - formats any AST node +- `join(list *List, sep string)` - joins list items with separator +- `WriteString(s string)` - writes raw SQL +- `QuoteIdent(name string)` - quotes identifiers (dialect-specific) +- `TypeName(ns, name string)` - formats type names (dialect-specific) + +### Pretty printing +The doc renderer lives in `ast/printer` (`printer.Buffer`), which knows +nothing about AST nodes; `TrackedBuffer` embeds it and adds the +AST-facing layer (`astFormat`, comment emission, anchors). +`TrackedBuffer` records a Wadler-style document (the model behind Prettier +and ruff): Format methods emit text plus layout tokens, and the renderer +decides which break opportunities become newlines. + +- `Line()` - a space when the group fits on one line, a newline otherwise +- `Softline()` - nothing when the group fits, a newline otherwise +- `Group()` / `EndGroup()` - a region laid out flat when its width fits +- `Indent()` / `EndIndent()` - one level deeper (2 spaces) after breaks +- `Breaker()` - forces every enclosing group to break (measures as + infinitely wide) +- `joinComma(list)` - joins items with `,` + `Line()` +- `condition(node)` - clause-level AND/OR chain without outer parentheses, + one branch per line when broken + +`ast.Format(n, d)` renders on a single line (all breaks collapse); +`ast.Pretty(n, d, width)` breaks lines to fit `width` columns. Statement +Format methods open a group and put `Line()` before each clause keyword +(`FROM`, `WHERE`, ...), so a statement that fits stays on one line and a +long one breaks at clause boundaries. When adding a Format method, write +tokens so the flat rendering is correct SQL; layout tokens are optional. + +The fmt command does not pass a real width: like gofmt it never rewraps +on its own, so it prints with an effectively infinite width and defers +to the author's line breaks instead. `AttachComments` records, for each +emission-point marker, whether its neighbouring printed nodes sat on +different source lines; when they did, `boundary()` emits a `Breaker()` +there on the real print, so the group the author broke stays broken and +everything else stays flat. + +### Comments +`ast.File{Stmts, Comments}` is what a comment-surfacing parser returns +(SQLite via meyer's ParseFile). `AttachComments(raw, d, comments, src)` +classifies each comment once, against a dry-run of the printer: source +positions and line numbers decide trailing (same line as the code +before) vs leading, and each comment is attached to the emission point +— node or clause/list boundary — where the printer will reach it. From +then on positions are never consulted: `PrettyWithComments(n, d, width, +table)` emits by node identity, which is what lets edited or synthetic +trees print their comments correctly (the dave/dst model; each record +also keeps the node the comment followed, for future rewriting tools). +A line comment forces every enclosing group to break — `hardline` and +`breaker` tokens measure as infinitely wide — so commented statements +format instead of collapsing. Emission points (`beforeClause`, +`boundary` in joinComma/condition) double as classification markers on +the dry run, guaranteeing attach-time decisions and print-time emission +agree. + +### Dialect Interface +Dialect-specific formatting is handled via the `Dialect` interface: +```go +type Dialect interface { + QuoteIdent(string) string + TypeName(ns, name string) string + Param(int) string // $1 for PostgreSQL, ? for MySQL + NamedParam(string) string // @name for PostgreSQL, :name for SQLite + Cast(string) string +} +``` + +## Adding New AST Nodes + +When adding a new AST node type: + +1. **Create the node file** (e.g., `variable_expr.go`): +```go +package ast + +type VariableExpr struct { + Name string + Location int +} + +func (n *VariableExpr) Pos() int { + return n.Location +} + +func (n *VariableExpr) Format(buf *TrackedBuffer) { + if n == nil { + return + } + buf.WriteString("@") + buf.WriteString(n.Name) +} +``` + +2. **Add to `astutils/walk.go`** - Add a case in the Walk function: +```go +case *ast.VariableExpr: + // Leaf node - no children to traverse +``` + +3. **Add to `astutils/rewrite.go`** - Add a case in the Apply function: +```go +case *ast.VariableExpr: + // Leaf node - no children to traverse +``` + +4. **Update the parser/converter** - In the relevant engine (e.g., `dolphin/convert.go` for MySQL) + +## Helper Functions for Format Methods + +- `set(node Node) bool` - returns true if node is non-nil and not an empty List +- `items(list *List) bool` - returns true if list has items +- `todo(node) Node` - placeholder for unimplemented conversions (returns nil) + +## Common Node Types + +### Statements +- `SelectStmt` - SELECT queries with FromClause, WhereClause, etc. +- `InsertStmt` - INSERT with Relation, Cols, SelectStmt, OnConflictClause +- `UpdateStmt` - UPDATE with Relations, TargetList, WhereClause +- `DeleteStmt` - DELETE with Relations, FromClause (for JOINs), Targets + +### Expressions +- `A_Expr` - General expression with operator (e.g., `a + b`, `@param`) +- `ColumnRef` - Column reference with Fields list +- `FuncCall` - Function call with Func, Args, aggregation options +- `TypeCast` - Type cast with Arg and TypeName +- `ParenExpr` - Parenthesized expression +- `VariableExpr` - MySQL user variable (e.g., `@user_id`) + +### Table References +- `RangeVar` - Table reference with schema, name, alias +- `JoinExpr` - JOIN with Larg, Rarg, Jointype, Quals/UsingClause + +## MySQL-Specific Nodes + +- `VariableExpr` - User variables (`@var`), distinct from sqlc's `@param` syntax +- `IntervalExpr` - INTERVAL expressions +- `OnDuplicateKeyUpdate` - MySQL's ON DUPLICATE KEY UPDATE clause +- `ParenExpr` - Explicit parentheses (TiDB parser wraps expressions) + +## Important Distinctions + +### MySQL @variable vs sqlc @param +- sqlc named parameters (`@param`) never reach the AST: `internal/sql/preprocess` + replaces them with the dialect's native placeholder before parsing, so engines + only ever see a `ParamRef` +- `@name` is only sqlc syntax where the preprocessor's dialect says so. MySQL is + excluded, so `@user_id` there stays a user variable (`VariableExpr`) + +### Type Modifiers +- `TypeName.Typmods` holds type modifiers like `varchar(255)` +- For MySQL, only populate Typmods for types where length is user-specified: + - VARCHAR, CHAR, VARBINARY, BINARY - need length + - DATETIME, TIMESTAMP, DATE - internal flen should NOT be output diff --git a/internal/sql/ast/a_array_expr.go b/internal/sql/ast/a_array_expr.go new file mode 100644 index 0000000..ed11abf --- /dev/null +++ b/internal/sql/ast/a_array_expr.go @@ -0,0 +1,23 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type A_ArrayExpr struct { + Tag NodeTag[A_ArrayExpr] `json:"tag"` + + Elements *List `json:"elements,omitempty"` + Location int `json:"location"` +} + +func (n *A_ArrayExpr) Pos() int { + return n.Location +} + +func (n *A_ArrayExpr) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteString("ARRAY[") + buf.join(n.Elements, d, ", ") + buf.WriteString("]") +} diff --git a/internal/sql/ast/a_const.go b/internal/sql/ast/a_const.go new file mode 100644 index 0000000..0f507d9 --- /dev/null +++ b/internal/sql/ast/a_const.go @@ -0,0 +1,27 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type A_Const struct { + Tag NodeTag[A_Const] `json:"tag"` + + Val Node `json:"val,omitempty"` + Location int `json:"location"` +} + +func (n *A_Const) Pos() int { + return n.Location +} + +func (n *A_Const) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + if _, ok := n.Val.(*String); ok { + buf.WriteString("'") + buf.astFormat(n.Val, d) + buf.WriteString("'") + } else { + buf.astFormat(n.Val, d) + } +} diff --git a/internal/sql/ast/a_expr.go b/internal/sql/ast/a_expr.go new file mode 100644 index 0000000..1327467 --- /dev/null +++ b/internal/sql/ast/a_expr.go @@ -0,0 +1,178 @@ +package ast + +import ( + "strings" + + "github.com/sqlc-dev/sqlc/internal/sql/format" +) + +type A_Expr struct { + Tag NodeTag[A_Expr] `json:"tag"` + + Kind A_Expr_Kind `json:"kind"` + // Name is the operator, as a list of String nodes: PostgreSQL's + // operator space is open (user-defined and schema-qualified operators), + // so the shared tree keeps pg_query's shape rather than an enum. Each + // engine's converter writes the operator as its parser saw it — for an + // engine that accepts more than one spelling of the same operator + // (SQLite's != for <>, == for =), that is the author's spelling, which + // is how the printer preserves it. + Name *List `json:"name,omitempty"` + Lexpr Node `json:"lexpr,omitempty"` + Rexpr Node `json:"rexpr,omitempty"` + Location int `json:"location"` +} + +func (n *A_Expr) Pos() int { + return n.Location +} + +// isNamedParam reports whether this A_Expr represents a named parameter, +// returning its sigil and name. Engines encode a named parameter as a +// prefix pseudo-operator carrying the sigil the author wrote (@name for +// most engines; SQLite also spells :name and $name). The spellings mean +// different things to sqlc, so the printer emits the one it was given. +func (n *A_Expr) isNamedParam() (sigil, name string, ok bool) { + if n.Name == nil || len(n.Name.Items) != 1 { + return "", "", false + } + s, sok := n.Name.Items[0].(*String) + if !sok || (s.Str != "@" && s.Str != ":" && s.Str != "$") { + return "", "", false + } + if set(n.Lexpr) || !set(n.Rexpr) { + return "", "", false + } + if nameStr, sok := n.Rexpr.(*String); sok { + return s.Str, nameStr.Str, true + } + // Before the compiler rewrites named parameters, @name parses as the @ + // operator applied to a bare column reference. + if col, sok := n.Rexpr.(*ColumnRef); sok && col.Fields != nil && len(col.Fields.Items) == 1 { + if f, sok := col.Fields.Items[0].(*String); sok { + return s.Str, f.Str, true + } + } + return "", "", false +} + +// gluePrefix reports that this prefix expression must print with no space +// between the operator and its operand. `@name::type` is a sqlc named +// parameter with a cast: the cast binds tighter than the operator, so the +// parse is @ applied to a TypeCast and isNamedParam does not see it — but +// `@ name::type` would break the parameter apart for sqlc's scanner. Glue +// the sigils onto any operand that starts with an identifier, which also +// keeps a genuine prefix operator like pg's absolute-value @ meaning the +// same thing. +func (n *A_Expr) gluePrefix() bool { + if set(n.Lexpr) || n.Name == nil || len(n.Name.Items) != 1 { + return false + } + s, ok := n.Name.Items[0].(*String) + if !ok || (s.Str != "@" && s.Str != ":" && s.Str != "$") { + return false + } + operand := n.Rexpr + if tc, ok := operand.(*TypeCast); ok { + operand = tc.Arg + } + switch operand.(type) { + case *ColumnRef, *FuncCall: + return true + } + return false +} + +// negated returns true when the expression's operator carries the negated +// spelling of a pattern-match operator (e.g. "!~~" for NOT LIKE). +func (n *A_Expr) negated() bool { + if n.Name == nil || len(n.Name.Items) != 1 { + return false + } + s, ok := n.Name.Items[0].(*String) + return ok && strings.HasPrefix(s.Str, "!") +} + +func (n *A_Expr) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + + // Check for named parameter first (works regardless of Kind) + if sigil, name, ok := n.isNamedParam(); ok { + buf.WriteString(sigil) + buf.WriteString(name) + return + } + + switch n.Kind { + case A_Expr_Kind_IN: + buf.astFormat(n.Lexpr, d) + buf.WriteString(" IN (") + buf.astFormat(n.Rexpr, d) + buf.WriteString(")") + case A_Expr_Kind_LIKE: + buf.astFormat(n.Lexpr, d) + if n.negated() { + buf.WriteString(" NOT LIKE ") + } else { + buf.WriteString(" LIKE ") + } + buf.astFormat(n.Rexpr, d) + case A_Expr_Kind_ILIKE: + buf.astFormat(n.Lexpr, d) + if n.negated() { + buf.WriteString(" NOT ILIKE ") + } else { + buf.WriteString(" ILIKE ") + } + buf.astFormat(n.Rexpr, d) + case A_Expr_Kind_SIMILAR: + buf.astFormat(n.Lexpr, d) + buf.WriteString(" SIMILAR TO ") + buf.astFormat(n.Rexpr, d) + case A_Expr_Kind_BETWEEN: + buf.astFormat(n.Lexpr, d) + buf.WriteString(" BETWEEN ") + if l, ok := n.Rexpr.(*List); ok && len(l.Items) == 2 { + buf.astFormat(l.Items[0], d) + buf.WriteString(" AND ") + buf.astFormat(l.Items[1], d) + } + case A_Expr_Kind_NOT_BETWEEN: + buf.astFormat(n.Lexpr, d) + buf.WriteString(" NOT BETWEEN ") + if l, ok := n.Rexpr.(*List); ok && len(l.Items) == 2 { + buf.astFormat(l.Items[0], d) + buf.WriteString(" AND ") + buf.astFormat(l.Items[1], d) + } + case A_Expr_Kind_DISTINCT: + buf.astFormat(n.Lexpr, d) + buf.WriteString(" IS DISTINCT FROM ") + buf.astFormat(n.Rexpr, d) + case A_Expr_Kind_NOT_DISTINCT: + buf.astFormat(n.Lexpr, d) + buf.WriteString(" IS NOT DISTINCT FROM ") + buf.astFormat(n.Rexpr, d) + case A_Expr_Kind_NULLIF: + buf.WriteString("NULLIF(") + buf.astFormat(n.Lexpr, d) + buf.WriteString(", ") + buf.astFormat(n.Rexpr, d) + buf.WriteString(")") + default: + // Standard operator (including A_Expr_Kind_OP) + if set(n.Lexpr) { + buf.astFormat(n.Lexpr, d) + buf.WriteString(" ") + } + buf.astFormat(n.Name, d) + if set(n.Rexpr) { + if !n.gluePrefix() { + buf.WriteString(" ") + } + buf.astFormat(n.Rexpr, d) + } + } +} diff --git a/internal/sql/ast/a_expr_kind.go b/internal/sql/ast/a_expr_kind.go new file mode 100644 index 0000000..3adc923 --- /dev/null +++ b/internal/sql/ast/a_expr_kind.go @@ -0,0 +1,24 @@ +package ast + +type A_Expr_Kind uint + +const ( + A_Expr_Kind_OP A_Expr_Kind = 1 + A_Expr_Kind_OP_ANY A_Expr_Kind = 2 + A_Expr_Kind_OP_ALL A_Expr_Kind = 3 + A_Expr_Kind_DISTINCT A_Expr_Kind = 4 + A_Expr_Kind_NOT_DISTINCT A_Expr_Kind = 5 + A_Expr_Kind_NULLIF A_Expr_Kind = 6 + A_Expr_Kind_IN A_Expr_Kind = 7 + A_Expr_Kind_LIKE A_Expr_Kind = 8 + A_Expr_Kind_ILIKE A_Expr_Kind = 9 + A_Expr_Kind_SIMILAR A_Expr_Kind = 10 + A_Expr_Kind_BETWEEN A_Expr_Kind = 11 + A_Expr_Kind_NOT_BETWEEN A_Expr_Kind = 12 + A_Expr_Kind_BETWEEN_SYM A_Expr_Kind = 13 + A_Expr_Kind_NOT_BETWEEN_SYM A_Expr_Kind = 14 +) + +func (n *A_Expr_Kind) Pos() int { + return 0 +} diff --git a/internal/sql/ast/a_indices.go b/internal/sql/ast/a_indices.go new file mode 100644 index 0000000..2f7715e --- /dev/null +++ b/internal/sql/ast/a_indices.go @@ -0,0 +1,34 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type A_Indices struct { + Tag NodeTag[A_Indices] `json:"tag"` + + IsSlice bool `json:"is_slice"` + Lidx Node `json:"lidx,omitempty"` + Uidx Node `json:"uidx,omitempty"` +} + +func (n *A_Indices) Pos() int { + return 0 +} + +func (n *A_Indices) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteString("[") + if n.IsSlice { + if set(n.Lidx) { + buf.astFormat(n.Lidx, d) + } + buf.WriteString(":") + if set(n.Uidx) { + buf.astFormat(n.Uidx, d) + } + } else { + buf.astFormat(n.Uidx, d) + } + buf.WriteString("]") +} diff --git a/internal/sql/ast/a_indirection.go b/internal/sql/ast/a_indirection.go new file mode 100644 index 0000000..df682bb --- /dev/null +++ b/internal/sql/ast/a_indirection.go @@ -0,0 +1,12 @@ +package ast + +type A_Indirection struct { + Tag NodeTag[A_Indirection] `json:"tag"` + + Arg Node `json:"arg,omitempty"` + Indirection *List `json:"indirection,omitempty"` +} + +func (n *A_Indirection) Pos() int { + return 0 +} diff --git a/internal/sql/ast/a_star.go b/internal/sql/ast/a_star.go new file mode 100644 index 0000000..c95d7c0 --- /dev/null +++ b/internal/sql/ast/a_star.go @@ -0,0 +1,18 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type A_Star struct { + Tag NodeTag[A_Star] `json:"tag"` +} + +func (n *A_Star) Pos() int { + return 0 +} + +func (n *A_Star) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteRune('*') +} diff --git a/internal/sql/ast/access_priv.go b/internal/sql/ast/access_priv.go new file mode 100644 index 0000000..ab16946 --- /dev/null +++ b/internal/sql/ast/access_priv.go @@ -0,0 +1,12 @@ +package ast + +type AccessPriv struct { + Tag NodeTag[AccessPriv] `json:"tag"` + + PrivName *string `json:"priv_name,omitempty"` + Cols *List `json:"cols,omitempty"` +} + +func (n *AccessPriv) Pos() int { + return 0 +} diff --git a/internal/sql/ast/agg_split.go b/internal/sql/ast/agg_split.go new file mode 100644 index 0000000..9c4b997 --- /dev/null +++ b/internal/sql/ast/agg_split.go @@ -0,0 +1,7 @@ +package ast + +type AggSplit uint + +func (n *AggSplit) Pos() int { + return 0 +} diff --git a/internal/sql/ast/agg_strategy.go b/internal/sql/ast/agg_strategy.go new file mode 100644 index 0000000..02b65a8 --- /dev/null +++ b/internal/sql/ast/agg_strategy.go @@ -0,0 +1,7 @@ +package ast + +type AggStrategy uint + +func (n *AggStrategy) Pos() int { + return 0 +} diff --git a/internal/sql/ast/aggref.go b/internal/sql/ast/aggref.go new file mode 100644 index 0000000..f9c8a08 --- /dev/null +++ b/internal/sql/ast/aggref.go @@ -0,0 +1,27 @@ +package ast + +type Aggref struct { + Tag NodeTag[Aggref] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Aggfnoid Oid `json:"aggfnoid"` + Aggtype Oid `json:"aggtype"` + Aggcollid Oid `json:"aggcollid"` + Inputcollid Oid `json:"inputcollid"` + Aggargtypes *List `json:"aggargtypes,omitempty"` + Aggdirectargs *List `json:"aggdirectargs,omitempty"` + Args *List `json:"args,omitempty"` + Aggorder *List `json:"aggorder,omitempty"` + Aggdistinct *List `json:"aggdistinct,omitempty"` + Aggfilter Node `json:"aggfilter,omitempty"` + Aggstar bool `json:"aggstar"` + Aggvariadic bool `json:"aggvariadic"` + Aggkind byte `json:"aggkind"` + Agglevelsup Index `json:"agglevelsup"` + Aggsplit AggSplit `json:"aggsplit"` + Location int `json:"location"` +} + +func (n *Aggref) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/alias.go b/internal/sql/ast/alias.go new file mode 100644 index 0000000..198120f --- /dev/null +++ b/internal/sql/ast/alias.go @@ -0,0 +1,28 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type Alias struct { + Tag NodeTag[Alias] `json:"tag"` + + Aliasname *string `json:"aliasname,omitempty"` + Colnames *List `json:"colnames,omitempty"` +} + +func (n *Alias) Pos() int { + return 0 +} + +func (n *Alias) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + if n.Aliasname != nil { + buf.WriteString(*n.Aliasname) + } + if items(n.Colnames) { + buf.WriteString("(") + buf.astFormat(n.Colnames, d) + buf.WriteString(")") + } +} diff --git a/internal/sql/ast/alter_collation_stmt.go b/internal/sql/ast/alter_collation_stmt.go new file mode 100644 index 0000000..fedcf5a --- /dev/null +++ b/internal/sql/ast/alter_collation_stmt.go @@ -0,0 +1,11 @@ +package ast + +type AlterCollationStmt struct { + Tag NodeTag[AlterCollationStmt] `json:"tag"` + + Collname *List `json:"collname,omitempty"` +} + +func (n *AlterCollationStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_database_set_stmt.go b/internal/sql/ast/alter_database_set_stmt.go new file mode 100644 index 0000000..14d485e --- /dev/null +++ b/internal/sql/ast/alter_database_set_stmt.go @@ -0,0 +1,12 @@ +package ast + +type AlterDatabaseSetStmt struct { + Tag NodeTag[AlterDatabaseSetStmt] `json:"tag"` + + Dbname *string `json:"dbname,omitempty"` + Setstmt *VariableSetStmt `json:"setstmt,omitempty"` +} + +func (n *AlterDatabaseSetStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_database_stmt.go b/internal/sql/ast/alter_database_stmt.go new file mode 100644 index 0000000..9eb3dae --- /dev/null +++ b/internal/sql/ast/alter_database_stmt.go @@ -0,0 +1,12 @@ +package ast + +type AlterDatabaseStmt struct { + Tag NodeTag[AlterDatabaseStmt] `json:"tag"` + + Dbname *string `json:"dbname,omitempty"` + Options *List `json:"options,omitempty"` +} + +func (n *AlterDatabaseStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_default_privileges_stmt.go b/internal/sql/ast/alter_default_privileges_stmt.go new file mode 100644 index 0000000..f72a412 --- /dev/null +++ b/internal/sql/ast/alter_default_privileges_stmt.go @@ -0,0 +1,12 @@ +package ast + +type AlterDefaultPrivilegesStmt struct { + Tag NodeTag[AlterDefaultPrivilegesStmt] `json:"tag"` + + Options *List `json:"options,omitempty"` + Action *GrantStmt `json:"action,omitempty"` +} + +func (n *AlterDefaultPrivilegesStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_domain_stmt.go b/internal/sql/ast/alter_domain_stmt.go new file mode 100644 index 0000000..669b7a5 --- /dev/null +++ b/internal/sql/ast/alter_domain_stmt.go @@ -0,0 +1,16 @@ +package ast + +type AlterDomainStmt struct { + Tag NodeTag[AlterDomainStmt] `json:"tag"` + + Subtype byte `json:"subtype"` + TypeName *List `json:"type_name,omitempty"` + Name *string `json:"name,omitempty"` + Def Node `json:"def,omitempty"` + Behavior DropBehavior `json:"behavior"` + MissingOk bool `json:"missing_ok"` +} + +func (n *AlterDomainStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_enum_stmt.go b/internal/sql/ast/alter_enum_stmt.go new file mode 100644 index 0000000..70a6a85 --- /dev/null +++ b/internal/sql/ast/alter_enum_stmt.go @@ -0,0 +1,16 @@ +package ast + +type AlterEnumStmt struct { + Tag NodeTag[AlterEnumStmt] `json:"tag"` + + TypeName *List `json:"type_name,omitempty"` + OldVal *string `json:"old_val,omitempty"` + NewVal *string `json:"new_val,omitempty"` + NewValNeighbor *string `json:"new_val_neighbor,omitempty"` + NewValIsAfter bool `json:"new_val_is_after"` + SkipIfNewValExists bool `json:"skip_if_new_val_exists"` +} + +func (n *AlterEnumStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_event_trig_stmt.go b/internal/sql/ast/alter_event_trig_stmt.go new file mode 100644 index 0000000..14356fa --- /dev/null +++ b/internal/sql/ast/alter_event_trig_stmt.go @@ -0,0 +1,12 @@ +package ast + +type AlterEventTrigStmt struct { + Tag NodeTag[AlterEventTrigStmt] `json:"tag"` + + Trigname *string `json:"trigname,omitempty"` + Tgenabled byte `json:"tgenabled"` +} + +func (n *AlterEventTrigStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_extension_contents_stmt.go b/internal/sql/ast/alter_extension_contents_stmt.go new file mode 100644 index 0000000..3821812 --- /dev/null +++ b/internal/sql/ast/alter_extension_contents_stmt.go @@ -0,0 +1,14 @@ +package ast + +type AlterExtensionContentsStmt struct { + Tag NodeTag[AlterExtensionContentsStmt] `json:"tag"` + + Extname *string `json:"extname,omitempty"` + Action int `json:"action"` + Objtype ObjectType `json:"objtype"` + Object Node `json:"object,omitempty"` +} + +func (n *AlterExtensionContentsStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_extension_stmt.go b/internal/sql/ast/alter_extension_stmt.go new file mode 100644 index 0000000..c1daf85 --- /dev/null +++ b/internal/sql/ast/alter_extension_stmt.go @@ -0,0 +1,12 @@ +package ast + +type AlterExtensionStmt struct { + Tag NodeTag[AlterExtensionStmt] `json:"tag"` + + Extname *string `json:"extname,omitempty"` + Options *List `json:"options,omitempty"` +} + +func (n *AlterExtensionStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_fdw_stmt.go b/internal/sql/ast/alter_fdw_stmt.go new file mode 100644 index 0000000..6a74137 --- /dev/null +++ b/internal/sql/ast/alter_fdw_stmt.go @@ -0,0 +1,13 @@ +package ast + +type AlterFdwStmt struct { + Tag NodeTag[AlterFdwStmt] `json:"tag"` + + Fdwname *string `json:"fdwname,omitempty"` + FuncOptions *List `json:"func_options,omitempty"` + Options *List `json:"options,omitempty"` +} + +func (n *AlterFdwStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_foreign_server_stmt.go b/internal/sql/ast/alter_foreign_server_stmt.go new file mode 100644 index 0000000..fcdbad1 --- /dev/null +++ b/internal/sql/ast/alter_foreign_server_stmt.go @@ -0,0 +1,14 @@ +package ast + +type AlterForeignServerStmt struct { + Tag NodeTag[AlterForeignServerStmt] `json:"tag"` + + Servername *string `json:"servername,omitempty"` + Version *string `json:"version,omitempty"` + Options *List `json:"options,omitempty"` + HasVersion bool `json:"has_version"` +} + +func (n *AlterForeignServerStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_function_stmt.go b/internal/sql/ast/alter_function_stmt.go new file mode 100644 index 0000000..93d3931 --- /dev/null +++ b/internal/sql/ast/alter_function_stmt.go @@ -0,0 +1,12 @@ +package ast + +type AlterFunctionStmt struct { + Tag NodeTag[AlterFunctionStmt] `json:"tag"` + + Func *ObjectWithArgs `json:"func,omitempty"` + Actions *List `json:"actions,omitempty"` +} + +func (n *AlterFunctionStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_object_depends_stmt.go b/internal/sql/ast/alter_object_depends_stmt.go new file mode 100644 index 0000000..f7b46ae --- /dev/null +++ b/internal/sql/ast/alter_object_depends_stmt.go @@ -0,0 +1,14 @@ +package ast + +type AlterObjectDependsStmt struct { + Tag NodeTag[AlterObjectDependsStmt] `json:"tag"` + + ObjectType ObjectType `json:"object_type"` + Relation *RangeVar `json:"relation,omitempty"` + Object Node `json:"object,omitempty"` + Extname Node `json:"extname,omitempty"` +} + +func (n *AlterObjectDependsStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_object_schema_stmt.go b/internal/sql/ast/alter_object_schema_stmt.go new file mode 100644 index 0000000..3a5a5bd --- /dev/null +++ b/internal/sql/ast/alter_object_schema_stmt.go @@ -0,0 +1,15 @@ +package ast + +type AlterObjectSchemaStmt struct { + Tag NodeTag[AlterObjectSchemaStmt] `json:"tag"` + + ObjectType ObjectType `json:"object_type"` + Relation *RangeVar `json:"relation,omitempty"` + Object Node `json:"object,omitempty"` + Newschema *string `json:"newschema,omitempty"` + MissingOk bool `json:"missing_ok"` +} + +func (n *AlterObjectSchemaStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_op_family_stmt.go b/internal/sql/ast/alter_op_family_stmt.go new file mode 100644 index 0000000..7d287d5 --- /dev/null +++ b/internal/sql/ast/alter_op_family_stmt.go @@ -0,0 +1,14 @@ +package ast + +type AlterOpFamilyStmt struct { + Tag NodeTag[AlterOpFamilyStmt] `json:"tag"` + + Opfamilyname *List `json:"opfamilyname,omitempty"` + Amname *string `json:"amname,omitempty"` + IsDrop bool `json:"is_drop"` + Items *List `json:"items,omitempty"` +} + +func (n *AlterOpFamilyStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_operator_stmt.go b/internal/sql/ast/alter_operator_stmt.go new file mode 100644 index 0000000..0d61c65 --- /dev/null +++ b/internal/sql/ast/alter_operator_stmt.go @@ -0,0 +1,12 @@ +package ast + +type AlterOperatorStmt struct { + Tag NodeTag[AlterOperatorStmt] `json:"tag"` + + Opername *ObjectWithArgs `json:"opername,omitempty"` + Options *List `json:"options,omitempty"` +} + +func (n *AlterOperatorStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_owner_stmt.go b/internal/sql/ast/alter_owner_stmt.go new file mode 100644 index 0000000..041c0d4 --- /dev/null +++ b/internal/sql/ast/alter_owner_stmt.go @@ -0,0 +1,14 @@ +package ast + +type AlterOwnerStmt struct { + Tag NodeTag[AlterOwnerStmt] `json:"tag"` + + ObjectType ObjectType `json:"object_type"` + Relation *RangeVar `json:"relation,omitempty"` + Object Node `json:"object,omitempty"` + Newowner *RoleSpec `json:"newowner,omitempty"` +} + +func (n *AlterOwnerStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_policy_stmt.go b/internal/sql/ast/alter_policy_stmt.go new file mode 100644 index 0000000..b7f9d7b --- /dev/null +++ b/internal/sql/ast/alter_policy_stmt.go @@ -0,0 +1,15 @@ +package ast + +type AlterPolicyStmt struct { + Tag NodeTag[AlterPolicyStmt] `json:"tag"` + + PolicyName *string `json:"policy_name,omitempty"` + Table *RangeVar `json:"table,omitempty"` + Roles *List `json:"roles,omitempty"` + Qual Node `json:"qual,omitempty"` + WithCheck Node `json:"with_check,omitempty"` +} + +func (n *AlterPolicyStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_publication_stmt.go b/internal/sql/ast/alter_publication_stmt.go new file mode 100644 index 0000000..718368f --- /dev/null +++ b/internal/sql/ast/alter_publication_stmt.go @@ -0,0 +1,15 @@ +package ast + +type AlterPublicationStmt struct { + Tag NodeTag[AlterPublicationStmt] `json:"tag"` + + Pubname *string `json:"pubname,omitempty"` + Options *List `json:"options,omitempty"` + Tables *List `json:"tables,omitempty"` + ForAllTables bool `json:"for_all_tables"` + TableAction DefElemAction `json:"table_action"` +} + +func (n *AlterPublicationStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_role_set_stmt.go b/internal/sql/ast/alter_role_set_stmt.go new file mode 100644 index 0000000..a973ccb --- /dev/null +++ b/internal/sql/ast/alter_role_set_stmt.go @@ -0,0 +1,13 @@ +package ast + +type AlterRoleSetStmt struct { + Tag NodeTag[AlterRoleSetStmt] `json:"tag"` + + Role *RoleSpec `json:"role,omitempty"` + Database *string `json:"database,omitempty"` + Setstmt *VariableSetStmt `json:"setstmt,omitempty"` +} + +func (n *AlterRoleSetStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_role_stmt.go b/internal/sql/ast/alter_role_stmt.go new file mode 100644 index 0000000..3c7d607 --- /dev/null +++ b/internal/sql/ast/alter_role_stmt.go @@ -0,0 +1,13 @@ +package ast + +type AlterRoleStmt struct { + Tag NodeTag[AlterRoleStmt] `json:"tag"` + + Role *RoleSpec `json:"role,omitempty"` + Options *List `json:"options,omitempty"` + Action int `json:"action"` +} + +func (n *AlterRoleStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_seq_stmt.go b/internal/sql/ast/alter_seq_stmt.go new file mode 100644 index 0000000..53e46d4 --- /dev/null +++ b/internal/sql/ast/alter_seq_stmt.go @@ -0,0 +1,14 @@ +package ast + +type AlterSeqStmt struct { + Tag NodeTag[AlterSeqStmt] `json:"tag"` + + Sequence *RangeVar `json:"sequence,omitempty"` + Options *List `json:"options,omitempty"` + ForIdentity bool `json:"for_identity"` + MissingOk bool `json:"missing_ok"` +} + +func (n *AlterSeqStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_subscription_stmt.go b/internal/sql/ast/alter_subscription_stmt.go new file mode 100644 index 0000000..3b54140 --- /dev/null +++ b/internal/sql/ast/alter_subscription_stmt.go @@ -0,0 +1,15 @@ +package ast + +type AlterSubscriptionStmt struct { + Tag NodeTag[AlterSubscriptionStmt] `json:"tag"` + + Kind AlterSubscriptionType `json:"kind"` + Subname *string `json:"subname,omitempty"` + Conninfo *string `json:"conninfo,omitempty"` + Publication *List `json:"publication,omitempty"` + Options *List `json:"options,omitempty"` +} + +func (n *AlterSubscriptionStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_subscription_type.go b/internal/sql/ast/alter_subscription_type.go new file mode 100644 index 0000000..1268bd6 --- /dev/null +++ b/internal/sql/ast/alter_subscription_type.go @@ -0,0 +1,7 @@ +package ast + +type AlterSubscriptionType uint + +func (n *AlterSubscriptionType) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_system_stmt.go b/internal/sql/ast/alter_system_stmt.go new file mode 100644 index 0000000..724ad8f --- /dev/null +++ b/internal/sql/ast/alter_system_stmt.go @@ -0,0 +1,11 @@ +package ast + +type AlterSystemStmt struct { + Tag NodeTag[AlterSystemStmt] `json:"tag"` + + Setstmt *VariableSetStmt `json:"setstmt,omitempty"` +} + +func (n *AlterSystemStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_table_cmd.go b/internal/sql/ast/alter_table_cmd.go new file mode 100644 index 0000000..b357605 --- /dev/null +++ b/internal/sql/ast/alter_table_cmd.go @@ -0,0 +1,59 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +const ( + AT_AddColumn AlterTableType = iota + AT_AlterColumnType + AT_DropColumn + AT_DropNotNull + AT_SetNotNull +) + +type AlterTableType int + +func (t AlterTableType) String() string { + switch t { + case AT_AddColumn: + return "AddColumn" + case AT_AlterColumnType: + return "AlterColumnType" + case AT_DropColumn: + return "DropColumn" + case AT_DropNotNull: + return "DropNotNull" + case AT_SetNotNull: + return "SetNotNull" + default: + return "Unknown" + } +} + +type AlterTableCmd struct { + Tag NodeTag[AlterTableCmd] `json:"tag"` + + Subtype AlterTableType `json:"subtype"` + Name *string `json:"name,omitempty"` + Def *ColumnDef `json:"def,omitempty"` + Newowner *RoleSpec `json:"newowner,omitempty"` + Behavior DropBehavior `json:"behavior"` + MissingOk bool `json:"missing_ok"` +} + +func (n *AlterTableCmd) Pos() int { + return 0 +} + +func (n *AlterTableCmd) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + switch n.Subtype { + case AT_AddColumn: + buf.WriteString(" ADD COLUMN ") + case AT_DropColumn: + buf.WriteString(" DROP COLUMN ") + } + + buf.astFormat(n.Def, d) +} diff --git a/internal/sql/ast/alter_table_move_all_stmt.go b/internal/sql/ast/alter_table_move_all_stmt.go new file mode 100644 index 0000000..ac028a0 --- /dev/null +++ b/internal/sql/ast/alter_table_move_all_stmt.go @@ -0,0 +1,15 @@ +package ast + +type AlterTableMoveAllStmt struct { + Tag NodeTag[AlterTableMoveAllStmt] `json:"tag"` + + OrigTablespacename *string `json:"orig_tablespacename,omitempty"` + Objtype ObjectType `json:"objtype"` + Roles *List `json:"roles,omitempty"` + NewTablespacename *string `json:"new_tablespacename,omitempty"` + Nowait bool `json:"nowait"` +} + +func (n *AlterTableMoveAllStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_table_set_schema_stmt.go b/internal/sql/ast/alter_table_set_schema_stmt.go new file mode 100644 index 0000000..d7f62bf --- /dev/null +++ b/internal/sql/ast/alter_table_set_schema_stmt.go @@ -0,0 +1,13 @@ +package ast + +type AlterTableSetSchemaStmt struct { + Tag NodeTag[AlterTableSetSchemaStmt] `json:"tag"` + + Table *TableName `json:"table,omitempty"` + NewSchema *string `json:"new_schema,omitempty"` + MissingOk bool `json:"missing_ok"` +} + +func (n *AlterTableSetSchemaStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_table_space_options_stmt.go b/internal/sql/ast/alter_table_space_options_stmt.go new file mode 100644 index 0000000..f9b97b2 --- /dev/null +++ b/internal/sql/ast/alter_table_space_options_stmt.go @@ -0,0 +1,13 @@ +package ast + +type AlterTableSpaceOptionsStmt struct { + Tag NodeTag[AlterTableSpaceOptionsStmt] `json:"tag"` + + Tablespacename *string `json:"tablespacename,omitempty"` + Options *List `json:"options,omitempty"` + IsReset bool `json:"is_reset"` +} + +func (n *AlterTableSpaceOptionsStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_table_stmt.go b/internal/sql/ast/alter_table_stmt.go new file mode 100644 index 0000000..5e54102 --- /dev/null +++ b/internal/sql/ast/alter_table_stmt.go @@ -0,0 +1,38 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type AlterTableStmt struct { + Tag NodeTag[AlterTableStmt] `json:"tag"` + + // TODO: Only TableName or Relation should be defined + Relation *RangeVar `json:"relation,omitempty"` + Table *TableName `json:"table,omitempty"` + Cmds *List `json:"cmds,omitempty"` + MissingOk bool `json:"missing_ok"` + Relkind ObjectType `json:"relkind"` + // Incomplete marks a statement whose source carried syntax this node + // does not model, such as column constraints beyond plain NOT NULL and + // PRIMARY KEY on an added column. No faithful rendering exists for it. + Incomplete bool `json:"incomplete"` +} + +func (n *AlterTableStmt) Pos() int { + return 0 +} + +func (n *AlterTableStmt) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + // An incomplete statement cannot be printed back: part of its source + // was parsed away. Render nothing, which no verification accepts, so + // the formatter keeps the statement as written. + if n.Incomplete { + return + } + buf.WriteString("ALTER TABLE ") + buf.astFormat(n.Relation, d) + buf.astFormat(n.Table, d) + buf.astFormat(n.Cmds, d) +} diff --git a/internal/sql/ast/alter_table_type.go b/internal/sql/ast/alter_table_type.go new file mode 100644 index 0000000..b592204 --- /dev/null +++ b/internal/sql/ast/alter_table_type.go @@ -0,0 +1,7 @@ +package ast + +type AlterTableType_PG uint + +func (n *AlterTableType_PG) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_ts_config_type.go b/internal/sql/ast/alter_ts_config_type.go new file mode 100644 index 0000000..05f6164 --- /dev/null +++ b/internal/sql/ast/alter_ts_config_type.go @@ -0,0 +1,7 @@ +package ast + +type AlterTSConfigType uint + +func (n *AlterTSConfigType) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_ts_configuration_stmt.go b/internal/sql/ast/alter_ts_configuration_stmt.go new file mode 100644 index 0000000..9ecd8bc --- /dev/null +++ b/internal/sql/ast/alter_ts_configuration_stmt.go @@ -0,0 +1,17 @@ +package ast + +type AlterTSConfigurationStmt struct { + Tag NodeTag[AlterTSConfigurationStmt] `json:"tag"` + + Kind AlterTSConfigType `json:"kind"` + Cfgname *List `json:"cfgname,omitempty"` + Tokentype *List `json:"tokentype,omitempty"` + Dicts *List `json:"dicts,omitempty"` + Override bool `json:"override"` + Replace bool `json:"replace"` + MissingOk bool `json:"missing_ok"` +} + +func (n *AlterTSConfigurationStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_ts_dictionary_stmt.go b/internal/sql/ast/alter_ts_dictionary_stmt.go new file mode 100644 index 0000000..6c89127 --- /dev/null +++ b/internal/sql/ast/alter_ts_dictionary_stmt.go @@ -0,0 +1,12 @@ +package ast + +type AlterTSDictionaryStmt struct { + Tag NodeTag[AlterTSDictionaryStmt] `json:"tag"` + + Dictname *List `json:"dictname,omitempty"` + Options *List `json:"options,omitempty"` +} + +func (n *AlterTSDictionaryStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_type_add_value_stmt.go b/internal/sql/ast/alter_type_add_value_stmt.go new file mode 100644 index 0000000..a8878d6 --- /dev/null +++ b/internal/sql/ast/alter_type_add_value_stmt.go @@ -0,0 +1,16 @@ +package ast + +type AlterTypeAddValueStmt struct { + Tag NodeTag[AlterTypeAddValueStmt] `json:"tag"` + + Type *TypeName `json:"type,omitempty"` + NewValue *string `json:"new_value,omitempty"` + NewValHasNeighbor bool `json:"new_val_has_neighbor"` + NewValNeighbor *string `json:"new_val_neighbor,omitempty"` + NewValIsAfter bool `json:"new_val_is_after"` + SkipIfNewValExists bool `json:"skip_if_new_val_exists"` +} + +func (n *AlterTypeAddValueStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_type_rename_value_stmt.go b/internal/sql/ast/alter_type_rename_value_stmt.go new file mode 100644 index 0000000..52e59d4 --- /dev/null +++ b/internal/sql/ast/alter_type_rename_value_stmt.go @@ -0,0 +1,13 @@ +package ast + +type AlterTypeRenameValueStmt struct { + Tag NodeTag[AlterTypeRenameValueStmt] `json:"tag"` + + Type *TypeName `json:"type,omitempty"` + OldValue *string `json:"old_value,omitempty"` + NewValue *string `json:"new_value,omitempty"` +} + +func (n *AlterTypeRenameValueStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_type_set_schema_stmt.go b/internal/sql/ast/alter_type_set_schema_stmt.go new file mode 100644 index 0000000..46d312b --- /dev/null +++ b/internal/sql/ast/alter_type_set_schema_stmt.go @@ -0,0 +1,12 @@ +package ast + +type AlterTypeSetSchemaStmt struct { + Tag NodeTag[AlterTypeSetSchemaStmt] `json:"tag"` + + Type *TypeName `json:"type,omitempty"` + NewSchema *string `json:"new_schema,omitempty"` +} + +func (n *AlterTypeSetSchemaStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alter_user_mapping_stmt.go b/internal/sql/ast/alter_user_mapping_stmt.go new file mode 100644 index 0000000..ab85751 --- /dev/null +++ b/internal/sql/ast/alter_user_mapping_stmt.go @@ -0,0 +1,13 @@ +package ast + +type AlterUserMappingStmt struct { + Tag NodeTag[AlterUserMappingStmt] `json:"tag"` + + User *RoleSpec `json:"user,omitempty"` + Servername *string `json:"servername,omitempty"` + Options *List `json:"options,omitempty"` +} + +func (n *AlterUserMappingStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/alternative_sub_plan.go b/internal/sql/ast/alternative_sub_plan.go new file mode 100644 index 0000000..ad374d1 --- /dev/null +++ b/internal/sql/ast/alternative_sub_plan.go @@ -0,0 +1,12 @@ +package ast + +type AlternativeSubPlan struct { + Tag NodeTag[AlternativeSubPlan] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Subplans *List `json:"subplans,omitempty"` +} + +func (n *AlternativeSubPlan) Pos() int { + return 0 +} diff --git a/internal/sql/ast/array_coerce_expr.go b/internal/sql/ast/array_coerce_expr.go new file mode 100644 index 0000000..ce8c952 --- /dev/null +++ b/internal/sql/ast/array_coerce_expr.go @@ -0,0 +1,19 @@ +package ast + +type ArrayCoerceExpr struct { + Tag NodeTag[ArrayCoerceExpr] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Arg Node `json:"arg,omitempty"` + Elemfuncid Oid `json:"elemfuncid"` + Resulttype Oid `json:"resulttype"` + Resulttypmod int32 `json:"resulttypmod"` + Resultcollid Oid `json:"resultcollid"` + IsExplicit bool `json:"is_explicit"` + Coerceformat CoercionForm `json:"coerceformat"` + Location int `json:"location"` +} + +func (n *ArrayCoerceExpr) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/array_expr.go b/internal/sql/ast/array_expr.go new file mode 100644 index 0000000..753ed0f --- /dev/null +++ b/internal/sql/ast/array_expr.go @@ -0,0 +1,17 @@ +package ast + +type ArrayExpr struct { + Tag NodeTag[ArrayExpr] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + ArrayTypeid Oid `json:"array_typeid"` + ArrayCollid Oid `json:"array_collid"` + ElementTypeid Oid `json:"element_typeid"` + Elements *List `json:"elements,omitempty"` + Multidims bool `json:"multidims"` + Location int `json:"location"` +} + +func (n *ArrayExpr) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/array_ref.go b/internal/sql/ast/array_ref.go new file mode 100644 index 0000000..9fb4a35 --- /dev/null +++ b/internal/sql/ast/array_ref.go @@ -0,0 +1,19 @@ +package ast + +type ArrayRef struct { + Tag NodeTag[ArrayRef] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Refarraytype Oid `json:"refarraytype"` + Refelemtype Oid `json:"refelemtype"` + Reftypmod int32 `json:"reftypmod"` + Refcollid Oid `json:"refcollid"` + Refupperindexpr *List `json:"refupperindexpr,omitempty"` + Reflowerindexpr *List `json:"reflowerindexpr,omitempty"` + Refexpr Node `json:"refexpr,omitempty"` + Refassgnexpr Node `json:"refassgnexpr,omitempty"` +} + +func (n *ArrayRef) Pos() int { + return 0 +} diff --git a/internal/sql/ast/between_expr.go b/internal/sql/ast/between_expr.go new file mode 100644 index 0000000..f1e4508 --- /dev/null +++ b/internal/sql/ast/between_expr.go @@ -0,0 +1,36 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type BetweenExpr struct { + Tag NodeTag[BetweenExpr] `json:"tag"` + + // Expr is the value expression to be compared. + Expr Node `json:"expr,omitempty"` + // Left is the left expression in the between statement. + Left Node `json:"left,omitempty"` + // Right is the right expression in the between statement. + Right Node `json:"right,omitempty"` + // Not is true, the expression is "not between". + Not bool `json:"not"` + Location int `json:"location"` +} + +func (n *BetweenExpr) Pos() int { + return n.Location +} + +func (n *BetweenExpr) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.astFormat(n.Expr, d) + if n.Not { + buf.WriteString(" NOT BETWEEN ") + } else { + buf.WriteString(" BETWEEN ") + } + buf.astFormat(n.Left, d) + buf.WriteString(" AND ") + buf.astFormat(n.Right, d) +} diff --git a/internal/sql/ast/bit_string.go b/internal/sql/ast/bit_string.go new file mode 100644 index 0000000..fb53f2d --- /dev/null +++ b/internal/sql/ast/bit_string.go @@ -0,0 +1,11 @@ +package ast + +type BitString struct { + Tag NodeTag[BitString] `json:"tag"` + + Str string `json:"str"` +} + +func (n *BitString) Pos() int { + return 0 +} diff --git a/internal/sql/ast/block_id_data.go b/internal/sql/ast/block_id_data.go new file mode 100644 index 0000000..bcb5171 --- /dev/null +++ b/internal/sql/ast/block_id_data.go @@ -0,0 +1,12 @@ +package ast + +type BlockIdData struct { + Tag NodeTag[BlockIdData] `json:"tag"` + + BiHi uint16 `json:"bi_hi"` + BiLo uint16 `json:"bi_lo"` +} + +func (n *BlockIdData) Pos() int { + return 0 +} diff --git a/internal/sql/ast/bool_expr.go b/internal/sql/ast/bool_expr.go new file mode 100644 index 0000000..9efea3d --- /dev/null +++ b/internal/sql/ast/bool_expr.go @@ -0,0 +1,70 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type BoolExpr struct { + Tag NodeTag[BoolExpr] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Boolop BoolExprType `json:"boolop"` + Args *List `json:"args,omitempty"` + Location int `json:"location"` +} + +func (n *BoolExpr) Pos() int { + return n.Location +} + +func (n *BoolExpr) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + switch n.Boolop { + case BoolExprTypeIsNull: + if items(n.Args) && len(n.Args.Items) > 0 { + buf.astFormat(n.Args.Items[0], d) + } + buf.WriteString(" IS NULL") + case BoolExprTypeIsNotNull: + if items(n.Args) && len(n.Args.Items) > 0 { + buf.astFormat(n.Args.Items[0], d) + } + buf.WriteString(" IS NOT NULL") + case BoolExprTypeNot: + // NOT expression: format as NOT + buf.WriteString("NOT ") + if items(n.Args) && len(n.Args.Items) > 0 { + buf.astFormat(n.Args.Items[0], d) + } + default: + var op string + switch n.Boolop { + case BoolExprTypeAnd: + op = "AND " + case BoolExprTypeOr: + op = "OR " + } + buf.WriteString("(") + buf.Group() + buf.Indent() + buf.Softline() + if items(n.Args) && op != "" { + first := true + for _, item := range n.Args.Items { + if _, ok := item.(*TODO); ok { + continue + } + if !first { + buf.Line() + buf.WriteString(op) + } + first = false + buf.astFormat(item, d) + } + } + buf.EndIndent() + buf.Softline() + buf.EndGroup() + buf.WriteString(")") + } +} diff --git a/internal/sql/ast/bool_expr_type.go b/internal/sql/ast/bool_expr_type.go new file mode 100644 index 0000000..7a4068d --- /dev/null +++ b/internal/sql/ast/bool_expr_type.go @@ -0,0 +1,19 @@ +package ast + +// https://github.com/pganalyze/libpg_query/blob/13-latest/protobuf/pg_query.proto#L2783-L2789 +const ( + _ BoolExprType = iota + BoolExprTypeAnd + BoolExprTypeOr + BoolExprTypeNot + + // Added for MySQL + BoolExprTypeIsNull + BoolExprTypeIsNotNull +) + +type BoolExprType uint + +func (n *BoolExprType) Pos() int { + return 0 +} diff --git a/internal/sql/ast/bool_test_type.go b/internal/sql/ast/bool_test_type.go new file mode 100644 index 0000000..b5e0198 --- /dev/null +++ b/internal/sql/ast/bool_test_type.go @@ -0,0 +1,7 @@ +package ast + +type BoolTestType uint + +func (n *BoolTestType) Pos() int { + return 0 +} diff --git a/internal/sql/ast/boolean.go b/internal/sql/ast/boolean.go new file mode 100644 index 0000000..b5a7502 --- /dev/null +++ b/internal/sql/ast/boolean.go @@ -0,0 +1,28 @@ +package ast + +import ( + "fmt" + + "github.com/sqlc-dev/sqlc/internal/sql/format" +) + +type Boolean struct { + Tag NodeTag[Boolean] `json:"tag"` + + Boolval bool `json:"boolval"` +} + +func (n *Boolean) Pos() int { + return 0 +} + +func (n *Boolean) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + if n.Boolval { + fmt.Fprintf(buf, "true") + } else { + fmt.Fprintf(buf, "false") + } +} diff --git a/internal/sql/ast/boolean_test_expr.go b/internal/sql/ast/boolean_test_expr.go new file mode 100644 index 0000000..f6f3d90 --- /dev/null +++ b/internal/sql/ast/boolean_test_expr.go @@ -0,0 +1,14 @@ +package ast + +type BooleanTest struct { + Tag NodeTag[BooleanTest] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Arg Node `json:"arg,omitempty"` + Booltesttype BoolTestType `json:"booltesttype"` + Location int `json:"location"` +} + +func (n *BooleanTest) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/call_stmt.go b/internal/sql/ast/call_stmt.go new file mode 100644 index 0000000..c64b5a8 --- /dev/null +++ b/internal/sql/ast/call_stmt.go @@ -0,0 +1,21 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type CallStmt struct { + Tag NodeTag[CallStmt] `json:"tag"` + + FuncCall *FuncCall `json:"func_call,omitempty"` +} + +func (n *CallStmt) Pos() int { + if n.FuncCall == nil { + return 0 + } + return n.FuncCall.Pos() +} + +func (n *CallStmt) Format(buf *TrackedBuffer, d format.Dialect) { + buf.WriteString("CALL ") + buf.astFormat(n.FuncCall, d) +} diff --git a/internal/sql/ast/case_expr.go b/internal/sql/ast/case_expr.go new file mode 100644 index 0000000..4d9b618 --- /dev/null +++ b/internal/sql/ast/case_expr.go @@ -0,0 +1,36 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type CaseExpr struct { + Tag NodeTag[CaseExpr] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Casetype Oid `json:"casetype"` + Casecollid Oid `json:"casecollid"` + Arg Node `json:"arg,omitempty"` + Args *List `json:"args,omitempty"` + Defresult Node `json:"defresult,omitempty"` + Location int `json:"location"` +} + +func (n *CaseExpr) Pos() int { + return n.Location +} + +func (n *CaseExpr) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteString("CASE ") + if set(n.Arg) { + buf.astFormat(n.Arg, d) + buf.WriteString(" ") + } + buf.join(n.Args, d, " ") + if set(n.Defresult) { + buf.WriteString(" ELSE ") + buf.astFormat(n.Defresult, d) + } + buf.WriteString(" END") +} diff --git a/internal/sql/ast/case_test_expr.go b/internal/sql/ast/case_test_expr.go new file mode 100644 index 0000000..493293e --- /dev/null +++ b/internal/sql/ast/case_test_expr.go @@ -0,0 +1,14 @@ +package ast + +type CaseTestExpr struct { + Tag NodeTag[CaseTestExpr] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + TypeId Oid `json:"type_id"` + TypeMod int32 `json:"type_mod"` + Collation Oid `json:"collation"` +} + +func (n *CaseTestExpr) Pos() int { + return 0 +} diff --git a/internal/sql/ast/case_when.go b/internal/sql/ast/case_when.go new file mode 100644 index 0000000..fb39c4e --- /dev/null +++ b/internal/sql/ast/case_when.go @@ -0,0 +1,26 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type CaseWhen struct { + Tag NodeTag[CaseWhen] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Expr Node `json:"expr,omitempty"` + Result Node `json:"result,omitempty"` + Location int `json:"location"` +} + +func (n *CaseWhen) Pos() int { + return n.Location +} + +func (n *CaseWhen) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteString("WHEN ") + buf.astFormat(n.Expr, d) + buf.WriteString(" THEN ") + buf.astFormat(n.Result, d) +} diff --git a/internal/sql/ast/check_point_stmt.go b/internal/sql/ast/check_point_stmt.go new file mode 100644 index 0000000..55f6d13 --- /dev/null +++ b/internal/sql/ast/check_point_stmt.go @@ -0,0 +1,9 @@ +package ast + +type CheckPointStmt struct { + Tag NodeTag[CheckPointStmt] `json:"tag"` +} + +func (n *CheckPointStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/close_portal_stmt.go b/internal/sql/ast/close_portal_stmt.go new file mode 100644 index 0000000..d690543 --- /dev/null +++ b/internal/sql/ast/close_portal_stmt.go @@ -0,0 +1,11 @@ +package ast + +type ClosePortalStmt struct { + Tag NodeTag[ClosePortalStmt] `json:"tag"` + + Portalname *string `json:"portalname,omitempty"` +} + +func (n *ClosePortalStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/cluster_stmt.go b/internal/sql/ast/cluster_stmt.go new file mode 100644 index 0000000..f2b4588 --- /dev/null +++ b/internal/sql/ast/cluster_stmt.go @@ -0,0 +1,13 @@ +package ast + +type ClusterStmt struct { + Tag NodeTag[ClusterStmt] `json:"tag"` + + Relation *RangeVar `json:"relation,omitempty"` + Indexname *string `json:"indexname,omitempty"` + Verbose bool `json:"verbose"` +} + +func (n *ClusterStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/cmd_type.go b/internal/sql/ast/cmd_type.go new file mode 100644 index 0000000..dfe9019 --- /dev/null +++ b/internal/sql/ast/cmd_type.go @@ -0,0 +1,7 @@ +package ast + +type CmdType uint + +func (n *CmdType) Pos() int { + return 0 +} diff --git a/internal/sql/ast/coalesce_expr.go b/internal/sql/ast/coalesce_expr.go new file mode 100644 index 0000000..f51c2c5 --- /dev/null +++ b/internal/sql/ast/coalesce_expr.go @@ -0,0 +1,28 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type CoalesceExpr struct { + Tag NodeTag[CoalesceExpr] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Coalescetype Oid `json:"coalescetype"` + Coalescecollid Oid `json:"coalescecollid"` + Args *List `json:"args,omitempty"` + Location int `json:"location"` +} + +func (n *CoalesceExpr) Pos() int { + return n.Location +} + +func (n *CoalesceExpr) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + // Lower case, like every other function name: the printer upper-cases + // keywords, and function names are identifiers, which fold lower. + buf.WriteString("coalesce(") + buf.astFormat(n.Args, d) + buf.WriteString(")") +} diff --git a/internal/sql/ast/coerce_to_domain.go b/internal/sql/ast/coerce_to_domain.go new file mode 100644 index 0000000..09e681b --- /dev/null +++ b/internal/sql/ast/coerce_to_domain.go @@ -0,0 +1,17 @@ +package ast + +type CoerceToDomain struct { + Tag NodeTag[CoerceToDomain] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Arg Node `json:"arg,omitempty"` + Resulttype Oid `json:"resulttype"` + Resulttypmod int32 `json:"resulttypmod"` + Resultcollid Oid `json:"resultcollid"` + Coercionformat CoercionForm `json:"coercionformat"` + Location int `json:"location"` +} + +func (n *CoerceToDomain) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/coerce_to_domain_value.go b/internal/sql/ast/coerce_to_domain_value.go new file mode 100644 index 0000000..d78b3bf --- /dev/null +++ b/internal/sql/ast/coerce_to_domain_value.go @@ -0,0 +1,15 @@ +package ast + +type CoerceToDomainValue struct { + Tag NodeTag[CoerceToDomainValue] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + TypeId Oid `json:"type_id"` + TypeMod int32 `json:"type_mod"` + Collation Oid `json:"collation"` + Location int `json:"location"` +} + +func (n *CoerceToDomainValue) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/coerce_via_io.go b/internal/sql/ast/coerce_via_io.go new file mode 100644 index 0000000..5c9f809 --- /dev/null +++ b/internal/sql/ast/coerce_via_io.go @@ -0,0 +1,16 @@ +package ast + +type CoerceViaIO struct { + Tag NodeTag[CoerceViaIO] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Arg Node `json:"arg,omitempty"` + Resulttype Oid `json:"resulttype"` + Resultcollid Oid `json:"resultcollid"` + Coerceformat CoercionForm `json:"coerceformat"` + Location int `json:"location"` +} + +func (n *CoerceViaIO) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/coercion_context.go b/internal/sql/ast/coercion_context.go new file mode 100644 index 0000000..82753f9 --- /dev/null +++ b/internal/sql/ast/coercion_context.go @@ -0,0 +1,7 @@ +package ast + +type CoercionContext uint + +func (n *CoercionContext) Pos() int { + return 0 +} diff --git a/internal/sql/ast/coercion_form.go b/internal/sql/ast/coercion_form.go new file mode 100644 index 0000000..43eccb4 --- /dev/null +++ b/internal/sql/ast/coercion_form.go @@ -0,0 +1,7 @@ +package ast + +type CoercionForm uint + +func (n *CoercionForm) Pos() int { + return 0 +} diff --git a/internal/sql/ast/collate_clause.go b/internal/sql/ast/collate_clause.go new file mode 100644 index 0000000..494b3e1 --- /dev/null +++ b/internal/sql/ast/collate_clause.go @@ -0,0 +1,13 @@ +package ast + +type CollateClause struct { + Tag NodeTag[CollateClause] `json:"tag"` + + Arg Node `json:"arg,omitempty"` + Collname *List `json:"collname,omitempty"` + Location int `json:"location"` +} + +func (n *CollateClause) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/collate_expr.go b/internal/sql/ast/collate_expr.go new file mode 100644 index 0000000..c564358 --- /dev/null +++ b/internal/sql/ast/collate_expr.go @@ -0,0 +1,25 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type CollateExpr struct { + Tag NodeTag[CollateExpr] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Arg Node `json:"arg,omitempty"` + CollOid Oid `json:"coll_oid"` + Location int `json:"location"` +} + +func (n *CollateExpr) Pos() int { + return n.Location +} + +func (n *CollateExpr) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.astFormat(n.Xpr, d) + buf.WriteString(" COLLATE ") + buf.astFormat(n.Arg, d) +} diff --git a/internal/sql/ast/column_def.go b/internal/sql/ast/column_def.go new file mode 100644 index 0000000..9bacaa8 --- /dev/null +++ b/internal/sql/ast/column_def.go @@ -0,0 +1,72 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type ColumnDef struct { + Tag NodeTag[ColumnDef] `json:"tag"` + + Colname string `json:"colname"` + // TypeName is the column's type for the catalog. When Typeless is set + // the author wrote no type at all — SQLite allows it — and the column + // prints without one, whatever TypeName carries. + TypeName *TypeName `json:"type_name,omitempty"` + Typeless bool `json:"typeless"` + IsNotNull bool `json:"is_not_null"` + IsUnsigned bool `json:"is_unsigned"` + IsArray bool `json:"is_array"` + ArrayDims int `json:"array_dims"` + Vals *List `json:"vals,omitempty"` + Length *int `json:"length,omitempty"` + PrimaryKey bool `json:"primary_key"` + // IsHidden marks a column a relation offers by name without listing it, + // like the column an sqlite fts5 table names after itself. The legacy + // catalog drops hidden columns; the core catalog keeps them out of star + // expansions and models. + IsHidden bool `json:"is_hidden"` + + // From pg.ColumnDef + Inhcount int `json:"inhcount"` + IsLocal bool `json:"is_local"` + IsFromType bool `json:"is_from_type"` + IsFromParent bool `json:"is_from_parent"` + Storage byte `json:"storage"` + RawDefault Node `json:"raw_default,omitempty"` + CookedDefault Node `json:"cooked_default,omitempty"` + Identity byte `json:"identity"` + CollClause *CollateClause `json:"coll_clause,omitempty"` + CollOid Oid `json:"coll_oid"` + Constraints *List `json:"constraints,omitempty"` + Fdwoptions *List `json:"fdwoptions,omitempty"` + Location int `json:"location"` + Comment string `json:"comment"` +} + +func (n *ColumnDef) Pos() int { + return n.Location +} + +func (n *ColumnDef) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteString(n.Colname) + if !n.Typeless { + buf.WriteString(" ") + buf.astFormat(n.TypeName, d) + // MySQL integer types: signedness is part of the type. + if n.IsUnsigned { + buf.WriteString(" unsigned") + } + } + // Use IsArray from ColumnDef since TypeName.ArrayBounds may not be set + // (for type resolution compatibility) + if n.IsArray && !items(n.TypeName.ArrayBounds) { + buf.WriteString("[]") + } + if n.PrimaryKey { + buf.WriteString(" PRIMARY KEY") + } else if n.IsNotNull { + buf.WriteString(" NOT NULL") + } + buf.astFormat(n.Constraints, d) +} diff --git a/internal/sql/ast/column_ref.go b/internal/sql/ast/column_ref.go new file mode 100644 index 0000000..f04c7b4 --- /dev/null +++ b/internal/sql/ast/column_ref.go @@ -0,0 +1,40 @@ +package ast + +import ( + "strings" + + "github.com/sqlc-dev/sqlc/internal/sql/format" +) + +type ColumnRef struct { + Tag NodeTag[ColumnRef] `json:"tag"` + + Name string `json:"name"` + + // From pg.ColumnRef + Fields *List `json:"fields,omitempty"` + Location int `json:"location"` +} + +func (n *ColumnRef) Pos() int { + return n.Location +} + +func (n *ColumnRef) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + + if n.Fields != nil { + var items []string + for _, item := range n.Fields.Items { + switch nn := item.(type) { + case *String: + items = append(items, d.QuoteIdent(nn.Str)) + case *A_Star: + items = append(items, "*") + } + } + buf.WriteString(strings.Join(items, ".")) + } +} diff --git a/internal/sql/ast/comment.go b/internal/sql/ast/comment.go new file mode 100644 index 0000000..ea87732 --- /dev/null +++ b/internal/sql/ast/comment.go @@ -0,0 +1,235 @@ +package ast + +import ( + "sort" + + "github.com/sqlc-dev/sqlc/internal/sql/format" +) + +// File is a parsed query file: its statements together with the comments +// the parser's lexer saw. Engines whose parsers surface their trivia — the +// lexical channel of whitespace and comments the grammar never sees, in +// Roslyn's terminology — return it from ParseFile, so the formatter gets +// statements and comments from one lexer pass. +type File struct { + Stmts []Statement + Comments []Comment +} + +// Comment is a single SQL comment, positioned by byte offsets into the +// source the statement was parsed from — the same coordinates the engine +// parsers stamp on nodes. +type Comment struct { + // Text is the comment as written, marker included ("-- x", "/* x */"). + Text string + Start int + End int + // OwnLine reports that only blank space preceded the comment on its + // line, so it leads the code after it rather than trailing the code + // before it. + OwnLine bool +} + +// Line reports whether the comment runs to the end of its line (-- or #), +// so nothing may be printed after it on the same line. +func (c Comment) Line() bool { + return len(c.Text) < 2 || c.Text[0] != '/' || c.Text[1] != '*' +} + +// commentRec is one attached comment: the anchor nodes on either side of it +// in print order, and whether it trails the code before it (same source +// line) or leads the code after it (its own line). +// +// The next anchor is where the printer emits the comment; the prev anchor +// is the node the comment belongs to when the tree is edited — a trailing +// comment travels with the node it annotates, the way dave/dst attaches +// decorations in the Go ecosystem. +type commentRec struct { + c Comment + prev, next Node + trailing bool +} + +// CommentTable holds a statement's comments attached to its nodes. It is +// built once by AttachComments, before any printing (or, later, editing): +// each comment is classified against the statement's anchor nodes by source +// position and line, and from then on positions are never consulted again — +// the printer emits comments by node identity, which is what lets an edited +// or synthetic tree print its comments correctly. +type CommentTable struct { + recs []commentRec + // byNext indexes recs by their next anchor, in source order; end holds + // the comments with no anchor after them, which trail the statement. + byNext map[Node][]int + end []int + taken []bool + nTaken int + // breaks marks the emission points where the author broke the line: + // the printer keeps those breaks, gofmt-style, instead of imposing a + // line width. + breaks map[Node]bool +} + +// breakAt reports whether the author broke the line at this emission point. +func (t *CommentTable) breakAt(n Node) bool { + return t != nil && t.breaks[n] +} + +// Exhausted reports whether every attached comment was printed. +func (t *CommentTable) Exhausted() bool { + return t == nil || t.nTaken == len(t.recs) +} + +// take returns and consumes the comments anchored to n, in order. +func (t *CommentTable) take(n Node) []commentRec { + if t == nil || n == nil { + return nil + } + idxs := t.byNext[n] + if len(idxs) == 0 { + return nil + } + out := make([]commentRec, 0, len(idxs)) + for _, i := range idxs { + if t.taken[i] { + continue + } + t.taken[i] = true + t.nTaken++ + out = append(out, t.recs[i]) + } + return out +} + +// takeRemaining returns and consumes every comment not yet printed; the +// statement is over, so everything left trails it. +func (t *CommentTable) takeRemaining() []commentRec { + if t == nil { + return nil + } + var out []commentRec + for i := range t.recs { + if t.taken[i] { + continue + } + t.taken[i] = true + t.nTaken++ + out = append(out, t.recs[i]) + } + return out +} + +// AttachComments classifies a statement's interior comments against its +// nodes, producing the table the printer (and any future rewriting tool) +// works from. Placement follows gofmt's rules, decided here once from +// source positions and lines: a comment on the same line as the code before +// it trails that code; any other comment leads the first node printed after +// it; a comment after the last node trails the statement. +func AttachComments(raw *RawStmt, d format.Dialect, comments []Comment, src string) *CommentTable { + anchors := collectAnchors(raw, d) + lines := []int{0} + for i := 0; i < len(src); i++ { + if src[i] == '\n' { + lines = append(lines, i+1) + } + } + lineOf := func(pos int) int { + return sort.SearchInts(lines, pos+1) - 1 + } + + table := &CommentTable{byNext: make(map[Node][]int, len(anchors))} + for _, c := range comments { + // prev: the printed node with the greatest position before the + // comment (for the trailing/leading call). next: the emission point + // for the first printed node after the comment — the node itself, + // or, when boundary markers immediately precede it in print order, + // the earliest of those markers, which is where the printer will + // look for this comment first. + var prev, next Node + prevPos := -1 + for _, a := range anchors { + if !a.marker && a.pos < c.Start && a.pos > prevPos { + prev, prevPos = a.node, a.pos + } + } + for i, a := range anchors { + if a.marker || a.pos <= c.Start { + continue + } + j := i + for j > 0 && anchors[j-1].marker { + j-- + } + next = anchors[j].node + break + } + rec := commentRec{ + c: c, + prev: prev, + next: next, + trailing: !c.OwnLine && prev != nil && lineOf(prevPos) == lineOf(c.Start), + } + table.recs = append(table.recs, rec) + i := len(table.recs) - 1 + if next == nil { + table.end = append(table.end, i) + } else { + table.byNext[next] = append(table.byNext[next], i) + } + } + table.taken = make([]bool, len(table.recs)) + + // Record where the author broke the line: an emission point whose + // neighbouring printed nodes sit on different source lines. The printer + // keeps these breaks (and only imposes new ones for comments), so the + // statement's shape stays the author's. + table.breaks = make(map[Node]bool) + for i, a := range anchors { + if !a.marker { + continue + } + prevPos, nextPos := -1, -1 + for j := i - 1; j >= 0; j-- { + if !anchors[j].marker { + prevPos = anchors[j].pos + break + } + } + for j := i + 1; j < len(anchors); j++ { + if !anchors[j].marker { + nextPos = anchors[j].pos + break + } + } + if prevPos >= 0 && nextPos >= 0 && lineOf(prevPos) != lineOf(nextPos) { + table.breaks[a.node] = true + } + } + return table +} + +type anchor struct { + node Node + pos int + // marker anchors are emission points (beforeClause, list boundaries) + // rather than printed nodes; they carry no position of their own. + marker bool +} + +// collectAnchors renders the statement once, flat, recording every +// positioned node in the order the printer visits them. Print order is what +// comment emission is defined against, so classifying against it keeps the +// attach-time decision and the print-time emission point identical. +func collectAnchors(n Node, d format.Dialect) (out []anchor) { + defer func() { + // A formatter panic here surfaces later, on the real print; anchors + // collected so far still place most comments. + recover() + }() + tb := NewTrackedBuffer() + tb.anchors = &out + if ft, ok := n.(nodeFormatter); ok { + ft.Format(tb, d) + } + return out +} diff --git a/internal/sql/ast/comment_on_column_stmt.go b/internal/sql/ast/comment_on_column_stmt.go new file mode 100644 index 0000000..c35517e --- /dev/null +++ b/internal/sql/ast/comment_on_column_stmt.go @@ -0,0 +1,13 @@ +package ast + +type CommentOnColumnStmt struct { + Tag NodeTag[CommentOnColumnStmt] `json:"tag"` + + Table *TableName `json:"table,omitempty"` + Col *ColumnRef `json:"col,omitempty"` + Comment *string `json:"comment,omitempty"` +} + +func (n *CommentOnColumnStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/comment_on_schema_stmt.go b/internal/sql/ast/comment_on_schema_stmt.go new file mode 100644 index 0000000..aac64c4 --- /dev/null +++ b/internal/sql/ast/comment_on_schema_stmt.go @@ -0,0 +1,12 @@ +package ast + +type CommentOnSchemaStmt struct { + Tag NodeTag[CommentOnSchemaStmt] `json:"tag"` + + Schema *String `json:"schema,omitempty"` + Comment *string `json:"comment,omitempty"` +} + +func (n *CommentOnSchemaStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/comment_on_table_stmt.go b/internal/sql/ast/comment_on_table_stmt.go new file mode 100644 index 0000000..d6056fa --- /dev/null +++ b/internal/sql/ast/comment_on_table_stmt.go @@ -0,0 +1,12 @@ +package ast + +type CommentOnTableStmt struct { + Tag NodeTag[CommentOnTableStmt] `json:"tag"` + + Table *TableName `json:"table,omitempty"` + Comment *string `json:"comment,omitempty"` +} + +func (n *CommentOnTableStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/comment_on_type_stmt.go b/internal/sql/ast/comment_on_type_stmt.go new file mode 100644 index 0000000..616fca3 --- /dev/null +++ b/internal/sql/ast/comment_on_type_stmt.go @@ -0,0 +1,12 @@ +package ast + +type CommentOnTypeStmt struct { + Tag NodeTag[CommentOnTypeStmt] `json:"tag"` + + Type *TypeName `json:"type,omitempty"` + Comment *string `json:"comment,omitempty"` +} + +func (n *CommentOnTypeStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/comment_on_view_stmt.go b/internal/sql/ast/comment_on_view_stmt.go new file mode 100644 index 0000000..c857f77 --- /dev/null +++ b/internal/sql/ast/comment_on_view_stmt.go @@ -0,0 +1,12 @@ +package ast + +type CommentOnViewStmt struct { + Tag NodeTag[CommentOnViewStmt] `json:"tag"` + + View *TableName `json:"view,omitempty"` + Comment *string `json:"comment,omitempty"` +} + +func (n *CommentOnViewStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/comment_stmt.go b/internal/sql/ast/comment_stmt.go new file mode 100644 index 0000000..61f6269 --- /dev/null +++ b/internal/sql/ast/comment_stmt.go @@ -0,0 +1,13 @@ +package ast + +type CommentStmt struct { + Tag NodeTag[CommentStmt] `json:"tag"` + + Objtype ObjectType `json:"objtype"` + Object Node `json:"object,omitempty"` + Comment *string `json:"comment,omitempty"` +} + +func (n *CommentStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/common_table_expr.go b/internal/sql/ast/common_table_expr.go new file mode 100644 index 0000000..84f7db4 --- /dev/null +++ b/internal/sql/ast/common_table_expr.go @@ -0,0 +1,49 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type CommonTableExpr struct { + Tag NodeTag[CommonTableExpr] `json:"tag"` + + Ctename *string `json:"ctename,omitempty"` + Aliascolnames *List `json:"aliascolnames,omitempty"` + Ctequery Node `json:"ctequery,omitempty"` + Location int `json:"location"` + Cterecursive bool `json:"cterecursive"` + Cterefcount int `json:"cterefcount"` + Ctecolnames *List `json:"ctecolnames,omitempty"` + Ctecoltypes *List `json:"ctecoltypes,omitempty"` + Ctecoltypmods *List `json:"ctecoltypmods,omitempty"` + Ctecolcollations *List `json:"ctecolcollations,omitempty"` +} + +func (n *CommonTableExpr) Pos() int { + return n.Location +} + +func (n *CommonTableExpr) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + if n.Ctename != nil { + buf.WriteString(*n.Ctename) + } + if items(n.Aliascolnames) { + buf.WriteString("(") + buf.join(n.Aliascolnames, d, ", ") + buf.WriteString(")") + } + buf.WriteString(" AS (") + buf.Group() + buf.Indent() + // The body's boundary: a comment at the top of the CTE prints here, and + // an author who broke the line after the parenthesis keeps the CTE — and + // therefore the statement around it — broken open. + buf.boundary(n.Ctequery) + buf.Softline() + buf.astFormat(n.Ctequery, d) + buf.EndIndent() + buf.Softline() + buf.EndGroup() + buf.WriteString(")") +} diff --git a/internal/sql/ast/composite_type_stmt.go b/internal/sql/ast/composite_type_stmt.go new file mode 100644 index 0000000..a7f27a8 --- /dev/null +++ b/internal/sql/ast/composite_type_stmt.go @@ -0,0 +1,13 @@ +package ast + +type CompositeTypeStmt struct { + Tag NodeTag[CompositeTypeStmt] `json:"tag"` + + TypeName *TypeName `json:"type_name,omitempty"` + // Coldeflist is the type's fields, each a ColumnDef. + Coldeflist *List `json:"coldeflist,omitempty"` +} + +func (n *CompositeTypeStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/const.go b/internal/sql/ast/const.go new file mode 100644 index 0000000..58d33e9 --- /dev/null +++ b/internal/sql/ast/const.go @@ -0,0 +1,19 @@ +package ast + +type Const struct { + Tag NodeTag[Const] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Consttype Oid `json:"consttype"` + Consttypmod int32 `json:"consttypmod"` + Constcollid Oid `json:"constcollid"` + Constlen int `json:"constlen"` + Constvalue Datum `json:"constvalue"` + Constisnull bool `json:"constisnull"` + Constbyval bool `json:"constbyval"` + Location int `json:"location"` +} + +func (n *Const) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/constr_type.go b/internal/sql/ast/constr_type.go new file mode 100644 index 0000000..c058682 --- /dev/null +++ b/internal/sql/ast/constr_type.go @@ -0,0 +1,14 @@ +package ast + +type ConstrType uint + +func (n *ConstrType) Pos() int { + return 0 +} + +// The constraint kinds the analysis reads, numbered as PostgreSQL's parser +// numbers them, which is what an engine's converter records. +const ( + ConstrTypeNull ConstrType = 1 + ConstrTypeNotNull ConstrType = 2 +) diff --git a/internal/sql/ast/constraint.go b/internal/sql/ast/constraint.go new file mode 100644 index 0000000..bd9c734 --- /dev/null +++ b/internal/sql/ast/constraint.go @@ -0,0 +1,36 @@ +package ast + +type Constraint struct { + Tag NodeTag[Constraint] `json:"tag"` + + Contype ConstrType `json:"contype"` + Conname *string `json:"conname,omitempty"` + Deferrable bool `json:"deferrable"` + Initdeferred bool `json:"initdeferred"` + Location int `json:"location"` + IsNoInherit bool `json:"is_no_inherit"` + RawExpr Node `json:"raw_expr,omitempty"` + CookedExpr *string `json:"cooked_expr,omitempty"` + GeneratedWhen byte `json:"generated_when"` + Keys *List `json:"keys,omitempty"` + Exclusions *List `json:"exclusions,omitempty"` + Options *List `json:"options,omitempty"` + Indexname *string `json:"indexname,omitempty"` + Indexspace *string `json:"indexspace,omitempty"` + AccessMethod *string `json:"access_method,omitempty"` + WhereClause Node `json:"where_clause,omitempty"` + Pktable *RangeVar `json:"pktable,omitempty"` + FkAttrs *List `json:"fk_attrs,omitempty"` + PkAttrs *List `json:"pk_attrs,omitempty"` + FkMatchtype byte `json:"fk_matchtype"` + FkUpdAction byte `json:"fk_upd_action"` + FkDelAction byte `json:"fk_del_action"` + OldConpfeqop *List `json:"old_conpfeqop,omitempty"` + OldPktableOid Oid `json:"old_pktable_oid"` + SkipValidation bool `json:"skip_validation"` + InitiallyValid bool `json:"initially_valid"` +} + +func (n *Constraint) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/constraints_set_stmt.go b/internal/sql/ast/constraints_set_stmt.go new file mode 100644 index 0000000..b677dca --- /dev/null +++ b/internal/sql/ast/constraints_set_stmt.go @@ -0,0 +1,12 @@ +package ast + +type ConstraintsSetStmt struct { + Tag NodeTag[ConstraintsSetStmt] `json:"tag"` + + Constraints *List `json:"constraints,omitempty"` + Deferred bool `json:"deferred"` +} + +func (n *ConstraintsSetStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/convert_rowtype_expr.go b/internal/sql/ast/convert_rowtype_expr.go new file mode 100644 index 0000000..60c3f12 --- /dev/null +++ b/internal/sql/ast/convert_rowtype_expr.go @@ -0,0 +1,15 @@ +package ast + +type ConvertRowtypeExpr struct { + Tag NodeTag[ConvertRowtypeExpr] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Arg Node `json:"arg,omitempty"` + Resulttype Oid `json:"resulttype"` + Convertformat CoercionForm `json:"convertformat"` + Location int `json:"location"` +} + +func (n *ConvertRowtypeExpr) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/copy_stmt.go b/internal/sql/ast/copy_stmt.go new file mode 100644 index 0000000..93d83d6 --- /dev/null +++ b/internal/sql/ast/copy_stmt.go @@ -0,0 +1,17 @@ +package ast + +type CopyStmt struct { + Tag NodeTag[CopyStmt] `json:"tag"` + + Relation *RangeVar `json:"relation,omitempty"` + Query Node `json:"query,omitempty"` + Attlist *List `json:"attlist,omitempty"` + IsFrom bool `json:"is_from"` + IsProgram bool `json:"is_program"` + Filename *string `json:"filename,omitempty"` + Options *List `json:"options,omitempty"` +} + +func (n *CopyStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_am_stmt.go b/internal/sql/ast/create_am_stmt.go new file mode 100644 index 0000000..8f08590 --- /dev/null +++ b/internal/sql/ast/create_am_stmt.go @@ -0,0 +1,13 @@ +package ast + +type CreateAmStmt struct { + Tag NodeTag[CreateAmStmt] `json:"tag"` + + Amname *string `json:"amname,omitempty"` + HandlerName *List `json:"handler_name,omitempty"` + Amtype byte `json:"amtype"` +} + +func (n *CreateAmStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_cast_stmt.go b/internal/sql/ast/create_cast_stmt.go new file mode 100644 index 0000000..188d633 --- /dev/null +++ b/internal/sql/ast/create_cast_stmt.go @@ -0,0 +1,15 @@ +package ast + +type CreateCastStmt struct { + Tag NodeTag[CreateCastStmt] `json:"tag"` + + Sourcetype *TypeName `json:"sourcetype,omitempty"` + Targettype *TypeName `json:"targettype,omitempty"` + Func *ObjectWithArgs `json:"func,omitempty"` + Context CoercionContext `json:"context"` + Inout bool `json:"inout"` +} + +func (n *CreateCastStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_conversion_stmt.go b/internal/sql/ast/create_conversion_stmt.go new file mode 100644 index 0000000..38be006 --- /dev/null +++ b/internal/sql/ast/create_conversion_stmt.go @@ -0,0 +1,15 @@ +package ast + +type CreateConversionStmt struct { + Tag NodeTag[CreateConversionStmt] `json:"tag"` + + ConversionName *List `json:"conversion_name,omitempty"` + ForEncodingName *string `json:"for_encoding_name,omitempty"` + ToEncodingName *string `json:"to_encoding_name,omitempty"` + FuncName *List `json:"func_name,omitempty"` + Def bool `json:"def"` +} + +func (n *CreateConversionStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_domain_stmt.go b/internal/sql/ast/create_domain_stmt.go new file mode 100644 index 0000000..8cc2324 --- /dev/null +++ b/internal/sql/ast/create_domain_stmt.go @@ -0,0 +1,14 @@ +package ast + +type CreateDomainStmt struct { + Tag NodeTag[CreateDomainStmt] `json:"tag"` + + Domainname *List `json:"domainname,omitempty"` + TypeName *TypeName `json:"type_name,omitempty"` + CollClause *CollateClause `json:"coll_clause,omitempty"` + Constraints *List `json:"constraints,omitempty"` +} + +func (n *CreateDomainStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_enum_stmt.go b/internal/sql/ast/create_enum_stmt.go new file mode 100644 index 0000000..f38316b --- /dev/null +++ b/internal/sql/ast/create_enum_stmt.go @@ -0,0 +1,12 @@ +package ast + +type CreateEnumStmt struct { + Tag NodeTag[CreateEnumStmt] `json:"tag"` + + TypeName *TypeName `json:"type_name,omitempty"` + Vals *List `json:"vals,omitempty"` +} + +func (n *CreateEnumStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_event_trig_stmt.go b/internal/sql/ast/create_event_trig_stmt.go new file mode 100644 index 0000000..eea8012 --- /dev/null +++ b/internal/sql/ast/create_event_trig_stmt.go @@ -0,0 +1,14 @@ +package ast + +type CreateEventTrigStmt struct { + Tag NodeTag[CreateEventTrigStmt] `json:"tag"` + + Trigname *string `json:"trigname,omitempty"` + Eventname *string `json:"eventname,omitempty"` + Whenclause *List `json:"whenclause,omitempty"` + Funcname *List `json:"funcname,omitempty"` +} + +func (n *CreateEventTrigStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_extension_stmt.go b/internal/sql/ast/create_extension_stmt.go new file mode 100644 index 0000000..d73aed8 --- /dev/null +++ b/internal/sql/ast/create_extension_stmt.go @@ -0,0 +1,28 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type CreateExtensionStmt struct { + Tag NodeTag[CreateExtensionStmt] `json:"tag"` + + Extname *string `json:"extname,omitempty"` + IfNotExists bool `json:"if_not_exists"` + Options *List `json:"options,omitempty"` +} + +func (n *CreateExtensionStmt) Pos() int { + return 0 +} + +func (n *CreateExtensionStmt) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteString("CREATE EXTENSION ") + if n.IfNotExists { + buf.WriteString("IF NOT EXISTS ") + } + if n.Extname != nil { + buf.WriteString(*n.Extname) + } +} diff --git a/internal/sql/ast/create_fdw_stmt.go b/internal/sql/ast/create_fdw_stmt.go new file mode 100644 index 0000000..74cb794 --- /dev/null +++ b/internal/sql/ast/create_fdw_stmt.go @@ -0,0 +1,13 @@ +package ast + +type CreateFdwStmt struct { + Tag NodeTag[CreateFdwStmt] `json:"tag"` + + Fdwname *string `json:"fdwname,omitempty"` + FuncOptions *List `json:"func_options,omitempty"` + Options *List `json:"options,omitempty"` +} + +func (n *CreateFdwStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_foreign_server_stmt.go b/internal/sql/ast/create_foreign_server_stmt.go new file mode 100644 index 0000000..da9d78a --- /dev/null +++ b/internal/sql/ast/create_foreign_server_stmt.go @@ -0,0 +1,16 @@ +package ast + +type CreateForeignServerStmt struct { + Tag NodeTag[CreateForeignServerStmt] `json:"tag"` + + Servername *string `json:"servername,omitempty"` + Servertype *string `json:"servertype,omitempty"` + Version *string `json:"version,omitempty"` + Fdwname *string `json:"fdwname,omitempty"` + IfNotExists bool `json:"if_not_exists"` + Options *List `json:"options,omitempty"` +} + +func (n *CreateForeignServerStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_foreign_table_stmt.go b/internal/sql/ast/create_foreign_table_stmt.go new file mode 100644 index 0000000..764e729 --- /dev/null +++ b/internal/sql/ast/create_foreign_table_stmt.go @@ -0,0 +1,13 @@ +package ast + +type CreateForeignTableStmt struct { + Tag NodeTag[CreateForeignTableStmt] `json:"tag"` + + Base *CreateStmt `json:"base,omitempty"` + Servername *string `json:"servername,omitempty"` + Options *List `json:"options,omitempty"` +} + +func (n *CreateForeignTableStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_function_stmt.go b/internal/sql/ast/create_function_stmt.go new file mode 100644 index 0000000..3fb3bb7 --- /dev/null +++ b/internal/sql/ast/create_function_stmt.go @@ -0,0 +1,47 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type CreateFunctionStmt struct { + Tag NodeTag[CreateFunctionStmt] `json:"tag"` + + Replace bool `json:"replace"` + Params *List `json:"params,omitempty"` + ReturnType *TypeName `json:"return_type,omitempty"` + Func *FuncName `json:"func,omitempty"` + // TODO: Understand these two fields + Options *List `json:"options,omitempty"` + WithClause *List `json:"with_clause,omitempty"` +} + +func (n *CreateFunctionStmt) Pos() int { + return 0 +} + +func (n *CreateFunctionStmt) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteString("CREATE ") + if n.Replace { + buf.WriteString("OR REPLACE ") + } + buf.WriteString("FUNCTION ") + buf.astFormat(n.Func, d) + buf.WriteString("(") + if items(n.Params) { + buf.join(n.Params, d, ", ") + } + buf.WriteString(")") + if n.ReturnType != nil { + buf.WriteString(" RETURNS ") + buf.astFormat(n.ReturnType, d) + } + // Format options (AS, LANGUAGE, etc.) + if items(n.Options) { + for _, opt := range n.Options.Items { + buf.WriteString(" ") + buf.astFormat(opt, d) + } + } +} diff --git a/internal/sql/ast/create_op_class_item.go b/internal/sql/ast/create_op_class_item.go new file mode 100644 index 0000000..0b1f4ad --- /dev/null +++ b/internal/sql/ast/create_op_class_item.go @@ -0,0 +1,16 @@ +package ast + +type CreateOpClassItem struct { + Tag NodeTag[CreateOpClassItem] `json:"tag"` + + Itemtype int `json:"itemtype"` + Name *ObjectWithArgs `json:"name,omitempty"` + Number int `json:"number"` + OrderFamily *List `json:"order_family,omitempty"` + ClassArgs *List `json:"class_args,omitempty"` + Storedtype *TypeName `json:"storedtype,omitempty"` +} + +func (n *CreateOpClassItem) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_op_class_stmt.go b/internal/sql/ast/create_op_class_stmt.go new file mode 100644 index 0000000..9b606c4 --- /dev/null +++ b/internal/sql/ast/create_op_class_stmt.go @@ -0,0 +1,16 @@ +package ast + +type CreateOpClassStmt struct { + Tag NodeTag[CreateOpClassStmt] `json:"tag"` + + Opclassname *List `json:"opclassname,omitempty"` + Opfamilyname *List `json:"opfamilyname,omitempty"` + Amname *string `json:"amname,omitempty"` + Datatype *TypeName `json:"datatype,omitempty"` + Items *List `json:"items,omitempty"` + IsDefault bool `json:"is_default"` +} + +func (n *CreateOpClassStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_op_family_stmt.go b/internal/sql/ast/create_op_family_stmt.go new file mode 100644 index 0000000..4db1cc4 --- /dev/null +++ b/internal/sql/ast/create_op_family_stmt.go @@ -0,0 +1,12 @@ +package ast + +type CreateOpFamilyStmt struct { + Tag NodeTag[CreateOpFamilyStmt] `json:"tag"` + + Opfamilyname *List `json:"opfamilyname,omitempty"` + Amname *string `json:"amname,omitempty"` +} + +func (n *CreateOpFamilyStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_p_lang_stmt.go b/internal/sql/ast/create_p_lang_stmt.go new file mode 100644 index 0000000..f6d4398 --- /dev/null +++ b/internal/sql/ast/create_p_lang_stmt.go @@ -0,0 +1,16 @@ +package ast + +type CreatePLangStmt struct { + Tag NodeTag[CreatePLangStmt] `json:"tag"` + + Replace bool `json:"replace"` + Plname *string `json:"plname,omitempty"` + Plhandler *List `json:"plhandler,omitempty"` + Plinline *List `json:"plinline,omitempty"` + Plvalidator *List `json:"plvalidator,omitempty"` + Pltrusted bool `json:"pltrusted"` +} + +func (n *CreatePLangStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_policy_stmt.go b/internal/sql/ast/create_policy_stmt.go new file mode 100644 index 0000000..3d191a2 --- /dev/null +++ b/internal/sql/ast/create_policy_stmt.go @@ -0,0 +1,17 @@ +package ast + +type CreatePolicyStmt struct { + Tag NodeTag[CreatePolicyStmt] `json:"tag"` + + PolicyName *string `json:"policy_name,omitempty"` + Table *RangeVar `json:"table,omitempty"` + CmdName *string `json:"cmd_name,omitempty"` + Permissive bool `json:"permissive"` + Roles *List `json:"roles,omitempty"` + Qual Node `json:"qual,omitempty"` + WithCheck Node `json:"with_check,omitempty"` +} + +func (n *CreatePolicyStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_publication_stmt.go b/internal/sql/ast/create_publication_stmt.go new file mode 100644 index 0000000..90e0c73 --- /dev/null +++ b/internal/sql/ast/create_publication_stmt.go @@ -0,0 +1,14 @@ +package ast + +type CreatePublicationStmt struct { + Tag NodeTag[CreatePublicationStmt] `json:"tag"` + + Pubname *string `json:"pubname,omitempty"` + Options *List `json:"options,omitempty"` + Tables *List `json:"tables,omitempty"` + ForAllTables bool `json:"for_all_tables"` +} + +func (n *CreatePublicationStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_range_stmt.go b/internal/sql/ast/create_range_stmt.go new file mode 100644 index 0000000..7ac3b8a --- /dev/null +++ b/internal/sql/ast/create_range_stmt.go @@ -0,0 +1,12 @@ +package ast + +type CreateRangeStmt struct { + Tag NodeTag[CreateRangeStmt] `json:"tag"` + + TypeName *List `json:"type_name,omitempty"` + Params *List `json:"params,omitempty"` +} + +func (n *CreateRangeStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_role_stmt.go b/internal/sql/ast/create_role_stmt.go new file mode 100644 index 0000000..667d702 --- /dev/null +++ b/internal/sql/ast/create_role_stmt.go @@ -0,0 +1,13 @@ +package ast + +type CreateRoleStmt struct { + Tag NodeTag[CreateRoleStmt] `json:"tag"` + + StmtType RoleStmtType `json:"stmt_type"` + Role *string `json:"role,omitempty"` + Options *List `json:"options,omitempty"` +} + +func (n *CreateRoleStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_schema_stmt.go b/internal/sql/ast/create_schema_stmt.go new file mode 100644 index 0000000..e07dafa --- /dev/null +++ b/internal/sql/ast/create_schema_stmt.go @@ -0,0 +1,14 @@ +package ast + +type CreateSchemaStmt struct { + Tag NodeTag[CreateSchemaStmt] `json:"tag"` + + Name *string `json:"name,omitempty"` + SchemaElts *List `json:"schema_elts,omitempty"` + Authrole *RoleSpec `json:"authrole,omitempty"` + IfNotExists bool `json:"if_not_exists"` +} + +func (n *CreateSchemaStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_seq_stmt.go b/internal/sql/ast/create_seq_stmt.go new file mode 100644 index 0000000..66c35a7 --- /dev/null +++ b/internal/sql/ast/create_seq_stmt.go @@ -0,0 +1,15 @@ +package ast + +type CreateSeqStmt struct { + Tag NodeTag[CreateSeqStmt] `json:"tag"` + + Sequence *RangeVar `json:"sequence,omitempty"` + Options *List `json:"options,omitempty"` + OwnerId Oid `json:"owner_id"` + ForIdentity bool `json:"for_identity"` + IfNotExists bool `json:"if_not_exists"` +} + +func (n *CreateSeqStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_stats_stmt.go b/internal/sql/ast/create_stats_stmt.go new file mode 100644 index 0000000..17b8af2 --- /dev/null +++ b/internal/sql/ast/create_stats_stmt.go @@ -0,0 +1,15 @@ +package ast + +type CreateStatsStmt struct { + Tag NodeTag[CreateStatsStmt] `json:"tag"` + + Defnames *List `json:"defnames,omitempty"` + StatTypes *List `json:"stat_types,omitempty"` + Exprs *List `json:"exprs,omitempty"` + Relations *List `json:"relations,omitempty"` + IfNotExists bool `json:"if_not_exists"` +} + +func (n *CreateStatsStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_stmt.go b/internal/sql/ast/create_stmt.go new file mode 100644 index 0000000..5d69e7b --- /dev/null +++ b/internal/sql/ast/create_stmt.go @@ -0,0 +1,21 @@ +package ast + +type CreateStmt struct { + Tag NodeTag[CreateStmt] `json:"tag"` + + Relation *RangeVar `json:"relation,omitempty"` + TableElts *List `json:"table_elts,omitempty"` + InhRelations *List `json:"inh_relations,omitempty"` + Partbound *PartitionBoundSpec `json:"partbound,omitempty"` + Partspec *PartitionSpec `json:"partspec,omitempty"` + OfTypename *TypeName `json:"of_typename,omitempty"` + Constraints *List `json:"constraints,omitempty"` + Options *List `json:"options,omitempty"` + Oncommit OnCommitAction `json:"oncommit"` + Tablespacename *string `json:"tablespacename,omitempty"` + IfNotExists bool `json:"if_not_exists"` +} + +func (n *CreateStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_subscription_stmt.go b/internal/sql/ast/create_subscription_stmt.go new file mode 100644 index 0000000..d4c3c67 --- /dev/null +++ b/internal/sql/ast/create_subscription_stmt.go @@ -0,0 +1,14 @@ +package ast + +type CreateSubscriptionStmt struct { + Tag NodeTag[CreateSubscriptionStmt] `json:"tag"` + + Subname *string `json:"subname,omitempty"` + Conninfo *string `json:"conninfo,omitempty"` + Publication *List `json:"publication,omitempty"` + Options *List `json:"options,omitempty"` +} + +func (n *CreateSubscriptionStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_table_as_stmt.go b/internal/sql/ast/create_table_as_stmt.go new file mode 100644 index 0000000..862d0c4 --- /dev/null +++ b/internal/sql/ast/create_table_as_stmt.go @@ -0,0 +1,15 @@ +package ast + +type CreateTableAsStmt struct { + Tag NodeTag[CreateTableAsStmt] `json:"tag"` + + Query Node `json:"query,omitempty"` + Into *IntoClause `json:"into,omitempty"` + Relkind ObjectType `json:"relkind"` + IsSelectInto bool `json:"is_select_into"` + IfNotExists bool `json:"if_not_exists"` +} + +func (n *CreateTableAsStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_table_space_stmt.go b/internal/sql/ast/create_table_space_stmt.go new file mode 100644 index 0000000..7c55d5d --- /dev/null +++ b/internal/sql/ast/create_table_space_stmt.go @@ -0,0 +1,14 @@ +package ast + +type CreateTableSpaceStmt struct { + Tag NodeTag[CreateTableSpaceStmt] `json:"tag"` + + Tablespacename *string `json:"tablespacename,omitempty"` + Owner *RoleSpec `json:"owner,omitempty"` + Location *string `json:"location,omitempty"` + Options *List `json:"options,omitempty"` +} + +func (n *CreateTableSpaceStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_table_stmt.go b/internal/sql/ast/create_table_stmt.go new file mode 100644 index 0000000..4abe5d0 --- /dev/null +++ b/internal/sql/ast/create_table_stmt.go @@ -0,0 +1,106 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type CreateTableStmt struct { + Tag NodeTag[CreateTableStmt] `json:"tag"` + + IfNotExists bool `json:"if_not_exists"` + Name *TableName `json:"name,omitempty"` + Cols []*ColumnDef `json:"cols,omitempty"` + ReferTable *TableName `json:"refer_table,omitempty"` + Comment string `json:"comment"` + Inherits []*TableName `json:"inherits,omitempty"` + // Using names the module of a virtual table (SQLite's CREATE VIRTUAL + // TABLE ... USING module(...)), and ModuleArgs carries the module's + // argument list as written — its grammar belongs to the module, so the + // arguments pass through verbatim; nil means the declaration had no + // argument list at all. Cols still holds the columns sqlc derives from + // the arguments for the catalog; the statement prints as its + // declaration, not as those columns. + Using string `json:"using"` + ModuleArgs []string `json:"module_args,omitempty"` + // ModuleArgsMultiline records that the declaration was written across + // lines. The arguments carry no positions, so the printer cannot keep + // the author's exact breaks and prints the canonical broken form — one + // argument per line — instead. + ModuleArgsMultiline bool `json:"module_args_multiline"` + // Incomplete marks a statement whose source carried syntax this node + // does not model — column or table constraints beyond plain NOT NULL + // and PRIMARY KEY, table options, TEMP, or an AS SELECT body. No + // faithful rendering exists for it. + Incomplete bool `json:"incomplete"` +} + +func (n *CreateTableStmt) Pos() int { + return 0 +} + +func (n *CreateTableStmt) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + // A virtual table prints as its declaration: the module name and the + // argument list as written. + if n.Using != "" { + buf.WriteString("CREATE VIRTUAL TABLE ") + if n.IfNotExists { + buf.WriteString("IF NOT EXISTS ") + } + buf.astFormat(n.Name, d) + buf.WriteString(" USING ") + buf.WriteString(n.Using) + if n.ModuleArgs != nil { + buf.WriteString("(") + buf.Group() + buf.Indent() + if n.ModuleArgsMultiline { + buf.Breaker() + } + buf.Softline() + for i, arg := range n.ModuleArgs { + if i > 0 { + buf.WriteString(",") + buf.Line() + } + buf.WriteString(arg) + } + buf.EndIndent() + buf.Softline() + buf.EndGroup() + buf.WriteString(")") + } + return + } + // An incomplete statement cannot be printed back: part of its source + // was parsed away. Render nothing, which no verification accepts, so + // the formatter keeps the statement as written. + if n.Incomplete { + return + } + buf.WriteString("CREATE TABLE ") + if n.IfNotExists { + buf.WriteString("IF NOT EXISTS ") + } + buf.astFormat(n.Name, d) + + buf.WriteString(" (") + buf.Group() + buf.Indent() + if len(n.Cols) > 0 { + buf.boundary(n.Cols[0]) + } + buf.Softline() + for i, col := range n.Cols { + if i > 0 { + buf.WriteString(",") + buf.boundary(col) + buf.Line() + } + buf.astFormat(col, d) + } + buf.EndIndent() + buf.Softline() + buf.EndGroup() + buf.WriteString(")") +} diff --git a/internal/sql/ast/create_transform_stmt.go b/internal/sql/ast/create_transform_stmt.go new file mode 100644 index 0000000..20b0c63 --- /dev/null +++ b/internal/sql/ast/create_transform_stmt.go @@ -0,0 +1,15 @@ +package ast + +type CreateTransformStmt struct { + Tag NodeTag[CreateTransformStmt] `json:"tag"` + + Replace bool `json:"replace"` + TypeName *TypeName `json:"type_name,omitempty"` + Lang *string `json:"lang,omitempty"` + Fromsql *ObjectWithArgs `json:"fromsql,omitempty"` + Tosql *ObjectWithArgs `json:"tosql,omitempty"` +} + +func (n *CreateTransformStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_trig_stmt.go b/internal/sql/ast/create_trig_stmt.go new file mode 100644 index 0000000..b0c81d6 --- /dev/null +++ b/internal/sql/ast/create_trig_stmt.go @@ -0,0 +1,24 @@ +package ast + +type CreateTrigStmt struct { + Tag NodeTag[CreateTrigStmt] `json:"tag"` + + Trigname *string `json:"trigname,omitempty"` + Relation *RangeVar `json:"relation,omitempty"` + Funcname *List `json:"funcname,omitempty"` + Args *List `json:"args,omitempty"` + Row bool `json:"row"` + Timing int16 `json:"timing"` + Events int16 `json:"events"` + Columns *List `json:"columns,omitempty"` + WhenClause Node `json:"when_clause,omitempty"` + Isconstraint bool `json:"isconstraint"` + TransitionRels *List `json:"transition_rels,omitempty"` + Deferrable bool `json:"deferrable"` + Initdeferred bool `json:"initdeferred"` + Constrrel *RangeVar `json:"constrrel,omitempty"` +} + +func (n *CreateTrigStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/create_user_mapping_stmt.go b/internal/sql/ast/create_user_mapping_stmt.go new file mode 100644 index 0000000..e67bd62 --- /dev/null +++ b/internal/sql/ast/create_user_mapping_stmt.go @@ -0,0 +1,14 @@ +package ast + +type CreateUserMappingStmt struct { + Tag NodeTag[CreateUserMappingStmt] `json:"tag"` + + User *RoleSpec `json:"user,omitempty"` + Servername *string `json:"servername,omitempty"` + IfNotExists bool `json:"if_not_exists"` + Options *List `json:"options,omitempty"` +} + +func (n *CreateUserMappingStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/createdb_stmt.go b/internal/sql/ast/createdb_stmt.go new file mode 100644 index 0000000..ee08567 --- /dev/null +++ b/internal/sql/ast/createdb_stmt.go @@ -0,0 +1,12 @@ +package ast + +type CreatedbStmt struct { + Tag NodeTag[CreatedbStmt] `json:"tag"` + + Dbname *string `json:"dbname,omitempty"` + Options *List `json:"options,omitempty"` +} + +func (n *CreatedbStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/current_of_expr.go b/internal/sql/ast/current_of_expr.go new file mode 100644 index 0000000..ac9eb35 --- /dev/null +++ b/internal/sql/ast/current_of_expr.go @@ -0,0 +1,14 @@ +package ast + +type CurrentOfExpr struct { + Tag NodeTag[CurrentOfExpr] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Cvarno Index `json:"cvarno"` + CursorName *string `json:"cursor_name,omitempty"` + CursorParam int `json:"cursor_param"` +} + +func (n *CurrentOfExpr) Pos() int { + return 0 +} diff --git a/internal/sql/ast/deallocate_stmt.go b/internal/sql/ast/deallocate_stmt.go new file mode 100644 index 0000000..c51908f --- /dev/null +++ b/internal/sql/ast/deallocate_stmt.go @@ -0,0 +1,11 @@ +package ast + +type DeallocateStmt struct { + Tag NodeTag[DeallocateStmt] `json:"tag"` + + Name *string `json:"name,omitempty"` +} + +func (n *DeallocateStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/declare_cursor_stmt.go b/internal/sql/ast/declare_cursor_stmt.go new file mode 100644 index 0000000..52c8a22 --- /dev/null +++ b/internal/sql/ast/declare_cursor_stmt.go @@ -0,0 +1,13 @@ +package ast + +type DeclareCursorStmt struct { + Tag NodeTag[DeclareCursorStmt] `json:"tag"` + + Portalname *string `json:"portalname,omitempty"` + Options int `json:"options"` + Query Node `json:"query,omitempty"` +} + +func (n *DeclareCursorStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/def_elem.go b/internal/sql/ast/def_elem.go new file mode 100644 index 0000000..9ccf443 --- /dev/null +++ b/internal/sql/ast/def_elem.go @@ -0,0 +1,70 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type DefElem struct { + Tag NodeTag[DefElem] `json:"tag"` + + Defnamespace *string `json:"defnamespace,omitempty"` + Defname *string `json:"defname,omitempty"` + Arg Node `json:"arg,omitempty"` + Defaction DefElemAction `json:"defaction"` + Location int `json:"location"` +} + +func (n *DefElem) Pos() int { + return n.Location +} + +func (n *DefElem) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + if n.Defname != nil { + switch *n.Defname { + case "as": + buf.WriteString("AS ") + // AS clause contains function body which needs quoting + if l, ok := n.Arg.(*List); ok { + for i, item := range l.Items { + if i > 0 { + buf.WriteString(", ") + } + if s, ok := item.(*String); ok { + buf.WriteString("'") + buf.WriteString(s.Str) + buf.WriteString("'") + } else { + buf.astFormat(item, d) + } + } + } else { + buf.astFormat(n.Arg, d) + } + case "language": + buf.WriteString("LANGUAGE ") + buf.astFormat(n.Arg, d) + case "volatility": + // VOLATILE, STABLE, IMMUTABLE + buf.astFormat(n.Arg, d) + case "strict": + if s, ok := n.Arg.(*Boolean); ok && s.Boolval { + buf.WriteString("STRICT") + } else { + buf.WriteString("CALLED ON NULL INPUT") + } + case "security": + if s, ok := n.Arg.(*Boolean); ok && s.Boolval { + buf.WriteString("SECURITY DEFINER") + } else { + buf.WriteString("SECURITY INVOKER") + } + default: + buf.WriteString(*n.Defname) + if n.Arg != nil { + buf.WriteString(" ") + buf.astFormat(n.Arg, d) + } + } + } +} diff --git a/internal/sql/ast/def_elem_action.go b/internal/sql/ast/def_elem_action.go new file mode 100644 index 0000000..7ff3d96 --- /dev/null +++ b/internal/sql/ast/def_elem_action.go @@ -0,0 +1,7 @@ +package ast + +type DefElemAction uint + +func (n *DefElemAction) Pos() int { + return 0 +} diff --git a/internal/sql/ast/define_stmt.go b/internal/sql/ast/define_stmt.go new file mode 100644 index 0000000..9ac5e7a --- /dev/null +++ b/internal/sql/ast/define_stmt.go @@ -0,0 +1,16 @@ +package ast + +type DefineStmt struct { + Tag NodeTag[DefineStmt] `json:"tag"` + + Kind ObjectType `json:"kind"` + Oldstyle bool `json:"oldstyle"` + Defnames *List `json:"defnames,omitempty"` + Args *List `json:"args,omitempty"` + Definition *List `json:"definition,omitempty"` + IfNotExists bool `json:"if_not_exists"` +} + +func (n *DefineStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/delete_stmt.go b/internal/sql/ast/delete_stmt.go new file mode 100644 index 0000000..5d584b6 --- /dev/null +++ b/internal/sql/ast/delete_stmt.go @@ -0,0 +1,91 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type DeleteStmt struct { + Tag NodeTag[DeleteStmt] `json:"tag"` + + Relations *List `json:"relations,omitempty"` + UsingClause *List `json:"using_clause,omitempty"` + WhereClause Node `json:"where_clause,omitempty"` + LimitCount Node `json:"limit_count,omitempty"` + ReturningList *List `json:"returning_list,omitempty"` + WithClause *WithClause `json:"with_clause,omitempty"` + // MySQL multi-table DELETE support + Targets *List `json:"targets,omitempty"` // Tables to delete from (e.g., jt.*, pt.*) + FromClause Node `json:"from_clause,omitempty"` // FROM clause with JOINs (Node to support JoinExpr) + // PostgreSQL 18 RETURNING WITH (OLD AS ..., NEW AS ...) aliases + ReturningOldAlias string `json:"returning_old_alias"` + ReturningNewAlias string `json:"returning_new_alias"` +} + +func (n *DeleteStmt) Pos() int { + return 0 +} + +func (n *DeleteStmt) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + + buf.Group() + defer buf.EndGroup() + + if n.WithClause != nil { + buf.astFormat(n.WithClause, d) + // The boundary between the WITH clause and the statement's own + // first keyword; the group keeps a break inside the WITH clause + // from forcing the statement body apart clause by clause. + buf.boundary(n.Relations) + buf.Line() + buf.Group() + defer buf.EndGroup() + } + + buf.WriteString("DELETE ") + + // MySQL multi-table DELETE: DELETE t1.*, t2.* FROM t1 JOIN t2 ... + if items(n.Targets) { + buf.join(n.Targets, d, ", ") + buf.WriteString(" FROM ") + if set(n.FromClause) { + buf.astFormat(n.FromClause, d) + } else if items(n.Relations) { + buf.astFormat(n.Relations, d) + } + } else { + buf.WriteString("FROM ") + if items(n.Relations) { + buf.astFormat(n.Relations, d) + } + } + + if items(n.UsingClause) { + buf.beforeClause(n.UsingClause, d) + buf.Line() + buf.WriteString("USING ") + buf.join(n.UsingClause, d, ", ") + } + + if set(n.WhereClause) { + buf.beforeClause(n.WhereClause, d) + buf.Line() + buf.WriteString("WHERE ") + buf.condition(n.WhereClause, d) + } + + if set(n.LimitCount) { + buf.beforeClause(n.LimitCount, d) + buf.Line() + buf.WriteString("LIMIT ") + buf.astFormat(n.LimitCount, d) + } + + if items(n.ReturningList) { + buf.beforeClause(n.ReturningList, d) + buf.Line() + buf.WriteString("RETURNING ") + formatReturningOptions(buf, d, n.ReturningOldAlias, n.ReturningNewAlias) + buf.astFormat(n.ReturningList, d) + } +} diff --git a/internal/sql/ast/discard_mode.go b/internal/sql/ast/discard_mode.go new file mode 100644 index 0000000..30b9e74 --- /dev/null +++ b/internal/sql/ast/discard_mode.go @@ -0,0 +1,7 @@ +package ast + +type DiscardMode uint + +func (n *DiscardMode) Pos() int { + return 0 +} diff --git a/internal/sql/ast/discard_stmt.go b/internal/sql/ast/discard_stmt.go new file mode 100644 index 0000000..6831f7d --- /dev/null +++ b/internal/sql/ast/discard_stmt.go @@ -0,0 +1,11 @@ +package ast + +type DiscardStmt struct { + Tag NodeTag[DiscardStmt] `json:"tag"` + + Target DiscardMode `json:"target"` +} + +func (n *DiscardStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/do_stmt.go b/internal/sql/ast/do_stmt.go new file mode 100644 index 0000000..f21bafe --- /dev/null +++ b/internal/sql/ast/do_stmt.go @@ -0,0 +1,32 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type DoStmt struct { + Tag NodeTag[DoStmt] `json:"tag"` + + Args *List `json:"args,omitempty"` +} + +func (n *DoStmt) Pos() int { + return 0 +} + +func (n *DoStmt) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteString("DO ") + // Find the "as" argument which contains the body + if items(n.Args) { + for _, arg := range n.Args.Items { + if de, ok := arg.(*DefElem); ok && de.Defname != nil && *de.Defname == "as" { + if s, ok := de.Arg.(*String); ok { + buf.WriteString("$$") + buf.WriteString(s.Str) + buf.WriteString("$$") + } + } + } + } +} diff --git a/internal/sql/ast/drop_behavior.go b/internal/sql/ast/drop_behavior.go new file mode 100644 index 0000000..557073c --- /dev/null +++ b/internal/sql/ast/drop_behavior.go @@ -0,0 +1,7 @@ +package ast + +type DropBehavior uint + +func (n *DropBehavior) Pos() int { + return 0 +} diff --git a/internal/sql/ast/drop_function_stmt.go b/internal/sql/ast/drop_function_stmt.go new file mode 100644 index 0000000..e5fec40 --- /dev/null +++ b/internal/sql/ast/drop_function_stmt.go @@ -0,0 +1,12 @@ +package ast + +type DropFunctionStmt struct { + Tag NodeTag[DropFunctionStmt] `json:"tag"` + + Funcs []*FuncSpec `json:"funcs,omitempty"` + MissingOk bool `json:"missing_ok"` +} + +func (n *DropFunctionStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/drop_owned_stmt.go b/internal/sql/ast/drop_owned_stmt.go new file mode 100644 index 0000000..ab98818 --- /dev/null +++ b/internal/sql/ast/drop_owned_stmt.go @@ -0,0 +1,12 @@ +package ast + +type DropOwnedStmt struct { + Tag NodeTag[DropOwnedStmt] `json:"tag"` + + Roles *List `json:"roles,omitempty"` + Behavior DropBehavior `json:"behavior"` +} + +func (n *DropOwnedStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/drop_role_stmt.go b/internal/sql/ast/drop_role_stmt.go new file mode 100644 index 0000000..2bdcffd --- /dev/null +++ b/internal/sql/ast/drop_role_stmt.go @@ -0,0 +1,12 @@ +package ast + +type DropRoleStmt struct { + Tag NodeTag[DropRoleStmt] `json:"tag"` + + Roles *List `json:"roles,omitempty"` + MissingOk bool `json:"missing_ok"` +} + +func (n *DropRoleStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/drop_schema_stmt.go b/internal/sql/ast/drop_schema_stmt.go new file mode 100644 index 0000000..f5d9f1e --- /dev/null +++ b/internal/sql/ast/drop_schema_stmt.go @@ -0,0 +1,12 @@ +package ast + +type DropSchemaStmt struct { + Tag NodeTag[DropSchemaStmt] `json:"tag"` + + Schemas []*String `json:"schemas,omitempty"` + MissingOk bool `json:"missing_ok"` +} + +func (n *DropSchemaStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/drop_stmt.go b/internal/sql/ast/drop_stmt.go new file mode 100644 index 0000000..3305e16 --- /dev/null +++ b/internal/sql/ast/drop_stmt.go @@ -0,0 +1,15 @@ +package ast + +type DropStmt struct { + Tag NodeTag[DropStmt] `json:"tag"` + + Objects *List `json:"objects,omitempty"` + RemoveType ObjectType `json:"remove_type"` + Behavior DropBehavior `json:"behavior"` + MissingOk bool `json:"missing_ok"` + Concurrent bool `json:"concurrent"` +} + +func (n *DropStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/drop_subscription_stmt.go b/internal/sql/ast/drop_subscription_stmt.go new file mode 100644 index 0000000..3fbd852 --- /dev/null +++ b/internal/sql/ast/drop_subscription_stmt.go @@ -0,0 +1,13 @@ +package ast + +type DropSubscriptionStmt struct { + Tag NodeTag[DropSubscriptionStmt] `json:"tag"` + + Subname *string `json:"subname,omitempty"` + MissingOk bool `json:"missing_ok"` + Behavior DropBehavior `json:"behavior"` +} + +func (n *DropSubscriptionStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/drop_table_space_stmt.go b/internal/sql/ast/drop_table_space_stmt.go new file mode 100644 index 0000000..8093e73 --- /dev/null +++ b/internal/sql/ast/drop_table_space_stmt.go @@ -0,0 +1,12 @@ +package ast + +type DropTableSpaceStmt struct { + Tag NodeTag[DropTableSpaceStmt] `json:"tag"` + + Tablespacename *string `json:"tablespacename,omitempty"` + MissingOk bool `json:"missing_ok"` +} + +func (n *DropTableSpaceStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/drop_table_stmt.go b/internal/sql/ast/drop_table_stmt.go new file mode 100644 index 0000000..4687b7c --- /dev/null +++ b/internal/sql/ast/drop_table_stmt.go @@ -0,0 +1,12 @@ +package ast + +type DropTableStmt struct { + Tag NodeTag[DropTableStmt] `json:"tag"` + + IfExists bool `json:"if_exists"` + Tables []*TableName `json:"tables,omitempty"` +} + +func (n *DropTableStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/drop_type_stmt.go b/internal/sql/ast/drop_type_stmt.go new file mode 100644 index 0000000..dcef895 --- /dev/null +++ b/internal/sql/ast/drop_type_stmt.go @@ -0,0 +1,12 @@ +package ast + +type DropTypeStmt struct { + Tag NodeTag[DropTypeStmt] `json:"tag"` + + IfExists bool `json:"if_exists"` + Types []*TypeName `json:"types,omitempty"` +} + +func (n *DropTypeStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/drop_user_mapping_stmt.go b/internal/sql/ast/drop_user_mapping_stmt.go new file mode 100644 index 0000000..9503d8a --- /dev/null +++ b/internal/sql/ast/drop_user_mapping_stmt.go @@ -0,0 +1,13 @@ +package ast + +type DropUserMappingStmt struct { + Tag NodeTag[DropUserMappingStmt] `json:"tag"` + + User *RoleSpec `json:"user,omitempty"` + Servername *string `json:"servername,omitempty"` + MissingOk bool `json:"missing_ok"` +} + +func (n *DropUserMappingStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/dropdb_stmt.go b/internal/sql/ast/dropdb_stmt.go new file mode 100644 index 0000000..da6eb86 --- /dev/null +++ b/internal/sql/ast/dropdb_stmt.go @@ -0,0 +1,12 @@ +package ast + +type DropdbStmt struct { + Tag NodeTag[DropdbStmt] `json:"tag"` + + Dbname *string `json:"dbname,omitempty"` + MissingOk bool `json:"missing_ok"` +} + +func (n *DropdbStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/execute_stmt.go b/internal/sql/ast/execute_stmt.go new file mode 100644 index 0000000..4ede4f4 --- /dev/null +++ b/internal/sql/ast/execute_stmt.go @@ -0,0 +1,12 @@ +package ast + +type ExecuteStmt struct { + Tag NodeTag[ExecuteStmt] `json:"tag"` + + Name *string `json:"name,omitempty"` + Params *List `json:"params,omitempty"` +} + +func (n *ExecuteStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/explain_stmt.go b/internal/sql/ast/explain_stmt.go new file mode 100644 index 0000000..66c5608 --- /dev/null +++ b/internal/sql/ast/explain_stmt.go @@ -0,0 +1,12 @@ +package ast + +type ExplainStmt struct { + Tag NodeTag[ExplainStmt] `json:"tag"` + + Query Node `json:"query,omitempty"` + Options *List `json:"options,omitempty"` +} + +func (n *ExplainStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/expr.go b/internal/sql/ast/expr.go new file mode 100644 index 0000000..4de58b5 --- /dev/null +++ b/internal/sql/ast/expr.go @@ -0,0 +1,9 @@ +package ast + +type Expr struct { + Tag NodeTag[Expr] `json:"tag"` +} + +func (n *Expr) Pos() int { + return 0 +} diff --git a/internal/sql/ast/fetch_direction.go b/internal/sql/ast/fetch_direction.go new file mode 100644 index 0000000..47e2683 --- /dev/null +++ b/internal/sql/ast/fetch_direction.go @@ -0,0 +1,7 @@ +package ast + +type FetchDirection uint + +func (n *FetchDirection) Pos() int { + return 0 +} diff --git a/internal/sql/ast/fetch_stmt.go b/internal/sql/ast/fetch_stmt.go new file mode 100644 index 0000000..7a59569 --- /dev/null +++ b/internal/sql/ast/fetch_stmt.go @@ -0,0 +1,14 @@ +package ast + +type FetchStmt struct { + Tag NodeTag[FetchStmt] `json:"tag"` + + Direction FetchDirection `json:"direction"` + HowMany int64 `json:"how_many"` + Portalname *string `json:"portalname,omitempty"` + Ismove bool `json:"ismove"` +} + +func (n *FetchStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/field_select.go b/internal/sql/ast/field_select.go new file mode 100644 index 0000000..57f77a6 --- /dev/null +++ b/internal/sql/ast/field_select.go @@ -0,0 +1,16 @@ +package ast + +type FieldSelect struct { + Tag NodeTag[FieldSelect] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Arg Node `json:"arg,omitempty"` + Fieldnum AttrNumber `json:"fieldnum"` + Resulttype Oid `json:"resulttype"` + Resulttypmod int32 `json:"resulttypmod"` + Resultcollid Oid `json:"resultcollid"` +} + +func (n *FieldSelect) Pos() int { + return 0 +} diff --git a/internal/sql/ast/field_store.go b/internal/sql/ast/field_store.go new file mode 100644 index 0000000..505c924 --- /dev/null +++ b/internal/sql/ast/field_store.go @@ -0,0 +1,15 @@ +package ast + +type FieldStore struct { + Tag NodeTag[FieldStore] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Arg Node `json:"arg,omitempty"` + Newvals *List `json:"newvals,omitempty"` + Fieldnums *List `json:"fieldnums,omitempty"` + Resulttype Oid `json:"resulttype"` +} + +func (n *FieldStore) Pos() int { + return 0 +} diff --git a/internal/sql/ast/float.go b/internal/sql/ast/float.go new file mode 100644 index 0000000..a91b89a --- /dev/null +++ b/internal/sql/ast/float.go @@ -0,0 +1,20 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type Float struct { + Tag NodeTag[Float] `json:"tag"` + + Str string `json:"str"` +} + +func (n *Float) Pos() int { + return 0 +} + +func (n *Float) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteString(n.Str) +} diff --git a/internal/sql/ast/from_expr.go b/internal/sql/ast/from_expr.go new file mode 100644 index 0000000..021ac30 --- /dev/null +++ b/internal/sql/ast/from_expr.go @@ -0,0 +1,12 @@ +package ast + +type FromExpr struct { + Tag NodeTag[FromExpr] `json:"tag"` + + Fromlist *List `json:"fromlist,omitempty"` + Quals Node `json:"quals,omitempty"` +} + +func (n *FromExpr) Pos() int { + return 0 +} diff --git a/internal/sql/ast/func_call.go b/internal/sql/ast/func_call.go new file mode 100644 index 0000000..f7e041f --- /dev/null +++ b/internal/sql/ast/func_call.go @@ -0,0 +1,68 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type FuncCall struct { + Tag NodeTag[FuncCall] `json:"tag"` + + Func *FuncName `json:"func,omitempty"` + Funcname *List `json:"funcname,omitempty"` + Args *List `json:"args,omitempty"` + AggOrder *List `json:"agg_order,omitempty"` + AggFilter Node `json:"agg_filter,omitempty"` + AggWithinGroup bool `json:"agg_within_group"` + AggStar bool `json:"agg_star"` + AggDistinct bool `json:"agg_distinct"` + FuncVariadic bool `json:"func_variadic"` + Over *WindowDef `json:"over,omitempty"` + Separator *string `json:"separator,omitempty"` // MySQL GROUP_CONCAT SEPARATOR + Location int `json:"location"` +} + +func (n *FuncCall) Pos() int { + return n.Location +} + +func (n *FuncCall) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.astFormat(n.Func, d) + buf.WriteString("(") + if n.AggDistinct { + buf.WriteString("DISTINCT ") + } + if n.AggStar { + buf.WriteString("*") + } else { + buf.astFormat(n.Args, d) + } + // ORDER BY inside function call (not WITHIN GROUP) + if items(n.AggOrder) && !n.AggWithinGroup { + buf.WriteString(" ORDER BY ") + buf.join(n.AggOrder, d, ", ") + } + // SEPARATOR for GROUP_CONCAT (MySQL) + if n.Separator != nil { + buf.WriteString(" SEPARATOR ") + buf.WriteString("'") + buf.WriteString(*n.Separator) + buf.WriteString("'") + } + buf.WriteString(")") + // WITHIN GROUP clause for ordered-set aggregates + if items(n.AggOrder) && n.AggWithinGroup { + buf.WriteString(" WITHIN GROUP (ORDER BY ") + buf.join(n.AggOrder, d, ", ") + buf.WriteString(")") + } + if set(n.AggFilter) { + buf.WriteString(" FILTER (WHERE ") + buf.astFormat(n.AggFilter, d) + buf.WriteString(")") + } + if n.Over != nil { + buf.WriteString(" OVER ") + buf.astFormat(n.Over, d) + } +} diff --git a/internal/sql/ast/func_expr.go b/internal/sql/ast/func_expr.go new file mode 100644 index 0000000..39dee6f --- /dev/null +++ b/internal/sql/ast/func_expr.go @@ -0,0 +1,20 @@ +package ast + +type FuncExpr struct { + Tag NodeTag[FuncExpr] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Funcid Oid `json:"funcid"` + Funcresulttype Oid `json:"funcresulttype"` + Funcretset bool `json:"funcretset"` + Funcvariadic bool `json:"funcvariadic"` + Funcformat CoercionForm `json:"funcformat"` + Funccollid Oid `json:"funccollid"` + Inputcollid Oid `json:"inputcollid"` + Args *List `json:"args,omitempty"` + Location int `json:"location"` +} + +func (n *FuncExpr) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/func_name.go b/internal/sql/ast/func_name.go new file mode 100644 index 0000000..0c1d6fb --- /dev/null +++ b/internal/sql/ast/func_name.go @@ -0,0 +1,28 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type FuncName struct { + Tag NodeTag[FuncName] `json:"tag"` + + Catalog string `json:"catalog"` + Schema string `json:"schema"` + Name string `json:"name"` +} + +func (n *FuncName) Pos() int { + return 0 +} + +func (n *FuncName) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + if n.Schema != "" { + buf.WriteString(n.Schema) + buf.WriteString(".") + } + if n.Name != "" { + buf.WriteString(n.Name) + } +} diff --git a/internal/sql/ast/func_param.go b/internal/sql/ast/func_param.go new file mode 100644 index 0000000..ae353f3 --- /dev/null +++ b/internal/sql/ast/func_param.go @@ -0,0 +1,49 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type FuncParamMode int + +const ( + FuncParamIn FuncParamMode = iota + FuncParamOut + FuncParamInOut + FuncParamVariadic + FuncParamTable + FuncParamDefault +) + +type FuncParam struct { + Tag NodeTag[FuncParam] `json:"tag"` + + Name *string `json:"name,omitempty"` + Type *TypeName `json:"type,omitempty"` + DefExpr Node `json:"def_expr,omitempty"` // Will always be &ast.TODO + Mode FuncParamMode `json:"mode"` +} + +func (n *FuncParam) Pos() int { + return 0 +} + +func (n *FuncParam) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + // Parameter mode prefix (OUT, INOUT, VARIADIC) + switch n.Mode { + case FuncParamOut: + buf.WriteString("OUT ") + case FuncParamInOut: + buf.WriteString("INOUT ") + case FuncParamVariadic: + buf.WriteString("VARIADIC ") + } + // Parameter name (if present) + if n.Name != nil { + buf.WriteString(*n.Name) + buf.WriteString(" ") + } + // Parameter type + buf.astFormat(n.Type, d) +} diff --git a/internal/sql/ast/func_spec.go b/internal/sql/ast/func_spec.go new file mode 100644 index 0000000..019bac9 --- /dev/null +++ b/internal/sql/ast/func_spec.go @@ -0,0 +1,13 @@ +package ast + +type FuncSpec struct { + Tag NodeTag[FuncSpec] `json:"tag"` + + Name *FuncName `json:"name,omitempty"` + Args []*TypeName `json:"args,omitempty"` + HasArgs bool `json:"has_args"` +} + +func (n *FuncSpec) Pos() int { + return 0 +} diff --git a/internal/sql/ast/function_parameter.go b/internal/sql/ast/function_parameter.go new file mode 100644 index 0000000..3bbb086 --- /dev/null +++ b/internal/sql/ast/function_parameter.go @@ -0,0 +1,14 @@ +package ast + +type FunctionParameter struct { + Tag NodeTag[FunctionParameter] `json:"tag"` + + Name *string `json:"name,omitempty"` + ArgType *TypeName `json:"arg_type,omitempty"` + Mode FunctionParameterMode `json:"mode"` + Defexpr Node `json:"defexpr,omitempty"` +} + +func (n *FunctionParameter) Pos() int { + return 0 +} diff --git a/internal/sql/ast/function_parameter_mode.go b/internal/sql/ast/function_parameter_mode.go new file mode 100644 index 0000000..9409ce5 --- /dev/null +++ b/internal/sql/ast/function_parameter_mode.go @@ -0,0 +1,7 @@ +package ast + +type FunctionParameterMode uint + +func (n *FunctionParameterMode) Pos() int { + return 0 +} diff --git a/internal/sql/ast/grant_object_type.go b/internal/sql/ast/grant_object_type.go new file mode 100644 index 0000000..7015de2 --- /dev/null +++ b/internal/sql/ast/grant_object_type.go @@ -0,0 +1,7 @@ +package ast + +type GrantObjectType uint + +func (n *GrantObjectType) Pos() int { + return 0 +} diff --git a/internal/sql/ast/grant_role_stmt.go b/internal/sql/ast/grant_role_stmt.go new file mode 100644 index 0000000..0dd26f9 --- /dev/null +++ b/internal/sql/ast/grant_role_stmt.go @@ -0,0 +1,15 @@ +package ast + +type GrantRoleStmt struct { + Tag NodeTag[GrantRoleStmt] `json:"tag"` + + GrantedRoles *List `json:"granted_roles,omitempty"` + GranteeRoles *List `json:"grantee_roles,omitempty"` + IsGrant bool `json:"is_grant"` + Grantor *RoleSpec `json:"grantor,omitempty"` + Behavior DropBehavior `json:"behavior"` +} + +func (n *GrantRoleStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/grant_stmt.go b/internal/sql/ast/grant_stmt.go new file mode 100644 index 0000000..964395c --- /dev/null +++ b/internal/sql/ast/grant_stmt.go @@ -0,0 +1,18 @@ +package ast + +type GrantStmt struct { + Tag NodeTag[GrantStmt] `json:"tag"` + + IsGrant bool `json:"is_grant"` + Targtype GrantTargetType `json:"targtype"` + Objtype GrantObjectType `json:"objtype"` + Objects *List `json:"objects,omitempty"` + Privileges *List `json:"privileges,omitempty"` + Grantees *List `json:"grantees,omitempty"` + GrantOption bool `json:"grant_option"` + Behavior DropBehavior `json:"behavior"` +} + +func (n *GrantStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/grant_target_type.go b/internal/sql/ast/grant_target_type.go new file mode 100644 index 0000000..4c723d6 --- /dev/null +++ b/internal/sql/ast/grant_target_type.go @@ -0,0 +1,7 @@ +package ast + +type GrantTargetType uint + +func (n *GrantTargetType) Pos() int { + return 0 +} diff --git a/internal/sql/ast/grouping_func.go b/internal/sql/ast/grouping_func.go new file mode 100644 index 0000000..80f8471 --- /dev/null +++ b/internal/sql/ast/grouping_func.go @@ -0,0 +1,16 @@ +package ast + +type GroupingFunc struct { + Tag NodeTag[GroupingFunc] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Args *List `json:"args,omitempty"` + Refs *List `json:"refs,omitempty"` + Cols *List `json:"cols,omitempty"` + Agglevelsup Index `json:"agglevelsup"` + Location int `json:"location"` +} + +func (n *GroupingFunc) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/grouping_set.go b/internal/sql/ast/grouping_set.go new file mode 100644 index 0000000..10c5098 --- /dev/null +++ b/internal/sql/ast/grouping_set.go @@ -0,0 +1,13 @@ +package ast + +type GroupingSet struct { + Tag NodeTag[GroupingSet] `json:"tag"` + + Kind GroupingSetKind `json:"kind"` + Content *List `json:"content,omitempty"` + Location int `json:"location"` +} + +func (n *GroupingSet) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/grouping_set_kind.go b/internal/sql/ast/grouping_set_kind.go new file mode 100644 index 0000000..a6feb84 --- /dev/null +++ b/internal/sql/ast/grouping_set_kind.go @@ -0,0 +1,7 @@ +package ast + +type GroupingSetKind uint + +func (n *GroupingSetKind) Pos() int { + return 0 +} diff --git a/internal/sql/ast/import_foreign_schema_stmt.go b/internal/sql/ast/import_foreign_schema_stmt.go new file mode 100644 index 0000000..7d824bd --- /dev/null +++ b/internal/sql/ast/import_foreign_schema_stmt.go @@ -0,0 +1,16 @@ +package ast + +type ImportForeignSchemaStmt struct { + Tag NodeTag[ImportForeignSchemaStmt] `json:"tag"` + + ServerName *string `json:"server_name,omitempty"` + RemoteSchema *string `json:"remote_schema,omitempty"` + LocalSchema *string `json:"local_schema,omitempty"` + ListType ImportForeignSchemaType `json:"list_type"` + TableList *List `json:"table_list,omitempty"` + Options *List `json:"options,omitempty"` +} + +func (n *ImportForeignSchemaStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/import_foreign_schema_type.go b/internal/sql/ast/import_foreign_schema_type.go new file mode 100644 index 0000000..905a534 --- /dev/null +++ b/internal/sql/ast/import_foreign_schema_type.go @@ -0,0 +1,7 @@ +package ast + +type ImportForeignSchemaType uint + +func (n *ImportForeignSchemaType) Pos() int { + return 0 +} diff --git a/internal/sql/ast/in.go b/internal/sql/ast/in.go new file mode 100644 index 0000000..6afa9fc --- /dev/null +++ b/internal/sql/ast/in.go @@ -0,0 +1,50 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +// In describes a 'select foo in (bar, baz)' type statement, though there are multiple important variants handled. +type In struct { + Tag NodeTag[In] `json:"tag"` + + // Expr is the value expression to be compared. + Expr Node `json:"expr,omitempty"` + // List is the list expression in compare list. + List []Node `json:"list,omitempty"` + // Not is true, the expression is "not in". + Not bool `json:"not"` + // Sel is the subquery, may be rewritten to other type of expression. + Sel Node `json:"sel,omitempty"` + Location int `json:"location"` +} + +// Pos returns the location. +func (n *In) Pos() int { + return n.Location +} + +// Format formats the In expression. +func (n *In) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.astFormat(n.Expr, d) + if n.Not { + buf.WriteString(" NOT IN ") + } else { + buf.WriteString(" IN ") + } + if n.Sel != nil { + buf.WriteString("(") + buf.astFormat(n.Sel, d) + buf.WriteString(")") + } else if len(n.List) > 0 { + buf.WriteString("(") + for i, item := range n.List { + if i > 0 { + buf.WriteString(", ") + } + buf.astFormat(item, d) + } + buf.WriteString(")") + } +} diff --git a/internal/sql/ast/index_elem.go b/internal/sql/ast/index_elem.go new file mode 100644 index 0000000..e49ea05 --- /dev/null +++ b/internal/sql/ast/index_elem.go @@ -0,0 +1,30 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type IndexElem struct { + Tag NodeTag[IndexElem] `json:"tag"` + + Name *string `json:"name,omitempty"` + Expr Node `json:"expr,omitempty"` + Indexcolname *string `json:"indexcolname,omitempty"` + Collation *List `json:"collation,omitempty"` + Opclass *List `json:"opclass,omitempty"` + Ordering SortByDir `json:"ordering"` + NullsOrdering SortByNulls `json:"nulls_ordering"` +} + +func (n *IndexElem) Pos() int { + return 0 +} + +func (n *IndexElem) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + if n.Name != nil && *n.Name != "" { + buf.WriteString(*n.Name) + } else if set(n.Expr) { + buf.astFormat(n.Expr, d) + } +} diff --git a/internal/sql/ast/index_stmt.go b/internal/sql/ast/index_stmt.go new file mode 100644 index 0000000..5eafbcb --- /dev/null +++ b/internal/sql/ast/index_stmt.go @@ -0,0 +1,28 @@ +package ast + +type IndexStmt struct { + Tag NodeTag[IndexStmt] `json:"tag"` + + Idxname *string `json:"idxname,omitempty"` + Relation *RangeVar `json:"relation,omitempty"` + AccessMethod *string `json:"access_method,omitempty"` + TableSpace *string `json:"table_space,omitempty"` + IndexParams *List `json:"index_params,omitempty"` + Options *List `json:"options,omitempty"` + WhereClause Node `json:"where_clause,omitempty"` + ExcludeOpNames *List `json:"exclude_op_names,omitempty"` + Idxcomment *string `json:"idxcomment,omitempty"` + IndexOid Oid `json:"index_oid"` + Unique bool `json:"unique"` + Primary bool `json:"primary"` + Isconstraint bool `json:"isconstraint"` + Deferrable bool `json:"deferrable"` + Initdeferred bool `json:"initdeferred"` + Transformed bool `json:"transformed"` + Concurrent bool `json:"concurrent"` + IfNotExists bool `json:"if_not_exists"` +} + +func (n *IndexStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/infer_clause.go b/internal/sql/ast/infer_clause.go new file mode 100644 index 0000000..f4dc4bc --- /dev/null +++ b/internal/sql/ast/infer_clause.go @@ -0,0 +1,34 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type InferClause struct { + Tag NodeTag[InferClause] `json:"tag"` + + IndexElems *List `json:"index_elems,omitempty"` + WhereClause Node `json:"where_clause,omitempty"` + Conname *string `json:"conname,omitempty"` + Location int `json:"location"` +} + +func (n *InferClause) Pos() int { + return n.Location +} + +func (n *InferClause) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + if n.Conname != nil && *n.Conname != "" { + buf.WriteString("ON CONSTRAINT ") + buf.WriteString(*n.Conname) + } else if items(n.IndexElems) { + buf.WriteString("(") + buf.join(n.IndexElems, d, ", ") + buf.WriteString(")") + if set(n.WhereClause) { + buf.WriteString(" WHERE ") + buf.astFormat(n.WhereClause, d) + } + } +} diff --git a/internal/sql/ast/inference_elem.go b/internal/sql/ast/inference_elem.go new file mode 100644 index 0000000..be27eb8 --- /dev/null +++ b/internal/sql/ast/inference_elem.go @@ -0,0 +1,14 @@ +package ast + +type InferenceElem struct { + Tag NodeTag[InferenceElem] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Expr Node `json:"expr,omitempty"` + Infercollid Oid `json:"infercollid"` + Inferopclass Oid `json:"inferopclass"` +} + +func (n *InferenceElem) Pos() int { + return 0 +} diff --git a/internal/sql/ast/inline_code_block.go b/internal/sql/ast/inline_code_block.go new file mode 100644 index 0000000..6698334 --- /dev/null +++ b/internal/sql/ast/inline_code_block.go @@ -0,0 +1,13 @@ +package ast + +type InlineCodeBlock struct { + Tag NodeTag[InlineCodeBlock] `json:"tag"` + + SourceText *string `json:"source_text,omitempty"` + LangOid Oid `json:"lang_oid"` + LangIsTrusted bool `json:"lang_is_trusted"` +} + +func (n *InlineCodeBlock) Pos() int { + return 0 +} diff --git a/internal/sql/ast/insert_stmt.go b/internal/sql/ast/insert_stmt.go new file mode 100644 index 0000000..e6d3d3a --- /dev/null +++ b/internal/sql/ast/insert_stmt.go @@ -0,0 +1,86 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type InsertStmt struct { + Tag NodeTag[InsertStmt] `json:"tag"` + + Relation *RangeVar `json:"relation,omitempty"` + Cols *List `json:"cols,omitempty"` + SelectStmt Node `json:"select_stmt,omitempty"` + OnConflictClause *OnConflictClause `json:"on_conflict_clause,omitempty"` + OnDuplicateKeyUpdate *OnDuplicateKeyUpdate `json:"on_duplicate_key_update,omitempty"` // MySQL-specific + ReturningList *List `json:"returning_list,omitempty"` + WithClause *WithClause `json:"with_clause,omitempty"` + Override OverridingKind `json:"override"` + DefaultValues bool `json:"default_values"` // SQLite-specific: INSERT INTO ... DEFAULT VALUES + // PostgreSQL 18 RETURNING WITH (OLD AS ..., NEW AS ...) aliases + ReturningOldAlias string `json:"returning_old_alias"` + ReturningNewAlias string `json:"returning_new_alias"` +} + +func (n *InsertStmt) Pos() int { + return 0 +} + +func (n *InsertStmt) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + + buf.Group() + defer buf.EndGroup() + + if n.WithClause != nil { + buf.astFormat(n.WithClause, d) + // The boundary between the WITH clause and the statement's own + // first keyword; the group keeps a break inside the WITH clause + // from forcing the statement body apart clause by clause. + buf.boundary(n.Relation) + buf.Line() + buf.Group() + defer buf.EndGroup() + } + + buf.WriteString("INSERT INTO ") + if n.Relation != nil { + buf.astFormat(n.Relation, d) + } + if items(n.Cols) { + buf.WriteString(" (") + buf.Group() + buf.Indent() + buf.Softline() + buf.joinComma(n.Cols, d) + buf.EndIndent() + buf.Softline() + buf.EndGroup() + buf.WriteString(")") + } + + if n.DefaultValues { + buf.WriteString(" DEFAULT VALUES") + } else if set(n.SelectStmt) { + buf.beforeClause(n.SelectStmt, d) + buf.Line() + buf.astFormat(n.SelectStmt, d) + } + + if n.OnConflictClause != nil { + buf.Line() + buf.astFormat(n.OnConflictClause, d) + } + + if n.OnDuplicateKeyUpdate != nil { + buf.Line() + buf.astFormat(n.OnDuplicateKeyUpdate, d) + } + + if items(n.ReturningList) { + buf.beforeClause(n.ReturningList, d) + buf.Line() + buf.WriteString("RETURNING ") + formatReturningOptions(buf, d, n.ReturningOldAlias, n.ReturningNewAlias) + buf.astFormat(n.ReturningList, d) + } +} diff --git a/internal/sql/ast/integer.go b/internal/sql/ast/integer.go new file mode 100644 index 0000000..30c2705 --- /dev/null +++ b/internal/sql/ast/integer.go @@ -0,0 +1,24 @@ +package ast + +import ( + "strconv" + + "github.com/sqlc-dev/sqlc/internal/sql/format" +) + +type Integer struct { + Tag NodeTag[Integer] `json:"tag"` + + Ival int64 `json:"ival"` +} + +func (n *Integer) Pos() int { + return 0 +} + +func (n *Integer) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteString(strconv.FormatInt(n.Ival, 10)) +} diff --git a/internal/sql/ast/interval_expr.go b/internal/sql/ast/interval_expr.go new file mode 100644 index 0000000..f89ceed --- /dev/null +++ b/internal/sql/ast/interval_expr.go @@ -0,0 +1,26 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +// IntervalExpr represents a MySQL INTERVAL expression like "INTERVAL 1 DAY" +type IntervalExpr struct { + Tag NodeTag[IntervalExpr] `json:"tag"` + + Value Node `json:"value,omitempty"` + Unit string `json:"unit"` + Location int `json:"location"` +} + +func (n *IntervalExpr) Pos() int { + return n.Location +} + +func (n *IntervalExpr) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteString("INTERVAL ") + buf.astFormat(n.Value, d) + buf.WriteString(" ") + buf.WriteString(n.Unit) +} diff --git a/internal/sql/ast/into_clause.go b/internal/sql/ast/into_clause.go new file mode 100644 index 0000000..1a74d37 --- /dev/null +++ b/internal/sql/ast/into_clause.go @@ -0,0 +1,17 @@ +package ast + +type IntoClause struct { + Tag NodeTag[IntoClause] `json:"tag"` + + Rel *RangeVar `json:"rel,omitempty"` + ColNames *List `json:"col_names,omitempty"` + Options *List `json:"options,omitempty"` + OnCommit OnCommitAction `json:"on_commit"` + TableSpaceName *string `json:"table_space_name,omitempty"` + ViewQuery Node `json:"view_query,omitempty"` + SkipData bool `json:"skip_data"` +} + +func (n *IntoClause) Pos() int { + return 0 +} diff --git a/internal/sql/ast/join_expr.go b/internal/sql/ast/join_expr.go new file mode 100644 index 0000000..59df9b3 --- /dev/null +++ b/internal/sql/ast/join_expr.go @@ -0,0 +1,59 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type JoinExpr struct { + Tag NodeTag[JoinExpr] `json:"tag"` + + Jointype JoinType `json:"jointype"` + IsNatural bool `json:"is_natural"` + Larg Node `json:"larg,omitempty"` + Rarg Node `json:"rarg,omitempty"` + UsingClause *List `json:"using_clause,omitempty"` + Quals Node `json:"quals,omitempty"` + Alias *Alias `json:"alias,omitempty"` + Rtindex int `json:"rtindex"` +} + +func (n *JoinExpr) Pos() int { + return 0 +} + +func (n *JoinExpr) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.astFormat(n.Larg, d) + if n.Jointype == JoinTypeComma { + buf.WriteString(",") + buf.beforeClause(n.Rarg, d) + buf.Line() + } else { + buf.beforeClause(n.Rarg, d) + buf.Line() + if n.IsNatural { + buf.WriteString("NATURAL ") + } + switch n.Jointype { + case JoinTypeLeft: + buf.WriteString("LEFT JOIN ") + case JoinTypeRight: + buf.WriteString("RIGHT JOIN ") + case JoinTypeFull: + buf.WriteString("FULL JOIN ") + case JoinTypeCross: + buf.WriteString("CROSS JOIN ") + default: + buf.WriteString("JOIN ") + } + } + buf.astFormat(n.Rarg, d) + if items(n.UsingClause) { + buf.WriteString(" USING (") + buf.join(n.UsingClause, d, ", ") + buf.WriteString(")") + } else if set(n.Quals) { + buf.WriteString(" ON ") + buf.condition(n.Quals, d) + } +} diff --git a/internal/sql/ast/join_type.go b/internal/sql/ast/join_type.go new file mode 100644 index 0000000..d4f5565 --- /dev/null +++ b/internal/sql/ast/join_type.go @@ -0,0 +1,28 @@ +package ast + +// JoinType is the reported type of the join +// Enum copies https://github.com/pganalyze/libpg_query/blob/13-latest/protobuf/pg_query.proto#L2890-L2901 +const ( + _ JoinType = iota + JoinTypeInner + JoinTypeLeft + JoinTypeFull + JoinTypeRight + JoinTypeSemi + JoinTypeAnti + JoinTypeUniqueOuter + JoinTypeUniqueInner + // Beyond the libpg_query set: joins SQLite spells (and treats) + // distinctly. Both behave as inner joins, but CROSS JOIN carries a + // planner hint — SQLite will not reorder the pair — and a + // comma-separated FROM item is its own syntax, so neither may be + // rewritten into the other. + JoinTypeCross + JoinTypeComma +) + +type JoinType uint + +func (n *JoinType) Pos() int { + return 0 +} diff --git a/internal/sql/ast/list.go b/internal/sql/ast/list.go new file mode 100644 index 0000000..86a3fe0 --- /dev/null +++ b/internal/sql/ast/list.go @@ -0,0 +1,20 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type List struct { + Tag NodeTag[List] `json:"tag"` + + Items []Node `json:"items,omitempty"` +} + +func (n *List) Pos() int { + return 0 +} + +func (n *List) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.join(n, d, ", ") +} diff --git a/internal/sql/ast/listen_stmt.go b/internal/sql/ast/listen_stmt.go new file mode 100644 index 0000000..3989225 --- /dev/null +++ b/internal/sql/ast/listen_stmt.go @@ -0,0 +1,23 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type ListenStmt struct { + Tag NodeTag[ListenStmt] `json:"tag"` + + Conditionname *string `json:"conditionname,omitempty"` +} + +func (n *ListenStmt) Pos() int { + return 0 +} + +func (n *ListenStmt) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteString("LISTEN ") + if n.Conditionname != nil { + buf.WriteString(*n.Conditionname) + } +} diff --git a/internal/sql/ast/load_stmt.go b/internal/sql/ast/load_stmt.go new file mode 100644 index 0000000..276f05a --- /dev/null +++ b/internal/sql/ast/load_stmt.go @@ -0,0 +1,11 @@ +package ast + +type LoadStmt struct { + Tag NodeTag[LoadStmt] `json:"tag"` + + Filename *string `json:"filename,omitempty"` +} + +func (n *LoadStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/lock_clause_strength.go b/internal/sql/ast/lock_clause_strength.go new file mode 100644 index 0000000..8756ccf --- /dev/null +++ b/internal/sql/ast/lock_clause_strength.go @@ -0,0 +1,7 @@ +package ast + +type LockClauseStrength uint + +func (n *LockClauseStrength) Pos() int { + return 0 +} diff --git a/internal/sql/ast/lock_stmt.go b/internal/sql/ast/lock_stmt.go new file mode 100644 index 0000000..82f2481 --- /dev/null +++ b/internal/sql/ast/lock_stmt.go @@ -0,0 +1,13 @@ +package ast + +type LockStmt struct { + Tag NodeTag[LockStmt] `json:"tag"` + + Relations *List `json:"relations,omitempty"` + Mode int `json:"mode"` + Nowait bool `json:"nowait"` +} + +func (n *LockStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/lock_wait_policy.go b/internal/sql/ast/lock_wait_policy.go new file mode 100644 index 0000000..2047388 --- /dev/null +++ b/internal/sql/ast/lock_wait_policy.go @@ -0,0 +1,7 @@ +package ast + +type LockWaitPolicy uint + +func (n *LockWaitPolicy) Pos() int { + return 0 +} diff --git a/internal/sql/ast/locking_clause.go b/internal/sql/ast/locking_clause.go new file mode 100644 index 0000000..00a3848 --- /dev/null +++ b/internal/sql/ast/locking_clause.go @@ -0,0 +1,59 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type LockingClause struct { + Tag NodeTag[LockingClause] `json:"tag"` + + LockedRels *List `json:"locked_rels,omitempty"` + Strength LockClauseStrength `json:"strength"` + WaitPolicy LockWaitPolicy `json:"wait_policy"` +} + +func (n *LockingClause) Pos() int { + return 0 +} + +// LockClauseStrength values (matching pg_query_go) +const ( + LockClauseStrengthUndefined LockClauseStrength = 0 + LockClauseStrengthNone LockClauseStrength = 1 + LockClauseStrengthForKeyShare LockClauseStrength = 2 + LockClauseStrengthForShare LockClauseStrength = 3 + LockClauseStrengthForNoKeyUpdate LockClauseStrength = 4 + LockClauseStrengthForUpdate LockClauseStrength = 5 +) + +// LockWaitPolicy values +const ( + LockWaitPolicyBlock LockWaitPolicy = 1 + LockWaitPolicySkip LockWaitPolicy = 2 + LockWaitPolicyError LockWaitPolicy = 3 +) + +func (n *LockingClause) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteString("FOR ") + switch n.Strength { + case LockClauseStrengthForKeyShare: + buf.WriteString("KEY SHARE") + case LockClauseStrengthForShare: + buf.WriteString("SHARE") + case LockClauseStrengthForNoKeyUpdate: + buf.WriteString("NO KEY UPDATE") + case LockClauseStrengthForUpdate: + buf.WriteString("UPDATE") + } + if items(n.LockedRels) { + buf.WriteString(" OF ") + buf.join(n.LockedRels, d, ", ") + } + switch n.WaitPolicy { + case LockWaitPolicySkip: + buf.WriteString(" SKIP LOCKED") + case LockWaitPolicyError: + buf.WriteString(" NOWAIT") + } +} diff --git a/internal/sql/ast/min_max_expr.go b/internal/sql/ast/min_max_expr.go new file mode 100644 index 0000000..56da82a --- /dev/null +++ b/internal/sql/ast/min_max_expr.go @@ -0,0 +1,17 @@ +package ast + +type MinMaxExpr struct { + Tag NodeTag[MinMaxExpr] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Minmaxtype Oid `json:"minmaxtype"` + Minmaxcollid Oid `json:"minmaxcollid"` + Inputcollid Oid `json:"inputcollid"` + Op MinMaxOp `json:"op"` + Args *List `json:"args,omitempty"` + Location int `json:"location"` +} + +func (n *MinMaxExpr) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/min_max_op.go b/internal/sql/ast/min_max_op.go new file mode 100644 index 0000000..cba26eb --- /dev/null +++ b/internal/sql/ast/min_max_op.go @@ -0,0 +1,7 @@ +package ast + +type MinMaxOp uint + +func (n *MinMaxOp) Pos() int { + return 0 +} diff --git a/internal/sql/ast/multi_assign_ref.go b/internal/sql/ast/multi_assign_ref.go new file mode 100644 index 0000000..c1a7e30 --- /dev/null +++ b/internal/sql/ast/multi_assign_ref.go @@ -0,0 +1,22 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type MultiAssignRef struct { + Tag NodeTag[MultiAssignRef] `json:"tag"` + + Source Node `json:"source,omitempty"` + Colno int `json:"colno"` + Ncolumns int `json:"ncolumns"` +} + +func (n *MultiAssignRef) Pos() int { + return 0 +} + +func (n *MultiAssignRef) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.astFormat(n.Source, d) +} diff --git a/internal/sql/ast/named_arg_expr.go b/internal/sql/ast/named_arg_expr.go new file mode 100644 index 0000000..ec3d5a1 --- /dev/null +++ b/internal/sql/ast/named_arg_expr.go @@ -0,0 +1,28 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type NamedArgExpr struct { + Tag NodeTag[NamedArgExpr] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Arg Node `json:"arg,omitempty"` + Name *string `json:"name,omitempty"` + Argnumber int `json:"argnumber"` + Location int `json:"location"` +} + +func (n *NamedArgExpr) Pos() int { + return n.Location +} + +func (n *NamedArgExpr) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + if n.Name != nil { + buf.WriteString(*n.Name) + } + buf.WriteString(" => ") + buf.astFormat(n.Arg, d) +} diff --git a/internal/sql/ast/next_value_expr.go b/internal/sql/ast/next_value_expr.go new file mode 100644 index 0000000..6832e40 --- /dev/null +++ b/internal/sql/ast/next_value_expr.go @@ -0,0 +1,13 @@ +package ast + +type NextValueExpr struct { + Tag NodeTag[NextValueExpr] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Seqid Oid `json:"seqid"` + TypeId Oid `json:"type_id"` +} + +func (n *NextValueExpr) Pos() int { + return 0 +} diff --git a/internal/sql/ast/node.go b/internal/sql/ast/node.go new file mode 100644 index 0000000..5c3afbe --- /dev/null +++ b/internal/sql/ast/node.go @@ -0,0 +1,5 @@ +package ast + +type Node interface { + Pos() int +} diff --git a/internal/sql/ast/node_tag.go b/internal/sql/ast/node_tag.go new file mode 100644 index 0000000..5b3f43b --- /dev/null +++ b/internal/sql/ast/node_tag.go @@ -0,0 +1,40 @@ +package ast + +import ( + "encoding/json" + "fmt" + "reflect" +) + +// NodeTag names its containing node type in JSON. +// +// Node is an interface, so the JSON encoding of an AST would otherwise carry no +// record of which node a given object is. Nodes with no fields of their own +// (A_Star, Null, TODO) would all encode as "{}", and an empty List would be +// indistinguishable from them. Every node struct instead declares +// +// Tag NodeTag[T] `json:"tag"` +// +// as its first field, with T the node's own type. The field is zero-sized and +// its zero value is valid, so constructing nodes as struct literals is +// unaffected; encoding/json calls MarshalJSON on the field, and the type +// parameter carries the node's identity to it at compile time. +type NodeTag[T any] struct{} + +func (NodeTag[T]) MarshalJSON() ([]byte, error) { + return json.Marshal(reflect.TypeFor[T]().Name()) +} + +// UnmarshalJSON accepts only the containing node's own name, so a document +// decoded into the wrong node type is an error rather than a silently +// misfielded tree. +func (*NodeTag[T]) UnmarshalJSON(data []byte) error { + var name string + if err := json.Unmarshal(data, &name); err != nil { + return err + } + if want := reflect.TypeFor[T]().Name(); name != want { + return fmt.Errorf("node tagged %q decoded into %s", name, want) + } + return nil +} diff --git a/internal/sql/ast/notify_stmt.go b/internal/sql/ast/notify_stmt.go new file mode 100644 index 0000000..1f2df47 --- /dev/null +++ b/internal/sql/ast/notify_stmt.go @@ -0,0 +1,29 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type NotifyStmt struct { + Tag NodeTag[NotifyStmt] `json:"tag"` + + Conditionname *string `json:"conditionname,omitempty"` + Payload *string `json:"payload,omitempty"` +} + +func (n *NotifyStmt) Pos() int { + return 0 +} + +func (n *NotifyStmt) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteString("NOTIFY ") + if n.Conditionname != nil { + buf.WriteString(*n.Conditionname) + } + if n.Payload != nil { + buf.WriteString(", '") + buf.WriteString(*n.Payload) + buf.WriteString("'") + } +} diff --git a/internal/sql/ast/null.go b/internal/sql/ast/null.go new file mode 100644 index 0000000..4fbba22 --- /dev/null +++ b/internal/sql/ast/null.go @@ -0,0 +1,14 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type Null struct { + Tag NodeTag[Null] `json:"tag"` +} + +func (n *Null) Pos() int { + return 0 +} +func (n *Null) Format(buf *TrackedBuffer, d format.Dialect) { + buf.WriteString("NULL") +} diff --git a/internal/sql/ast/null_test_expr.go b/internal/sql/ast/null_test_expr.go new file mode 100644 index 0000000..ed0d1fd --- /dev/null +++ b/internal/sql/ast/null_test_expr.go @@ -0,0 +1,36 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type NullTest struct { + Tag NodeTag[NullTest] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Arg Node `json:"arg,omitempty"` + Nulltesttype NullTestType `json:"nulltesttype"` + Argisrow bool `json:"argisrow"` + Location int `json:"location"` +} + +func (n *NullTest) Pos() int { + return n.Location +} + +// NullTestType values +const ( + NullTestTypeIsNull NullTestType = 1 + NullTestTypeIsNotNull NullTestType = 2 +) + +func (n *NullTest) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.astFormat(n.Arg, d) + switch n.Nulltesttype { + case NullTestTypeIsNull: + buf.WriteString(" IS NULL") + case NullTestTypeIsNotNull: + buf.WriteString(" IS NOT NULL") + } +} diff --git a/internal/sql/ast/null_test_type.go b/internal/sql/ast/null_test_type.go new file mode 100644 index 0000000..8ea2f12 --- /dev/null +++ b/internal/sql/ast/null_test_type.go @@ -0,0 +1,7 @@ +package ast + +type NullTestType uint + +func (n *NullTestType) Pos() int { + return 0 +} diff --git a/internal/sql/ast/object_type.go b/internal/sql/ast/object_type.go new file mode 100644 index 0000000..4451dc3 --- /dev/null +++ b/internal/sql/ast/object_type.go @@ -0,0 +1,7 @@ +package ast + +type ObjectType uint + +func (n *ObjectType) Pos() int { + return 0 +} diff --git a/internal/sql/ast/object_with_args.go b/internal/sql/ast/object_with_args.go new file mode 100644 index 0000000..05b0a0c --- /dev/null +++ b/internal/sql/ast/object_with_args.go @@ -0,0 +1,13 @@ +package ast + +type ObjectWithArgs struct { + Tag NodeTag[ObjectWithArgs] `json:"tag"` + + Objname *List `json:"objname,omitempty"` + Objargs *List `json:"objargs,omitempty"` + ArgsUnspecified bool `json:"args_unspecified"` +} + +func (n *ObjectWithArgs) Pos() int { + return 0 +} diff --git a/internal/sql/ast/on_commit_action.go b/internal/sql/ast/on_commit_action.go new file mode 100644 index 0000000..7aea66d --- /dev/null +++ b/internal/sql/ast/on_commit_action.go @@ -0,0 +1,7 @@ +package ast + +type OnCommitAction uint + +func (n *OnCommitAction) Pos() int { + return 0 +} diff --git a/internal/sql/ast/on_conflict_action.go b/internal/sql/ast/on_conflict_action.go new file mode 100644 index 0000000..96ea08a --- /dev/null +++ b/internal/sql/ast/on_conflict_action.go @@ -0,0 +1,7 @@ +package ast + +type OnConflictAction uint + +func (n *OnConflictAction) Pos() int { + return 0 +} diff --git a/internal/sql/ast/on_conflict_clause.go b/internal/sql/ast/on_conflict_clause.go new file mode 100644 index 0000000..bbf01d6 --- /dev/null +++ b/internal/sql/ast/on_conflict_clause.go @@ -0,0 +1,75 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type OnConflictClause struct { + Tag NodeTag[OnConflictClause] `json:"tag"` + + Action OnConflictAction `json:"action"` + Infer *InferClause `json:"infer,omitempty"` + TargetList *List `json:"target_list,omitempty"` + WhereClause Node `json:"where_clause,omitempty"` + Location int `json:"location"` +} + +func (n *OnConflictClause) Pos() int { + return n.Location +} + +// OnConflictAction values matching pg_query_go +const ( + OnConflictActionUndefined OnConflictAction = 0 + OnConflictActionNone OnConflictAction = 1 + OnConflictActionNothing OnConflictAction = 2 + OnConflictActionUpdate OnConflictAction = 3 +) + +func (n *OnConflictClause) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteString("ON CONFLICT ") + if n.Infer != nil { + buf.astFormat(n.Infer, d) + buf.WriteString(" ") + } + switch n.Action { + case OnConflictActionNothing: + buf.WriteString("DO NOTHING") + case OnConflictActionUpdate: + buf.WriteString("DO UPDATE SET") + buf.Group() + buf.Indent() + // Format as assignment list: name = val, one per line when the + // author broke the list (or a comment forces it open). + if n.TargetList != nil { + for i, item := range n.TargetList.Items { + if i == 0 { + buf.boundary(item) + buf.Line() + } else { + buf.WriteString(",") + buf.boundary(item) + buf.Line() + } + if rt, ok := item.(*ResTarget); ok { + if rt.Name != nil { + buf.WriteString(*rt.Name) + } + buf.WriteString(" = ") + buf.astFormat(rt.Val, d) + } else { + buf.astFormat(item, d) + } + } + } + buf.EndIndent() + if set(n.WhereClause) { + buf.boundary(n.WhereClause) + buf.Line() + buf.WriteString("WHERE ") + buf.condition(n.WhereClause, d) + } + buf.EndGroup() + } +} diff --git a/internal/sql/ast/on_conflict_expr.go b/internal/sql/ast/on_conflict_expr.go new file mode 100644 index 0000000..5bd559e --- /dev/null +++ b/internal/sql/ast/on_conflict_expr.go @@ -0,0 +1,18 @@ +package ast + +type OnConflictExpr struct { + Tag NodeTag[OnConflictExpr] `json:"tag"` + + Action OnConflictAction `json:"action"` + ArbiterElems *List `json:"arbiter_elems,omitempty"` + ArbiterWhere Node `json:"arbiter_where,omitempty"` + Constraint Oid `json:"constraint"` + OnConflictSet *List `json:"on_conflict_set,omitempty"` + OnConflictWhere Node `json:"on_conflict_where,omitempty"` + ExclRelIndex int `json:"excl_rel_index"` + ExclRelTlist *List `json:"excl_rel_tlist,omitempty"` +} + +func (n *OnConflictExpr) Pos() int { + return 0 +} diff --git a/internal/sql/ast/on_duplicate_key_update.go b/internal/sql/ast/on_duplicate_key_update.go new file mode 100644 index 0000000..bc1dbf4 --- /dev/null +++ b/internal/sql/ast/on_duplicate_key_update.go @@ -0,0 +1,39 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +// OnDuplicateKeyUpdate represents MySQL's ON DUPLICATE KEY UPDATE clause +type OnDuplicateKeyUpdate struct { + Tag NodeTag[OnDuplicateKeyUpdate] `json:"tag"` + + // TargetList contains the assignments (column = value pairs) + TargetList *List `json:"target_list,omitempty"` + Location int `json:"location"` +} + +func (n *OnDuplicateKeyUpdate) Pos() int { + return n.Location +} + +func (n *OnDuplicateKeyUpdate) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteString("ON DUPLICATE KEY UPDATE ") + if n.TargetList != nil { + for i, item := range n.TargetList.Items { + if i > 0 { + buf.WriteString(", ") + } + if rt, ok := item.(*ResTarget); ok { + if rt.Name != nil { + buf.WriteString(*rt.Name) + } + buf.WriteString(" = ") + buf.astFormat(rt.Val, d) + } else { + buf.astFormat(item, d) + } + } + } +} diff --git a/internal/sql/ast/op_expr.go b/internal/sql/ast/op_expr.go new file mode 100644 index 0000000..0d81af5 --- /dev/null +++ b/internal/sql/ast/op_expr.go @@ -0,0 +1,18 @@ +package ast + +type OpExpr struct { + Tag NodeTag[OpExpr] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Opno Oid `json:"opno"` + Opresulttype Oid `json:"opresulttype"` + Opretset bool `json:"opretset"` + Opcollid Oid `json:"opcollid"` + Inputcollid Oid `json:"inputcollid"` + Args *List `json:"args,omitempty"` + Location int `json:"location"` +} + +func (n *OpExpr) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/overriding_kind.go b/internal/sql/ast/overriding_kind.go new file mode 100644 index 0000000..622893c --- /dev/null +++ b/internal/sql/ast/overriding_kind.go @@ -0,0 +1,7 @@ +package ast + +type OverridingKind uint + +func (n *OverridingKind) Pos() int { + return 0 +} diff --git a/internal/sql/ast/param.go b/internal/sql/ast/param.go new file mode 100644 index 0000000..d9121de --- /dev/null +++ b/internal/sql/ast/param.go @@ -0,0 +1,17 @@ +package ast + +type Param struct { + Tag NodeTag[Param] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Paramkind ParamKind `json:"paramkind"` + Paramid int `json:"paramid"` + Paramtype Oid `json:"paramtype"` + Paramtypmod int32 `json:"paramtypmod"` + Paramcollid Oid `json:"paramcollid"` + Location int `json:"location"` +} + +func (n *Param) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/param_exec_data.go b/internal/sql/ast/param_exec_data.go new file mode 100644 index 0000000..6f151ea --- /dev/null +++ b/internal/sql/ast/param_exec_data.go @@ -0,0 +1,13 @@ +package ast + +type ParamExecData struct { + Tag NodeTag[ParamExecData] `json:"tag"` + + ExecPlan any `json:"exec_plan,omitempty"` + Value Datum `json:"value"` + Isnull bool `json:"isnull"` +} + +func (n *ParamExecData) Pos() int { + return 0 +} diff --git a/internal/sql/ast/param_extern_data.go b/internal/sql/ast/param_extern_data.go new file mode 100644 index 0000000..4da009f --- /dev/null +++ b/internal/sql/ast/param_extern_data.go @@ -0,0 +1,14 @@ +package ast + +type ParamExternData struct { + Tag NodeTag[ParamExternData] `json:"tag"` + + Value Datum `json:"value"` + Isnull bool `json:"isnull"` + Pflags uint16 `json:"pflags"` + Ptype Oid `json:"ptype"` +} + +func (n *ParamExternData) Pos() int { + return 0 +} diff --git a/internal/sql/ast/param_kind.go b/internal/sql/ast/param_kind.go new file mode 100644 index 0000000..2bc9b50 --- /dev/null +++ b/internal/sql/ast/param_kind.go @@ -0,0 +1,7 @@ +package ast + +type ParamKind uint + +func (n *ParamKind) Pos() int { + return 0 +} diff --git a/internal/sql/ast/param_list_info_data.go b/internal/sql/ast/param_list_info_data.go new file mode 100644 index 0000000..30e34d0 --- /dev/null +++ b/internal/sql/ast/param_list_info_data.go @@ -0,0 +1,14 @@ +package ast + +type ParamListInfoData struct { + Tag NodeTag[ParamListInfoData] `json:"tag"` + + ParamFetchArg any `json:"param_fetch_arg,omitempty"` + ParserSetupArg any `json:"parser_setup_arg,omitempty"` + NumParams int `json:"num_params"` + ParamMask []uint32 `json:"param_mask,omitempty"` +} + +func (n *ParamListInfoData) Pos() int { + return 0 +} diff --git a/internal/sql/ast/param_ref.go b/internal/sql/ast/param_ref.go new file mode 100644 index 0000000..0936c60 --- /dev/null +++ b/internal/sql/ast/param_ref.go @@ -0,0 +1,25 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type ParamRef struct { + Tag NodeTag[ParamRef] `json:"tag"` + + Number int `json:"number"` + Location int `json:"location"` + Dollar bool `json:"dollar"` + // Name is the name the query gave the placeholder, when its syntax + // has one: ClickHouse's {name:Type}. + Name string `json:"name,omitempty"` +} + +func (n *ParamRef) Pos() int { + return n.Location +} + +func (n *ParamRef) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteString(d.Param(n.Number, n.Dollar)) +} diff --git a/internal/sql/ast/paren_expr.go b/internal/sql/ast/paren_expr.go new file mode 100644 index 0000000..79cb15b --- /dev/null +++ b/internal/sql/ast/paren_expr.go @@ -0,0 +1,24 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +// ParenExpr represents a parenthesized expression +type ParenExpr struct { + Tag NodeTag[ParenExpr] `json:"tag"` + + Expr Node `json:"expr,omitempty"` + Location int `json:"location"` +} + +func (n *ParenExpr) Pos() int { + return n.Location +} + +func (n *ParenExpr) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteString("(") + buf.astFormat(n.Expr, d) + buf.WriteString(")") +} diff --git a/internal/sql/ast/partition_bound_spec.go b/internal/sql/ast/partition_bound_spec.go new file mode 100644 index 0000000..6f45517 --- /dev/null +++ b/internal/sql/ast/partition_bound_spec.go @@ -0,0 +1,15 @@ +package ast + +type PartitionBoundSpec struct { + Tag NodeTag[PartitionBoundSpec] `json:"tag"` + + Strategy byte `json:"strategy"` + Listdatums *List `json:"listdatums,omitempty"` + Lowerdatums *List `json:"lowerdatums,omitempty"` + Upperdatums *List `json:"upperdatums,omitempty"` + Location int `json:"location"` +} + +func (n *PartitionBoundSpec) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/partition_cmd.go b/internal/sql/ast/partition_cmd.go new file mode 100644 index 0000000..931b809 --- /dev/null +++ b/internal/sql/ast/partition_cmd.go @@ -0,0 +1,12 @@ +package ast + +type PartitionCmd struct { + Tag NodeTag[PartitionCmd] `json:"tag"` + + Name *RangeVar `json:"name,omitempty"` + Bound *PartitionBoundSpec `json:"bound,omitempty"` +} + +func (n *PartitionCmd) Pos() int { + return 0 +} diff --git a/internal/sql/ast/partition_elem.go b/internal/sql/ast/partition_elem.go new file mode 100644 index 0000000..1fe38fc --- /dev/null +++ b/internal/sql/ast/partition_elem.go @@ -0,0 +1,15 @@ +package ast + +type PartitionElem struct { + Tag NodeTag[PartitionElem] `json:"tag"` + + Name *string `json:"name,omitempty"` + Expr Node `json:"expr,omitempty"` + Collation *List `json:"collation,omitempty"` + Opclass *List `json:"opclass,omitempty"` + Location int `json:"location"` +} + +func (n *PartitionElem) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/partition_range_datum.go b/internal/sql/ast/partition_range_datum.go new file mode 100644 index 0000000..d827ced --- /dev/null +++ b/internal/sql/ast/partition_range_datum.go @@ -0,0 +1,13 @@ +package ast + +type PartitionRangeDatum struct { + Tag NodeTag[PartitionRangeDatum] `json:"tag"` + + Kind PartitionRangeDatumKind `json:"kind"` + Value Node `json:"value,omitempty"` + Location int `json:"location"` +} + +func (n *PartitionRangeDatum) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/partition_range_datum_kind.go b/internal/sql/ast/partition_range_datum_kind.go new file mode 100644 index 0000000..d254de1 --- /dev/null +++ b/internal/sql/ast/partition_range_datum_kind.go @@ -0,0 +1,7 @@ +package ast + +type PartitionRangeDatumKind uint + +func (n *PartitionRangeDatumKind) Pos() int { + return 0 +} diff --git a/internal/sql/ast/partition_spec.go b/internal/sql/ast/partition_spec.go new file mode 100644 index 0000000..1d0b174 --- /dev/null +++ b/internal/sql/ast/partition_spec.go @@ -0,0 +1,13 @@ +package ast + +type PartitionSpec struct { + Tag NodeTag[PartitionSpec] `json:"tag"` + + Strategy *string `json:"strategy,omitempty"` + PartParams *List `json:"part_params,omitempty"` + Location int `json:"location"` +} + +func (n *PartitionSpec) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/prepare_stmt.go b/internal/sql/ast/prepare_stmt.go new file mode 100644 index 0000000..a31633d --- /dev/null +++ b/internal/sql/ast/prepare_stmt.go @@ -0,0 +1,13 @@ +package ast + +type PrepareStmt struct { + Tag NodeTag[PrepareStmt] `json:"tag"` + + Name *string `json:"name,omitempty"` + Argtypes *List `json:"argtypes,omitempty"` + Query Node `json:"query,omitempty"` +} + +func (n *PrepareStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/print.go b/internal/sql/ast/print.go new file mode 100644 index 0000000..1ec48a0 --- /dev/null +++ b/internal/sql/ast/print.go @@ -0,0 +1,269 @@ +package ast + +import ( + "github.com/sqlc-dev/sqlc/internal/debug" + "github.com/sqlc-dev/sqlc/internal/sql/ast/printer" + "github.com/sqlc-dev/sqlc/internal/sql/format" +) + +type nodeFormatter interface { + Format(*TrackedBuffer, format.Dialect) +} + +// TrackedBuffer layers AST formatting over the document renderer in +// ast/printer: node dispatch, list joins, and comment emission. The +// renderer itself — tokens, groups, width fitting — lives in the printer +// package; TrackedBuffer stays here because every node's Format method +// names it, which an ast → printer → ast import cycle would forbid. +type TrackedBuffer struct { + *printer.Buffer + // ct, when set, carries the statement's interior comments attached to + // their anchor nodes; the buffer emits each comment when it reaches the + // comment's anchor. Positions were consulted once, in AttachComments — + // never here — so edited and synthetic trees print comments correctly. + ct *CommentTable + // anchors, when set, records every positioned node and emission point + // in print order instead of producing output; AttachComments uses this + // dry run to classify comments against the same order printing will + // use. + anchors *[]anchor +} + +// NewTrackedBuffer creates a new TrackedBuffer. +func NewTrackedBuffer() *TrackedBuffer { + return &TrackedBuffer{Buffer: &printer.Buffer{}} +} + +func (t *TrackedBuffer) astFormat(n Node, d format.Dialect) { + if t.anchors != nil && n != nil && n.Pos() > 0 { + *t.anchors = append(*t.anchors, anchor{node: n, pos: n.Pos()}) + } + if t.ct != nil && n != nil { + t.emitComments(t.ct.take(n)) + } + if ft, ok := n.(nodeFormatter); ok { + ft.Format(t, d) + } else { + debug.Dump(n) + } +} + +// emitComments prints attached comments at the boundary before their anchor +// node. A trailing comment continues the line before it (a line comment +// then forces the enclosing groups to break); an own-line or line comment +// goes on its own line; an inline block comment stays in the flow. +func (t *TrackedBuffer) emitComments(recs []commentRec) { + for _, rec := range recs { + switch { + case rec.trailing: + t.WriteString(" ") + t.WriteString(rec.c.Text) + if rec.c.Line() { + t.Breaker() + } + case rec.c.OwnLine || rec.c.Line(): + t.Hardline() + t.WriteString(rec.c.Text) + t.Hardline() + default: + t.WriteString(rec.c.Text) + t.WriteString(" ") + } + } +} + +// beforeClause is the emission point for comments that sit between the +// previous clause and the one about to be printed, so they land before the +// clause keyword. Call it before the clause's line break. During the +// AttachComments dry run it records itself as a boundary marker, which is +// how classification and emission are guaranteed to pick the same spot — +// and how the author's own line break before the clause is observed and +// kept. +func (t *TrackedBuffer) beforeClause(n Node, d format.Dialect) { + t.boundary(n) +} + +// boundary is a separator-adjacent emission point (before a clause, after a +// comma, before an AND/OR): comments classified to the upcoming node print +// here, before the separator's line break, and a line break the author +// wrote at this boundary forces the break to stay. On the dry run it +// records a marker instead, so classification and emission agree by +// construction. +func (t *TrackedBuffer) boundary(next Node) { + if next == nil { + return + } + if t.anchors != nil { + *t.anchors = append(*t.anchors, anchor{node: next, marker: true}) + return + } + if t.ct != nil { + t.emitComments(t.ct.take(next)) + if t.ct.breakAt(next) { + t.Breaker() + } + } +} + +// flushRemaining prints every comment not yet printed; the statement is +// over, so everything left trails it. +func (t *TrackedBuffer) flushRemaining() { + if t.ct == nil { + return + } + for _, rec := range t.ct.takeRemaining() { + if rec.trailing { + t.WriteString(" ") + t.WriteString(rec.c.Text) + if rec.c.Line() { + t.Breaker() + } + } else { + t.Hardline() + t.WriteString(rec.c.Text) + } + } +} + +func (t *TrackedBuffer) join(n *List, d format.Dialect, sep string) { + if n == nil { + return + } + first := true + for _, item := range n.Items { + if _, ok := item.(*TODO); ok { + continue + } + if !first { + t.WriteString(sep) + } + first = false + t.astFormat(item, d) + } +} + +// joinComma writes the list items separated by a comma and a break +// opportunity, so a list that fits stays on one line and a list that does +// not puts every item on its own line. An item's trailing comment prints +// after the comma, gofmt-style: `total, -- computed`. +func (t *TrackedBuffer) joinComma(n *List, d format.Dialect) { + if n == nil { + return + } + items := make([]Node, 0, len(n.Items)) + for _, item := range n.Items { + if _, ok := item.(*TODO); ok { + continue + } + items = append(items, item) + } + for i, item := range items { + if i > 0 { + t.WriteString(",") + t.boundary(item) + t.Line() + } + t.astFormat(item, d) + } +} + +// condition formats a clause-level boolean condition (WHERE, HAVING, ON). +// A top-level AND/OR chain is printed without the enclosing parentheses a +// nested BoolExpr gets — the clause keyword already delimits it — and each +// branch goes on its own line when the chain does not fit: +// +// WHERE name LIKE $1 +// AND id > $2 +func (t *TrackedBuffer) condition(n Node, d format.Dialect) { + be, ok := n.(*BoolExpr) + if !ok || (be.Boolop != BoolExprTypeAnd && be.Boolop != BoolExprTypeOr) { + t.astFormat(n, d) + return + } + op := "AND " + if be.Boolop == BoolExprTypeOr { + op = "OR " + } + t.Group() + t.Indent() + first := true + t.conditionArgs(be, d, op, &first) + t.EndIndent() + t.EndGroup() +} + +// conditionArgs writes the branches of an AND/OR chain, flattening nested +// chains of the same operator (some parsers produce `a AND b AND c` as a +// left-nested tree) so no redundant parentheses appear. +func (t *TrackedBuffer) conditionArgs(be *BoolExpr, d format.Dialect, op string, first *bool) { + if be.Args == nil { + return + } + for _, item := range be.Args.Items { + if _, ok := item.(*TODO); ok { + continue + } + if nested, ok := item.(*BoolExpr); ok && nested.Boolop == be.Boolop { + t.conditionArgs(nested, d, op, first) + continue + } + if !*first { + t.boundary(item) + t.Line() + t.WriteString(op) + } + *first = false + t.astFormat(item, d) + } +} + +// Format renders the node as SQL on a single line. +func Format(n Node, d format.Dialect) string { + return Pretty(n, d, -1) +} + +// Pretty renders the node as SQL, breaking lines so the output fits within +// width columns where the statement's structure allows it. A negative width +// renders everything on a single line. +func Pretty(n Node, d format.Dialect, width int) string { + return PrettyWithComments(n, d, width, nil) +} + +// PrettyWithComments renders the node as SQL like Pretty, emitting the +// comments a prior AttachComments call anchored to its nodes and keeping +// the line breaks the author wrote at the boundaries the printer models. +// Each comment prints at the boundary before its anchor, a trailing comment +// continues the line of the code it followed, and every comment in the +// table is printed — anything left when the statement ends trails it. +func PrettyWithComments(n Node, d format.Dialect, width int, ct *CommentTable) string { + tb := NewTrackedBuffer() + tb.ct = ct + if ft, ok := n.(nodeFormatter); ok { + ft.Format(tb, d) + } + return tb.Print(width) +} + +func set(n Node) bool { + if n == nil { + return false + } + _, ok := n.(*TODO) + return !ok +} + +func items(n *List) bool { + if n == nil { + return false + } + return len(n.Items) > 0 +} + +func todo(n *List) bool { + for _, item := range n.Items { + if _, ok := item.(*TODO); !ok { + return false + } + } + return true +} diff --git a/internal/sql/ast/printer/printer.go b/internal/sql/ast/printer/printer.go new file mode 100644 index 0000000..69c8bba --- /dev/null +++ b/internal/sql/ast/printer/printer.go @@ -0,0 +1,250 @@ +// Package printer implements the document renderer the SQL formatter +// prints through: a small Wadler-style engine, the model behind Prettier +// and ruff (via Biome's printer). Callers emit a stream of tokens — literal +// text, break opportunities, and markers that open and close groups and +// indented regions — and Print lays each group out on a single line when +// its flat width fits, breaking it otherwise. The package knows nothing +// about SQL or the AST; the ast package's TrackedBuffer embeds a Buffer and +// layers node formatting and comment emission on top. +package printer + +import ( + "strings" + "unicode/utf8" +) + +type tokenKind uint8 + +const ( + tokenText tokenKind = iota + // tokenLine renders as a single space when its group fits on one line + // and as a line break when the group is broken. + tokenLine + // tokenSoftline renders as nothing when its group fits on one line and + // as a line break when the group is broken. + tokenSoftline + // tokenHardline always renders a line break and forces every group + // containing it to break (it measures as infinitely wide). Emitted + // around comments, which pin the author's layout open. + tokenHardline + // tokenBreaker renders nothing but forces every group containing it to + // break. Emitted after a trailing line comment, whose text swallows the + // rest of the line, and at boundaries where the author broke the line. + tokenBreaker + tokenOpenGroup + tokenCloseGroup + tokenOpenIndent + tokenCloseIndent +) + +// breakWidth is the measured width of tokens that force a break: wider than +// any real line, so no group containing one ever fits. +const breakWidth = 1 << 24 + +// indentWidth is the number of spaces per indentation level in broken +// (multi-line) output. +const indentWidth = 2 + +type token struct { + kind tokenKind + text string +} + +// Buffer accumulates the document token stream. +type Buffer struct { + tokens []token +} + +func (t *Buffer) WriteString(s string) (int, error) { + if s == "" { + return 0, nil + } + t.tokens = append(t.tokens, token{kind: tokenText, text: s}) + return len(s), nil +} + +// Write implements io.Writer so callers can use fmt.Fprintf. +func (t *Buffer) Write(p []byte) (int, error) { + return t.WriteString(string(p)) +} + +func (t *Buffer) WriteRune(r rune) (int, error) { + return t.WriteString(string(r)) +} + +// String renders the buffer on a single line. +func (t *Buffer) String() string { + return t.Print(-1) +} + +// Line marks a break opportunity between two tokens: a space when the +// surrounding group fits on one line, a line break when it does not. +func (t *Buffer) Line() { + t.tokens = append(t.tokens, token{kind: tokenLine}) +} + +// Softline marks a break opportunity that disappears entirely when the +// surrounding group fits on one line. +func (t *Buffer) Softline() { + t.tokens = append(t.tokens, token{kind: tokenSoftline}) +} + +// Hardline always renders a line break and forces every enclosing group to +// break. +func (t *Buffer) Hardline() { + t.tokens = append(t.tokens, token{kind: tokenHardline}) +} + +// Breaker renders nothing but forces every enclosing group to break, so the +// next break opportunity becomes a real line break. +func (t *Buffer) Breaker() { + t.tokens = append(t.tokens, token{kind: tokenBreaker}) +} + +// Group opens a region the renderer tries to lay out on a single line, +// breaking it only when its flat form does not fit. Must be paired with +// EndGroup. +func (t *Buffer) Group() { + t.tokens = append(t.tokens, token{kind: tokenOpenGroup}) +} + +func (t *Buffer) EndGroup() { + t.tokens = append(t.tokens, token{kind: tokenCloseGroup}) +} + +// Indent opens a region printed one indentation level deeper when line +// breaks occur inside it. Must be paired with EndIndent. +func (t *Buffer) Indent() { + t.tokens = append(t.tokens, token{kind: tokenOpenIndent}) +} + +func (t *Buffer) EndIndent() { + t.tokens = append(t.tokens, token{kind: tokenCloseIndent}) +} + +// docNode is the tree form of the token stream: text and break tokens are +// leaves, groups and indented regions are interior nodes. +type docNode struct { + kind tokenKind + text string + kids []*docNode + width int // flat width in runes, filled in by measure +} + +// tree assembles the flat token stream into a document tree. Stray close +// markers are ignored and unclosed regions end at the end of the stream. +func (t *Buffer) tree() *docNode { + root := &docNode{kind: tokenOpenGroup} + stack := []*docNode{root} + for _, tok := range t.tokens { + top := stack[len(stack)-1] + switch tok.kind { + case tokenText, tokenLine, tokenSoftline, tokenHardline, tokenBreaker: + top.kids = append(top.kids, &docNode{kind: tok.kind, text: tok.text}) + case tokenOpenGroup, tokenOpenIndent: + n := &docNode{kind: tok.kind} + top.kids = append(top.kids, n) + stack = append(stack, n) + case tokenCloseGroup, tokenCloseIndent: + if len(stack) > 1 { + stack = stack[:len(stack)-1] + } + } + } + return root +} + +// measure computes the width of every node when rendered flat. Hardlines +// and breakers measure wider than any real line, so no group containing one +// ever fits — Prettier's breakParent, by arithmetic. +func measure(d *docNode) int { + switch d.kind { + case tokenText: + d.width = utf8.RuneCountInString(d.text) + case tokenLine: + d.width = 1 + case tokenSoftline: + d.width = 0 + case tokenHardline, tokenBreaker: + d.width = breakWidth + default: + for _, kid := range d.kids { + d.width += measure(kid) + if d.width > breakWidth { + d.width = breakWidth + } + } + } + return d.width +} + +// Print renders the token stream. A negative width renders everything on +// one line; otherwise each group is rendered flat only when it fits in the +// space remaining on its line — and a group holding a hardline or breaker +// never fits, whatever the width, so forced breaks survive even an +// unlimited line length. +func (t *Buffer) Print(width int) string { + root := t.tree() + measure(root) + + type frame struct { + d *docNode + indent int + flat bool + } + var sb strings.Builder + col := 0 + // atLineStart dedupes consecutive breaks: a break that fires when the + // output is already at the start of a fresh line writes nothing, so a + // comment's surrounding hardlines collapse against clause breaks + // instead of leaving blank lines. + atLineStart := true + newline := func(indent int) { + if atLineStart { + return + } + sb.WriteByte('\n') + for i := 0; i < indent; i++ { + sb.WriteByte(' ') + } + col = indent + atLineStart = true + } + stack := []frame{{d: root, flat: width < 0}} + for len(stack) > 0 { + f := stack[len(stack)-1] + stack = stack[:len(stack)-1] + switch f.d.kind { + case tokenText: + sb.WriteString(f.d.text) + col += f.d.width + atLineStart = false + case tokenLine: + if f.flat { + sb.WriteByte(' ') + col++ + atLineStart = false + } else { + newline(f.indent) + } + case tokenSoftline: + if !f.flat { + newline(f.indent) + } + case tokenHardline: + newline(f.indent) + case tokenBreaker: + // forces enclosing groups broken; renders nothing + case tokenOpenGroup: + flat := f.flat || (f.d.width < breakWidth && f.d.width <= width-col) + for i := len(f.d.kids) - 1; i >= 0; i-- { + stack = append(stack, frame{d: f.d.kids[i], indent: f.indent, flat: flat}) + } + case tokenOpenIndent: + for i := len(f.d.kids) - 1; i >= 0; i-- { + stack = append(stack, frame{d: f.d.kids[i], indent: f.indent + indentWidth, flat: f.flat}) + } + } + } + return sb.String() +} diff --git a/internal/sql/ast/query.go b/internal/sql/ast/query.go new file mode 100644 index 0000000..7ace8aa --- /dev/null +++ b/internal/sql/ast/query.go @@ -0,0 +1,46 @@ +package ast + +type Query struct { + Tag NodeTag[Query] `json:"tag"` + + CommandType CmdType `json:"command_type"` + QuerySource QuerySource `json:"query_source"` + QueryId uint32 `json:"query_id"` + CanSetTag bool `json:"can_set_tag"` + UtilityStmt Node `json:"utility_stmt,omitempty"` + ResultRelation int `json:"result_relation"` + HasAggs bool `json:"has_aggs"` + HasWindowFuncs bool `json:"has_window_funcs"` + HasTargetSrfs bool `json:"has_target_srfs"` + HasSubLinks bool `json:"has_sub_links"` + HasDistinctOn bool `json:"has_distinct_on"` + HasRecursive bool `json:"has_recursive"` + HasModifyingCte bool `json:"has_modifying_cte"` + HasForUpdate bool `json:"has_for_update"` + HasRowSecurity bool `json:"has_row_security"` + CteList *List `json:"cte_list,omitempty"` + Rtable *List `json:"rtable,omitempty"` + Jointree *FromExpr `json:"jointree,omitempty"` + TargetList *List `json:"target_list,omitempty"` + Override OverridingKind `json:"override"` + OnConflict *OnConflictExpr `json:"on_conflict,omitempty"` + ReturningList *List `json:"returning_list,omitempty"` + GroupClause *List `json:"group_clause,omitempty"` + GroupingSets *List `json:"grouping_sets,omitempty"` + HavingQual Node `json:"having_qual,omitempty"` + WindowClause *List `json:"window_clause,omitempty"` + DistinctClause *List `json:"distinct_clause,omitempty"` + SortClause *List `json:"sort_clause,omitempty"` + LimitOffset Node `json:"limit_offset,omitempty"` + LimitCount Node `json:"limit_count,omitempty"` + RowMarks *List `json:"row_marks,omitempty"` + SetOperations Node `json:"set_operations,omitempty"` + ConstraintDeps *List `json:"constraint_deps,omitempty"` + WithCheckOptions *List `json:"with_check_options,omitempty"` + StmtLocation int `json:"stmt_location"` + StmtLen int `json:"stmt_len"` +} + +func (n *Query) Pos() int { + return 0 +} diff --git a/internal/sql/ast/query_source.go b/internal/sql/ast/query_source.go new file mode 100644 index 0000000..43f6eaf --- /dev/null +++ b/internal/sql/ast/query_source.go @@ -0,0 +1,7 @@ +package ast + +type QuerySource uint + +func (n *QuerySource) Pos() int { + return 0 +} diff --git a/internal/sql/ast/range_function.go b/internal/sql/ast/range_function.go new file mode 100644 index 0000000..3d1b6d0 --- /dev/null +++ b/internal/sql/ast/range_function.go @@ -0,0 +1,35 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type RangeFunction struct { + Tag NodeTag[RangeFunction] `json:"tag"` + + Lateral bool `json:"lateral"` + Ordinality bool `json:"ordinality"` + IsRowsfrom bool `json:"is_rowsfrom"` + Functions *List `json:"functions,omitempty"` + Alias *Alias `json:"alias,omitempty"` + Coldeflist *List `json:"coldeflist,omitempty"` +} + +func (n *RangeFunction) Pos() int { + return 0 +} + +func (n *RangeFunction) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + if n.Lateral { + buf.WriteString("LATERAL ") + } + buf.astFormat(n.Functions, d) + if n.Ordinality { + buf.WriteString(" WITH ORDINALITY") + } + if n.Alias != nil { + buf.WriteString(" AS ") + buf.astFormat(n.Alias, d) + } +} diff --git a/internal/sql/ast/range_subselect.go b/internal/sql/ast/range_subselect.go new file mode 100644 index 0000000..8f2efe9 --- /dev/null +++ b/internal/sql/ast/range_subselect.go @@ -0,0 +1,31 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type RangeSubselect struct { + Tag NodeTag[RangeSubselect] `json:"tag"` + + Lateral bool `json:"lateral"` + Subquery Node `json:"subquery,omitempty"` + Alias *Alias `json:"alias,omitempty"` +} + +func (n *RangeSubselect) Pos() int { + return 0 +} + +func (n *RangeSubselect) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + if n.Lateral { + buf.WriteString("LATERAL ") + } + buf.WriteString("(") + buf.astFormat(n.Subquery, d) + buf.WriteString(")") + if n.Alias != nil { + buf.WriteString(" AS ") + buf.astFormat(n.Alias, d) + } +} diff --git a/internal/sql/ast/range_table_func.go b/internal/sql/ast/range_table_func.go new file mode 100644 index 0000000..7758339 --- /dev/null +++ b/internal/sql/ast/range_table_func.go @@ -0,0 +1,17 @@ +package ast + +type RangeTableFunc struct { + Tag NodeTag[RangeTableFunc] `json:"tag"` + + Lateral bool `json:"lateral"` + Docexpr Node `json:"docexpr,omitempty"` + Rowexpr Node `json:"rowexpr,omitempty"` + Namespaces *List `json:"namespaces,omitempty"` + Columns *List `json:"columns,omitempty"` + Alias *Alias `json:"alias,omitempty"` + Location int `json:"location"` +} + +func (n *RangeTableFunc) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/range_table_func_col.go b/internal/sql/ast/range_table_func_col.go new file mode 100644 index 0000000..d3fc620 --- /dev/null +++ b/internal/sql/ast/range_table_func_col.go @@ -0,0 +1,17 @@ +package ast + +type RangeTableFuncCol struct { + Tag NodeTag[RangeTableFuncCol] `json:"tag"` + + Colname *string `json:"colname,omitempty"` + TypeName *TypeName `json:"type_name,omitempty"` + ForOrdinality bool `json:"for_ordinality"` + IsNotNull bool `json:"is_not_null"` + Colexpr Node `json:"colexpr,omitempty"` + Coldefexpr Node `json:"coldefexpr,omitempty"` + Location int `json:"location"` +} + +func (n *RangeTableFuncCol) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/range_table_sample.go b/internal/sql/ast/range_table_sample.go new file mode 100644 index 0000000..cf4c41f --- /dev/null +++ b/internal/sql/ast/range_table_sample.go @@ -0,0 +1,15 @@ +package ast + +type RangeTableSample struct { + Tag NodeTag[RangeTableSample] `json:"tag"` + + Relation Node `json:"relation,omitempty"` + Method *List `json:"method,omitempty"` + Args *List `json:"args,omitempty"` + Repeatable Node `json:"repeatable,omitempty"` + Location int `json:"location"` +} + +func (n *RangeTableSample) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/range_tbl_entry.go b/internal/sql/ast/range_tbl_entry.go new file mode 100644 index 0000000..e3dbf2b --- /dev/null +++ b/internal/sql/ast/range_tbl_entry.go @@ -0,0 +1,41 @@ +package ast + +type RangeTblEntry struct { + Tag NodeTag[RangeTblEntry] `json:"tag"` + + Rtekind RTEKind `json:"rtekind"` + Relid Oid `json:"relid"` + Relkind byte `json:"relkind"` + Tablesample *TableSampleClause `json:"tablesample,omitempty"` + Subquery *Query `json:"subquery,omitempty"` + SecurityBarrier bool `json:"security_barrier"` + Jointype JoinType `json:"jointype"` + Joinaliasvars *List `json:"joinaliasvars,omitempty"` + Functions *List `json:"functions,omitempty"` + Funcordinality bool `json:"funcordinality"` + Tablefunc *TableFunc `json:"tablefunc,omitempty"` + ValuesLists *List `json:"values_lists,omitempty"` + Ctename *string `json:"ctename,omitempty"` + Ctelevelsup Index `json:"ctelevelsup"` + SelfReference bool `json:"self_reference"` + Coltypes *List `json:"coltypes,omitempty"` + Coltypmods *List `json:"coltypmods,omitempty"` + Colcollations *List `json:"colcollations,omitempty"` + Enrname *string `json:"enrname,omitempty"` + Enrtuples float64 `json:"enrtuples"` + Alias *Alias `json:"alias,omitempty"` + Eref *Alias `json:"eref,omitempty"` + Lateral bool `json:"lateral"` + Inh bool `json:"inh"` + InFromCl bool `json:"in_from_cl"` + RequiredPerms AclMode `json:"required_perms"` + CheckAsUser Oid `json:"check_as_user"` + SelectedCols []uint32 `json:"selected_cols,omitempty"` + InsertedCols []uint32 `json:"inserted_cols,omitempty"` + UpdatedCols []uint32 `json:"updated_cols,omitempty"` + SecurityQuals *List `json:"security_quals,omitempty"` +} + +func (n *RangeTblEntry) Pos() int { + return 0 +} diff --git a/internal/sql/ast/range_tbl_function.go b/internal/sql/ast/range_tbl_function.go new file mode 100644 index 0000000..c4f54e1 --- /dev/null +++ b/internal/sql/ast/range_tbl_function.go @@ -0,0 +1,17 @@ +package ast + +type RangeTblFunction struct { + Tag NodeTag[RangeTblFunction] `json:"tag"` + + Funcexpr Node `json:"funcexpr,omitempty"` + Funccolcount int `json:"funccolcount"` + Funccolnames *List `json:"funccolnames,omitempty"` + Funccoltypes *List `json:"funccoltypes,omitempty"` + Funccoltypmods *List `json:"funccoltypmods,omitempty"` + Funccolcollations *List `json:"funccolcollations,omitempty"` + Funcparams []uint32 `json:"funcparams,omitempty"` +} + +func (n *RangeTblFunction) Pos() int { + return 0 +} diff --git a/internal/sql/ast/range_tbl_ref.go b/internal/sql/ast/range_tbl_ref.go new file mode 100644 index 0000000..e3e1cc2 --- /dev/null +++ b/internal/sql/ast/range_tbl_ref.go @@ -0,0 +1,11 @@ +package ast + +type RangeTblRef struct { + Tag NodeTag[RangeTblRef] `json:"tag"` + + Rtindex int `json:"rtindex"` +} + +func (n *RangeTblRef) Pos() int { + return 0 +} diff --git a/internal/sql/ast/range_var.go b/internal/sql/ast/range_var.go new file mode 100644 index 0000000..ce70c97 --- /dev/null +++ b/internal/sql/ast/range_var.go @@ -0,0 +1,36 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type RangeVar struct { + Tag NodeTag[RangeVar] `json:"tag"` + + Catalogname *string `json:"catalogname,omitempty"` + Schemaname *string `json:"schemaname,omitempty"` + Relname *string `json:"relname,omitempty"` + Inh bool `json:"inh"` + Relpersistence byte `json:"relpersistence"` + Alias *Alias `json:"alias,omitempty"` + Location int `json:"location"` +} + +func (n *RangeVar) Pos() int { + return n.Location +} + +func (n *RangeVar) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + if n.Schemaname != nil && *n.Schemaname != "" { + buf.WriteString(d.QuoteIdent(*n.Schemaname)) + buf.WriteString(".") + } + if n.Relname != nil { + buf.WriteString(d.QuoteIdent(*n.Relname)) + } + if n.Alias != nil { + buf.WriteString(" AS ") + buf.astFormat(n.Alias, d) + } +} diff --git a/internal/sql/ast/raw_stmt.go b/internal/sql/ast/raw_stmt.go new file mode 100644 index 0000000..73e50d5 --- /dev/null +++ b/internal/sql/ast/raw_stmt.go @@ -0,0 +1,24 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type RawStmt struct { + Tag NodeTag[RawStmt] `json:"tag"` + + Stmt Node `json:"stmt,omitempty"` + StmtLocation int `json:"stmt_location"` + StmtLen int `json:"stmt_len"` +} + +func (n *RawStmt) Pos() int { + return n.StmtLocation +} + +func (n *RawStmt) Format(buf *TrackedBuffer, d format.Dialect) { + if n.Stmt != nil { + buf.astFormat(n.Stmt, d) + } + // The terminator goes first: a trailing line comment would swallow it. + buf.WriteString(";") + buf.flushRemaining() +} diff --git a/internal/sql/ast/reassign_owned_stmt.go b/internal/sql/ast/reassign_owned_stmt.go new file mode 100644 index 0000000..d062e78 --- /dev/null +++ b/internal/sql/ast/reassign_owned_stmt.go @@ -0,0 +1,12 @@ +package ast + +type ReassignOwnedStmt struct { + Tag NodeTag[ReassignOwnedStmt] `json:"tag"` + + Roles *List `json:"roles,omitempty"` + Newrole *RoleSpec `json:"newrole,omitempty"` +} + +func (n *ReassignOwnedStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/refresh_mat_view_stmt.go b/internal/sql/ast/refresh_mat_view_stmt.go new file mode 100644 index 0000000..d8c76e5 --- /dev/null +++ b/internal/sql/ast/refresh_mat_view_stmt.go @@ -0,0 +1,23 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type RefreshMatViewStmt struct { + Tag NodeTag[RefreshMatViewStmt] `json:"tag"` + + Concurrent bool `json:"concurrent"` + SkipData bool `json:"skip_data"` + Relation *RangeVar `json:"relation,omitempty"` +} + +func (n *RefreshMatViewStmt) Pos() int { + return 0 +} + +func (n *RefreshMatViewStmt) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteString("REFRESH MATERIALIZED VIEW ") + buf.astFormat(n.Relation, d) +} diff --git a/internal/sql/ast/reindex_object_type.go b/internal/sql/ast/reindex_object_type.go new file mode 100644 index 0000000..8e2bf83 --- /dev/null +++ b/internal/sql/ast/reindex_object_type.go @@ -0,0 +1,7 @@ +package ast + +type ReindexObjectType uint + +func (n *ReindexObjectType) Pos() int { + return 0 +} diff --git a/internal/sql/ast/reindex_stmt.go b/internal/sql/ast/reindex_stmt.go new file mode 100644 index 0000000..7261134 --- /dev/null +++ b/internal/sql/ast/reindex_stmt.go @@ -0,0 +1,14 @@ +package ast + +type ReindexStmt struct { + Tag NodeTag[ReindexStmt] `json:"tag"` + + Kind ReindexObjectType `json:"kind"` + Relation *RangeVar `json:"relation,omitempty"` + Name *string `json:"name,omitempty"` + Options int `json:"options"` +} + +func (n *ReindexStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/relabel_type.go b/internal/sql/ast/relabel_type.go new file mode 100644 index 0000000..efaf742 --- /dev/null +++ b/internal/sql/ast/relabel_type.go @@ -0,0 +1,17 @@ +package ast + +type RelabelType struct { + Tag NodeTag[RelabelType] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Arg Node `json:"arg,omitempty"` + Resulttype Oid `json:"resulttype"` + Resulttypmod int32 `json:"resulttypmod"` + Resultcollid Oid `json:"resultcollid"` + Relabelformat CoercionForm `json:"relabelformat"` + Location int `json:"location"` +} + +func (n *RelabelType) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/rename_column_stmt.go b/internal/sql/ast/rename_column_stmt.go new file mode 100644 index 0000000..e677ce4 --- /dev/null +++ b/internal/sql/ast/rename_column_stmt.go @@ -0,0 +1,14 @@ +package ast + +type RenameColumnStmt struct { + Tag NodeTag[RenameColumnStmt] `json:"tag"` + + Table *TableName `json:"table,omitempty"` + Col *ColumnRef `json:"col,omitempty"` + NewName *string `json:"new_name,omitempty"` + MissingOk bool `json:"missing_ok"` +} + +func (n *RenameColumnStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/rename_stmt.go b/internal/sql/ast/rename_stmt.go new file mode 100644 index 0000000..4786513 --- /dev/null +++ b/internal/sql/ast/rename_stmt.go @@ -0,0 +1,18 @@ +package ast + +type RenameStmt struct { + Tag NodeTag[RenameStmt] `json:"tag"` + + RenameType ObjectType `json:"rename_type"` + RelationType ObjectType `json:"relation_type"` + Relation *RangeVar `json:"relation,omitempty"` + Object Node `json:"object,omitempty"` + Subname *string `json:"subname,omitempty"` + Newname *string `json:"newname,omitempty"` + Behavior DropBehavior `json:"behavior"` + MissingOk bool `json:"missing_ok"` +} + +func (n *RenameStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/rename_table_stmt.go b/internal/sql/ast/rename_table_stmt.go new file mode 100644 index 0000000..a8473e0 --- /dev/null +++ b/internal/sql/ast/rename_table_stmt.go @@ -0,0 +1,13 @@ +package ast + +type RenameTableStmt struct { + Tag NodeTag[RenameTableStmt] `json:"tag"` + + Table *TableName `json:"table,omitempty"` + NewName *string `json:"new_name,omitempty"` + MissingOk bool `json:"missing_ok"` +} + +func (n *RenameTableStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/rename_type_stmt.go b/internal/sql/ast/rename_type_stmt.go new file mode 100644 index 0000000..fced204 --- /dev/null +++ b/internal/sql/ast/rename_type_stmt.go @@ -0,0 +1,12 @@ +package ast + +type RenameTypeStmt struct { + Tag NodeTag[RenameTypeStmt] `json:"tag"` + + Type *TypeName `json:"type,omitempty"` + NewName *string `json:"new_name,omitempty"` +} + +func (n *RenameTypeStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/replica_identity_stmt.go b/internal/sql/ast/replica_identity_stmt.go new file mode 100644 index 0000000..abe08e0 --- /dev/null +++ b/internal/sql/ast/replica_identity_stmt.go @@ -0,0 +1,12 @@ +package ast + +type ReplicaIdentityStmt struct { + Tag NodeTag[ReplicaIdentityStmt] `json:"tag"` + + IdentityType byte `json:"identity_type"` + Name *string `json:"name,omitempty"` +} + +func (n *ReplicaIdentityStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/res_target.go b/internal/sql/ast/res_target.go new file mode 100644 index 0000000..8a58b27 --- /dev/null +++ b/internal/sql/ast/res_target.go @@ -0,0 +1,37 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type ResTarget struct { + Tag NodeTag[ResTarget] `json:"tag"` + + Name *string `json:"name,omitempty"` + Indirection *List `json:"indirection,omitempty"` + Val Node `json:"val,omitempty"` + Location int `json:"location"` + // Relation qualifies Name in a multi-table UPDATE's SET list (MySQL: + // SET t.col = ...). Analysis matches on Name alone; printing needs the + // qualifier to keep the assignment on the table the author named. + Relation *string `json:"relation,omitempty"` +} + +func (n *ResTarget) Pos() int { + return n.Location +} + +func (n *ResTarget) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + if set(n.Val) { + buf.astFormat(n.Val, d) + if n.Name != nil { + buf.WriteString(" AS ") + buf.WriteString(d.QuoteIdent(*n.Name)) + } + } else { + if n.Name != nil { + buf.WriteString(d.QuoteIdent(*n.Name)) + } + } +} diff --git a/internal/sql/ast/returning.go b/internal/sql/ast/returning.go new file mode 100644 index 0000000..70de843 --- /dev/null +++ b/internal/sql/ast/returning.go @@ -0,0 +1,24 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +// formatReturningOptions writes the PostgreSQL 18 RETURNING WITH (...) option +// list that renames the OLD and NEW aliases available in a RETURNING clause. +func formatReturningOptions(buf *TrackedBuffer, d format.Dialect, oldAlias, newAlias string) { + if oldAlias == "" && newAlias == "" { + return + } + buf.WriteString("WITH (") + if oldAlias != "" { + buf.WriteString("OLD AS ") + buf.WriteString(d.QuoteIdent(oldAlias)) + } + if newAlias != "" { + if oldAlias != "" { + buf.WriteString(", ") + } + buf.WriteString("NEW AS ") + buf.WriteString(d.QuoteIdent(newAlias)) + } + buf.WriteString(") ") +} diff --git a/internal/sql/ast/role_spec.go b/internal/sql/ast/role_spec.go new file mode 100644 index 0000000..154ddf3 --- /dev/null +++ b/internal/sql/ast/role_spec.go @@ -0,0 +1,13 @@ +package ast + +type RoleSpec struct { + Tag NodeTag[RoleSpec] `json:"tag"` + + Roletype RoleSpecType `json:"roletype"` + Rolename *string `json:"rolename,omitempty"` + Location int `json:"location"` +} + +func (n *RoleSpec) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/role_spec_type.go b/internal/sql/ast/role_spec_type.go new file mode 100644 index 0000000..b7ed4cc --- /dev/null +++ b/internal/sql/ast/role_spec_type.go @@ -0,0 +1,7 @@ +package ast + +type RoleSpecType uint + +func (n *RoleSpecType) Pos() int { + return 0 +} diff --git a/internal/sql/ast/role_stmt_type.go b/internal/sql/ast/role_stmt_type.go new file mode 100644 index 0000000..19d57cd --- /dev/null +++ b/internal/sql/ast/role_stmt_type.go @@ -0,0 +1,7 @@ +package ast + +type RoleStmtType uint + +func (n *RoleStmtType) Pos() int { + return 0 +} diff --git a/internal/sql/ast/row_compare_expr.go b/internal/sql/ast/row_compare_expr.go new file mode 100644 index 0000000..bbab320 --- /dev/null +++ b/internal/sql/ast/row_compare_expr.go @@ -0,0 +1,17 @@ +package ast + +type RowCompareExpr struct { + Tag NodeTag[RowCompareExpr] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Rctype RowCompareType `json:"rctype"` + Opnos *List `json:"opnos,omitempty"` + Opfamilies *List `json:"opfamilies,omitempty"` + Inputcollids *List `json:"inputcollids,omitempty"` + Largs *List `json:"largs,omitempty"` + Rargs *List `json:"rargs,omitempty"` +} + +func (n *RowCompareExpr) Pos() int { + return 0 +} diff --git a/internal/sql/ast/row_compare_type.go b/internal/sql/ast/row_compare_type.go new file mode 100644 index 0000000..74c16ea --- /dev/null +++ b/internal/sql/ast/row_compare_type.go @@ -0,0 +1,7 @@ +package ast + +type RowCompareType uint + +func (n *RowCompareType) Pos() int { + return 0 +} diff --git a/internal/sql/ast/row_expr.go b/internal/sql/ast/row_expr.go new file mode 100644 index 0000000..d898086 --- /dev/null +++ b/internal/sql/ast/row_expr.go @@ -0,0 +1,33 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type RowExpr struct { + Tag NodeTag[RowExpr] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Args *List `json:"args,omitempty"` + RowTypeid Oid `json:"row_typeid"` + RowFormat CoercionForm `json:"row_format"` + Colnames *List `json:"colnames,omitempty"` + Location int `json:"location"` +} + +func (n *RowExpr) Pos() int { + return n.Location +} + +func (n *RowExpr) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + if items(n.Args) { + buf.WriteString("args") + buf.astFormat(n.Args, d) + } + buf.astFormat(n.Xpr, d) + if items(n.Colnames) { + buf.WriteString("cols") + buf.astFormat(n.Colnames, d) + } +} diff --git a/internal/sql/ast/row_mark_clause.go b/internal/sql/ast/row_mark_clause.go new file mode 100644 index 0000000..121174e --- /dev/null +++ b/internal/sql/ast/row_mark_clause.go @@ -0,0 +1,14 @@ +package ast + +type RowMarkClause struct { + Tag NodeTag[RowMarkClause] `json:"tag"` + + Rti Index `json:"rti"` + Strength LockClauseStrength `json:"strength"` + WaitPolicy LockWaitPolicy `json:"wait_policy"` + PushedDown bool `json:"pushed_down"` +} + +func (n *RowMarkClause) Pos() int { + return 0 +} diff --git a/internal/sql/ast/rte_kind.go b/internal/sql/ast/rte_kind.go new file mode 100644 index 0000000..037fe71 --- /dev/null +++ b/internal/sql/ast/rte_kind.go @@ -0,0 +1,7 @@ +package ast + +type RTEKind uint + +func (n *RTEKind) Pos() int { + return 0 +} diff --git a/internal/sql/ast/rule_stmt.go b/internal/sql/ast/rule_stmt.go new file mode 100644 index 0000000..7821866 --- /dev/null +++ b/internal/sql/ast/rule_stmt.go @@ -0,0 +1,17 @@ +package ast + +type RuleStmt struct { + Tag NodeTag[RuleStmt] `json:"tag"` + + Relation *RangeVar `json:"relation,omitempty"` + Rulename *string `json:"rulename,omitempty"` + WhereClause Node `json:"where_clause,omitempty"` + Event CmdType `json:"event"` + Instead bool `json:"instead"` + Actions *List `json:"actions,omitempty"` + Replace bool `json:"replace"` +} + +func (n *RuleStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/scalar_array_op_expr.go b/internal/sql/ast/scalar_array_op_expr.go new file mode 100644 index 0000000..a427fd0 --- /dev/null +++ b/internal/sql/ast/scalar_array_op_expr.go @@ -0,0 +1,37 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type ScalarArrayOpExpr struct { + Tag NodeTag[ScalarArrayOpExpr] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Opno Oid `json:"opno"` + UseOr bool `json:"use_or"` + Inputcollid Oid `json:"inputcollid"` + Args *List `json:"args,omitempty"` + Location int `json:"location"` +} + +func (n *ScalarArrayOpExpr) Pos() int { + return n.Location +} + +func (n *ScalarArrayOpExpr) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + // ScalarArrayOpExpr represents "scalar op ANY/ALL (array)" + // Args[0] is the left operand, Args[1] is the array + if n.Args != nil && len(n.Args.Items) >= 2 { + buf.astFormat(n.Args.Items[0], d) + buf.WriteString(" = ") // TODO: Use actual operator based on Opno + if n.UseOr { + buf.WriteString("ANY(") + } else { + buf.WriteString("ALL(") + } + buf.astFormat(n.Args.Items[1], d) + buf.WriteString(")") + } +} diff --git a/internal/sql/ast/scan_direction.go b/internal/sql/ast/scan_direction.go new file mode 100644 index 0000000..0e5c72d --- /dev/null +++ b/internal/sql/ast/scan_direction.go @@ -0,0 +1,7 @@ +package ast + +type ScanDirection uint + +func (n *ScanDirection) Pos() int { + return 0 +} diff --git a/internal/sql/ast/sec_label_stmt.go b/internal/sql/ast/sec_label_stmt.go new file mode 100644 index 0000000..3a00bee --- /dev/null +++ b/internal/sql/ast/sec_label_stmt.go @@ -0,0 +1,14 @@ +package ast + +type SecLabelStmt struct { + Tag NodeTag[SecLabelStmt] `json:"tag"` + + Objtype ObjectType `json:"objtype"` + Object Node `json:"object,omitempty"` + Provider *string `json:"provider,omitempty"` + Label *string `json:"label,omitempty"` +} + +func (n *SecLabelStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/select_stmt.go b/internal/sql/ast/select_stmt.go new file mode 100644 index 0000000..e4e9eaf --- /dev/null +++ b/internal/sql/ast/select_stmt.go @@ -0,0 +1,183 @@ +package ast + +import ( + "github.com/sqlc-dev/sqlc/internal/sql/format" +) + +type SelectStmt struct { + Tag NodeTag[SelectStmt] `json:"tag"` + + DistinctClause *List `json:"distinct_clause,omitempty"` + IntoClause *IntoClause `json:"into_clause,omitempty"` + TargetList *List `json:"target_list,omitempty"` + FromClause *List `json:"from_clause,omitempty"` + WhereClause Node `json:"where_clause,omitempty"` + GroupClause *List `json:"group_clause,omitempty"` + HavingClause Node `json:"having_clause,omitempty"` + WindowClause *List `json:"window_clause,omitempty"` + ValuesLists *List `json:"values_lists,omitempty"` + SortClause *List `json:"sort_clause,omitempty"` + LimitOffset Node `json:"limit_offset,omitempty"` + LimitCount Node `json:"limit_count,omitempty"` + LockingClause *List `json:"locking_clause,omitempty"` + WithClause *WithClause `json:"with_clause,omitempty"` + Op SetOperation `json:"op"` + All bool `json:"all"` + Larg *SelectStmt `json:"larg,omitempty"` + Rarg *SelectStmt `json:"rarg,omitempty"` + // TableHints is the text inside a MySQL optimizer-hint comment + // (SELECT /*+ MAX_EXECUTION_TIME(1000) */ ...). The compiler ignores + // hints; printing keeps them because they change how the server runs + // the query. + TableHints string `json:"table_hints,omitempty"` +} + +func (n *SelectStmt) Pos() int { + return 0 +} + +func (n *SelectStmt) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + + if items(n.ValuesLists) { + buf.WriteString("VALUES ") + // ValuesLists is a list of rows, where each row is a List of values + for i, row := range n.ValuesLists.Items { + if i > 0 { + buf.WriteString(", ") + } + buf.WriteString("(") + buf.Group() + buf.Indent() + buf.Softline() + if r, ok := row.(*List); ok { + buf.joinComma(r, d) + } else { + buf.astFormat(row, d) + } + buf.EndIndent() + buf.Softline() + buf.EndGroup() + buf.WriteString(")") + } + return + } + + buf.Group() + defer buf.EndGroup() + + if n.WithClause != nil { + buf.astFormat(n.WithClause, d) + // The boundary between the WITH clause and the statement's own + // first keyword; the group keeps a break inside the WITH clause + // from forcing the statement body apart clause by clause. + if n.Larg != nil { + buf.boundary(n.Larg) + } else { + buf.boundary(n.TargetList) + } + buf.Line() + buf.Group() + defer buf.EndGroup() + } + + if n.Larg != nil && n.Rarg != nil { + buf.astFormat(n.Larg, d) + // The seam between the compound halves: an author who broke the + // line around UNION / INTERSECT / EXCEPT keeps the operator on its + // own line, and a comment above it prints here. + buf.boundary(n.Rarg) + buf.Line() + switch n.Op { + case Union: + buf.WriteString("UNION") + case Except: + buf.WriteString("EXCEPT") + case Intersect: + buf.WriteString("INTERSECT") + } + if n.All { + buf.WriteString(" ALL") + } + buf.Line() + buf.astFormat(n.Rarg, d) + } else { + buf.WriteString("SELECT") + if n.TableHints != "" { + buf.WriteString(" /*+ ") + buf.WriteString(n.TableHints) + buf.WriteString(" */") + } + if items(n.DistinctClause) { + buf.WriteString(" DISTINCT") + if !todo(n.DistinctClause) { + buf.WriteString(" ON (") + buf.astFormat(n.DistinctClause, d) + buf.WriteString(")") + } + } + buf.Group() + buf.Indent() + buf.Line() + buf.joinComma(n.TargetList, d) + buf.EndIndent() + buf.EndGroup() + } + + if items(n.FromClause) { + buf.beforeClause(n.FromClause, d) + buf.Line() + buf.WriteString("FROM ") + buf.astFormat(n.FromClause, d) + } + + if set(n.WhereClause) { + buf.beforeClause(n.WhereClause, d) + buf.Line() + buf.WriteString("WHERE ") + buf.condition(n.WhereClause, d) + } + + if items(n.GroupClause) { + buf.beforeClause(n.GroupClause, d) + buf.Line() + buf.WriteString("GROUP BY ") + buf.astFormat(n.GroupClause, d) + } + + if set(n.HavingClause) { + buf.beforeClause(n.HavingClause, d) + buf.Line() + buf.WriteString("HAVING ") + buf.condition(n.HavingClause, d) + } + + if items(n.SortClause) { + buf.beforeClause(n.SortClause, d) + buf.Line() + buf.WriteString("ORDER BY ") + buf.astFormat(n.SortClause, d) + } + + if set(n.LimitCount) { + buf.beforeClause(n.LimitCount, d) + buf.Line() + buf.WriteString("LIMIT ") + buf.astFormat(n.LimitCount, d) + } + + if set(n.LimitOffset) { + buf.beforeClause(n.LimitOffset, d) + buf.Line() + buf.WriteString("OFFSET ") + buf.astFormat(n.LimitOffset, d) + } + + if items(n.LockingClause) { + buf.Line() + buf.astFormat(n.LockingClause, d) + } + +} diff --git a/internal/sql/ast/set_op_cmd.go b/internal/sql/ast/set_op_cmd.go new file mode 100644 index 0000000..f079e10 --- /dev/null +++ b/internal/sql/ast/set_op_cmd.go @@ -0,0 +1,7 @@ +package ast + +type SetOpCmd uint + +func (n *SetOpCmd) Pos() int { + return 0 +} diff --git a/internal/sql/ast/set_op_strategy.go b/internal/sql/ast/set_op_strategy.go new file mode 100644 index 0000000..bcb7c47 --- /dev/null +++ b/internal/sql/ast/set_op_strategy.go @@ -0,0 +1,7 @@ +package ast + +type SetOpStrategy uint + +func (n *SetOpStrategy) Pos() int { + return 0 +} diff --git a/internal/sql/ast/set_operation.go b/internal/sql/ast/set_operation.go new file mode 100644 index 0000000..b0db93c --- /dev/null +++ b/internal/sql/ast/set_operation.go @@ -0,0 +1,31 @@ +package ast + +import "strconv" + +const ( + None SetOperation = iota + Union + Intersect + Except +) + +type SetOperation uint + +func (n *SetOperation) Pos() int { + return 0 +} + +func (n SetOperation) String() string { + switch n { + case None: + return "None" + case Union: + return "Union" + case Intersect: + return "Intersect" + case Except: + return "Except" + default: + return "Unknown(" + strconv.FormatUint(uint64(n), 10) + ")" + } +} diff --git a/internal/sql/ast/set_operation_stmt.go b/internal/sql/ast/set_operation_stmt.go new file mode 100644 index 0000000..975460f --- /dev/null +++ b/internal/sql/ast/set_operation_stmt.go @@ -0,0 +1,18 @@ +package ast + +type SetOperationStmt struct { + Tag NodeTag[SetOperationStmt] `json:"tag"` + + Op SetOperation `json:"op"` + All bool `json:"all"` + Larg Node `json:"larg,omitempty"` + Rarg Node `json:"rarg,omitempty"` + ColTypes *List `json:"col_types,omitempty"` + ColTypmods *List `json:"col_typmods,omitempty"` + ColCollations *List `json:"col_collations,omitempty"` + GroupClauses *List `json:"group_clauses,omitempty"` +} + +func (n *SetOperationStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/set_to_default.go b/internal/sql/ast/set_to_default.go new file mode 100644 index 0000000..6ae1d06 --- /dev/null +++ b/internal/sql/ast/set_to_default.go @@ -0,0 +1,15 @@ +package ast + +type SetToDefault struct { + Tag NodeTag[SetToDefault] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + TypeId Oid `json:"type_id"` + TypeMod int32 `json:"type_mod"` + Collation Oid `json:"collation"` + Location int `json:"location"` +} + +func (n *SetToDefault) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/sort_by.go b/internal/sql/ast/sort_by.go new file mode 100644 index 0000000..f1e241c --- /dev/null +++ b/internal/sql/ast/sort_by.go @@ -0,0 +1,36 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type SortBy struct { + Tag NodeTag[SortBy] `json:"tag"` + + Node Node `json:"node,omitempty"` + SortbyDir SortByDir `json:"sortby_dir"` + SortbyNulls SortByNulls `json:"sortby_nulls"` + UseOp *List `json:"use_op,omitempty"` + Location int `json:"location"` +} + +func (n *SortBy) Pos() int { + return n.Location +} + +func (n *SortBy) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.astFormat(n.Node, d) + switch n.SortbyDir { + case SortByDirAsc: + buf.WriteString(" ASC") + case SortByDirDesc: + buf.WriteString(" DESC") + } + switch n.SortbyNulls { + case SortByNullsFirst: + buf.WriteString(" NULLS FIRST") + case SortByNullsLast: + buf.WriteString(" NULLS LAST") + } +} diff --git a/internal/sql/ast/sort_by_dir.go b/internal/sql/ast/sort_by_dir.go new file mode 100644 index 0000000..3ebd212 --- /dev/null +++ b/internal/sql/ast/sort_by_dir.go @@ -0,0 +1,15 @@ +package ast + +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 new file mode 100644 index 0000000..512b5a1 --- /dev/null +++ b/internal/sql/ast/sort_by_nulls.go @@ -0,0 +1,14 @@ +package ast + +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/internal/sql/ast/sort_group_clause.go b/internal/sql/ast/sort_group_clause.go new file mode 100644 index 0000000..e28cc89 --- /dev/null +++ b/internal/sql/ast/sort_group_clause.go @@ -0,0 +1,15 @@ +package ast + +type SortGroupClause struct { + Tag NodeTag[SortGroupClause] `json:"tag"` + + TleSortGroupRef Index `json:"tle_sort_group_ref"` + Eqop Oid `json:"eqop"` + Sortop Oid `json:"sortop"` + NullsFirst bool `json:"nulls_first"` + Hashable bool `json:"hashable"` +} + +func (n *SortGroupClause) Pos() int { + return 0 +} diff --git a/internal/sql/ast/sql_value_function.go b/internal/sql/ast/sql_value_function.go new file mode 100644 index 0000000..4c9fd2b --- /dev/null +++ b/internal/sql/ast/sql_value_function.go @@ -0,0 +1,41 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type SQLValueFunction struct { + Tag NodeTag[SQLValueFunction] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Op SQLValueFunctionOp `json:"op"` + Type Oid `json:"type"` + Typmod int32 `json:"typmod"` + Location int `json:"location"` +} + +func (n *SQLValueFunction) Pos() int { + return n.Location +} + +func (n *SQLValueFunction) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + switch n.Op { + case SVFOpCurrentDate: + buf.WriteString("CURRENT_DATE") + case SVFOpCurrentTime: + case SVFOpCurrentTimeN: + case SVFOpCurrentTimestamp: + case SVFOpCurrentTimestampN: + case SVFOpLocaltime: + case SVFOpLocaltimeN: + case SVFOpLocaltimestamp: + case SVFOpLocaltimestampN: + case SVFOpCurrentRole: + case SVFOpCurrentUser: + case SVFOpUser: + case SVFOpSessionUser: + case SVFOpCurrentCatalog: + case SVFOpCurrentSchema: + } +} diff --git a/internal/sql/ast/sql_value_function_op.go b/internal/sql/ast/sql_value_function_op.go new file mode 100644 index 0000000..5d99afa --- /dev/null +++ b/internal/sql/ast/sql_value_function_op.go @@ -0,0 +1,27 @@ +package ast + +type SQLValueFunctionOp uint + +const ( + // https://github.com/pganalyze/libpg_query/blob/15-latest/protobuf/pg_query.proto#L2984C1-L3003C1 + _ SQLValueFunctionOp = iota + SVFOpCurrentDate + SVFOpCurrentTime + SVFOpCurrentTimeN + SVFOpCurrentTimestamp + SVFOpCurrentTimestampN + SVFOpLocaltime + SVFOpLocaltimeN + SVFOpLocaltimestamp + SVFOpLocaltimestampN + SVFOpCurrentRole + SVFOpCurrentUser + SVFOpUser + SVFOpSessionUser + SVFOpCurrentCatalog + SVFOpCurrentSchema +) + +func (n *SQLValueFunctionOp) Pos() int { + return 0 +} diff --git a/internal/sql/ast/statement.go b/internal/sql/ast/statement.go new file mode 100644 index 0000000..dff54d6 --- /dev/null +++ b/internal/sql/ast/statement.go @@ -0,0 +1,11 @@ +package ast + +type Statement struct { + Tag NodeTag[Statement] `json:"tag"` + + Raw *RawStmt `json:"raw,omitempty"` +} + +func (n *Statement) Pos() int { + return 0 +} diff --git a/internal/sql/ast/string.go b/internal/sql/ast/string.go new file mode 100644 index 0000000..b2ebe3b --- /dev/null +++ b/internal/sql/ast/string.go @@ -0,0 +1,20 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type String struct { + Tag NodeTag[String] `json:"tag"` + + Str string `json:"str"` +} + +func (n *String) Pos() int { + return 0 +} + +func (n *String) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteString(n.Str) +} diff --git a/internal/sql/ast/sub_link.go b/internal/sql/ast/sub_link.go new file mode 100644 index 0000000..184f36c --- /dev/null +++ b/internal/sql/ast/sub_link.go @@ -0,0 +1,67 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type SubLinkType uint + +const ( + EXISTS_SUBLINK SubLinkType = iota + ALL_SUBLINK + ANY_SUBLINK + ROWCOMPARE_SUBLINK + EXPR_SUBLINK + MULTIEXPR_SUBLINK + ARRAY_SUBLINK + CTE_SUBLINK /* for SubPlans only */ +) + +type SubLink struct { + Tag NodeTag[SubLink] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + SubLinkType SubLinkType `json:"sub_link_type"` + SubLinkId int `json:"sub_link_id"` + Testexpr Node `json:"testexpr,omitempty"` + OperName *List `json:"oper_name,omitempty"` + Subselect Node `json:"subselect,omitempty"` + Location int `json:"location"` +} + +func (n *SubLink) Pos() int { + return n.Location +} + +func (n *SubLink) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + // Format the test expression if present (for IN subqueries etc.) + hasTestExpr := n.Testexpr != nil + if hasTestExpr { + buf.astFormat(n.Testexpr, d) + } + switch n.SubLinkType { + case EXISTS_SUBLINK: + buf.WriteString("EXISTS (") + case ANY_SUBLINK: + if hasTestExpr { + buf.WriteString(" IN (") + } else { + buf.WriteString("IN (") + } + default: + if hasTestExpr { + buf.WriteString(" (") + } else { + buf.WriteString("(") + } + } + buf.Group() + buf.Indent() + buf.Softline() + buf.astFormat(n.Subselect, d) + buf.EndIndent() + buf.Softline() + buf.EndGroup() + buf.WriteString(")") +} diff --git a/internal/sql/ast/sub_plan.go b/internal/sql/ast/sub_plan.go new file mode 100644 index 0000000..50908c7 --- /dev/null +++ b/internal/sql/ast/sub_plan.go @@ -0,0 +1,27 @@ +package ast + +type SubPlan struct { + Tag NodeTag[SubPlan] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + SubLinkType SubLinkType `json:"sub_link_type"` + Testexpr Node `json:"testexpr,omitempty"` + ParamIds *List `json:"param_ids,omitempty"` + PlanId int `json:"plan_id"` + PlanName *string `json:"plan_name,omitempty"` + FirstColType Oid `json:"first_col_type"` + FirstColTypmod int32 `json:"first_col_typmod"` + FirstColCollation Oid `json:"first_col_collation"` + UseHashTable bool `json:"use_hash_table"` + UnknownEqFalse bool `json:"unknown_eq_false"` + ParallelSafe bool `json:"parallel_safe"` + SetParam *List `json:"set_param,omitempty"` + ParParam *List `json:"par_param,omitempty"` + Args *List `json:"args,omitempty"` + StartupCost Cost `json:"startup_cost"` + PerCallCost Cost `json:"per_call_cost"` +} + +func (n *SubPlan) Pos() int { + return 0 +} diff --git a/internal/sql/ast/table_func.go b/internal/sql/ast/table_func.go new file mode 100644 index 0000000..d2a22e3 --- /dev/null +++ b/internal/sql/ast/table_func.go @@ -0,0 +1,23 @@ +package ast + +type TableFunc struct { + Tag NodeTag[TableFunc] `json:"tag"` + + NsUris *List `json:"ns_uris,omitempty"` + NsNames *List `json:"ns_names,omitempty"` + Docexpr Node `json:"docexpr,omitempty"` + Rowexpr Node `json:"rowexpr,omitempty"` + Colnames *List `json:"colnames,omitempty"` + Coltypes *List `json:"coltypes,omitempty"` + Coltypmods *List `json:"coltypmods,omitempty"` + Colcollations *List `json:"colcollations,omitempty"` + Colexprs *List `json:"colexprs,omitempty"` + Coldefexprs *List `json:"coldefexprs,omitempty"` + Notnulls []uint32 `json:"notnulls,omitempty"` + Ordinalitycol int `json:"ordinalitycol"` + Location int `json:"location"` +} + +func (n *TableFunc) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/table_like_clause.go b/internal/sql/ast/table_like_clause.go new file mode 100644 index 0000000..8a5af1d --- /dev/null +++ b/internal/sql/ast/table_like_clause.go @@ -0,0 +1,12 @@ +package ast + +type TableLikeClause struct { + Tag NodeTag[TableLikeClause] `json:"tag"` + + Relation *RangeVar `json:"relation,omitempty"` + Options uint32 `json:"options"` +} + +func (n *TableLikeClause) Pos() int { + return 0 +} diff --git a/internal/sql/ast/table_like_option.go b/internal/sql/ast/table_like_option.go new file mode 100644 index 0000000..56e1b9a --- /dev/null +++ b/internal/sql/ast/table_like_option.go @@ -0,0 +1,7 @@ +package ast + +type TableLikeOption uint + +func (n *TableLikeOption) Pos() int { + return 0 +} diff --git a/internal/sql/ast/table_name.go b/internal/sql/ast/table_name.go new file mode 100644 index 0000000..1dfe61f --- /dev/null +++ b/internal/sql/ast/table_name.go @@ -0,0 +1,28 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type TableName struct { + Tag NodeTag[TableName] `json:"tag"` + + Catalog string `json:"catalog"` + Schema string `json:"schema"` + Name string `json:"name"` +} + +func (n *TableName) Pos() int { + return 0 +} + +func (n *TableName) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + if n.Schema != "" { + buf.WriteString(n.Schema) + buf.WriteString(".") + } + if n.Name != "" { + buf.WriteString(n.Name) + } +} diff --git a/internal/sql/ast/table_sample_clause.go b/internal/sql/ast/table_sample_clause.go new file mode 100644 index 0000000..c8d0577 --- /dev/null +++ b/internal/sql/ast/table_sample_clause.go @@ -0,0 +1,13 @@ +package ast + +type TableSampleClause struct { + Tag NodeTag[TableSampleClause] `json:"tag"` + + Tsmhandler Oid `json:"tsmhandler"` + Args *List `json:"args,omitempty"` + Repeatable Node `json:"repeatable,omitempty"` +} + +func (n *TableSampleClause) Pos() int { + return 0 +} diff --git a/internal/sql/ast/target_entry.go b/internal/sql/ast/target_entry.go new file mode 100644 index 0000000..eeb5a33 --- /dev/null +++ b/internal/sql/ast/target_entry.go @@ -0,0 +1,18 @@ +package ast + +type TargetEntry struct { + Tag NodeTag[TargetEntry] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Expr Node `json:"expr,omitempty"` + Resno AttrNumber `json:"resno"` + Resname *string `json:"resname,omitempty"` + Ressortgroupref Index `json:"ressortgroupref"` + Resorigtbl Oid `json:"resorigtbl"` + Resorigcol AttrNumber `json:"resorigcol"` + Resjunk bool `json:"resjunk"` +} + +func (n *TargetEntry) Pos() int { + return 0 +} diff --git a/internal/sql/ast/todo.go b/internal/sql/ast/todo.go new file mode 100644 index 0000000..c9b9d05 --- /dev/null +++ b/internal/sql/ast/todo.go @@ -0,0 +1,9 @@ +package ast + +type TODO struct { + Tag NodeTag[TODO] `json:"tag"` +} + +func (n *TODO) Pos() int { + return 0 +} diff --git a/internal/sql/ast/transaction_stmt.go b/internal/sql/ast/transaction_stmt.go new file mode 100644 index 0000000..60dbe32 --- /dev/null +++ b/internal/sql/ast/transaction_stmt.go @@ -0,0 +1,13 @@ +package ast + +type TransactionStmt struct { + Tag NodeTag[TransactionStmt] `json:"tag"` + + Kind TransactionStmtKind `json:"kind"` + Options *List `json:"options,omitempty"` + Gid *string `json:"gid,omitempty"` +} + +func (n *TransactionStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/transaction_stmt_kind.go b/internal/sql/ast/transaction_stmt_kind.go new file mode 100644 index 0000000..fe38666 --- /dev/null +++ b/internal/sql/ast/transaction_stmt_kind.go @@ -0,0 +1,7 @@ +package ast + +type TransactionStmtKind uint + +func (n *TransactionStmtKind) Pos() int { + return 0 +} diff --git a/internal/sql/ast/trigger_transition.go b/internal/sql/ast/trigger_transition.go new file mode 100644 index 0000000..1d09a95 --- /dev/null +++ b/internal/sql/ast/trigger_transition.go @@ -0,0 +1,13 @@ +package ast + +type TriggerTransition struct { + Tag NodeTag[TriggerTransition] `json:"tag"` + + Name *string `json:"name,omitempty"` + IsNew bool `json:"is_new"` + IsTable bool `json:"is_table"` +} + +func (n *TriggerTransition) Pos() int { + return 0 +} diff --git a/internal/sql/ast/truncate_stmt.go b/internal/sql/ast/truncate_stmt.go new file mode 100644 index 0000000..9a7a21d --- /dev/null +++ b/internal/sql/ast/truncate_stmt.go @@ -0,0 +1,23 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type TruncateStmt struct { + Tag NodeTag[TruncateStmt] `json:"tag"` + + Relations *List `json:"relations,omitempty"` + RestartSeqs bool `json:"restart_seqs"` + Behavior DropBehavior `json:"behavior"` +} + +func (n *TruncateStmt) Pos() int { + return 0 +} + +func (n *TruncateStmt) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteString("TRUNCATE ") + buf.astFormat(n.Relations, d) +} diff --git a/internal/sql/ast/type_cast.go b/internal/sql/ast/type_cast.go new file mode 100644 index 0000000..56c8fbb --- /dev/null +++ b/internal/sql/ast/type_cast.go @@ -0,0 +1,29 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type TypeCast struct { + Tag NodeTag[TypeCast] `json:"tag"` + + Arg Node `json:"arg,omitempty"` + TypeName *TypeName `json:"type_name,omitempty"` + Location int `json:"location"` +} + +func (n *TypeCast) Pos() int { + return n.Location +} + +func (n *TypeCast) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + // Format the arg and type to strings first + argBuf := NewTrackedBuffer() + argBuf.astFormat(n.Arg, d) + + typeBuf := NewTrackedBuffer() + typeBuf.astFormat(n.TypeName, d) + + buf.WriteString(d.Cast(argBuf.String(), typeBuf.String())) +} diff --git a/internal/sql/ast/type_name.go b/internal/sql/ast/type_name.go new file mode 100644 index 0000000..ddf7dec --- /dev/null +++ b/internal/sql/ast/type_name.go @@ -0,0 +1,76 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type TypeName struct { + Tag NodeTag[TypeName] `json:"tag"` + + Catalog string `json:"catalog"` + Schema string `json:"schema"` + Name string `json:"name"` + // Spelling is the type as the author wrote it, when that differs from + // Name: SQLite folds the spaces out of multi-word type names ("VARYING + // CHARACTER" resolves as "VARYINGCHARACTER" in the catalog), so the + // formatter prints this back instead of the folded form. + Spelling string `json:"spelling"` + // Canonical is the type as a call expression the analysis core reads, + // when an engine spells it differently from what the formatter prints + // back: DuckDB's STRUCT(a INTEGER, b VARCHAR) as struct(a: integer, b: + // varchar), ClickHouse's Enum('a', 'b') as Enum8('a' = 1, 'b' = 2). + Canonical string `json:"canonical,omitempty"` + + // From pg.TypeName + Names *List `json:"names,omitempty"` + TypeOid Oid `json:"type_oid"` + Setof bool `json:"setof"` + PctType bool `json:"pct_type"` + Typmods *List `json:"typmods,omitempty"` + Typemod int32 `json:"typemod"` + ArrayBounds *List `json:"array_bounds,omitempty"` + Location int `json:"location"` +} + +func (n *TypeName) Pos() int { + return n.Location +} + +func (n *TypeName) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + if n.Spelling != "" { + buf.WriteString(n.Spelling) + goto addMods + } + if items(n.Names) { + // Check if this is a qualified type (e.g., pg_catalog.int4) + if len(n.Names.Items) == 2 { + first, _ := n.Names.Items[0].(*String) + second, _ := n.Names.Items[1].(*String) + if first != nil && second != nil { + buf.WriteString(d.TypeName(first.Str, second.Str)) + goto addMods + } + } + // For single name types, just output as-is + if len(n.Names.Items) == 1 { + if s, ok := n.Names.Items[0].(*String); ok { + buf.WriteString(d.TypeName("", s.Str)) + goto addMods + } + } + buf.join(n.Names, d, ".") + } else { + buf.WriteString(d.TypeName(n.Schema, n.Name)) + } +addMods: + // Add type modifiers (e.g., varchar(255)) + if items(n.Typmods) { + buf.WriteString("(") + buf.join(n.Typmods, d, ", ") + buf.WriteString(")") + } + if items(n.ArrayBounds) { + buf.WriteString("[]") + } +} diff --git a/internal/sql/ast/typedefs.go b/internal/sql/ast/typedefs.go new file mode 100644 index 0000000..924fad7 --- /dev/null +++ b/internal/sql/ast/typedefs.go @@ -0,0 +1,150 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type AclMode uint32 + +func (n *AclMode) Pos() int { + return 0 +} + +type DistinctExpr OpExpr + +func (n *DistinctExpr) Pos() int { + return 0 +} + +type NullIfExpr OpExpr + +func (n *NullIfExpr) Pos() int { + return 0 +} + +func (n *NullIfExpr) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteString("NULLIF(") + buf.join(n.Args, d, ", ") + buf.WriteString(")") +} + +type Selectivity float64 + +func (n *Selectivity) Pos() int { + return 0 +} + +type Cost float64 + +func (n *Cost) Pos() int { + return 0 +} + +type ParamListInfo ParamListInfoData + +func (n *ParamListInfo) Pos() int { + return 0 +} + +type AttrNumber int16 + +func (n *AttrNumber) Pos() int { + return 0 +} + +type Pointer byte + +func (n *Pointer) Pos() int { + return 0 +} + +type Index uint64 + +func (n *Index) Pos() int { + return 0 +} + +type Offset int64 + +func (n *Offset) Pos() int { + return 0 +} + +type regproc Oid + +func (n *regproc) Pos() int { + return 0 +} + +type RegProcedure regproc + +func (n *RegProcedure) Pos() int { + return 0 +} + +type TransactionId uint32 + +func (n *TransactionId) Pos() int { + return 0 +} + +type LocalTransactionId uint32 + +func (n *LocalTransactionId) Pos() int { + return 0 +} + +type SubTransactionId uint32 + +func (n *SubTransactionId) Pos() int { + return 0 +} + +type MultiXactId TransactionId + +func (n *MultiXactId) Pos() int { + return 0 +} + +type MultiXactOffset uint32 + +func (n *MultiXactOffset) Pos() int { + return 0 +} + +type CommandId uint32 + +func (n *CommandId) Pos() int { + return 0 +} + +type Datum uintptr + +func (n *Datum) Pos() int { + return 0 +} + +type DatumPtr Datum + +func (n *DatumPtr) Pos() int { + return 0 +} + +type Oid uint64 + +func (n *Oid) Pos() int { + return 0 +} + +type BlockNumber uint32 + +func (n *BlockNumber) Pos() int { + return 0 +} + +type BlockId BlockIdData + +func (n *BlockId) Pos() int { + return 0 +} diff --git a/internal/sql/ast/unlisten_stmt.go b/internal/sql/ast/unlisten_stmt.go new file mode 100644 index 0000000..8c57881 --- /dev/null +++ b/internal/sql/ast/unlisten_stmt.go @@ -0,0 +1,11 @@ +package ast + +type UnlistenStmt struct { + Tag NodeTag[UnlistenStmt] `json:"tag"` + + Conditionname *string `json:"conditionname,omitempty"` +} + +func (n *UnlistenStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/update_stmt.go b/internal/sql/ast/update_stmt.go new file mode 100644 index 0000000..3c92fb9 --- /dev/null +++ b/internal/sql/ast/update_stmt.go @@ -0,0 +1,164 @@ +package ast + +import ( + "strings" + + "github.com/sqlc-dev/sqlc/internal/sql/format" +) + +type UpdateStmt struct { + Tag NodeTag[UpdateStmt] `json:"tag"` + + Relations *List `json:"relations,omitempty"` + TargetList *List `json:"target_list,omitempty"` + WhereClause Node `json:"where_clause,omitempty"` + FromClause *List `json:"from_clause,omitempty"` + LimitCount Node `json:"limit_count,omitempty"` + ReturningList *List `json:"returning_list,omitempty"` + WithClause *WithClause `json:"with_clause,omitempty"` + // PostgreSQL 18 RETURNING WITH (OLD AS ..., NEW AS ...) aliases + ReturningOldAlias string `json:"returning_old_alias"` + ReturningNewAlias string `json:"returning_new_alias"` + // TableRefs is the statement's table-reference tree as the author wrote + // it (MySQL: UPDATE a JOIN b ON ...). Relations flattens that tree to + // bare tables for analysis; printing prefers TableRefs when it is set, + // so a join's ON condition survives formatting. + TableRefs *List `json:"table_refs,omitempty"` +} + +func (n *UpdateStmt) Pos() int { + return 0 +} + +func (n *UpdateStmt) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.Group() + defer buf.EndGroup() + + if n.WithClause != nil { + buf.astFormat(n.WithClause, d) + // The boundary between the WITH clause and the statement's own + // first keyword; the group keeps a break inside the WITH clause + // from forcing the statement body apart clause by clause. + buf.boundary(n.Relations) + buf.Line() + buf.Group() + defer buf.EndGroup() + } + + buf.WriteString("UPDATE ") + if items(n.TableRefs) { + buf.astFormat(n.TableRefs, d) + } else if items(n.Relations) { + buf.astFormat(n.Relations, d) + } + + if items(n.TargetList) { + buf.beforeClause(n.TargetList, d) + buf.Line() + buf.WriteString("SET ") + + multi := false + for _, item := range n.TargetList.Items { + switch nn := item.(type) { + case *ResTarget: + if _, ok := nn.Val.(*MultiAssignRef); ok { + multi = true + } + } + } + if multi { + names := []string{} + vals := &List{} + for _, item := range n.TargetList.Items { + res, ok := item.(*ResTarget) + if !ok { + continue + } + if res.Name != nil { + names = append(names, *res.Name) + } + multi, ok := res.Val.(*MultiAssignRef) + if !ok { + vals.Items = append(vals.Items, res.Val) + continue + } + row, ok := multi.Source.(*RowExpr) + if !ok { + vals.Items = append(vals.Items, res.Val) + continue + } + vals.Items = append(vals.Items, row.Args.Items[multi.Colno-1]) + } + + buf.WriteString("(") + buf.WriteString(strings.Join(names, ",")) + buf.WriteString(") = (") + buf.join(vals, d, ",") + buf.WriteString(")") + } else { + buf.Group() + buf.Indent() + for i, item := range n.TargetList.Items { + if i > 0 { + buf.WriteString(",") + buf.boundary(item) + buf.Line() + } + switch nn := item.(type) { + case *ResTarget: + if nn.Relation != nil { + buf.WriteString(d.QuoteIdent(*nn.Relation)) + buf.WriteString(".") + } + if nn.Name != nil { + buf.WriteString(d.QuoteIdent(*nn.Name)) + } + // Handle array subscript indirection (e.g., names[$1]) + if items(nn.Indirection) { + for _, ind := range nn.Indirection.Items { + buf.astFormat(ind, d) + } + } + buf.WriteString(" = ") + buf.astFormat(nn.Val, d) + default: + buf.astFormat(item, d) + } + } + buf.EndIndent() + buf.EndGroup() + } + } + + if items(n.FromClause) { + buf.beforeClause(n.FromClause, d) + buf.Line() + buf.WriteString("FROM ") + buf.astFormat(n.FromClause, d) + } + + if set(n.WhereClause) { + buf.beforeClause(n.WhereClause, d) + buf.Line() + buf.WriteString("WHERE ") + buf.condition(n.WhereClause, d) + } + + if set(n.LimitCount) { + buf.beforeClause(n.LimitCount, d) + buf.Line() + buf.WriteString("LIMIT ") + buf.astFormat(n.LimitCount, d) + } + + if items(n.ReturningList) { + buf.beforeClause(n.ReturningList, d) + buf.Line() + buf.WriteString("RETURNING ") + formatReturningOptions(buf, d, n.ReturningOldAlias, n.ReturningNewAlias) + buf.astFormat(n.ReturningList, d) + } +} diff --git a/internal/sql/ast/vacuum_option.go b/internal/sql/ast/vacuum_option.go new file mode 100644 index 0000000..b74691e --- /dev/null +++ b/internal/sql/ast/vacuum_option.go @@ -0,0 +1,7 @@ +package ast + +type VacuumOption uint + +func (n *VacuumOption) Pos() int { + return 0 +} diff --git a/internal/sql/ast/vacuum_stmt.go b/internal/sql/ast/vacuum_stmt.go new file mode 100644 index 0000000..c04ebc6 --- /dev/null +++ b/internal/sql/ast/vacuum_stmt.go @@ -0,0 +1,13 @@ +package ast + +type VacuumStmt struct { + Tag NodeTag[VacuumStmt] `json:"tag"` + + Options int `json:"options"` + Relation *RangeVar `json:"relation,omitempty"` + VaCols *List `json:"va_cols,omitempty"` +} + +func (n *VacuumStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/var.go b/internal/sql/ast/var.go new file mode 100644 index 0000000..97d707f --- /dev/null +++ b/internal/sql/ast/var.go @@ -0,0 +1,20 @@ +package ast + +type Var struct { + Tag NodeTag[Var] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Varno Index `json:"varno"` + Varattno AttrNumber `json:"varattno"` + Vartype Oid `json:"vartype"` + Vartypmod int32 `json:"vartypmod"` + Varcollid Oid `json:"varcollid"` + Varlevelsup Index `json:"varlevelsup"` + Varnoold Index `json:"varnoold"` + Varoattno AttrNumber `json:"varoattno"` + Location int `json:"location"` +} + +func (n *Var) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/variable_expr.go b/internal/sql/ast/variable_expr.go new file mode 100644 index 0000000..84026a1 --- /dev/null +++ b/internal/sql/ast/variable_expr.go @@ -0,0 +1,24 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +// VariableExpr represents a MySQL user variable (e.g., @user_id) +// This is distinct from sqlc's @param named parameter syntax. +type VariableExpr struct { + Tag NodeTag[VariableExpr] `json:"tag"` + + Name string `json:"name"` + Location int `json:"location"` +} + +func (n *VariableExpr) Pos() int { + return n.Location +} + +func (n *VariableExpr) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteString("@") + buf.WriteString(n.Name) +} diff --git a/internal/sql/ast/variable_set_kind.go b/internal/sql/ast/variable_set_kind.go new file mode 100644 index 0000000..0a89e63 --- /dev/null +++ b/internal/sql/ast/variable_set_kind.go @@ -0,0 +1,7 @@ +package ast + +type VariableSetKind uint + +func (n *VariableSetKind) Pos() int { + return 0 +} diff --git a/internal/sql/ast/variable_set_stmt.go b/internal/sql/ast/variable_set_stmt.go new file mode 100644 index 0000000..74cf712 --- /dev/null +++ b/internal/sql/ast/variable_set_stmt.go @@ -0,0 +1,14 @@ +package ast + +type VariableSetStmt struct { + Tag NodeTag[VariableSetStmt] `json:"tag"` + + Kind VariableSetKind `json:"kind"` + Name *string `json:"name,omitempty"` + Args *List `json:"args,omitempty"` + IsLocal bool `json:"is_local"` +} + +func (n *VariableSetStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/variable_show_stmt.go b/internal/sql/ast/variable_show_stmt.go new file mode 100644 index 0000000..e697115 --- /dev/null +++ b/internal/sql/ast/variable_show_stmt.go @@ -0,0 +1,11 @@ +package ast + +type VariableShowStmt struct { + Tag NodeTag[VariableShowStmt] `json:"tag"` + + Name *string `json:"name,omitempty"` +} + +func (n *VariableShowStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/view_check_option.go b/internal/sql/ast/view_check_option.go new file mode 100644 index 0000000..2f05ac7 --- /dev/null +++ b/internal/sql/ast/view_check_option.go @@ -0,0 +1,7 @@ +package ast + +type ViewCheckOption uint + +func (n *ViewCheckOption) Pos() int { + return 0 +} diff --git a/internal/sql/ast/view_stmt.go b/internal/sql/ast/view_stmt.go new file mode 100644 index 0000000..ec99b66 --- /dev/null +++ b/internal/sql/ast/view_stmt.go @@ -0,0 +1,16 @@ +package ast + +type ViewStmt struct { + Tag NodeTag[ViewStmt] `json:"tag"` + + View *RangeVar `json:"view,omitempty"` + Aliases *List `json:"aliases,omitempty"` + Query Node `json:"query,omitempty"` + Replace bool `json:"replace"` + Options *List `json:"options,omitempty"` + WithCheckOption ViewCheckOption `json:"with_check_option"` +} + +func (n *ViewStmt) Pos() int { + return 0 +} diff --git a/internal/sql/ast/wco_kind.go b/internal/sql/ast/wco_kind.go new file mode 100644 index 0000000..b51ca49 --- /dev/null +++ b/internal/sql/ast/wco_kind.go @@ -0,0 +1,7 @@ +package ast + +type WCOKind uint + +func (n *WCOKind) Pos() int { + return 0 +} diff --git a/internal/sql/ast/window_clause.go b/internal/sql/ast/window_clause.go new file mode 100644 index 0000000..6f5a826 --- /dev/null +++ b/internal/sql/ast/window_clause.go @@ -0,0 +1,19 @@ +package ast + +type WindowClause struct { + Tag NodeTag[WindowClause] `json:"tag"` + + Name *string `json:"name,omitempty"` + Refname *string `json:"refname,omitempty"` + PartitionClause *List `json:"partition_clause,omitempty"` + OrderClause *List `json:"order_clause,omitempty"` + FrameOptions int `json:"frame_options"` + StartOffset Node `json:"start_offset,omitempty"` + EndOffset Node `json:"end_offset,omitempty"` + Winref Index `json:"winref"` + CopiedOrder bool `json:"copied_order"` +} + +func (n *WindowClause) Pos() int { + return 0 +} diff --git a/internal/sql/ast/window_def.go b/internal/sql/ast/window_def.go new file mode 100644 index 0000000..7a04800 --- /dev/null +++ b/internal/sql/ast/window_def.go @@ -0,0 +1,116 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type WindowDef struct { + Tag NodeTag[WindowDef] `json:"tag"` + + Name *string `json:"name,omitempty"` + Refname *string `json:"refname,omitempty"` + PartitionClause *List `json:"partition_clause,omitempty"` + OrderClause *List `json:"order_clause,omitempty"` + FrameOptions int `json:"frame_options"` + StartOffset Node `json:"start_offset,omitempty"` + EndOffset Node `json:"end_offset,omitempty"` + Location int `json:"location"` +} + +func (n *WindowDef) Pos() int { + return n.Location +} + +// Frame option constants (from PostgreSQL's parsenodes.h) +const ( + FrameOptionNonDefault = 0x00001 + FrameOptionRange = 0x00002 + FrameOptionRows = 0x00004 + FrameOptionGroups = 0x00008 + FrameOptionBetween = 0x00010 + FrameOptionStartUnboundedPreceding = 0x00020 + FrameOptionEndUnboundedPreceding = 0x00040 + FrameOptionStartUnboundedFollowing = 0x00080 + FrameOptionEndUnboundedFollowing = 0x00100 + FrameOptionStartCurrentRow = 0x00200 + FrameOptionEndCurrentRow = 0x00400 + FrameOptionStartOffset = 0x00800 + FrameOptionEndOffset = 0x01000 + FrameOptionExcludeCurrentRow = 0x02000 + FrameOptionExcludeGroup = 0x04000 + FrameOptionExcludeTies = 0x08000 +) + +func (n *WindowDef) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + + // Named window reference + if n.Refname != nil && *n.Refname != "" { + buf.WriteString(*n.Refname) + return + } + + buf.WriteString("(") + needSpace := false + + if items(n.PartitionClause) { + buf.WriteString("PARTITION BY ") + buf.join(n.PartitionClause, d, ", ") + needSpace = true + } + + if items(n.OrderClause) { + if needSpace { + buf.WriteString(" ") + } + buf.WriteString("ORDER BY ") + buf.join(n.OrderClause, d, ", ") + needSpace = true + } + + // Frame clause + if n.FrameOptions&FrameOptionNonDefault != 0 { + if needSpace { + buf.WriteString(" ") + } + + // Frame type + if n.FrameOptions&FrameOptionRows != 0 { + buf.WriteString("ROWS ") + } else if n.FrameOptions&FrameOptionRange != 0 { + buf.WriteString("RANGE ") + } else if n.FrameOptions&FrameOptionGroups != 0 { + buf.WriteString("GROUPS ") + } + + if n.FrameOptions&FrameOptionBetween != 0 { + buf.WriteString("BETWEEN ") + } + + // Start bound + if n.FrameOptions&FrameOptionStartUnboundedPreceding != 0 { + buf.WriteString("UNBOUNDED PRECEDING") + } else if n.FrameOptions&FrameOptionStartCurrentRow != 0 { + buf.WriteString("CURRENT ROW") + } else if n.FrameOptions&FrameOptionStartOffset != 0 { + buf.astFormat(n.StartOffset, d) + buf.WriteString(" PRECEDING") + } + + if n.FrameOptions&FrameOptionBetween != 0 { + buf.WriteString(" AND ") + + // End bound + if n.FrameOptions&FrameOptionEndUnboundedFollowing != 0 { + buf.WriteString("UNBOUNDED FOLLOWING") + } else if n.FrameOptions&FrameOptionEndCurrentRow != 0 { + buf.WriteString("CURRENT ROW") + } else if n.FrameOptions&FrameOptionEndOffset != 0 { + buf.astFormat(n.EndOffset, d) + buf.WriteString(" FOLLOWING") + } + } + } + + buf.WriteString(")") +} diff --git a/internal/sql/ast/window_func.go b/internal/sql/ast/window_func.go new file mode 100644 index 0000000..4202b48 --- /dev/null +++ b/internal/sql/ast/window_func.go @@ -0,0 +1,21 @@ +package ast + +type WindowFunc struct { + Tag NodeTag[WindowFunc] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Winfnoid Oid `json:"winfnoid"` + Wintype Oid `json:"wintype"` + Wincollid Oid `json:"wincollid"` + Inputcollid Oid `json:"inputcollid"` + Args *List `json:"args,omitempty"` + Aggfilter Node `json:"aggfilter,omitempty"` + Winref Index `json:"winref"` + Winstar bool `json:"winstar"` + Winagg bool `json:"winagg"` + Location int `json:"location"` +} + +func (n *WindowFunc) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/with_check_option.go b/internal/sql/ast/with_check_option.go new file mode 100644 index 0000000..416c92d --- /dev/null +++ b/internal/sql/ast/with_check_option.go @@ -0,0 +1,15 @@ +package ast + +type WithCheckOption struct { + Tag NodeTag[WithCheckOption] `json:"tag"` + + Kind WCOKind `json:"kind"` + Relname *string `json:"relname,omitempty"` + Polname *string `json:"polname,omitempty"` + Qual Node `json:"qual,omitempty"` + Cascaded bool `json:"cascaded"` +} + +func (n *WithCheckOption) Pos() int { + return 0 +} diff --git a/internal/sql/ast/with_clause.go b/internal/sql/ast/with_clause.go new file mode 100644 index 0000000..0124661 --- /dev/null +++ b/internal/sql/ast/with_clause.go @@ -0,0 +1,26 @@ +package ast + +import "github.com/sqlc-dev/sqlc/internal/sql/format" + +type WithClause struct { + Tag NodeTag[WithClause] `json:"tag"` + + Ctes *List `json:"ctes,omitempty"` + Recursive bool `json:"recursive"` + Location int `json:"location"` +} + +func (n *WithClause) Pos() int { + return n.Location +} + +func (n *WithClause) Format(buf *TrackedBuffer, d format.Dialect) { + if n == nil { + return + } + buf.WriteString("WITH ") + if n.Recursive { + buf.WriteString("RECURSIVE ") + } + buf.joinComma(n.Ctes, d) +} diff --git a/internal/sql/ast/xml_expr.go b/internal/sql/ast/xml_expr.go new file mode 100644 index 0000000..4249711 --- /dev/null +++ b/internal/sql/ast/xml_expr.go @@ -0,0 +1,20 @@ +package ast + +type XmlExpr struct { + Tag NodeTag[XmlExpr] `json:"tag"` + + Xpr Node `json:"xpr,omitempty"` + Op XmlExprOp `json:"op"` + Name *string `json:"name,omitempty"` + NamedArgs *List `json:"named_args,omitempty"` + ArgNames *List `json:"arg_names,omitempty"` + Args *List `json:"args,omitempty"` + Xmloption XmlOptionType `json:"xmloption"` + Type Oid `json:"type"` + Typmod int32 `json:"typmod"` + Location int `json:"location"` +} + +func (n *XmlExpr) Pos() int { + return n.Location +} diff --git a/internal/sql/ast/xml_expr_op.go b/internal/sql/ast/xml_expr_op.go new file mode 100644 index 0000000..e7faff6 --- /dev/null +++ b/internal/sql/ast/xml_expr_op.go @@ -0,0 +1,7 @@ +package ast + +type XmlExprOp uint + +func (n *XmlExprOp) Pos() int { + return 0 +} diff --git a/internal/sql/ast/xml_option_type.go b/internal/sql/ast/xml_option_type.go new file mode 100644 index 0000000..77d9b98 --- /dev/null +++ b/internal/sql/ast/xml_option_type.go @@ -0,0 +1,7 @@ +package ast + +type XmlOptionType uint + +func (n *XmlOptionType) Pos() int { + return 0 +} diff --git a/internal/sql/ast/xml_serialize.go b/internal/sql/ast/xml_serialize.go new file mode 100644 index 0000000..e514db5 --- /dev/null +++ b/internal/sql/ast/xml_serialize.go @@ -0,0 +1,14 @@ +package ast + +type XmlSerialize struct { + Tag NodeTag[XmlSerialize] `json:"tag"` + + Xmloption XmlOptionType `json:"xmloption"` + Expr Node `json:"expr,omitempty"` + TypeName *TypeName `json:"type_name,omitempty"` + Location int `json:"location"` +} + +func (n *XmlSerialize) Pos() int { + return n.Location +} diff --git a/internal/sql/astutils/CLAUDE.md b/internal/sql/astutils/CLAUDE.md new file mode 100644 index 0000000..7575ea9 --- /dev/null +++ b/internal/sql/astutils/CLAUDE.md @@ -0,0 +1,122 @@ +# AST Utilities Package - Claude Code Guide + +This package provides utilities for traversing and transforming AST nodes. + +## Key Functions + +### Walk +`Walk(f Visitor, node ast.Node)` traverses the AST depth-first, calling `f.Visit()` on each node. + +```go +type Visitor interface { + Visit(node ast.Node) Visitor +} +``` + +**Important**: When adding new AST node types, you MUST add a case to the switch statement in `walk.go`, otherwise you'll get a panic: +``` +panic: walk: unexpected node type *ast.YourNewType +``` + +### Apply (Rewrite) +`Apply(root ast.Node, pre, post ApplyFunc) ast.Node` traverses and optionally transforms the AST. + +```go +type ApplyFunc func(*Cursor) bool +``` + +The `Cursor` provides: +- `Node()` - current node +- `Parent()` - parent node +- `Name()` - field name in parent +- `Index()` - index if in a list +- `Replace(node)` - replace current node + +**Important**: When adding new AST node types, you MUST add a case to the switch statement in `rewrite.go`, otherwise you'll get a panic: +``` +panic: Apply: unexpected node type *ast.YourNewType +``` + +### Search +`Search(root ast.Node, fn func(ast.Node) bool) *ast.List` finds all nodes matching a predicate. + +### Join +`Join(list *ast.List, sep string) string` joins string nodes with a separator. + +## Adding Support for New AST Nodes + +When you create a new AST node type, you must update BOTH `walk.go` and `rewrite.go`: + +### In walk.go +Add a case that walks all child nodes: +```go +case *ast.YourNewType: + if n.ChildField != nil { + Walk(f, n.ChildField) + } + if n.ChildList != nil { + Walk(f, n.ChildList) + } +``` + +For leaf nodes with no children: +```go +case *ast.YourNewType: + // Leaf node - no children to traverse +``` + +### In rewrite.go +Add a case that applies to all child nodes: +```go +case *ast.YourNewType: + a.apply(n, "ChildField", nil, n.ChildField) + a.apply(n, "ChildList", nil, n.ChildList) +``` + +For leaf nodes: +```go +case *ast.YourNewType: + // Leaf node - no children to traverse +``` + +## Common Patterns + +### Finding All Tables in a Statement +```go +var tv tableVisitor +astutils.Walk(&tv, stmt.FromClause) +// tv.list now contains all RangeVar nodes +``` + +### Rewriting Nodes In Place +Apply replaces a node with a new one as the tree is walked: +```go +astutils.Apply(root, func(cr *astutils.Cursor) bool { + if _, ok := cr.Node().(*ast.SomeType); ok { + cr.Replace(&ast.OtherType{}) + } + return true +}, nil) +``` + +Note that sqlc syntax (`sqlc.arg()`, `@name`) is *not* handled here. It is +rewritten to native SQL by `internal/sql/preprocess` before the engine parses a +query, so a node type missing from walk.go/rewrite.go can no longer silently +drop a parameter. + +## Node Types That Must Be Handled + +All node types in `internal/sql/ast/` must have cases in both walk.go and rewrite.go. Key MySQL-specific nodes: +- `IntervalExpr` - INTERVAL expressions +- `OnDuplicateKeyUpdate` - MySQL ON DUPLICATE KEY UPDATE +- `ParenExpr` - Parenthesized expressions +- `VariableExpr` - MySQL user variables (@var) + +## Debugging Tips + +If you see a panic like: +``` +panic: walk: unexpected node type *ast.SomeType +``` + +Check that `SomeType` has a case in both `walk.go` and `rewrite.go`. diff --git a/internal/sql/astutils/join.go b/internal/sql/astutils/join.go new file mode 100644 index 0000000..5535d72 --- /dev/null +++ b/internal/sql/astutils/join.go @@ -0,0 +1,21 @@ +package astutils + +import ( + "strings" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +func Join(list *ast.List, sep string) string { + if list == nil { + return "" + } + + var items []string + for _, item := range list.Items { + if n, ok := item.(*ast.String); ok { + items = append(items, n.Str) + } + } + return strings.Join(items, sep) +} diff --git a/internal/sql/astutils/rewrite.go b/internal/sql/astutils/rewrite.go new file mode 100644 index 0000000..25b274a --- /dev/null +++ b/internal/sql/astutils/rewrite.go @@ -0,0 +1,1271 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package astutils + +import ( + "fmt" + "reflect" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +// An ApplyFunc is invoked by Apply for each node n, even if n is nil, +// before and/or after the node's children, using a Cursor describing +// the current node and providing operations on it. +// +// The return value of ApplyFunc controls the syntax tree traversal. +// See Apply for details. +type ApplyFunc func(*Cursor) bool + +// Apply traverses a syntax tree recursively, starting with root, +// and calling pre and post for each node as described below. +// Apply returns the syntax tree, possibly modified. +// +// If pre is not nil, it is called for each node before the node's +// children are traversed (pre-order). If pre returns false, no +// children are traversed, and post is not called for that node. +// +// If post is not nil, and a prior call of pre didn't return false, +// post is called for each node after its children are traversed +// (post-order). If post returns false, traversal is terminated and +// Apply returns immediately. +// +// Only fields that refer to AST nodes are considered children; +// i.e., token.Pos, Scopes, Objects, and fields of basic types +// (strings, etc.) are ignored. +// +// Children are traversed in the order in which they appear in the +// respective node's struct definition. A package's files are +// traversed in the filenames' alphabetical order. +func Apply(root ast.Node, pre, post ApplyFunc) (result ast.Node) { + parent := &struct{ ast.Node }{root} + defer func() { + if r := recover(); r != nil && r != abort { + panic(r) + } + result = parent.Node + }() + a := &application{pre: pre, post: post} + a.apply(parent, "Node", nil, root) + return +} + +var abort = new(int) // singleton, to signal termination of Apply + +// A Cursor describes a node encountered during Apply. +// Information about the node and its parent is available +// from the Node, Parent, Name, and Index methods. +// +// If p is a variable of type and value of the current parent node +// c.Parent(), and f is the field identifier with name c.Name(), +// the following invariants hold: +// +// p.f == c.Node() if c.Index() < 0 +// p.f[c.Index()] == c.Node() if c.Index() >= 0 +// +// The methods Replace, Delete, InsertBefore, and InsertAfter +// can be used to change the AST without disrupting Apply. +type Cursor struct { + parent ast.Node + name string + iter *iterator // valid if non-nil + node ast.Node +} + +// Node returns the current Node. +func (c *Cursor) Node() ast.Node { return c.node } + +// Parent returns the parent of the current Node. +func (c *Cursor) Parent() ast.Node { return c.parent } + +// Name returns the name of the parent Node field that contains the current Node. +// If the parent is a *ast.Package and the current Node is a *ast.File, Name returns +// the filename for the current Node. +func (c *Cursor) Name() string { return c.name } + +// Index reports the index >= 0 of the current Node in the slice of Nodes that +// contains it, or a value < 0 if the current Node is not part of a slice. +// The index of the current node changes if InsertBefore is called while +// processing the current node. +func (c *Cursor) Index() int { + if c.iter != nil { + return c.iter.index + } + return -1 +} + +// field returns the current node's parent field value. +func (c *Cursor) field() reflect.Value { + return reflect.Indirect(reflect.ValueOf(c.parent)).FieldByName(c.name) +} + +// Replace replaces the current Node with n. +// The replacement node is not walked by Apply. +func (c *Cursor) Replace(n ast.Node) { + v := c.field() + if i := c.Index(); i >= 0 { + v = v.Index(i) + } + v.Set(reflect.ValueOf(n)) +} + +// D// application carries all the shared data so we can pass it around cheaply. +type application struct { + pre, post ApplyFunc + cursor Cursor + iter iterator +} + +func (a *application) apply(parent ast.Node, name string, iter *iterator, n ast.Node) { + // convert typed nil into untyped nil + if v := reflect.ValueOf(n); v.Kind() == reflect.Pointer && v.IsNil() { + n = nil + } + + // avoid heap-allocating a new cursor for each apply call; reuse a.cursor instead + saved := a.cursor + a.cursor.parent = parent + a.cursor.name = name + a.cursor.iter = iter + a.cursor.node = n + + if a.pre != nil && !a.pre(&a.cursor) { + a.cursor = saved + return + } + + // walk children + // (the order of the cases matches the order of the corresponding node types in go/ast) + switch n := n.(type) { + case nil: + // nothing to do + + case *ast.AlterTableSetSchemaStmt: + a.apply(n, "Table", nil, n.Table) + + case *ast.AlterTypeAddValueStmt: + a.apply(n, "Type", nil, n.Type) + + case *ast.AlterTypeRenameValueStmt: + a.apply(n, "Type", nil, n.Type) + + case *ast.CommentOnColumnStmt: + a.apply(n, "Table", nil, n.Table) + a.apply(n, "Col", nil, n.Col) + + case *ast.CommentOnSchemaStmt: + a.apply(n, "Schema", nil, n.Schema) + + case *ast.CommentOnTableStmt: + a.apply(n, "Table", nil, n.Table) + + case *ast.CommentOnTypeStmt: + a.apply(n, "Type", nil, n.Type) + + case *ast.CommentOnViewStmt: + a.apply(n, "View", nil, n.View) + + case *ast.CreateTableStmt: + a.apply(n, "Name", nil, n.Name) + + case *ast.DropFunctionStmt: + // pass + + case *ast.DropSchemaStmt: + // pass + + case *ast.DropTableStmt: + // pass + + case *ast.DropTypeStmt: + // pass + + case *ast.FuncName: + // pass + + case *ast.FuncParam: + a.apply(n, "Type", nil, n.Type) + a.apply(n, "DefExpr", nil, n.DefExpr) + + case *ast.FuncSpec: + a.apply(n, "Name", nil, n.Name) + + case *ast.In: + a.applyList(n, "List") + a.apply(n, "Sel", nil, n.Sel) + + case *ast.List: + // Since item is a slice + a.applyList(n, "Items") + + case *ast.RawStmt: + a.apply(n, "Stmt", nil, n.Stmt) + + case *ast.RenameColumnStmt: + a.apply(n, "Table", nil, n.Table) + a.apply(n, "Col", nil, n.Col) + + case *ast.RenameTableStmt: + a.apply(n, "Table", nil, n.Table) + + case *ast.RenameTypeStmt: + a.apply(n, "Type", nil, n.Type) + + case *ast.Statement: + a.apply(n, "Raw", nil, n.Raw) + + case *ast.String: + // pass + + case *ast.TODO: + // pass + + case *ast.TableName: + // pass + + case *ast.A_ArrayExpr: + a.apply(n, "Elements", nil, n.Elements) + + case *ast.A_Const: + a.apply(n, "Val", nil, n.Val) + + case *ast.A_Expr: + a.apply(n, "Name", nil, n.Name) + a.apply(n, "Lexpr", nil, n.Lexpr) + a.apply(n, "Rexpr", nil, n.Rexpr) + + case *ast.A_Indices: + a.apply(n, "Lidx", nil, n.Lidx) + a.apply(n, "Uidx", nil, n.Uidx) + + case *ast.A_Indirection: + a.apply(n, "Arg", nil, n.Arg) + a.apply(n, "Indirection", nil, n.Indirection) + + case *ast.A_Star: + // pass + + case *ast.AccessPriv: + a.apply(n, "Cols", nil, n.Cols) + + case *ast.Aggref: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Aggargtypes", nil, n.Aggargtypes) + a.apply(n, "Aggdirectargs", nil, n.Aggdirectargs) + a.apply(n, "Args", nil, n.Args) + a.apply(n, "Aggorder", nil, n.Aggorder) + a.apply(n, "Aggdistinct", nil, n.Aggdistinct) + a.apply(n, "Aggfilter", nil, n.Aggfilter) + + case *ast.Alias: + a.apply(n, "Colnames", nil, n.Colnames) + + case *ast.AlterCollationStmt: + a.apply(n, "Collname", nil, n.Collname) + + case *ast.AlterDatabaseSetStmt: + a.apply(n, "Setstmt", nil, n.Setstmt) + + case *ast.AlterDatabaseStmt: + a.apply(n, "Options", nil, n.Options) + + case *ast.AlterDefaultPrivilegesStmt: + a.apply(n, "Options", nil, n.Options) + a.apply(n, "Action", nil, n.Action) + + case *ast.AlterDomainStmt: + a.apply(n, "TypeName", nil, n.TypeName) + a.apply(n, "Def", nil, n.Def) + + case *ast.AlterEnumStmt: + a.apply(n, "TypeName", nil, n.TypeName) + + case *ast.AlterEventTrigStmt: + // pass + + case *ast.AlterExtensionContentsStmt: + a.apply(n, "Object", nil, n.Object) + + case *ast.AlterExtensionStmt: + a.apply(n, "Options", nil, n.Options) + + case *ast.AlterFdwStmt: + a.apply(n, "FuncOptions", nil, n.FuncOptions) + a.apply(n, "Options", nil, n.Options) + + case *ast.AlterForeignServerStmt: + a.apply(n, "Options", nil, n.Options) + + case *ast.AlterFunctionStmt: + a.apply(n, "Func", nil, n.Func) + a.apply(n, "Actions", nil, n.Actions) + + case *ast.AlterObjectDependsStmt: + a.apply(n, "Relation", nil, n.Relation) + a.apply(n, "Object", nil, n.Object) + a.apply(n, "Extname", nil, n.Extname) + + case *ast.AlterObjectSchemaStmt: + a.apply(n, "Relation", nil, n.Relation) + a.apply(n, "Object", nil, n.Object) + + case *ast.AlterOpFamilyStmt: + a.apply(n, "Opfamilyname", nil, n.Opfamilyname) + a.apply(n, "Items", nil, n.Items) + + case *ast.AlterOperatorStmt: + a.apply(n, "Opername", nil, n.Opername) + a.apply(n, "Options", nil, n.Options) + + case *ast.AlterOwnerStmt: + a.apply(n, "Relation", nil, n.Relation) + a.apply(n, "Object", nil, n.Object) + a.apply(n, "Newowner", nil, n.Newowner) + + case *ast.AlterPolicyStmt: + a.apply(n, "Table", nil, n.Table) + a.apply(n, "Roles", nil, n.Roles) + a.apply(n, "Qual", nil, n.Qual) + a.apply(n, "WithCheck", nil, n.WithCheck) + + case *ast.AlterPublicationStmt: + a.apply(n, "Options", nil, n.Options) + a.apply(n, "Tables", nil, n.Tables) + + case *ast.AlterRoleSetStmt: + a.apply(n, "Role", nil, n.Role) + a.apply(n, "Setstmt", nil, n.Setstmt) + + case *ast.AlterRoleStmt: + a.apply(n, "Role", nil, n.Role) + a.apply(n, "Options", nil, n.Options) + + case *ast.AlterSeqStmt: + a.apply(n, "Sequence", nil, n.Sequence) + a.apply(n, "Options", nil, n.Options) + + case *ast.AlterSubscriptionStmt: + a.apply(n, "Publication", nil, n.Publication) + a.apply(n, "Options", nil, n.Options) + + case *ast.AlterSystemStmt: + a.apply(n, "Setstmt", nil, n.Setstmt) + + case *ast.AlterTSConfigurationStmt: + a.apply(n, "Cfgname", nil, n.Cfgname) + a.apply(n, "Tokentype", nil, n.Tokentype) + a.apply(n, "Dicts", nil, n.Dicts) + + case *ast.AlterTSDictionaryStmt: + a.apply(n, "Dictname", nil, n.Dictname) + a.apply(n, "Options", nil, n.Options) + + case *ast.AlterTableCmd: + a.apply(n, "Newowner", nil, n.Newowner) + a.apply(n, "Def", nil, n.Def) + + case *ast.AlterTableMoveAllStmt: + a.apply(n, "Roles", nil, n.Roles) + + case *ast.AlterTableSpaceOptionsStmt: + a.apply(n, "Options", nil, n.Options) + + case *ast.AlterTableStmt: + a.apply(n, "Relation", nil, n.Relation) + a.apply(n, "Table", nil, n.Table) + a.apply(n, "Cmds", nil, n.Cmds) + + case *ast.AlterUserMappingStmt: + a.apply(n, "User", nil, n.User) + a.apply(n, "Options", nil, n.Options) + + case *ast.AlternativeSubPlan: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Subplans", nil, n.Subplans) + + case *ast.ArrayCoerceExpr: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Arg", nil, n.Arg) + + case *ast.ArrayExpr: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Elements", nil, n.Elements) + + case *ast.ArrayRef: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Refupperindexpr", nil, n.Refupperindexpr) + a.apply(n, "Reflowerindexpr", nil, n.Reflowerindexpr) + a.apply(n, "Refexpr", nil, n.Refexpr) + a.apply(n, "Refassgnexpr", nil, n.Refassgnexpr) + + case *ast.BetweenExpr: + a.apply(n, "Expr", nil, n.Expr) + a.apply(n, "Left", nil, n.Left) + a.apply(n, "Right", nil, n.Right) + + case *ast.BitString: + // pass + + case *ast.BlockIdData: + // pass + + case *ast.Boolean: + // pass + + case *ast.BoolExpr: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Args", nil, n.Args) + + case *ast.BooleanTest: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Arg", nil, n.Arg) + + case *ast.CallStmt: + a.apply(n, "FuncCall", nil, n.FuncCall) + + case *ast.CaseExpr: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Arg", nil, n.Arg) + a.apply(n, "Args", nil, n.Args) + a.apply(n, "Defresult", nil, n.Defresult) + + case *ast.CaseTestExpr: + a.apply(n, "Xpr", nil, n.Xpr) + + case *ast.CaseWhen: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Expr", nil, n.Expr) + a.apply(n, "Result", nil, n.Result) + + case *ast.CheckPointStmt: + // pass + + case *ast.ClosePortalStmt: + // pass + + case *ast.ClusterStmt: + a.apply(n, "Relation", nil, n.Relation) + + case *ast.CoalesceExpr: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Args", nil, n.Args) + + case *ast.CoerceToDomain: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Arg", nil, n.Arg) + + case *ast.CoerceToDomainValue: + a.apply(n, "Xpr", nil, n.Xpr) + + case *ast.CoerceViaIO: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Arg", nil, n.Arg) + + case *ast.CollateClause: + a.apply(n, "Arg", nil, n.Arg) + a.apply(n, "Collname", nil, n.Collname) + + case *ast.CollateExpr: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Arg", nil, n.Arg) + + case *ast.ColumnDef: + a.apply(n, "TypeName", nil, n.TypeName) + a.apply(n, "RawDefault", nil, n.RawDefault) + a.apply(n, "CookedDefault", nil, n.CookedDefault) + a.apply(n, "CollClause", nil, n.CollClause) + a.apply(n, "Constraints", nil, n.Constraints) + a.apply(n, "Fdwoptions", nil, n.Fdwoptions) + + case *ast.ColumnRef: + a.apply(n, "Fields", nil, n.Fields) + + case *ast.CommentStmt: + a.apply(n, "Object", nil, n.Object) + + case *ast.CommonTableExpr: + a.apply(n, "Aliascolnames", nil, n.Aliascolnames) + a.apply(n, "Ctequery", nil, n.Ctequery) + a.apply(n, "Ctecolnames", nil, n.Ctecolnames) + a.apply(n, "Ctecoltypes", nil, n.Ctecoltypes) + a.apply(n, "Ctecoltypmods", nil, n.Ctecoltypmods) + a.apply(n, "Ctecolcollations", nil, n.Ctecolcollations) + + case *ast.CompositeTypeStmt: + a.apply(n, "TypeName", nil, n.TypeName) + + case *ast.Const: + a.apply(n, "Xpr", nil, n.Xpr) + + case *ast.Constraint: + a.apply(n, "RawExpr", nil, n.RawExpr) + a.apply(n, "Keys", nil, n.Keys) + a.apply(n, "Exclusions", nil, n.Exclusions) + a.apply(n, "Options", nil, n.Options) + a.apply(n, "WhereClause", nil, n.WhereClause) + a.apply(n, "Pktable", nil, n.Pktable) + a.apply(n, "FkAttrs", nil, n.FkAttrs) + a.apply(n, "PkAttrs", nil, n.PkAttrs) + a.apply(n, "OldConpfeqop", nil, n.OldConpfeqop) + + case *ast.ConstraintsSetStmt: + a.apply(n, "Constraints", nil, n.Constraints) + + case *ast.ConvertRowtypeExpr: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Arg", nil, n.Arg) + + case *ast.CopyStmt: + a.apply(n, "Relation", nil, n.Relation) + a.apply(n, "Query", nil, n.Query) + a.apply(n, "Attlist", nil, n.Attlist) + a.apply(n, "Options", nil, n.Options) + + case *ast.CreateAmStmt: + a.apply(n, "HandlerName", nil, n.HandlerName) + + case *ast.CreateCastStmt: + a.apply(n, "Sourcetype", nil, n.Sourcetype) + a.apply(n, "Targettype", nil, n.Targettype) + a.apply(n, "Func", nil, n.Func) + + case *ast.CreateConversionStmt: + a.apply(n, "ConversionName", nil, n.ConversionName) + a.apply(n, "FuncName", nil, n.FuncName) + + case *ast.CreateDomainStmt: + a.apply(n, "Domainname", nil, n.Domainname) + a.apply(n, "TypeName", nil, n.TypeName) + a.apply(n, "CollClause", nil, n.CollClause) + a.apply(n, "Constraints", nil, n.Constraints) + + case *ast.CreateEnumStmt: + a.apply(n, "TypeName", nil, n.TypeName) + a.apply(n, "Vals", nil, n.Vals) + + case *ast.CreateEventTrigStmt: + a.apply(n, "Whenclause", nil, n.Whenclause) + a.apply(n, "Funcname", nil, n.Funcname) + + case *ast.CreateExtensionStmt: + a.apply(n, "Options", nil, n.Options) + + case *ast.CreateFdwStmt: + a.apply(n, "FuncOptions", nil, n.FuncOptions) + a.apply(n, "Options", nil, n.Options) + + case *ast.CreateForeignServerStmt: + a.apply(n, "Options", nil, n.Options) + + case *ast.CreateForeignTableStmt: + a.apply(n, "Base", nil, n.Base) + a.apply(n, "Options", nil, n.Options) + + case *ast.CreateFunctionStmt: + a.apply(n, "Func", nil, n.Func) + a.apply(n, "Params", nil, n.Params) + a.apply(n, "ReturnType", nil, n.ReturnType) + a.apply(n, "Options", nil, n.Options) + a.apply(n, "WithClause", nil, n.WithClause) + + case *ast.CreateOpClassItem: + a.apply(n, "Name", nil, n.Name) + a.apply(n, "OrderFamily", nil, n.OrderFamily) + a.apply(n, "ClassArgs", nil, n.ClassArgs) + a.apply(n, "Storedtype", nil, n.Storedtype) + + case *ast.CreateOpClassStmt: + a.apply(n, "Opclassname", nil, n.Opclassname) + a.apply(n, "Opfamilyname", nil, n.Opfamilyname) + a.apply(n, "Datatype", nil, n.Datatype) + a.apply(n, "Items", nil, n.Items) + + case *ast.CreateOpFamilyStmt: + a.apply(n, "Opfamilyname", nil, n.Opfamilyname) + + case *ast.CreatePLangStmt: + a.apply(n, "Plhandler", nil, n.Plhandler) + a.apply(n, "Plinline", nil, n.Plinline) + a.apply(n, "Plvalidator", nil, n.Plvalidator) + + case *ast.CreatePolicyStmt: + a.apply(n, "Table", nil, n.Table) + a.apply(n, "Roles", nil, n.Roles) + a.apply(n, "Qual", nil, n.Qual) + a.apply(n, "WithCheck", nil, n.WithCheck) + + case *ast.CreatePublicationStmt: + a.apply(n, "Options", nil, n.Options) + a.apply(n, "Tables", nil, n.Tables) + + case *ast.CreateRangeStmt: + a.apply(n, "TypeName", nil, n.TypeName) + a.apply(n, "Params", nil, n.Params) + + case *ast.CreateRoleStmt: + a.apply(n, "Options", nil, n.Options) + + case *ast.CreateSchemaStmt: + a.apply(n, "Authrole", nil, n.Authrole) + a.apply(n, "SchemaElts", nil, n.SchemaElts) + + case *ast.CreateSeqStmt: + a.apply(n, "Sequence", nil, n.Sequence) + a.apply(n, "Options", nil, n.Options) + + case *ast.CreateStatsStmt: + a.apply(n, "Defnames", nil, n.Defnames) + a.apply(n, "StatTypes", nil, n.StatTypes) + a.apply(n, "Exprs", nil, n.Exprs) + a.apply(n, "Relations", nil, n.Relations) + + case *ast.CreateStmt: + a.apply(n, "Relation", nil, n.Relation) + a.apply(n, "TableElts", nil, n.TableElts) + a.apply(n, "InhRelations", nil, n.InhRelations) + a.apply(n, "Partbound", nil, n.Partbound) + a.apply(n, "Partspec", nil, n.Partspec) + a.apply(n, "OfTypename", nil, n.OfTypename) + a.apply(n, "Constraints", nil, n.Constraints) + a.apply(n, "Options", nil, n.Options) + + case *ast.CreateSubscriptionStmt: + a.apply(n, "Publication", nil, n.Publication) + a.apply(n, "Options", nil, n.Options) + + case *ast.CreateTableAsStmt: + a.apply(n, "Query", nil, n.Query) + a.apply(n, "Into", nil, n.Into) + + case *ast.CreateTableSpaceStmt: + a.apply(n, "Owner", nil, n.Owner) + a.apply(n, "Options", nil, n.Options) + + case *ast.CreateTransformStmt: + a.apply(n, "TypeName", nil, n.TypeName) + a.apply(n, "Fromsql", nil, n.Fromsql) + a.apply(n, "Tosql", nil, n.Tosql) + + case *ast.CreateTrigStmt: + a.apply(n, "Relation", nil, n.Relation) + a.apply(n, "Funcname", nil, n.Funcname) + a.apply(n, "Args", nil, n.Args) + a.apply(n, "Columns", nil, n.Columns) + a.apply(n, "WhenClause", nil, n.WhenClause) + a.apply(n, "TransitionRels", nil, n.TransitionRels) + a.apply(n, "Constrrel", nil, n.Constrrel) + + case *ast.CreateUserMappingStmt: + a.apply(n, "User", nil, n.User) + a.apply(n, "Options", nil, n.Options) + + case *ast.CreatedbStmt: + a.apply(n, "Options", nil, n.Options) + + case *ast.CurrentOfExpr: + a.apply(n, "Xpr", nil, n.Xpr) + + case *ast.DeallocateStmt: + // pass + + case *ast.DeclareCursorStmt: + a.apply(n, "Query", nil, n.Query) + + case *ast.DefElem: + a.apply(n, "Arg", nil, n.Arg) + + case *ast.DefineStmt: + a.apply(n, "Defnames", nil, n.Defnames) + a.apply(n, "Args", nil, n.Args) + a.apply(n, "Definition", nil, n.Definition) + + case *ast.DeleteStmt: + a.apply(n, "Relations", nil, n.Relations) + a.apply(n, "UsingClause", nil, n.UsingClause) + a.apply(n, "WhereClause", nil, n.WhereClause) + a.apply(n, "ReturningList", nil, n.ReturningList) + a.apply(n, "WithClause", nil, n.WithClause) + a.apply(n, "Targets", nil, n.Targets) + a.apply(n, "FromClause", nil, n.FromClause) + + case *ast.DiscardStmt: + // pass + + case *ast.DoStmt: + a.apply(n, "Args", nil, n.Args) + + case *ast.DropOwnedStmt: + a.apply(n, "Roles", nil, n.Roles) + + case *ast.DropRoleStmt: + a.apply(n, "Roles", nil, n.Roles) + + case *ast.DropStmt: + a.apply(n, "Objects", nil, n.Objects) + + case *ast.DropSubscriptionStmt: + // pass + + case *ast.DropTableSpaceStmt: + // pass + + case *ast.DropUserMappingStmt: + a.apply(n, "User", nil, n.User) + + case *ast.DropdbStmt: + // pass + + case *ast.ExecuteStmt: + a.apply(n, "Params", nil, n.Params) + + case *ast.ExplainStmt: + a.apply(n, "Query", nil, n.Query) + a.apply(n, "Options", nil, n.Options) + + case *ast.Expr: + // pass + + case *ast.FetchStmt: + // pass + + case *ast.FieldSelect: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Arg", nil, n.Arg) + + case *ast.FieldStore: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Arg", nil, n.Arg) + a.apply(n, "Newvals", nil, n.Newvals) + a.apply(n, "Fieldnums", nil, n.Fieldnums) + + case *ast.Float: + // pass + + case *ast.FromExpr: + a.apply(n, "Fromlist", nil, n.Fromlist) + a.apply(n, "Quals", nil, n.Quals) + + case *ast.FuncCall: + a.apply(n, "Func", nil, n.Func) + a.apply(n, "Funcname", nil, n.Funcname) + a.apply(n, "Args", nil, n.Args) + a.apply(n, "AggOrder", nil, n.AggOrder) + a.apply(n, "AggFilter", nil, n.AggFilter) + a.apply(n, "Over", nil, n.Over) + + case *ast.FuncExpr: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Args", nil, n.Args) + + case *ast.FunctionParameter: + a.apply(n, "ArgType", nil, n.ArgType) + a.apply(n, "Defexpr", nil, n.Defexpr) + + case *ast.GrantRoleStmt: + a.apply(n, "GrantedRoles", nil, n.GrantedRoles) + a.apply(n, "GranteeRoles", nil, n.GranteeRoles) + a.apply(n, "Grantor", nil, n.Grantor) + + case *ast.GrantStmt: + a.apply(n, "Objects", nil, n.Objects) + a.apply(n, "Privileges", nil, n.Privileges) + a.apply(n, "Grantees", nil, n.Grantees) + + case *ast.GroupingFunc: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Args", nil, n.Args) + a.apply(n, "Refs", nil, n.Refs) + a.apply(n, "Cols", nil, n.Cols) + + case *ast.GroupingSet: + a.apply(n, "Content", nil, n.Content) + + case *ast.ImportForeignSchemaStmt: + a.apply(n, "TableList", nil, n.TableList) + a.apply(n, "Options", nil, n.Options) + + case *ast.IndexElem: + a.apply(n, "Expr", nil, n.Expr) + a.apply(n, "Collation", nil, n.Collation) + a.apply(n, "Opclass", nil, n.Opclass) + + case *ast.IndexStmt: + a.apply(n, "Relation", nil, n.Relation) + a.apply(n, "IndexParams", nil, n.IndexParams) + a.apply(n, "Options", nil, n.Options) + a.apply(n, "WhereClause", nil, n.WhereClause) + a.apply(n, "ExcludeOpNames", nil, n.ExcludeOpNames) + + case *ast.InferClause: + a.apply(n, "IndexElems", nil, n.IndexElems) + a.apply(n, "WhereClause", nil, n.WhereClause) + + case *ast.InferenceElem: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Expr", nil, n.Expr) + + case *ast.InlineCodeBlock: + // pass + + case *ast.InsertStmt: + a.apply(n, "Relation", nil, n.Relation) + a.apply(n, "Cols", nil, n.Cols) + a.apply(n, "SelectStmt", nil, n.SelectStmt) + a.apply(n, "OnConflictClause", nil, n.OnConflictClause) + a.apply(n, "OnDuplicateKeyUpdate", nil, n.OnDuplicateKeyUpdate) + a.apply(n, "ReturningList", nil, n.ReturningList) + a.apply(n, "WithClause", nil, n.WithClause) + + case *ast.Integer: + // pass + + case *ast.IntervalExpr: + a.apply(n, "Value", nil, n.Value) + + case *ast.IntoClause: + a.apply(n, "Rel", nil, n.Rel) + a.apply(n, "ColNames", nil, n.ColNames) + a.apply(n, "Options", nil, n.Options) + a.apply(n, "ViewQuery", nil, n.ViewQuery) + + case *ast.JoinExpr: + a.apply(n, "Larg", nil, n.Larg) + a.apply(n, "Rarg", nil, n.Rarg) + a.apply(n, "UsingClause", nil, n.UsingClause) + a.apply(n, "Quals", nil, n.Quals) + a.apply(n, "Alias", nil, n.Alias) + + case *ast.ListenStmt: + // pass + + case *ast.LoadStmt: + // pass + + case *ast.LockStmt: + a.apply(n, "Relations", nil, n.Relations) + + case *ast.LockingClause: + a.apply(n, "LockedRels", nil, n.LockedRels) + + case *ast.MinMaxExpr: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Args", nil, n.Args) + + case *ast.MultiAssignRef: + a.apply(n, "Source", nil, n.Source) + + case *ast.NamedArgExpr: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Arg", nil, n.Arg) + + case *ast.NextValueExpr: + a.apply(n, "Xpr", nil, n.Xpr) + + case *ast.NotifyStmt: + // pass + + case *ast.Null: + // pass + + case *ast.NullTest: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Arg", nil, n.Arg) + + case *ast.ObjectWithArgs: + a.apply(n, "Objname", nil, n.Objname) + a.apply(n, "Objargs", nil, n.Objargs) + + case *ast.OnConflictClause: + a.apply(n, "Infer", nil, n.Infer) + a.apply(n, "TargetList", nil, n.TargetList) + a.apply(n, "WhereClause", nil, n.WhereClause) + + case *ast.OnConflictExpr: + a.apply(n, "ArbiterElems", nil, n.ArbiterElems) + a.apply(n, "ArbiterWhere", nil, n.ArbiterWhere) + a.apply(n, "OnConflictSet", nil, n.OnConflictSet) + a.apply(n, "OnConflictWhere", nil, n.OnConflictWhere) + a.apply(n, "ExclRelTlist", nil, n.ExclRelTlist) + + case *ast.OnDuplicateKeyUpdate: + a.apply(n, "TargetList", nil, n.TargetList) + + case *ast.OpExpr: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Args", nil, n.Args) + + case *ast.Param: + a.apply(n, "Xpr", nil, n.Xpr) + + case *ast.ParamExecData: + // pass + + case *ast.ParamExternData: + // pass + + case *ast.ParamListInfoData: + // pass + + case *ast.ParamRef: + // pass + + case *ast.ParenExpr: + a.apply(n, "Expr", nil, n.Expr) + + case *ast.VariableExpr: + // Leaf node - no children to traverse + + case *ast.PartitionBoundSpec: + a.apply(n, "Listdatums", nil, n.Listdatums) + a.apply(n, "Lowerdatums", nil, n.Lowerdatums) + a.apply(n, "Upperdatums", nil, n.Upperdatums) + + case *ast.PartitionCmd: + a.apply(n, "Name", nil, n.Name) + a.apply(n, "Bound", nil, n.Bound) + + case *ast.PartitionElem: + a.apply(n, "Expr", nil, n.Expr) + a.apply(n, "Collation", nil, n.Collation) + a.apply(n, "Opclass", nil, n.Opclass) + + case *ast.PartitionRangeDatum: + a.apply(n, "Value", nil, n.Value) + + case *ast.PartitionSpec: + a.apply(n, "PartParams", nil, n.PartParams) + + case *ast.PrepareStmt: + a.apply(n, "Argtypes", nil, n.Argtypes) + a.apply(n, "Query", nil, n.Query) + + case *ast.Query: + a.apply(n, "UtilityStmt", nil, n.UtilityStmt) + a.apply(n, "CteList", nil, n.CteList) + a.apply(n, "Rtable", nil, n.Rtable) + a.apply(n, "Jointree", nil, n.Jointree) + a.apply(n, "TargetList", nil, n.TargetList) + a.apply(n, "OnConflict", nil, n.OnConflict) + a.apply(n, "ReturningList", nil, n.ReturningList) + a.apply(n, "GroupClause", nil, n.GroupClause) + a.apply(n, "GroupingSets", nil, n.GroupingSets) + a.apply(n, "HavingQual", nil, n.HavingQual) + a.apply(n, "WindowClause", nil, n.WindowClause) + a.apply(n, "DistinctClause", nil, n.DistinctClause) + a.apply(n, "SortClause", nil, n.SortClause) + a.apply(n, "LimitOffset", nil, n.LimitOffset) + a.apply(n, "LimitCount", nil, n.LimitCount) + a.apply(n, "RowMarks", nil, n.RowMarks) + a.apply(n, "SetOperations", nil, n.SetOperations) + a.apply(n, "ConstraintDeps", nil, n.ConstraintDeps) + a.apply(n, "WithCheckOptions", nil, n.WithCheckOptions) + + case *ast.RangeFunction: + a.apply(n, "Functions", nil, n.Functions) + a.apply(n, "Alias", nil, n.Alias) + a.apply(n, "Coldeflist", nil, n.Coldeflist) + + case *ast.RangeSubselect: + a.apply(n, "Subquery", nil, n.Subquery) + a.apply(n, "Alias", nil, n.Alias) + + case *ast.RangeTableFunc: + a.apply(n, "Docexpr", nil, n.Docexpr) + a.apply(n, "Rowexpr", nil, n.Rowexpr) + a.apply(n, "Namespaces", nil, n.Namespaces) + a.apply(n, "Columns", nil, n.Columns) + a.apply(n, "Alias", nil, n.Alias) + + case *ast.RangeTableFuncCol: + a.apply(n, "TypeName", nil, n.TypeName) + a.apply(n, "Colexpr", nil, n.Colexpr) + a.apply(n, "Coldefexpr", nil, n.Coldefexpr) + + case *ast.RangeTableSample: + a.apply(n, "Relation", nil, n.Relation) + a.apply(n, "Method", nil, n.Method) + a.apply(n, "Args", nil, n.Args) + a.apply(n, "Repeatable", nil, n.Repeatable) + + case *ast.RangeTblEntry: + a.apply(n, "Tablesample", nil, n.Tablesample) + a.apply(n, "Subquery", nil, n.Subquery) + a.apply(n, "Joinaliasvars", nil, n.Joinaliasvars) + a.apply(n, "Functions", nil, n.Functions) + a.apply(n, "Tablefunc", nil, n.Tablefunc) + a.apply(n, "ValuesLists", nil, n.ValuesLists) + a.apply(n, "Coltypes", nil, n.Coltypes) + a.apply(n, "Coltypmods", nil, n.Coltypmods) + a.apply(n, "Colcollations", nil, n.Colcollations) + a.apply(n, "Alias", nil, n.Alias) + a.apply(n, "Eref", nil, n.Eref) + a.apply(n, "SecurityQuals", nil, n.SecurityQuals) + + case *ast.RangeTblFunction: + a.apply(n, "Funcexpr", nil, n.Funcexpr) + a.apply(n, "Funccolnames", nil, n.Funccolnames) + a.apply(n, "Funccoltypes", nil, n.Funccoltypes) + a.apply(n, "Funccoltypmods", nil, n.Funccoltypmods) + a.apply(n, "Funccolcollations", nil, n.Funccolcollations) + + case *ast.RangeTblRef: + // pass + + case *ast.RangeVar: + a.apply(n, "Alias", nil, n.Alias) + + case *ast.ReassignOwnedStmt: + a.apply(n, "Roles", nil, n.Roles) + a.apply(n, "Newrole", nil, n.Newrole) + + case *ast.RefreshMatViewStmt: + a.apply(n, "Relation", nil, n.Relation) + + case *ast.ReindexStmt: + a.apply(n, "Relation", nil, n.Relation) + + case *ast.RelabelType: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Arg", nil, n.Arg) + + case *ast.RenameStmt: + a.apply(n, "Relation", nil, n.Relation) + a.apply(n, "Object", nil, n.Object) + + case *ast.ReplicaIdentityStmt: + // pass + + case *ast.ResTarget: + a.apply(n, "Indirection", nil, n.Indirection) + a.apply(n, "Val", nil, n.Val) + + case *ast.RoleSpec: + // pass + + case *ast.RowCompareExpr: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Opnos", nil, n.Opnos) + a.apply(n, "Opfamilies", nil, n.Opfamilies) + a.apply(n, "Inputcollids", nil, n.Inputcollids) + a.apply(n, "Largs", nil, n.Largs) + a.apply(n, "Rargs", nil, n.Rargs) + + case *ast.RowExpr: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Args", nil, n.Args) + a.apply(n, "Colnames", nil, n.Colnames) + + case *ast.RowMarkClause: + // pass + + case *ast.RuleStmt: + a.apply(n, "Relation", nil, n.Relation) + a.apply(n, "WhereClause", nil, n.WhereClause) + a.apply(n, "Actions", nil, n.Actions) + + case *ast.SQLValueFunction: + a.apply(n, "Xpr", nil, n.Xpr) + + case *ast.ScalarArrayOpExpr: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Args", nil, n.Args) + + case *ast.SecLabelStmt: + a.apply(n, "Object", nil, n.Object) + + case *ast.SelectStmt: + a.apply(n, "DistinctClause", nil, n.DistinctClause) + a.apply(n, "IntoClause", nil, n.IntoClause) + a.apply(n, "TargetList", nil, n.TargetList) + a.apply(n, "FromClause", nil, n.FromClause) + a.apply(n, "WhereClause", nil, n.WhereClause) + a.apply(n, "GroupClause", nil, n.GroupClause) + a.apply(n, "HavingClause", nil, n.HavingClause) + a.apply(n, "WindowClause", nil, n.WindowClause) + a.apply(n, "ValuesLists", nil, n.ValuesLists) + a.apply(n, "SortClause", nil, n.SortClause) + a.apply(n, "LimitOffset", nil, n.LimitOffset) + a.apply(n, "LimitCount", nil, n.LimitCount) + a.apply(n, "LockingClause", nil, n.LockingClause) + a.apply(n, "WithClause", nil, n.WithClause) + a.apply(n, "Larg", nil, n.Larg) + a.apply(n, "Rarg", nil, n.Rarg) + + case *ast.SetOperationStmt: + a.apply(n, "Larg", nil, n.Larg) + a.apply(n, "Rarg", nil, n.Rarg) + a.apply(n, "ColTypes", nil, n.ColTypes) + a.apply(n, "ColTypmods", nil, n.ColTypmods) + a.apply(n, "ColCollations", nil, n.ColCollations) + a.apply(n, "GroupClauses", nil, n.GroupClauses) + + case *ast.SetToDefault: + a.apply(n, "Xpr", nil, n.Xpr) + + case *ast.SortBy: + a.apply(n, "Node", nil, n.Node) + a.apply(n, "UseOp", nil, n.UseOp) + + case *ast.SortGroupClause: + // pass + + case *ast.SubLink: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Testexpr", nil, n.Testexpr) + a.apply(n, "OperName", nil, n.OperName) + a.apply(n, "Subselect", nil, n.Subselect) + + case *ast.SubPlan: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Testexpr", nil, n.Testexpr) + a.apply(n, "ParamIds", nil, n.ParamIds) + a.apply(n, "SetParam", nil, n.SetParam) + a.apply(n, "ParParam", nil, n.ParParam) + a.apply(n, "Args", nil, n.Args) + + case *ast.TableFunc: + a.apply(n, "NsUris", nil, n.NsUris) + a.apply(n, "NsNames", nil, n.NsNames) + a.apply(n, "Docexpr", nil, n.Docexpr) + a.apply(n, "Rowexpr", nil, n.Rowexpr) + a.apply(n, "Colnames", nil, n.Colnames) + a.apply(n, "Coltypes", nil, n.Coltypes) + a.apply(n, "Coltypmods", nil, n.Coltypmods) + a.apply(n, "Colcollations", nil, n.Colcollations) + a.apply(n, "Colexprs", nil, n.Colexprs) + a.apply(n, "Coldefexprs", nil, n.Coldefexprs) + + case *ast.TableLikeClause: + a.apply(n, "Relation", nil, n.Relation) + + case *ast.TableSampleClause: + a.apply(n, "Args", nil, n.Args) + a.apply(n, "Repeatable", nil, n.Repeatable) + + case *ast.TargetEntry: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Expr", nil, n.Expr) + + case *ast.TransactionStmt: + a.apply(n, "Options", nil, n.Options) + + case *ast.TriggerTransition: + // pass + + case *ast.TruncateStmt: + a.apply(n, "Relations", nil, n.Relations) + + case *ast.TypeCast: + a.apply(n, "Arg", nil, n.Arg) + a.apply(n, "TypeName", nil, n.TypeName) + + case *ast.TypeName: + a.apply(n, "Names", nil, n.Names) + a.apply(n, "Typmods", nil, n.Typmods) + a.apply(n, "ArrayBounds", nil, n.ArrayBounds) + + case *ast.UnlistenStmt: + // pass + + case *ast.UpdateStmt: + a.apply(n, "Relations", nil, n.Relations) + a.apply(n, "TargetList", nil, n.TargetList) + a.apply(n, "WhereClause", nil, n.WhereClause) + a.apply(n, "FromClause", nil, n.FromClause) + a.apply(n, "ReturningList", nil, n.ReturningList) + a.apply(n, "WithClause", nil, n.WithClause) + + case *ast.VacuumStmt: + a.apply(n, "Relation", nil, n.Relation) + a.apply(n, "VaCols", nil, n.VaCols) + + case *ast.Var: + a.apply(n, "Xpr", nil, n.Xpr) + + case *ast.VariableSetStmt: + a.apply(n, "Args", nil, n.Args) + + case *ast.VariableShowStmt: + // pass + + case *ast.ViewStmt: + a.apply(n, "View", nil, n.View) + a.apply(n, "Aliases", nil, n.Aliases) + a.apply(n, "Query", nil, n.Query) + a.apply(n, "Options", nil, n.Options) + + case *ast.WindowClause: + a.apply(n, "PartitionClause", nil, n.PartitionClause) + a.apply(n, "OrderClause", nil, n.OrderClause) + a.apply(n, "StartOffset", nil, n.StartOffset) + a.apply(n, "EndOffset", nil, n.EndOffset) + + case *ast.WindowDef: + a.apply(n, "PartitionClause", nil, n.PartitionClause) + a.apply(n, "OrderClause", nil, n.OrderClause) + a.apply(n, "StartOffset", nil, n.StartOffset) + a.apply(n, "EndOffset", nil, n.EndOffset) + + case *ast.WindowFunc: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "Args", nil, n.Args) + a.apply(n, "Aggfilter", nil, n.Aggfilter) + + case *ast.WithCheckOption: + a.apply(n, "Qual", nil, n.Qual) + + case *ast.WithClause: + a.apply(n, "Ctes", nil, n.Ctes) + + case *ast.XmlExpr: + a.apply(n, "Xpr", nil, n.Xpr) + a.apply(n, "NamedArgs", nil, n.NamedArgs) + a.apply(n, "ArgNames", nil, n.ArgNames) + a.apply(n, "Args", nil, n.Args) + + case *ast.XmlSerialize: + a.apply(n, "Expr", nil, n.Expr) + a.apply(n, "TypeName", nil, n.TypeName) + + // Comments and fields + default: + panic(fmt.Sprintf("Apply: unexpected node type %T", n)) + } + + if a.post != nil && !a.post(&a.cursor) { + panic(abort) + } + + a.cursor = saved +} + +// An iterator controls iteration over a slice of nodes. +type iterator struct { + index, step int +} + +func (a *application) applyList(parent ast.Node, name string) { + // avoid heap-allocating a new iterator for each applyList call; reuse a.iter instead + saved := a.iter + a.iter.index = 0 + for { + // must reload parent.name each time, since cursor modifications might change it + v := reflect.Indirect(reflect.ValueOf(parent)).FieldByName(name) + if a.iter.index >= v.Len() { + break + } + + // element x may be nil in a bad AST - be cautious + var x ast.Node + if e := v.Index(a.iter.index); e.IsValid() { + x = e.Interface().(ast.Node) + } + + a.iter.step = 1 + a.apply(parent, name, &a.iter, x) + a.iter.index += a.iter.step + } + a.iter = saved +} diff --git a/internal/sql/astutils/search.go b/internal/sql/astutils/search.go new file mode 100644 index 0000000..d61ee13 --- /dev/null +++ b/internal/sql/astutils/search.go @@ -0,0 +1,21 @@ +package astutils + +import "github.com/sqlc-dev/sqlc/internal/sql/ast" + +type nodeSearch struct { + list *ast.List + check func(ast.Node) bool +} + +func (s *nodeSearch) Visit(node ast.Node) Visitor { + if s.check(node) { + s.list.Items = append(s.list.Items, node) + } + return s +} + +func Search(root ast.Node, f func(ast.Node) bool) *ast.List { + ns := &nodeSearch{check: f, list: &ast.List{}} + Walk(ns, root) + return ns.list +} diff --git a/internal/sql/astutils/walk.go b/internal/sql/astutils/walk.go new file mode 100644 index 0000000..6d5e80b --- /dev/null +++ b/internal/sql/astutils/walk.go @@ -0,0 +1,2200 @@ +package astutils + +import ( + "fmt" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +type Visitor interface { + Visit(ast.Node) Visitor +} + +type VisitorFunc func(ast.Node) + +func (vf VisitorFunc) Visit(node ast.Node) Visitor { + vf(node) + return vf +} + +func Walk(f Visitor, node ast.Node) { + if f = f.Visit(node); f == nil { + return + } + switch n := node.(type) { + + case *ast.AlterTableSetSchemaStmt: + if n.Table != nil { + Walk(f, n.Table) + } + + case *ast.AlterTableStmt: + if n.Relation != nil { + Walk(f, n.Relation) + } + if n.Table != nil { + Walk(f, n.Table) + } + if n.Cmds != nil { + Walk(f, n.Cmds) + } + + case *ast.AlterTypeAddValueStmt: + if n.Type != nil { + Walk(f, n.Type) + } + + case *ast.AlterTypeSetSchemaStmt: + if n.Type != nil { + Walk(f, n.Type) + } + + case *ast.AlterTypeRenameValueStmt: + if n.Type != nil { + Walk(f, n.Type) + } + + case *ast.CommentOnColumnStmt: + if n.Table != nil { + Walk(f, n.Table) + } + if n.Col != nil { + Walk(f, n.Col) + } + + case *ast.CommentOnSchemaStmt: + if n.Schema != nil { + Walk(f, n.Schema) + } + + case *ast.CommentOnTableStmt: + if n.Table != nil { + Walk(f, n.Table) + } + + case *ast.CommentOnTypeStmt: + if n.Type != nil { + Walk(f, n.Type) + } + + case *ast.CommentOnViewStmt: + if n.View != nil { + Walk(f, n.View) + } + + case *ast.CompositeTypeStmt: + if n.TypeName != nil { + Walk(f, n.TypeName) + } + + case *ast.CreateTableStmt: + if n.Name != nil { + Walk(f, n.Name) + } + + case *ast.DropFunctionStmt: + // pass + + case *ast.DropSchemaStmt: + // pass + + case *ast.DropTableStmt: + // pass + + case *ast.DropTypeStmt: + // pass + + case *ast.FuncName: + // pass + + case *ast.FuncParam: + if n.Type != nil { + Walk(f, n.Type) + } + if n.DefExpr != nil { + Walk(f, n.DefExpr) + } + + case *ast.FuncSpec: + if n.Name != nil { + Walk(f, n.Name) + } + + case *ast.List: + for _, item := range n.Items { + Walk(f, item) + } + + case *ast.RenameColumnStmt: + if n.Table != nil { + Walk(f, n.Table) + } + if n.Col != nil { + Walk(f, n.Col) + } + + case *ast.RenameTableStmt: + if n.Table != nil { + Walk(f, n.Table) + } + + case *ast.RenameTypeStmt: + if n.Type != nil { + Walk(f, n.Type) + } + + case *ast.Statement: + if n.Raw != nil { + Walk(f, n.Raw) + } + + case *ast.TODO: + // pass + + case *ast.TableName: + // pass + + case *ast.A_ArrayExpr: + if n.Elements != nil { + Walk(f, n.Elements) + } + + case *ast.A_Const: + if n.Val != nil { + Walk(f, n.Val) + } + + case *ast.A_Expr: + if n.Name != nil { + Walk(f, n.Name) + } + if n.Lexpr != nil { + Walk(f, n.Lexpr) + } + if n.Rexpr != nil { + Walk(f, n.Rexpr) + } + + case *ast.A_Indices: + if n.Lidx != nil { + Walk(f, n.Lidx) + } + if n.Uidx != nil { + Walk(f, n.Uidx) + } + + case *ast.A_Indirection: + if n.Arg != nil { + Walk(f, n.Arg) + } + if n.Indirection != nil { + Walk(f, n.Indirection) + } + + case *ast.A_Star: + // pass + + case *ast.AccessPriv: + if n.Cols != nil { + Walk(f, n.Cols) + } + + case *ast.Aggref: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Aggargtypes != nil { + Walk(f, n.Aggargtypes) + } + if n.Aggdirectargs != nil { + Walk(f, n.Aggdirectargs) + } + if n.Args != nil { + Walk(f, n.Args) + } + if n.Aggorder != nil { + Walk(f, n.Aggorder) + } + if n.Aggdistinct != nil { + Walk(f, n.Aggdistinct) + } + if n.Aggfilter != nil { + Walk(f, n.Aggfilter) + } + + case *ast.Alias: + if n.Colnames != nil { + Walk(f, n.Colnames) + } + + case *ast.AlterCollationStmt: + if n.Collname != nil { + Walk(f, n.Collname) + } + + case *ast.AlterDatabaseSetStmt: + if n.Setstmt != nil { + Walk(f, n.Setstmt) + } + + case *ast.AlterDatabaseStmt: + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.AlterDefaultPrivilegesStmt: + if n.Options != nil { + Walk(f, n.Options) + } + if n.Action != nil { + Walk(f, n.Action) + } + + case *ast.AlterDomainStmt: + if n.TypeName != nil { + Walk(f, n.TypeName) + } + if n.Def != nil { + Walk(f, n.Def) + } + + case *ast.AlterEnumStmt: + if n.TypeName != nil { + Walk(f, n.TypeName) + } + + case *ast.AlterEventTrigStmt: + // pass + + case *ast.AlterExtensionContentsStmt: + if n.Object != nil { + Walk(f, n.Object) + } + + case *ast.AlterExtensionStmt: + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.AlterFdwStmt: + if n.FuncOptions != nil { + Walk(f, n.FuncOptions) + } + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.AlterForeignServerStmt: + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.AlterFunctionStmt: + if n.Func != nil { + Walk(f, n.Func) + } + if n.Actions != nil { + Walk(f, n.Actions) + } + + case *ast.AlterObjectDependsStmt: + if n.Relation != nil { + Walk(f, n.Relation) + } + if n.Object != nil { + Walk(f, n.Object) + } + if n.Extname != nil { + Walk(f, n.Extname) + } + + case *ast.AlterObjectSchemaStmt: + if n.Relation != nil { + Walk(f, n.Relation) + } + if n.Object != nil { + Walk(f, n.Object) + } + + case *ast.AlterOpFamilyStmt: + if n.Opfamilyname != nil { + Walk(f, n.Opfamilyname) + } + if n.Items != nil { + Walk(f, n.Items) + } + + case *ast.AlterOperatorStmt: + if n.Opername != nil { + Walk(f, n.Opername) + } + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.AlterOwnerStmt: + if n.Relation != nil { + Walk(f, n.Relation) + } + if n.Object != nil { + Walk(f, n.Object) + } + if n.Newowner != nil { + Walk(f, n.Newowner) + } + + case *ast.AlterPolicyStmt: + if n.Table != nil { + Walk(f, n.Table) + } + if n.Roles != nil { + Walk(f, n.Roles) + } + if n.Qual != nil { + Walk(f, n.Qual) + } + if n.WithCheck != nil { + Walk(f, n.WithCheck) + } + + case *ast.AlterPublicationStmt: + if n.Options != nil { + Walk(f, n.Options) + } + if n.Tables != nil { + Walk(f, n.Tables) + } + + case *ast.AlterRoleSetStmt: + if n.Role != nil { + Walk(f, n.Role) + } + if n.Setstmt != nil { + Walk(f, n.Setstmt) + } + + case *ast.AlterRoleStmt: + if n.Role != nil { + Walk(f, n.Role) + } + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.AlterSeqStmt: + if n.Sequence != nil { + Walk(f, n.Sequence) + } + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.AlterSubscriptionStmt: + if n.Publication != nil { + Walk(f, n.Publication) + } + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.AlterSystemStmt: + if n.Setstmt != nil { + Walk(f, n.Setstmt) + } + + case *ast.AlterTSConfigurationStmt: + if n.Cfgname != nil { + Walk(f, n.Cfgname) + } + if n.Tokentype != nil { + Walk(f, n.Tokentype) + } + if n.Dicts != nil { + Walk(f, n.Dicts) + } + + case *ast.AlterTSDictionaryStmt: + if n.Dictname != nil { + Walk(f, n.Dictname) + } + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.AlterTableCmd: + if n.Newowner != nil { + Walk(f, n.Newowner) + } + if n.Def != nil { + Walk(f, n.Def) + } + + case *ast.AlterTableMoveAllStmt: + if n.Roles != nil { + Walk(f, n.Roles) + } + + case *ast.AlterTableSpaceOptionsStmt: + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.AlterUserMappingStmt: + if n.User != nil { + Walk(f, n.User) + } + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.AlternativeSubPlan: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Subplans != nil { + Walk(f, n.Subplans) + } + + case *ast.ArrayCoerceExpr: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Arg != nil { + Walk(f, n.Arg) + } + + case *ast.ArrayExpr: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Elements != nil { + Walk(f, n.Elements) + } + + case *ast.ArrayRef: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Refupperindexpr != nil { + Walk(f, n.Refupperindexpr) + } + if n.Reflowerindexpr != nil { + Walk(f, n.Reflowerindexpr) + } + if n.Refexpr != nil { + Walk(f, n.Refexpr) + } + if n.Refassgnexpr != nil { + Walk(f, n.Refassgnexpr) + } + + case *ast.BetweenExpr: + if n.Expr != nil { + Walk(f, n.Expr) + } + if n.Left != nil { + Walk(f, n.Left) + } + if n.Right != nil { + Walk(f, n.Right) + } + + case *ast.BitString: + // pass + + case *ast.BlockIdData: + // pass + + case *ast.BoolExpr: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Args != nil { + Walk(f, n.Args) + } + + case *ast.Boolean: + // pass + + case *ast.BooleanTest: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Arg != nil { + Walk(f, n.Arg) + } + + case *ast.CallStmt: + if n.FuncCall != nil { + Walk(f, n.FuncCall) + } + + case *ast.CaseExpr: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Arg != nil { + Walk(f, n.Arg) + } + if n.Args != nil { + Walk(f, n.Args) + } + if n.Defresult != nil { + Walk(f, n.Defresult) + } + + case *ast.CaseTestExpr: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + + case *ast.CaseWhen: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Expr != nil { + Walk(f, n.Expr) + } + if n.Result != nil { + Walk(f, n.Result) + } + + case *ast.CheckPointStmt: + // pass + + case *ast.ClosePortalStmt: + // pass + + case *ast.ClusterStmt: + if n.Relation != nil { + Walk(f, n.Relation) + } + + case *ast.CoalesceExpr: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Args != nil { + Walk(f, n.Args) + } + + case *ast.CoerceToDomain: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Arg != nil { + Walk(f, n.Arg) + } + + case *ast.CoerceToDomainValue: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + + case *ast.CoerceViaIO: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Arg != nil { + Walk(f, n.Arg) + } + + case *ast.CollateClause: + if n.Arg != nil { + Walk(f, n.Arg) + } + if n.Collname != nil { + Walk(f, n.Collname) + } + + case *ast.CollateExpr: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Arg != nil { + Walk(f, n.Arg) + } + + case *ast.ColumnDef: + if n.TypeName != nil { + Walk(f, n.TypeName) + } + if n.RawDefault != nil { + Walk(f, n.RawDefault) + } + if n.CookedDefault != nil { + Walk(f, n.CookedDefault) + } + if n.CollClause != nil { + Walk(f, n.CollClause) + } + if n.Constraints != nil { + Walk(f, n.Constraints) + } + if n.Fdwoptions != nil { + Walk(f, n.Fdwoptions) + } + + case *ast.ColumnRef: + if n.Fields != nil { + Walk(f, n.Fields) + } + + case *ast.CommentStmt: + if n.Object != nil { + Walk(f, n.Object) + } + + case *ast.CommonTableExpr: + if n.Aliascolnames != nil { + Walk(f, n.Aliascolnames) + } + if n.Ctequery != nil { + Walk(f, n.Ctequery) + } + if n.Ctecolnames != nil { + Walk(f, n.Ctecolnames) + } + if n.Ctecoltypes != nil { + Walk(f, n.Ctecoltypes) + } + if n.Ctecoltypmods != nil { + Walk(f, n.Ctecoltypmods) + } + if n.Ctecolcollations != nil { + Walk(f, n.Ctecolcollations) + } + + case *ast.Const: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + + case *ast.Constraint: + if n.RawExpr != nil { + Walk(f, n.RawExpr) + } + if n.Keys != nil { + Walk(f, n.Keys) + } + if n.Exclusions != nil { + Walk(f, n.Exclusions) + } + if n.Options != nil { + Walk(f, n.Options) + } + if n.WhereClause != nil { + Walk(f, n.WhereClause) + } + if n.Pktable != nil { + Walk(f, n.Pktable) + } + if n.FkAttrs != nil { + Walk(f, n.FkAttrs) + } + if n.PkAttrs != nil { + Walk(f, n.PkAttrs) + } + if n.OldConpfeqop != nil { + Walk(f, n.OldConpfeqop) + } + + case *ast.ConstraintsSetStmt: + if n.Constraints != nil { + Walk(f, n.Constraints) + } + + case *ast.ConvertRowtypeExpr: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Arg != nil { + Walk(f, n.Arg) + } + + case *ast.CopyStmt: + if n.Relation != nil { + Walk(f, n.Relation) + } + if n.Query != nil { + Walk(f, n.Query) + } + if n.Attlist != nil { + Walk(f, n.Attlist) + } + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.CreateAmStmt: + if n.HandlerName != nil { + Walk(f, n.HandlerName) + } + + case *ast.CreateCastStmt: + if n.Sourcetype != nil { + Walk(f, n.Sourcetype) + } + if n.Targettype != nil { + Walk(f, n.Targettype) + } + if n.Func != nil { + Walk(f, n.Func) + } + + case *ast.CreateConversionStmt: + if n.ConversionName != nil { + Walk(f, n.ConversionName) + } + if n.FuncName != nil { + Walk(f, n.FuncName) + } + + case *ast.CreateDomainStmt: + if n.Domainname != nil { + Walk(f, n.Domainname) + } + if n.TypeName != nil { + Walk(f, n.TypeName) + } + if n.CollClause != nil { + Walk(f, n.CollClause) + } + if n.Constraints != nil { + Walk(f, n.Constraints) + } + + case *ast.CreateEnumStmt: + if n.TypeName != nil { + Walk(f, n.TypeName) + } + if n.Vals != nil { + Walk(f, n.Vals) + } + + case *ast.CreateEventTrigStmt: + if n.Whenclause != nil { + Walk(f, n.Whenclause) + } + if n.Funcname != nil { + Walk(f, n.Funcname) + } + + case *ast.CreateExtensionStmt: + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.CreateFdwStmt: + if n.FuncOptions != nil { + Walk(f, n.FuncOptions) + } + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.CreateForeignServerStmt: + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.CreateForeignTableStmt: + if n.Base != nil { + Walk(f, n.Base) + } + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.CreateFunctionStmt: + if n.Func != nil { + Walk(f, n.Func) + } + if n.Params != nil { + Walk(f, n.Params) + } + if n.ReturnType != nil { + Walk(f, n.ReturnType) + } + if n.Options != nil { + Walk(f, n.Options) + } + if n.WithClause != nil { + Walk(f, n.WithClause) + } + + case *ast.CreateOpClassItem: + if n.Name != nil { + Walk(f, n.Name) + } + if n.OrderFamily != nil { + Walk(f, n.OrderFamily) + } + if n.ClassArgs != nil { + Walk(f, n.ClassArgs) + } + if n.Storedtype != nil { + Walk(f, n.Storedtype) + } + + case *ast.CreateOpClassStmt: + if n.Opclassname != nil { + Walk(f, n.Opclassname) + } + if n.Opfamilyname != nil { + Walk(f, n.Opfamilyname) + } + if n.Datatype != nil { + Walk(f, n.Datatype) + } + if n.Items != nil { + Walk(f, n.Items) + } + + case *ast.CreateOpFamilyStmt: + if n.Opfamilyname != nil { + Walk(f, n.Opfamilyname) + } + + case *ast.CreatePLangStmt: + if n.Plhandler != nil { + Walk(f, n.Plhandler) + } + if n.Plinline != nil { + Walk(f, n.Plinline) + } + if n.Plvalidator != nil { + Walk(f, n.Plvalidator) + } + + case *ast.CreatePolicyStmt: + if n.Table != nil { + Walk(f, n.Table) + } + if n.Roles != nil { + Walk(f, n.Roles) + } + if n.Qual != nil { + Walk(f, n.Qual) + } + if n.WithCheck != nil { + Walk(f, n.WithCheck) + } + + case *ast.CreatePublicationStmt: + if n.Options != nil { + Walk(f, n.Options) + } + if n.Tables != nil { + Walk(f, n.Tables) + } + + case *ast.CreateRangeStmt: + if n.TypeName != nil { + Walk(f, n.TypeName) + } + if n.Params != nil { + Walk(f, n.Params) + } + + case *ast.CreateRoleStmt: + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.CreateSchemaStmt: + if n.Authrole != nil { + Walk(f, n.Authrole) + } + if n.SchemaElts != nil { + Walk(f, n.SchemaElts) + } + + case *ast.CreateSeqStmt: + if n.Sequence != nil { + Walk(f, n.Sequence) + } + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.CreateStatsStmt: + if n.Defnames != nil { + Walk(f, n.Defnames) + } + if n.StatTypes != nil { + Walk(f, n.StatTypes) + } + if n.Exprs != nil { + Walk(f, n.Exprs) + } + if n.Relations != nil { + Walk(f, n.Relations) + } + + case *ast.CreateStmt: + if n.Relation != nil { + Walk(f, n.Relation) + } + if n.TableElts != nil { + Walk(f, n.TableElts) + } + if n.InhRelations != nil { + Walk(f, n.InhRelations) + } + if n.Partbound != nil { + Walk(f, n.Partbound) + } + if n.Partspec != nil { + Walk(f, n.Partspec) + } + if n.OfTypename != nil { + Walk(f, n.OfTypename) + } + if n.Constraints != nil { + Walk(f, n.Constraints) + } + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.CreateSubscriptionStmt: + if n.Publication != nil { + Walk(f, n.Publication) + } + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.CreateTableAsStmt: + if n.Query != nil { + Walk(f, n.Query) + } + if n.Into != nil { + Walk(f, n.Into) + } + + case *ast.CreateTableSpaceStmt: + if n.Owner != nil { + Walk(f, n.Owner) + } + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.CreateTransformStmt: + if n.TypeName != nil { + Walk(f, n.TypeName) + } + if n.Fromsql != nil { + Walk(f, n.Fromsql) + } + if n.Tosql != nil { + Walk(f, n.Tosql) + } + + case *ast.CreateTrigStmt: + if n.Relation != nil { + Walk(f, n.Relation) + } + if n.Funcname != nil { + Walk(f, n.Funcname) + } + if n.Args != nil { + Walk(f, n.Args) + } + if n.Columns != nil { + Walk(f, n.Columns) + } + if n.WhenClause != nil { + Walk(f, n.WhenClause) + } + if n.TransitionRels != nil { + Walk(f, n.TransitionRels) + } + if n.Constrrel != nil { + Walk(f, n.Constrrel) + } + + case *ast.CreateUserMappingStmt: + if n.User != nil { + Walk(f, n.User) + } + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.CreatedbStmt: + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.CurrentOfExpr: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + + case *ast.DeallocateStmt: + // pass + + case *ast.DeclareCursorStmt: + if n.Query != nil { + Walk(f, n.Query) + } + + case *ast.DefElem: + if n.Arg != nil { + Walk(f, n.Arg) + } + + case *ast.DefineStmt: + if n.Defnames != nil { + Walk(f, n.Defnames) + } + if n.Args != nil { + Walk(f, n.Args) + } + if n.Definition != nil { + Walk(f, n.Definition) + } + + case *ast.DeleteStmt: + if n.Relations != nil { + Walk(f, n.Relations) + } + if n.UsingClause != nil { + Walk(f, n.UsingClause) + } + if n.WhereClause != nil { + Walk(f, n.WhereClause) + } + if n.LimitCount != nil { + Walk(f, n.LimitCount) + } + if n.ReturningList != nil { + Walk(f, n.ReturningList) + } + if n.WithClause != nil { + Walk(f, n.WithClause) + } + if n.Targets != nil { + Walk(f, n.Targets) + } + if n.FromClause != nil { + Walk(f, n.FromClause) + } + + case *ast.DiscardStmt: + // pass + + case *ast.DoStmt: + if n.Args != nil { + Walk(f, n.Args) + } + + case *ast.DropOwnedStmt: + if n.Roles != nil { + Walk(f, n.Roles) + } + + case *ast.DropRoleStmt: + if n.Roles != nil { + Walk(f, n.Roles) + } + + case *ast.DropStmt: + if n.Objects != nil { + Walk(f, n.Objects) + } + + case *ast.DropSubscriptionStmt: + // pass + + case *ast.DropTableSpaceStmt: + // pass + + case *ast.DropUserMappingStmt: + if n.User != nil { + Walk(f, n.User) + } + + case *ast.DropdbStmt: + // pass + + case *ast.ExecuteStmt: + if n.Params != nil { + Walk(f, n.Params) + } + + case *ast.ExplainStmt: + if n.Query != nil { + Walk(f, n.Query) + } + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.Expr: + // pass + + case *ast.FetchStmt: + // pass + + case *ast.FieldSelect: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Arg != nil { + Walk(f, n.Arg) + } + + case *ast.FieldStore: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Arg != nil { + Walk(f, n.Arg) + } + if n.Newvals != nil { + Walk(f, n.Newvals) + } + if n.Fieldnums != nil { + Walk(f, n.Fieldnums) + } + + case *ast.Float: + // pass + + case *ast.FromExpr: + if n.Fromlist != nil { + Walk(f, n.Fromlist) + } + if n.Quals != nil { + Walk(f, n.Quals) + } + + case *ast.FuncCall: + if n.Func != nil { + Walk(f, n.Func) + } + if n.Funcname != nil { + Walk(f, n.Funcname) + } + if n.Args != nil { + Walk(f, n.Args) + } + if n.AggOrder != nil { + Walk(f, n.AggOrder) + } + if n.AggFilter != nil { + Walk(f, n.AggFilter) + } + if n.Over != nil { + Walk(f, n.Over) + } + + case *ast.FuncExpr: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Args != nil { + Walk(f, n.Args) + } + + case *ast.FunctionParameter: + if n.ArgType != nil { + Walk(f, n.ArgType) + } + if n.Defexpr != nil { + Walk(f, n.Defexpr) + } + + case *ast.GrantRoleStmt: + if n.GrantedRoles != nil { + Walk(f, n.GrantedRoles) + } + if n.GranteeRoles != nil { + Walk(f, n.GranteeRoles) + } + if n.Grantor != nil { + Walk(f, n.Grantor) + } + + case *ast.GrantStmt: + if n.Objects != nil { + Walk(f, n.Objects) + } + if n.Privileges != nil { + Walk(f, n.Privileges) + } + if n.Grantees != nil { + Walk(f, n.Grantees) + } + + case *ast.GroupingFunc: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Args != nil { + Walk(f, n.Args) + } + if n.Refs != nil { + Walk(f, n.Refs) + } + if n.Cols != nil { + Walk(f, n.Cols) + } + + case *ast.GroupingSet: + if n.Content != nil { + Walk(f, n.Content) + } + + case *ast.ImportForeignSchemaStmt: + if n.TableList != nil { + Walk(f, n.TableList) + } + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.IndexElem: + if n.Expr != nil { + Walk(f, n.Expr) + } + if n.Collation != nil { + Walk(f, n.Collation) + } + if n.Opclass != nil { + Walk(f, n.Opclass) + } + + case *ast.IndexStmt: + if n.Relation != nil { + Walk(f, n.Relation) + } + if n.IndexParams != nil { + Walk(f, n.IndexParams) + } + if n.Options != nil { + Walk(f, n.Options) + } + if n.WhereClause != nil { + Walk(f, n.WhereClause) + } + if n.ExcludeOpNames != nil { + Walk(f, n.ExcludeOpNames) + } + + case *ast.InferClause: + if n.IndexElems != nil { + Walk(f, n.IndexElems) + } + if n.WhereClause != nil { + Walk(f, n.WhereClause) + } + + case *ast.InferenceElem: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Expr != nil { + Walk(f, n.Expr) + } + + case *ast.InlineCodeBlock: + // pass + + case *ast.InsertStmt: + if n.Relation != nil { + Walk(f, n.Relation) + } + if n.Cols != nil { + Walk(f, n.Cols) + } + if n.SelectStmt != nil { + Walk(f, n.SelectStmt) + } + if n.OnConflictClause != nil { + Walk(f, n.OnConflictClause) + } + if n.OnDuplicateKeyUpdate != nil { + Walk(f, n.OnDuplicateKeyUpdate) + } + if n.ReturningList != nil { + Walk(f, n.ReturningList) + } + if n.WithClause != nil { + Walk(f, n.WithClause) + } + + case *ast.Integer: + // pass + + case *ast.IntoClause: + if n.Rel != nil { + Walk(f, n.Rel) + } + if n.ColNames != nil { + Walk(f, n.ColNames) + } + if n.Options != nil { + Walk(f, n.Options) + } + if n.ViewQuery != nil { + Walk(f, n.ViewQuery) + } + + case *ast.IntervalExpr: + if n.Value != nil { + Walk(f, n.Value) + } + + case *ast.JoinExpr: + if n.Larg != nil { + Walk(f, n.Larg) + } + if n.Rarg != nil { + Walk(f, n.Rarg) + } + if n.UsingClause != nil { + Walk(f, n.UsingClause) + } + if n.Quals != nil { + Walk(f, n.Quals) + } + if n.Alias != nil { + Walk(f, n.Alias) + } + + case *ast.ListenStmt: + // pass + + case *ast.LoadStmt: + // pass + + case *ast.LockStmt: + if n.Relations != nil { + Walk(f, n.Relations) + } + + case *ast.LockingClause: + if n.LockedRels != nil { + Walk(f, n.LockedRels) + } + + case *ast.MinMaxExpr: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Args != nil { + Walk(f, n.Args) + } + + case *ast.MultiAssignRef: + if n.Source != nil { + Walk(f, n.Source) + } + + case *ast.NamedArgExpr: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Arg != nil { + Walk(f, n.Arg) + } + + case *ast.NextValueExpr: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + + case *ast.NotifyStmt: + // pass + + case *ast.Null: + // pass + + case *ast.NullTest: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Arg != nil { + Walk(f, n.Arg) + } + + case *ast.ObjectWithArgs: + if n.Objname != nil { + Walk(f, n.Objname) + } + if n.Objargs != nil { + Walk(f, n.Objargs) + } + + case *ast.OnConflictClause: + if n.Infer != nil { + Walk(f, n.Infer) + } + if n.TargetList != nil { + Walk(f, n.TargetList) + } + if n.WhereClause != nil { + Walk(f, n.WhereClause) + } + + case *ast.OnConflictExpr: + if n.ArbiterElems != nil { + Walk(f, n.ArbiterElems) + } + if n.ArbiterWhere != nil { + Walk(f, n.ArbiterWhere) + } + if n.OnConflictSet != nil { + Walk(f, n.OnConflictSet) + } + if n.OnConflictWhere != nil { + Walk(f, n.OnConflictWhere) + } + if n.ExclRelTlist != nil { + Walk(f, n.ExclRelTlist) + } + + case *ast.OnDuplicateKeyUpdate: + if n.TargetList != nil { + Walk(f, n.TargetList) + } + + case *ast.OpExpr: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Args != nil { + Walk(f, n.Args) + } + + case *ast.Param: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + + case *ast.ParamExecData: + // pass + + case *ast.ParamExternData: + // pass + + case *ast.ParamListInfoData: + // pass + + case *ast.ParamRef: + // pass + + case *ast.ParenExpr: + if n.Expr != nil { + Walk(f, n.Expr) + } + + case *ast.VariableExpr: + // Leaf node - no children to traverse + + case *ast.PartitionBoundSpec: + if n.Listdatums != nil { + Walk(f, n.Listdatums) + } + if n.Lowerdatums != nil { + Walk(f, n.Lowerdatums) + } + if n.Upperdatums != nil { + Walk(f, n.Upperdatums) + } + + case *ast.PartitionCmd: + if n.Name != nil { + Walk(f, n.Name) + } + if n.Bound != nil { + Walk(f, n.Bound) + } + + case *ast.PartitionElem: + if n.Expr != nil { + Walk(f, n.Expr) + } + if n.Collation != nil { + Walk(f, n.Collation) + } + if n.Opclass != nil { + Walk(f, n.Opclass) + } + + case *ast.PartitionRangeDatum: + if n.Value != nil { + Walk(f, n.Value) + } + + case *ast.PartitionSpec: + if n.PartParams != nil { + Walk(f, n.PartParams) + } + + case *ast.PrepareStmt: + if n.Argtypes != nil { + Walk(f, n.Argtypes) + } + if n.Query != nil { + Walk(f, n.Query) + } + + case *ast.Query: + if n.UtilityStmt != nil { + Walk(f, n.UtilityStmt) + } + if n.CteList != nil { + Walk(f, n.CteList) + } + if n.Rtable != nil { + Walk(f, n.Rtable) + } + if n.Jointree != nil { + Walk(f, n.Jointree) + } + if n.TargetList != nil { + Walk(f, n.TargetList) + } + if n.OnConflict != nil { + Walk(f, n.OnConflict) + } + if n.ReturningList != nil { + Walk(f, n.ReturningList) + } + if n.GroupClause != nil { + Walk(f, n.GroupClause) + } + if n.GroupingSets != nil { + Walk(f, n.GroupingSets) + } + if n.HavingQual != nil { + Walk(f, n.HavingQual) + } + if n.WindowClause != nil { + Walk(f, n.WindowClause) + } + if n.DistinctClause != nil { + Walk(f, n.DistinctClause) + } + if n.SortClause != nil { + Walk(f, n.SortClause) + } + if n.LimitOffset != nil { + Walk(f, n.LimitOffset) + } + if n.LimitCount != nil { + Walk(f, n.LimitCount) + } + if n.RowMarks != nil { + Walk(f, n.RowMarks) + } + if n.SetOperations != nil { + Walk(f, n.SetOperations) + } + if n.ConstraintDeps != nil { + Walk(f, n.ConstraintDeps) + } + if n.WithCheckOptions != nil { + Walk(f, n.WithCheckOptions) + } + + case *ast.RangeFunction: + if n.Functions != nil { + Walk(f, n.Functions) + } + if n.Alias != nil { + Walk(f, n.Alias) + } + if n.Coldeflist != nil { + Walk(f, n.Coldeflist) + } + + case *ast.RangeSubselect: + if n.Subquery != nil { + Walk(f, n.Subquery) + } + if n.Alias != nil { + Walk(f, n.Alias) + } + + case *ast.RangeTableFunc: + if n.Docexpr != nil { + Walk(f, n.Docexpr) + } + if n.Rowexpr != nil { + Walk(f, n.Rowexpr) + } + if n.Namespaces != nil { + Walk(f, n.Namespaces) + } + if n.Columns != nil { + Walk(f, n.Columns) + } + if n.Alias != nil { + Walk(f, n.Alias) + } + + case *ast.RangeTableFuncCol: + if n.TypeName != nil { + Walk(f, n.TypeName) + } + if n.Colexpr != nil { + Walk(f, n.Colexpr) + } + if n.Coldefexpr != nil { + Walk(f, n.Coldefexpr) + } + + case *ast.RangeTableSample: + if n.Relation != nil { + Walk(f, n.Relation) + } + if n.Method != nil { + Walk(f, n.Method) + } + if n.Args != nil { + Walk(f, n.Args) + } + if n.Repeatable != nil { + Walk(f, n.Repeatable) + } + + case *ast.RangeTblEntry: + if n.Tablesample != nil { + Walk(f, n.Tablesample) + } + if n.Subquery != nil { + Walk(f, n.Subquery) + } + if n.Joinaliasvars != nil { + Walk(f, n.Joinaliasvars) + } + if n.Functions != nil { + Walk(f, n.Functions) + } + if n.Tablefunc != nil { + Walk(f, n.Tablefunc) + } + if n.ValuesLists != nil { + Walk(f, n.ValuesLists) + } + if n.Coltypes != nil { + Walk(f, n.Coltypes) + } + if n.Coltypmods != nil { + Walk(f, n.Coltypmods) + } + if n.Colcollations != nil { + Walk(f, n.Colcollations) + } + if n.Alias != nil { + Walk(f, n.Alias) + } + if n.Eref != nil { + Walk(f, n.Eref) + } + if n.SecurityQuals != nil { + Walk(f, n.SecurityQuals) + } + + case *ast.RangeTblFunction: + if n.Funcexpr != nil { + Walk(f, n.Funcexpr) + } + if n.Funccolnames != nil { + Walk(f, n.Funccolnames) + } + if n.Funccoltypes != nil { + Walk(f, n.Funccoltypes) + } + if n.Funccoltypmods != nil { + Walk(f, n.Funccoltypmods) + } + if n.Funccolcollations != nil { + Walk(f, n.Funccolcollations) + } + + case *ast.RangeTblRef: + // pass + + case *ast.RangeVar: + if n.Alias != nil { + Walk(f, n.Alias) + } + + case *ast.RawStmt: + if n.Stmt != nil { + Walk(f, n.Stmt) + } + + case *ast.ReassignOwnedStmt: + if n.Roles != nil { + Walk(f, n.Roles) + } + if n.Newrole != nil { + Walk(f, n.Newrole) + } + + case *ast.RefreshMatViewStmt: + if n.Relation != nil { + Walk(f, n.Relation) + } + + case *ast.ReindexStmt: + if n.Relation != nil { + Walk(f, n.Relation) + } + + case *ast.RelabelType: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Arg != nil { + Walk(f, n.Arg) + } + + case *ast.RenameStmt: + if n.Relation != nil { + Walk(f, n.Relation) + } + if n.Object != nil { + Walk(f, n.Object) + } + + case *ast.ReplicaIdentityStmt: + // pass + + case *ast.ResTarget: + if n.Indirection != nil { + Walk(f, n.Indirection) + } + if n.Val != nil { + Walk(f, n.Val) + } + + case *ast.RoleSpec: + // pass + + case *ast.RowCompareExpr: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Opnos != nil { + Walk(f, n.Opnos) + } + if n.Opfamilies != nil { + Walk(f, n.Opfamilies) + } + if n.Inputcollids != nil { + Walk(f, n.Inputcollids) + } + if n.Largs != nil { + Walk(f, n.Largs) + } + if n.Rargs != nil { + Walk(f, n.Rargs) + } + + case *ast.RowExpr: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Args != nil { + Walk(f, n.Args) + } + if n.Colnames != nil { + Walk(f, n.Colnames) + } + + case *ast.RowMarkClause: + // pass + + case *ast.RuleStmt: + if n.Relation != nil { + Walk(f, n.Relation) + } + if n.WhereClause != nil { + Walk(f, n.WhereClause) + } + if n.Actions != nil { + Walk(f, n.Actions) + } + + case *ast.SQLValueFunction: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + + case *ast.ScalarArrayOpExpr: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Args != nil { + Walk(f, n.Args) + } + + case *ast.SecLabelStmt: + if n.Object != nil { + Walk(f, n.Object) + } + + case *ast.SelectStmt: + if n.DistinctClause != nil { + Walk(f, n.DistinctClause) + } + if n.IntoClause != nil { + Walk(f, n.IntoClause) + } + if n.TargetList != nil { + Walk(f, n.TargetList) + } + if n.FromClause != nil { + Walk(f, n.FromClause) + } + if n.WhereClause != nil { + Walk(f, n.WhereClause) + } + if n.GroupClause != nil { + Walk(f, n.GroupClause) + } + if n.HavingClause != nil { + Walk(f, n.HavingClause) + } + if n.WindowClause != nil { + Walk(f, n.WindowClause) + } + if n.ValuesLists != nil { + Walk(f, n.ValuesLists) + } + if n.SortClause != nil { + Walk(f, n.SortClause) + } + if n.LimitOffset != nil { + Walk(f, n.LimitOffset) + } + if n.LimitCount != nil { + Walk(f, n.LimitCount) + } + if n.LockingClause != nil { + Walk(f, n.LockingClause) + } + if n.WithClause != nil { + Walk(f, n.WithClause) + } + if n.Larg != nil { + Walk(f, n.Larg) + } + if n.Rarg != nil { + Walk(f, n.Rarg) + } + + case *ast.SetOperationStmt: + if n.Larg != nil { + Walk(f, n.Larg) + } + if n.Rarg != nil { + Walk(f, n.Rarg) + } + if n.ColTypes != nil { + Walk(f, n.ColTypes) + } + if n.ColTypmods != nil { + Walk(f, n.ColTypmods) + } + if n.ColCollations != nil { + Walk(f, n.ColCollations) + } + if n.GroupClauses != nil { + Walk(f, n.GroupClauses) + } + + case *ast.SetToDefault: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + + case *ast.SortBy: + if n.Node != nil { + Walk(f, n.Node) + } + if n.UseOp != nil { + Walk(f, n.UseOp) + } + + case *ast.SortGroupClause: + // pass + + case *ast.String: + // pass + + case *ast.SubLink: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Testexpr != nil { + Walk(f, n.Testexpr) + } + if n.OperName != nil { + Walk(f, n.OperName) + } + if n.Subselect != nil { + Walk(f, n.Subselect) + } + + case *ast.SubPlan: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Testexpr != nil { + Walk(f, n.Testexpr) + } + if n.ParamIds != nil { + Walk(f, n.ParamIds) + } + if n.SetParam != nil { + Walk(f, n.SetParam) + } + if n.ParParam != nil { + Walk(f, n.ParParam) + } + if n.Args != nil { + Walk(f, n.Args) + } + + case *ast.TableFunc: + if n.NsUris != nil { + Walk(f, n.NsUris) + } + if n.NsNames != nil { + Walk(f, n.NsNames) + } + if n.Docexpr != nil { + Walk(f, n.Docexpr) + } + if n.Rowexpr != nil { + Walk(f, n.Rowexpr) + } + if n.Colnames != nil { + Walk(f, n.Colnames) + } + if n.Coltypes != nil { + Walk(f, n.Coltypes) + } + if n.Coltypmods != nil { + Walk(f, n.Coltypmods) + } + if n.Colcollations != nil { + Walk(f, n.Colcollations) + } + if n.Colexprs != nil { + Walk(f, n.Colexprs) + } + if n.Coldefexprs != nil { + Walk(f, n.Coldefexprs) + } + + case *ast.TableLikeClause: + if n.Relation != nil { + Walk(f, n.Relation) + } + + case *ast.TableSampleClause: + if n.Args != nil { + Walk(f, n.Args) + } + if n.Repeatable != nil { + Walk(f, n.Repeatable) + } + + case *ast.TargetEntry: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Expr != nil { + Walk(f, n.Expr) + } + + case *ast.TransactionStmt: + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.TriggerTransition: + // pass + + case *ast.TruncateStmt: + if n.Relations != nil { + Walk(f, n.Relations) + } + + case *ast.TypeCast: + if n.Arg != nil { + Walk(f, n.Arg) + } + if n.TypeName != nil { + Walk(f, n.TypeName) + } + + case *ast.TypeName: + if n.Names != nil { + Walk(f, n.Names) + } + if n.Typmods != nil { + Walk(f, n.Typmods) + } + if n.ArrayBounds != nil { + Walk(f, n.ArrayBounds) + } + + case *ast.UnlistenStmt: + // pass + + case *ast.UpdateStmt: + if n.Relations != nil { + Walk(f, n.Relations) + } + if n.TargetList != nil { + Walk(f, n.TargetList) + } + if n.WhereClause != nil { + Walk(f, n.WhereClause) + } + if n.FromClause != nil { + Walk(f, n.FromClause) + } + if n.LimitCount != nil { + Walk(f, n.LimitCount) + } + if n.ReturningList != nil { + Walk(f, n.ReturningList) + } + if n.WithClause != nil { + Walk(f, n.WithClause) + } + + case *ast.VacuumStmt: + if n.Relation != nil { + Walk(f, n.Relation) + } + if n.VaCols != nil { + Walk(f, n.VaCols) + } + + case *ast.Var: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + + case *ast.VariableSetStmt: + if n.Args != nil { + Walk(f, n.Args) + } + + case *ast.VariableShowStmt: + // pass + + case *ast.ViewStmt: + if n.View != nil { + Walk(f, n.View) + } + if n.Aliases != nil { + Walk(f, n.Aliases) + } + if n.Query != nil { + Walk(f, n.Query) + } + if n.Options != nil { + Walk(f, n.Options) + } + + case *ast.WindowClause: + if n.PartitionClause != nil { + Walk(f, n.PartitionClause) + } + if n.OrderClause != nil { + Walk(f, n.OrderClause) + } + if n.StartOffset != nil { + Walk(f, n.StartOffset) + } + if n.EndOffset != nil { + Walk(f, n.EndOffset) + } + + case *ast.WindowDef: + if n.PartitionClause != nil { + Walk(f, n.PartitionClause) + } + if n.OrderClause != nil { + Walk(f, n.OrderClause) + } + if n.StartOffset != nil { + Walk(f, n.StartOffset) + } + if n.EndOffset != nil { + Walk(f, n.EndOffset) + } + + case *ast.WindowFunc: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.Args != nil { + Walk(f, n.Args) + } + if n.Aggfilter != nil { + Walk(f, n.Aggfilter) + } + + case *ast.WithCheckOption: + if n.Qual != nil { + Walk(f, n.Qual) + } + + case *ast.WithClause: + if n.Ctes != nil { + Walk(f, n.Ctes) + } + + case *ast.XmlExpr: + if n.Xpr != nil { + Walk(f, n.Xpr) + } + if n.NamedArgs != nil { + Walk(f, n.NamedArgs) + } + if n.ArgNames != nil { + Walk(f, n.ArgNames) + } + if n.Args != nil { + Walk(f, n.Args) + } + + case *ast.XmlSerialize: + if n.Expr != nil { + Walk(f, n.Expr) + } + if n.TypeName != nil { + Walk(f, n.TypeName) + } + + case *ast.In: + for _, l := range n.List { + Walk(f, l) + } + if n.Sel != nil { + Walk(f, n.Sel) + } + + default: + panic(fmt.Sprintf("walk: unexpected node type %T", n)) + } + + f.Visit(nil) +} diff --git a/internal/sql/catalog/catalog.go b/internal/sql/catalog/catalog.go new file mode 100644 index 0000000..278ea87 --- /dev/null +++ b/internal/sql/catalog/catalog.go @@ -0,0 +1,142 @@ +package catalog + +import ( + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +// Catalog describes a database instance consisting of metadata in which database objects are defined +type Catalog struct { + Comment string + DefaultSchema string + Name string + Schemas []*Schema + SearchPath []string + LoadExtension func(string) *Schema + + // TODO: un-export + Extensions map[string]struct{} +} + +// New creates a new catalog +func New(defaultSchema string) *Catalog { + + newCatalog := &Catalog{ + DefaultSchema: defaultSchema, + Schemas: make([]*Schema, 0), + Extensions: make(map[string]struct{}), + } + + if newCatalog.DefaultSchema != "" { + newCatalog.Schemas = append(newCatalog.Schemas, &Schema{Name: defaultSchema}) + } + + return newCatalog +} + +func (c *Catalog) Build(stmts []ast.Statement) error { + for i := range stmts { + if err := c.Update(stmts[i], nil); err != nil { + return err + } + } + return nil +} + +func (c *Catalog) Update(stmt ast.Statement, colGen columnGenerator) error { + if stmt.Raw == nil { + return nil + } + var err error + switch n := stmt.Raw.Stmt.(type) { + + case *ast.AlterTableStmt: + err = c.alterTable(n) + + case *ast.AlterTableSetSchemaStmt: + err = c.alterTableSetSchema(n) + + case *ast.AlterTypeAddValueStmt: + err = c.alterTypeAddValue(n) + + case *ast.AlterTypeRenameValueStmt: + err = c.alterTypeRenameValue(n) + + case *ast.AlterTypeSetSchemaStmt: + err = c.alterTypeSetSchema(n) + + case *ast.CommentOnColumnStmt: + err = c.commentOnColumn(n) + + case *ast.CommentOnSchemaStmt: + err = c.commentOnSchema(n) + + case *ast.CommentOnTableStmt: + err = c.commentOnTable(n) + + case *ast.CommentOnTypeStmt: + err = c.commentOnType(n) + + case *ast.CommentOnViewStmt: + err = c.commentOnView(n) + + case *ast.CompositeTypeStmt: + err = c.createCompositeType(n) + + case *ast.CreateEnumStmt: + err = c.createEnum(n) + + case *ast.CreateExtensionStmt: + err = c.createExtension(n) + + case *ast.CreateFunctionStmt: + err = c.createFunction(n) + + case *ast.CreateSchemaStmt: + err = c.createSchema(n) + + case *ast.CreateTableStmt: + err = c.createTable(n) + + case *ast.CreateTableAsStmt: + err = c.createTableAs(n, colGen) + + case *ast.ViewStmt: + err = c.createView(n, colGen) + + case *ast.DropFunctionStmt: + err = c.dropFunction(n) + + case *ast.DropSchemaStmt: + err = c.dropSchema(n) + + case *ast.DropTableStmt: + err = c.dropTable(n) + + case *ast.DropTypeStmt: + err = c.dropType(n) + + case *ast.RenameColumnStmt: + err = c.renameColumn(n) + + case *ast.RenameTableStmt: + err = c.renameTable(n) + + case *ast.RenameTypeStmt: + err = c.renameType(n) + + case *ast.List: + for _, nn := range n.Items { + if err = c.Update(ast.Statement{ + Raw: &ast.RawStmt{ + Stmt: nn, + StmtLocation: stmt.Raw.StmtLocation, + StmtLen: stmt.Raw.StmtLen, + }, + }, colGen); err != nil { + return err + } + } + + } + return err +} diff --git a/internal/sql/catalog/comment_on.go b/internal/sql/catalog/comment_on.go new file mode 100644 index 0000000..49c7144 --- /dev/null +++ b/internal/sql/catalog/comment_on.go @@ -0,0 +1,76 @@ +package catalog + +import ( + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/sqlerr" +) + +func (c *Catalog) commentOnColumn(stmt *ast.CommentOnColumnStmt) error { + _, t, err := c.getTable(stmt.Table) + if err != nil { + return err + } + for i := range t.Columns { + if t.Columns[i].Name == stmt.Col.Name { + if stmt.Comment != nil { + t.Columns[i].Comment = *stmt.Comment + } else { + t.Columns[i].Comment = "" + } + return nil + } + } + return sqlerr.ColumnNotFound(stmt.Table.Name, stmt.Col.Name) +} + +func (c *Catalog) commentOnSchema(stmt *ast.CommentOnSchemaStmt) error { + s, err := c.getSchema(stmt.Schema.Str) + if err != nil { + return err + } + if stmt.Comment != nil { + s.Comment = *stmt.Comment + } else { + s.Comment = "" + } + return nil +} + +func (c *Catalog) commentOnTable(stmt *ast.CommentOnTableStmt) error { + _, t, err := c.getTable(stmt.Table) + if err != nil { + return err + } + if stmt.Comment != nil { + t.Comment = *stmt.Comment + } else { + t.Comment = "" + } + return nil +} + +func (c *Catalog) commentOnType(stmt *ast.CommentOnTypeStmt) error { + t, _, err := c.getType(stmt.Type) + if err != nil { + return err + } + if stmt.Comment != nil { + t.SetComment(*stmt.Comment) + } else { + t.SetComment("") + } + return nil +} + +func (c *Catalog) commentOnView(stmt *ast.CommentOnViewStmt) error { + _, t, err := c.getTable(stmt.View) + if err != nil { + return err + } + if stmt.Comment != nil { + t.Comment = *stmt.Comment + } else { + t.Comment = "" + } + return nil +} diff --git a/internal/sql/catalog/extension.go b/internal/sql/catalog/extension.go new file mode 100644 index 0000000..268bf01 --- /dev/null +++ b/internal/sql/catalog/extension.go @@ -0,0 +1,41 @@ +package catalog + +import ( + "github.com/sqlc-dev/sqlc/internal/sql/ast" +) + +func (c *Catalog) createExtension(stmt *ast.CreateExtensionStmt) error { + if stmt.Extname == nil { + return nil + } + // TODO: Implement IF NOT EXISTS + return c.loadExtension(*stmt.Extname) +} + +// loadExtension adds what the engine knows of the named extension — or of +// the virtual table module that stands for one — to the default schema, +// once. An engine without extension data, or without data for this one, +// adds nothing. +func (c *Catalog) loadExtension(name string) error { + if _, exists := c.Extensions[name]; exists { + return nil + } + if c.LoadExtension == nil { + return nil + } + ext := c.LoadExtension(name) + if ext == nil { + return nil + } + if c.Extensions == nil { + c.Extensions = map[string]struct{}{} + } + c.Extensions[name] = struct{}{} + s, err := c.getSchema(c.DefaultSchema) + if err != nil { + return err + } + // TODO: Error on duplicate functions + s.Funcs = append(s.Funcs, ext.Funcs...) + return nil +} diff --git a/internal/sql/catalog/func.go b/internal/sql/catalog/func.go new file mode 100644 index 0000000..e170777 --- /dev/null +++ b/internal/sql/catalog/func.go @@ -0,0 +1,122 @@ +package catalog + +import ( + "errors" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/sqlerr" +) + +// Function describes a database function +// +// A database function is a method written to perform a specific operation on data within the database. +type Function struct { + Name string + Args []*Argument + ReturnType *ast.TypeName + Comment string + Desc string + ReturnTypeNullable bool +} + +type Argument struct { + Name string + Type *ast.TypeName + HasDefault bool + Mode ast.FuncParamMode +} + +func (f *Function) InArgs() []*Argument { + var args []*Argument + for _, a := range f.Args { + switch a.Mode { + case ast.FuncParamTable, ast.FuncParamOut: + continue + default: + args = append(args, a) + } + } + return args +} + +func (f *Function) OutArgs() []*Argument { + var args []*Argument + for _, a := range f.Args { + switch a.Mode { + case ast.FuncParamOut: + args = append(args, a) + } + } + return args +} + +func (c *Catalog) createFunction(stmt *ast.CreateFunctionStmt) error { + ns := stmt.Func.Schema + if ns == "" { + ns = c.DefaultSchema + } + s, err := c.getSchema(ns) + if err != nil { + return err + } + fn := &Function{ + Name: stmt.Func.Name, + Args: make([]*Argument, len(stmt.Params.Items)), + ReturnType: stmt.ReturnType, + } + types := make([]*ast.TypeName, len(stmt.Params.Items)) + for i, item := range stmt.Params.Items { + arg := item.(*ast.FuncParam) + var name string + if arg.Name != nil { + name = *arg.Name + } + fn.Args[i] = &Argument{ + Name: name, + Type: arg.Type, + Mode: arg.Mode, + HasDefault: arg.DefExpr != nil, + } + types[i] = arg.Type + } + + _, idx, err := s.getFunc(stmt.Func, types) + if err == nil && !stmt.Replace { + return sqlerr.RelationExists(stmt.Func.Name) + } + + if idx >= 0 { + s.Funcs[idx] = fn + } else { + s.Funcs = append(s.Funcs, fn) + } + return nil +} + +func (c *Catalog) dropFunction(stmt *ast.DropFunctionStmt) error { + for _, spec := range stmt.Funcs { + ns := spec.Name.Schema + if ns == "" { + ns = c.DefaultSchema + } + s, err := c.getSchema(ns) + if errors.Is(err, sqlerr.NotFound) && stmt.MissingOk { + continue + } else if err != nil { + return err + } + var idx int + if spec.HasArgs { + _, idx, err = s.getFunc(spec.Name, spec.Args) + } else { + _, idx, err = s.getFuncByName(spec.Name) + } + if errors.Is(err, sqlerr.NotFound) && stmt.MissingOk { + continue + } else if err != nil { + return err + } + s.Funcs = append(s.Funcs[:idx], s.Funcs[idx+1:]...) + } + return nil +} diff --git a/internal/sql/catalog/public.go b/internal/sql/catalog/public.go new file mode 100644 index 0000000..19fd507 --- /dev/null +++ b/internal/sql/catalog/public.go @@ -0,0 +1,133 @@ +package catalog + +import ( + "fmt" + "strings" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/sqlerr" +) + +func (c *Catalog) schemasToSearch(ns string) []string { + if ns == "" { + ns = c.DefaultSchema + } + return append(c.SearchPath, ns) +} + +func (c *Catalog) ListFuncsByName(rel *ast.FuncName) ([]Function, error) { + var funcs []Function + lowered := strings.ToLower(rel.Name) + for _, ns := range c.schemasToSearch(rel.Schema) { + s, err := c.getSchema(ns) + if err != nil { + return nil, err + } + for i := range s.Funcs { + if strings.ToLower(s.Funcs[i].Name) == lowered { + funcs = append(funcs, *s.Funcs[i]) + } + } + } + return funcs, nil +} + +func (c *Catalog) ResolveFuncCall(call *ast.FuncCall) (*Function, error) { + // Do not validate unknown functions + funs, err := c.ListFuncsByName(call.Func) + if err != nil || len(funs) == 0 { + return nil, sqlerr.FunctionNotFound(call.Func.Name) + } + + // https://www.postgresql.org/docs/current/sql-syntax-calling-funcs.html + var positional []ast.Node + var named []*ast.NamedArgExpr + + if call.Args != nil { + for _, arg := range call.Args.Items { + if narg, ok := arg.(*ast.NamedArgExpr); ok { + named = append(named, narg) + } else { + // The mixed notation combines positional and named notation. + // However, as already mentioned, named arguments cannot precede + // positional arguments. + if len(named) > 0 { + return nil, &sqlerr.Error{ + Code: "", + Message: "positional argument cannot follow named argument", + Location: call.Pos(), + } + } + positional = append(positional, arg) + } + } + } + + for _, fun := range funs { + args := fun.InArgs() + var defaults int + var variadic bool + known := map[string]struct{}{} + for _, arg := range args { + if arg.HasDefault { + defaults += 1 + } + if arg.Mode == ast.FuncParamVariadic { + variadic = true + defaults += 1 + } + if arg.Name != "" { + known[arg.Name] = struct{}{} + } + } + + if variadic { + if (len(named) + len(positional)) < (len(args) - defaults) { + continue + } + } else { + if (len(named) + len(positional)) > len(args) { + continue + } + if (len(named) + len(positional)) < (len(args) - defaults) { + continue + } + } + + // Validate that the provided named arguments exist in the function + var unknownArgName bool + for _, expr := range named { + if expr.Name != nil { + if _, found := known[*expr.Name]; !found { + unknownArgName = true + } + } + } + if unknownArgName { + continue + } + + return &fun, nil + } + + var sig []string + for range call.Args.Items { + sig = append(sig, "unknown") + } + + return nil, &sqlerr.Error{ + Code: "42883", + Message: fmt.Sprintf("function %s(%s) does not exist", call.Func.Name, strings.Join(sig, ", ")), + Location: call.Pos(), + // Hint: "No function matches the given name and argument types. You might need to add explicit type casts.", + } +} + +func (c *Catalog) GetTable(rel *ast.TableName) (Table, error) { + _, table, err := c.getTable(rel) + if table == nil { + return Table{}, err + } else { + return *table, err + } +} diff --git a/internal/sql/catalog/schema.go b/internal/sql/catalog/schema.go new file mode 100644 index 0000000..72a32a6 --- /dev/null +++ b/internal/sql/catalog/schema.go @@ -0,0 +1,134 @@ +package catalog + +import ( + "fmt" + "strings" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/sqlerr" +) + +// Schema describes how the data in a relational database may relate to other tables or other data models +type Schema struct { + Name string + Tables []*Table + Types []Type + Funcs []*Function + + Comment string +} + +func (s *Schema) getFunc(rel *ast.FuncName, tns []*ast.TypeName) (*Function, int, error) { + for i := range s.Funcs { + if !strings.EqualFold(s.Funcs[i].Name, rel.Name) { + continue + } + + args := s.Funcs[i].InArgs() + if len(args) != len(tns) { + continue + } + found := true + for j := range args { + if !sameType(s.Funcs[i].Args[j].Type, tns[j]) { + found = false + break + } + } + if !found { + continue + } + return s.Funcs[i], i, nil + } + return nil, -1, sqlerr.RelationNotFound(rel.Name) +} + +func (s *Schema) getFuncByName(rel *ast.FuncName) (*Function, int, error) { + idx := -1 + name := strings.ToLower(rel.Name) + for i := range s.Funcs { + lowered := strings.ToLower(s.Funcs[i].Name) + if lowered == name && idx >= 0 { + return nil, -1, sqlerr.FunctionNotUnique(rel.Name) + } + if lowered == name { + idx = i + } + } + if idx < 0 { + return nil, -1, sqlerr.RelationNotFound(rel.Name) + } + return s.Funcs[idx], idx, nil +} + +func (s *Schema) getTable(rel *ast.TableName) (*Table, int, error) { + for i := range s.Tables { + if s.Tables[i].Rel.Name == rel.Name { + return s.Tables[i], i, nil + } + } + return nil, -1, sqlerr.RelationNotFound(rel.Name) +} + +func (s *Schema) getType(rel *ast.TypeName) (Type, int, error) { + for i := range s.Types { + switch typ := s.Types[i].(type) { + case *Enum: + if typ.Name == rel.Name { + return s.Types[i], i, nil + } + case *CompositeType: + if typ.Name == rel.Name { + return s.Types[i], i, nil + } + } + } + return nil, -1, sqlerr.TypeNotFound(rel.Name) +} + +func (c *Catalog) getSchema(name string) (*Schema, error) { + for i := range c.Schemas { + if c.Schemas[i].Name == name { + return c.Schemas[i], nil + } + } + return nil, sqlerr.SchemaNotFound(name) +} + +func (c *Catalog) createSchema(stmt *ast.CreateSchemaStmt) error { + if stmt.Name == nil { + return fmt.Errorf("create schema: empty name") + } + if _, err := c.getSchema(*stmt.Name); err == nil { + // If the default schema already exists, treat additional CREATE SCHEMA + // statements as no-ops. + if *stmt.Name == c.DefaultSchema { + return nil + } + if !stmt.IfNotExists { + return sqlerr.SchemaExists(*stmt.Name) + } + } + c.Schemas = append(c.Schemas, &Schema{Name: *stmt.Name}) + return nil +} + +func (c *Catalog) dropSchema(stmt *ast.DropSchemaStmt) error { + // TODO: n^2 in the worst-case + for _, name := range stmt.Schemas { + idx := -1 + for i := range c.Schemas { + if c.Schemas[i].Name == name.Str { + idx = i + } + } + if idx == -1 { + if stmt.MissingOk { + continue + } + return sqlerr.SchemaNotFound(name.Str) + } + c.Schemas = append(c.Schemas[:idx], c.Schemas[idx+1:]...) + } + return nil +} diff --git a/internal/sql/catalog/table.go b/internal/sql/catalog/table.go new file mode 100644 index 0000000..a91e399 --- /dev/null +++ b/internal/sql/catalog/table.go @@ -0,0 +1,505 @@ +package catalog + +import ( + "errors" + "fmt" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/sqlerr" +) + +// Table describes a relational database table +// +// A database table is a collection of related data held in a table format within a database. +// It consists of columns and rows. +type Table struct { + Rel *ast.TableName + Columns []*Column + Comment string +} + +func checkMissing(err error, missingOK bool) error { + var serr *sqlerr.Error + if errors.As(err, &serr) { + if serr.Err == sqlerr.NotFound && missingOK { + return nil + } + } + return err +} + +func (table *Table) isExistColumn(cmd *ast.AlterTableCmd) (int, error) { + for i, c := range table.Columns { + if c.Name == *cmd.Name { + return i, nil + } + } + if !cmd.MissingOk { + return -1, sqlerr.ColumnNotFound(table.Rel.Name, *cmd.Name) + } + // Missing column is allowed + return -1, nil +} + +func (c *Catalog) addColumn(table *Table, cmd *ast.AlterTableCmd) error { + for _, c := range table.Columns { + if c.Name == cmd.Def.Colname { + if !cmd.MissingOk { + return sqlerr.ColumnExists(table.Rel.Name, cmd.Def.Colname) + } + return nil + } + } + tc, err := c.defineColumn(table.Rel, cmd.Def) + if err != nil { + return err + } + table.Columns = append(table.Columns, tc) + return nil +} + +func (table *Table) alterColumnType(cmd *ast.AlterTableCmd) error { + index, err := table.isExistColumn(cmd) + if err != nil { + return err + } + if index >= 0 { + table.Columns[index].Type = *cmd.Def.TypeName + table.Columns[index].IsArray = cmd.Def.IsArray + table.Columns[index].ArrayDims = cmd.Def.ArrayDims + } + return nil +} + +func (c *Catalog) dropColumn(table *Table, cmd *ast.AlterTableCmd) error { + index, err := table.isExistColumn(cmd) + if err != nil { + return err + } + if index < 0 { + return nil + } + col := table.Columns[index] + if col.linkedType { + drop := &ast.DropTypeStmt{ + Types: []*ast.TypeName{ + &col.Type, + }, + } + if err := c.dropType(drop); err != nil { + return err + } + } + table.Columns = append(table.Columns[:index], table.Columns[index+1:]...) + return nil +} + +func (table *Table) dropNotNull(cmd *ast.AlterTableCmd) error { + index, err := table.isExistColumn(cmd) + if err != nil { + return err + } + if index >= 0 { + table.Columns[index].IsNotNull = false + } + return nil +} + +func (table *Table) setNotNull(cmd *ast.AlterTableCmd) error { + index, err := table.isExistColumn(cmd) + if err != nil { + return err + } + if index >= 0 { + table.Columns[index].IsNotNull = true + } + return nil +} + +// Column describes a set of data values of a particular type in a relational database table +// +// TODO: Should this just be ast Nodes? +type Column struct { + Name string + Type ast.TypeName + IsNotNull bool + IsUnsigned bool + IsArray bool + ArrayDims int + Comment string + Length *int + + linkedType bool +} + +// An interface is used to resolve a circular import between the catalog and compiler packages. +// The createView function requires access to functions in the compiler package to parse the SELECT +// statement that defines the view. +type columnGenerator interface { + OutputColumns(node ast.Node) ([]*Column, error) +} + +func (c *Catalog) getTable(tableName *ast.TableName) (*Schema, *Table, error) { + schemaName := tableName.Schema + if schemaName == "" { + schemaName = c.DefaultSchema + } + var schema *Schema + for i := range c.Schemas { + if c.Schemas[i].Name == schemaName { + schema = c.Schemas[i] + break + } + } + if schema == nil { + return nil, nil, sqlerr.SchemaNotFound(schemaName) + } + table, _, err := schema.getTable(tableName) + if err != nil { + return nil, nil, err + } + return schema, table, nil +} + +func isStmtImplemented(stmt *ast.AlterTableStmt) bool { + var implemented bool + for _, item := range stmt.Cmds.Items { + switch cmd := item.(type) { + case *ast.AlterTableCmd: + switch cmd.Subtype { + case ast.AT_AddColumn: + implemented = true + case ast.AT_AlterColumnType: + implemented = true + case ast.AT_DropColumn: + implemented = true + case ast.AT_DropNotNull: + implemented = true + case ast.AT_SetNotNull: + implemented = true + } + } + } + return implemented +} + +func (c *Catalog) alterTable(stmt *ast.AlterTableStmt) error { + if !isStmtImplemented(stmt) { + return nil + } + _, table, err := c.getTable(stmt.Table) + if err != nil { + return checkMissing(err, stmt.MissingOk) + } + for _, item := range stmt.Cmds.Items { + switch cmd := item.(type) { + case *ast.AlterTableCmd: + switch cmd.Subtype { + case ast.AT_AddColumn: + if err := c.addColumn(table, cmd); err != nil { + return err + } + case ast.AT_AlterColumnType: + if err := table.alterColumnType(cmd); err != nil { + return err + } + case ast.AT_DropColumn: + if err := c.dropColumn(table, cmd); err != nil { + return err + } + case ast.AT_DropNotNull: + if err := table.dropNotNull(cmd); err != nil { + return err + } + case ast.AT_SetNotNull: + if err := table.setNotNull(cmd); err != nil { + return err + } + } + } + } + return nil +} + +func (c *Catalog) alterTableSetSchema(stmt *ast.AlterTableSetSchemaStmt) error { + ns := stmt.Table.Schema + if ns == "" { + ns = c.DefaultSchema + } + oldSchema, err := c.getSchema(ns) + if err != nil { + return checkMissing(err, stmt.MissingOk) + } + tbl, idx, err := oldSchema.getTable(stmt.Table) + if err != nil { + return checkMissing(err, stmt.MissingOk) + } + tbl.Rel.Schema = *stmt.NewSchema + newSchema, err := c.getSchema(*stmt.NewSchema) + if err != nil { + return err + } + if _, _, err := newSchema.getTable(stmt.Table); err == nil { + return sqlerr.RelationExists(stmt.Table.Name) + } + oldSchema.Tables = append(oldSchema.Tables[:idx], oldSchema.Tables[idx+1:]...) + newSchema.Tables = append(newSchema.Tables, tbl) + return nil +} + +func (c *Catalog) createTable(stmt *ast.CreateTableStmt) error { + // A virtual table's module is the engine's word for the extension it + // needs, the way CREATE EXTENSION is PostgreSQL's. + if stmt.Using != "" { + if err := c.loadExtension(stmt.Using); err != nil { + return err + } + } + ns := stmt.Name.Schema + if ns == "" { + ns = c.DefaultSchema + } + schema, err := c.getSchema(ns) + if err != nil { + return err + } + _, _, err = schema.getTable(stmt.Name) + if err == nil && stmt.IfNotExists { + return nil + } else if err == nil { + return sqlerr.RelationExists(stmt.Name.Name) + } + + tbl := Table{Rel: stmt.Name, Comment: stmt.Comment} + coltype := make(map[string]ast.TypeName) // used to check for duplicate column names + seen := make(map[string]bool) // used to check for duplicate column names + for _, inheritTable := range stmt.Inherits { + t, _, err := schema.getTable(inheritTable) + if err != nil { + return err + } + // check and ignore duplicate columns + for _, col := range t.Columns { + if notNull, ok := seen[col.Name]; ok { + seen[col.Name] = notNull || col.IsNotNull + if a, ok := coltype[col.Name]; ok { + if !sameType(&a, &col.Type) { + return fmt.Errorf("column %q has a type conflict", col.Name) + } + } + continue + } + + seen[col.Name] = col.IsNotNull + coltype[col.Name] = col.Type + tbl.Columns = append(tbl.Columns, col) + } + } + + if stmt.ReferTable != nil { + _, original, err := c.getTable(stmt.ReferTable) + if err != nil { + return err + } + for _, col := range original.Columns { + newCol := *col // make a copy, so changes to the ReferTable don't propagate + tbl.Columns = append(tbl.Columns, &newCol) + } + } + + for _, col := range stmt.Cols { + // The legacy catalog has no notion of a hidden column, so it drops + // them rather than list them on the table. + if col.IsHidden { + continue + } + if notNull, ok := seen[col.Colname]; ok { + seen[col.Colname] = notNull || col.IsNotNull + if a, ok := coltype[col.Colname]; ok { + if !sameType(&a, col.TypeName) { + return fmt.Errorf("column %q has a type conflict", col.Colname) + } + } + continue + } + tc, err := c.defineColumn(stmt.Name, col) + if err != nil { + return err + } + tbl.Columns = append(tbl.Columns, tc) + } + + // If one of the merged columns was not null, mark the column as not null + for i := range tbl.Columns { + if notNull, ok := seen[tbl.Columns[i].Name]; ok { + tbl.Columns[i].IsNotNull = notNull + } + } + + schema.Tables = append(schema.Tables, &tbl) + return nil +} + +func (c *Catalog) defineColumn(table *ast.TableName, col *ast.ColumnDef) (*Column, error) { + tc := &Column{ + Name: col.Colname, + Type: *col.TypeName, + IsNotNull: col.IsNotNull, + IsUnsigned: col.IsUnsigned, + IsArray: col.IsArray, + ArrayDims: col.ArrayDims, + Comment: col.Comment, + Length: col.Length, + } + if col.Vals != nil { + typeName := ast.TypeName{ + Name: fmt.Sprintf("%s_%s", table.Name, col.Colname), + } + s := &ast.CreateEnumStmt{TypeName: &typeName, Vals: col.Vals} + if err := c.createEnum(s); err != nil { + return nil, err + } + tc.Type = typeName + tc.linkedType = true + } + return tc, nil +} + +func (c *Catalog) dropTable(stmt *ast.DropTableStmt) error { + for _, name := range stmt.Tables { + ns := name.Schema + if ns == "" { + ns = c.DefaultSchema + } + schema, err := c.getSchema(ns) + if errors.Is(err, sqlerr.NotFound) && stmt.IfExists { + continue + } else if err != nil { + return err + } + + tbl, idx, err := schema.getTable(name) + if errors.Is(err, sqlerr.NotFound) && stmt.IfExists { + continue + } else if err != nil { + return err + } + + drop := &ast.DropTypeStmt{} + for _, col := range tbl.Columns { + if !col.linkedType { + continue + } + drop.Types = append(drop.Types, &col.Type) + } + if err := c.dropType(drop); err != nil { + return err + } + + schema.Tables = append(schema.Tables[:idx], schema.Tables[idx+1:]...) + } + return nil +} + +func (c *Catalog) renameColumn(stmt *ast.RenameColumnStmt) error { + _, tbl, err := c.getTable(stmt.Table) + if err != nil { + return checkMissing(err, stmt.MissingOk) + } + idx := -1 + for i := range tbl.Columns { + if tbl.Columns[i].Name == stmt.Col.Name { + idx = i + } + if tbl.Columns[i].Name == *stmt.NewName { + return sqlerr.ColumnExists(tbl.Rel.Name, *stmt.NewName) + } + } + if idx == -1 { + return sqlerr.ColumnNotFound(tbl.Rel.Name, stmt.Col.Name) + } + tbl.Columns[idx].Name = *stmt.NewName + + if tbl.Columns[idx].linkedType { + name := fmt.Sprintf("%s_%s", tbl.Rel.Name, *stmt.NewName) + rename := &ast.RenameTypeStmt{ + Type: &tbl.Columns[idx].Type, + NewName: &name, + } + if err := c.renameType(rename); err != nil { + return err + } + } + + return nil +} + +func (c *Catalog) renameTable(stmt *ast.RenameTableStmt) error { + sch, tbl, err := c.getTable(stmt.Table) + if err != nil { + return checkMissing(err, stmt.MissingOk) + } + if _, _, err := sch.getTable(&ast.TableName{Name: *stmt.NewName}); err == nil { + return sqlerr.RelationExists(*stmt.NewName) + } + if stmt.NewName != nil { + tbl.Rel.Name = *stmt.NewName + } + + for idx := range tbl.Columns { + if tbl.Columns[idx].linkedType { + name := fmt.Sprintf("%s_%s", *stmt.NewName, tbl.Columns[idx].Name) + rename := &ast.RenameTypeStmt{ + Type: &tbl.Columns[idx].Type, + NewName: &name, + } + if err := c.renameType(rename); err != nil { + return err + } + } + } + + return nil +} + +func (c *Catalog) createTableAs(stmt *ast.CreateTableAsStmt, colGen columnGenerator) error { + cols, err := colGen.OutputColumns(stmt.Query) + if err != nil { + return err + } + + catName := "" + if stmt.Into.Rel.Catalogname != nil { + catName = *stmt.Into.Rel.Catalogname + } + schemaName := "" + if stmt.Into.Rel.Schemaname != nil { + schemaName = *stmt.Into.Rel.Schemaname + } + + tbl := Table{ + Rel: &ast.TableName{ + Catalog: catName, + Schema: schemaName, + Name: *stmt.Into.Rel.Relname, + }, + Columns: cols, + } + + ns := tbl.Rel.Schema + if ns == "" { + ns = c.DefaultSchema + } + schema, err := c.getSchema(ns) + if err != nil { + return err + } + _, _, err = schema.getTable(tbl.Rel) + if err == nil { + return sqlerr.RelationExists(tbl.Rel.Name) + } + + schema.Tables = append(schema.Tables, &tbl) + + return nil +} diff --git a/internal/sql/catalog/types.go b/internal/sql/catalog/types.go new file mode 100644 index 0000000..464472b --- /dev/null +++ b/internal/sql/catalog/types.go @@ -0,0 +1,374 @@ +package catalog + +import ( + "errors" + "fmt" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/sqlerr" +) + +type Type interface { + isType() + + SetComment(string) +} + +type Enum struct { + Name string + Vals []string + Comment string +} + +func (e *Enum) SetComment(c string) { + e.Comment = c +} + +func (e *Enum) isType() { +} + +type CompositeType struct { + Name string + Comment string +} + +func (ct *CompositeType) isType() { +} + +func (ct *CompositeType) SetComment(c string) { + ct.Comment = c +} + +func sameType(a, b *ast.TypeName) bool { + if a.Catalog != b.Catalog { + return false + } + // The pg_catalog schema is searched by default, so take that into + // account when comparing schemas + aSchema := a.Schema + bSchema := b.Schema + if aSchema == "pg_catalog" { + aSchema = "" + } + if bSchema == "pg_catalog" { + bSchema = "" + } + if aSchema != bSchema { + return false + } + if a.Name != b.Name { + return false + } + return true +} + +func (c *Catalog) createEnum(stmt *ast.CreateEnumStmt) error { + ns := stmt.TypeName.Schema + if ns == "" { + ns = c.DefaultSchema + } + schema, err := c.getSchema(ns) + if err != nil { + return err + } + // Because tables have associated data types, the type name must also + // be distinct from the name of any existing table in the same + // schema. + // https://www.postgresql.org/docs/current/sql-createtype.html + tbl := &ast.TableName{ + Name: stmt.TypeName.Name, + } + if _, _, err := schema.getTable(tbl); err == nil { + return sqlerr.RelationExists(tbl.Name) + } + if _, _, err := schema.getType(stmt.TypeName); err == nil { + return sqlerr.TypeExists(tbl.Name) + } + schema.Types = append(schema.Types, &Enum{ + Name: stmt.TypeName.Name, + Vals: stringSlice(stmt.Vals), + }) + return nil +} + +func stringSlice(list *ast.List) []string { + items := []string{} + for _, item := range list.Items { + if n, ok := item.(*ast.String); ok { + items = append(items, n.Str) + } + } + return items +} + +func (c *Catalog) getType(rel *ast.TypeName) (Type, int, error) { + ns := rel.Schema + if ns == "" { + ns = c.DefaultSchema + } + s, err := c.getSchema(ns) + if err != nil { + return nil, -1, err + } + return s.getType(rel) +} + +func (c *Catalog) createCompositeType(stmt *ast.CompositeTypeStmt) error { + ns := stmt.TypeName.Schema + if ns == "" { + ns = c.DefaultSchema + } + schema, err := c.getSchema(ns) + if err != nil { + return err + } + // Because tables have associated data types, the type name must also + // be distinct from the name of any existing table in the same + // schema. + // https://www.postgresql.org/docs/current/sql-createtype.html + tbl := &ast.TableName{ + Name: stmt.TypeName.Name, + } + if _, _, err := schema.getTable(tbl); err == nil { + return sqlerr.RelationExists(tbl.Name) + } + if _, _, err := schema.getType(stmt.TypeName); err == nil { + return sqlerr.TypeExists(tbl.Name) + } + schema.Types = append(schema.Types, &CompositeType{ + Name: stmt.TypeName.Name, + }) + return nil +} + +func (c *Catalog) alterTypeRenameValue(stmt *ast.AlterTypeRenameValueStmt) error { + ns := stmt.Type.Schema + if ns == "" { + ns = c.DefaultSchema + } + schema, err := c.getSchema(ns) + if err != nil { + return err + } + typ, _, err := schema.getType(stmt.Type) + if err != nil { + return err + } + enum, ok := typ.(*Enum) + if !ok { + return fmt.Errorf("type is not an enum: %T", stmt.Type) + } + + oldIndex := -1 + newIndex := -1 + for i, val := range enum.Vals { + if val == *stmt.OldValue { + oldIndex = i + } + if val == *stmt.NewValue { + newIndex = i + } + } + if oldIndex < 0 { + return fmt.Errorf("type %T does not have value %s", stmt.Type, *stmt.OldValue) + } + if newIndex >= 0 { + return fmt.Errorf("type %T already has value %s", stmt.Type, *stmt.NewValue) + } + enum.Vals[oldIndex] = *stmt.NewValue + return nil +} + +func (c *Catalog) alterTypeAddValue(stmt *ast.AlterTypeAddValueStmt) error { + ns := stmt.Type.Schema + if ns == "" { + ns = c.DefaultSchema + } + schema, err := c.getSchema(ns) + if err != nil { + return err + } + typ, _, err := schema.getType(stmt.Type) + if err != nil { + return err + } + enum, ok := typ.(*Enum) + if !ok { + return fmt.Errorf("type is not an enum: %T", stmt.Type) + } + + existingIndex := -1 + for i, val := range enum.Vals { + if val == *stmt.NewValue { + existingIndex = i + } + } + + if existingIndex >= 0 { + if !stmt.SkipIfNewValExists { + return fmt.Errorf("enum %s already has value %s", enum.Name, *stmt.NewValue) + } else { + return nil + } + } + + insertIndex := len(enum.Vals) + if stmt.NewValHasNeighbor { + foundNeighbor := false + for i, val := range enum.Vals { + if val == *stmt.NewValNeighbor { + if stmt.NewValIsAfter { + insertIndex = i + 1 + } else { + insertIndex = i + } + foundNeighbor = true + break + } + } + + if !foundNeighbor { + return fmt.Errorf("enum %s unable to find existing neighbor value %s for new value %s", enum.Name, *stmt.NewValNeighbor, *stmt.NewValue) + } + } + + if insertIndex == len(enum.Vals) { + enum.Vals = append(enum.Vals, *stmt.NewValue) + } else { + enum.Vals = append(enum.Vals[:insertIndex+1], enum.Vals[insertIndex:]...) + enum.Vals[insertIndex] = *stmt.NewValue + } + + return nil +} + +func (c *Catalog) alterTypeSetSchema(stmt *ast.AlterTypeSetSchemaStmt) error { + ns := stmt.Type.Schema + if ns == "" { + ns = c.DefaultSchema + } + oldSchema, err := c.getSchema(ns) + if err != nil { + return err + } + typ, idx, err := oldSchema.getType(stmt.Type) + if err != nil { + return err + } + oldType := *stmt.Type + stmt.Type.Schema = *stmt.NewSchema + newSchema, err := c.getSchema(*stmt.NewSchema) + if err != nil { + return err + } + // Because tables have associated data types, the type name must also + // be distinct from the name of any existing table in the same + // schema. + // https://www.postgresql.org/docs/current/sql-createtype.html + tbl := &ast.TableName{ + Name: stmt.Type.Name, + } + if _, _, err := newSchema.getTable(tbl); err == nil { + return sqlerr.RelationExists(tbl.Name) + } + if _, _, err := newSchema.getType(stmt.Type); err == nil { + return sqlerr.TypeExists(stmt.Type.Name) + } + oldSchema.Types = append(oldSchema.Types[:idx], oldSchema.Types[idx+1:]...) + newSchema.Types = append(newSchema.Types, typ) + + // Update all the table columns with the new type + for _, schema := range c.Schemas { + for _, table := range schema.Tables { + for _, column := range table.Columns { + if column.Type == oldType { + column.Type.Schema = *stmt.NewSchema + } + } + } + } + return nil +} + +func (c *Catalog) dropType(stmt *ast.DropTypeStmt) error { + for _, name := range stmt.Types { + ns := name.Schema + if ns == "" { + ns = c.DefaultSchema + } + schema, err := c.getSchema(ns) + if errors.Is(err, sqlerr.NotFound) && stmt.IfExists { + continue + } else if err != nil { + return err + } + + _, idx, err := schema.getType(name) + if errors.Is(err, sqlerr.NotFound) && stmt.IfExists { + continue + } else if err != nil { + return err + } + + schema.Types = append(schema.Types[:idx], schema.Types[idx+1:]...) + } + return nil +} + +func (c *Catalog) renameType(stmt *ast.RenameTypeStmt) error { + if stmt.NewName == nil { + return fmt.Errorf("rename type: empty name") + } + newName := *stmt.NewName + ns := stmt.Type.Schema + if ns == "" { + ns = c.DefaultSchema + } + schema, err := c.getSchema(ns) + if err != nil { + return err + } + ityp, idx, err := schema.getType(stmt.Type) + if err != nil { + return err + } + if _, _, err := schema.getTable(&ast.TableName{Name: newName}); err == nil { + return sqlerr.RelationExists(newName) + } + if _, _, err := schema.getType(&ast.TypeName{Name: newName}); err == nil { + return sqlerr.TypeExists(newName) + } + + switch typ := ityp.(type) { + + case *CompositeType: + schema.Types[idx] = &CompositeType{ + Name: newName, + Comment: typ.Comment, + } + + case *Enum: + schema.Types[idx] = &Enum{ + Name: newName, + Vals: typ.Vals, + Comment: typ.Comment, + } + + default: + return fmt.Errorf("unsupported type: %T", typ) + + } + + // Update all the table columns with the new type + for _, schema := range c.Schemas { + for _, table := range schema.Tables { + for _, column := range table.Columns { + if column.Type == *stmt.Type { + column.Type.Name = newName + } + } + } + } + + return nil +} diff --git a/internal/sql/catalog/view.go b/internal/sql/catalog/view.go new file mode 100644 index 0000000..d5222c4 --- /dev/null +++ b/internal/sql/catalog/view.go @@ -0,0 +1,52 @@ +package catalog + +import ( + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/sqlerr" +) + +func (c *Catalog) createView(stmt *ast.ViewStmt, colGen columnGenerator) error { + cols, err := colGen.OutputColumns(stmt.Query) + if err != nil { + return err + } + + catName := "" + if stmt.View.Catalogname != nil { + catName = *stmt.View.Catalogname + } + schemaName := "" + if stmt.View.Schemaname != nil { + schemaName = *stmt.View.Schemaname + } + + tbl := Table{ + Rel: &ast.TableName{ + Catalog: catName, + Schema: schemaName, + Name: *stmt.View.Relname, + }, + Columns: cols, + } + + ns := tbl.Rel.Schema + if ns == "" { + ns = c.DefaultSchema + } + schema, err := c.getSchema(ns) + if err != nil { + return err + } + _, existingIdx, err := schema.getTable(tbl.Rel) + if err == nil && !stmt.Replace { + return sqlerr.RelationExists(tbl.Rel.Name) + } + + if stmt.Replace && err == nil { + schema.Tables[existingIdx] = &tbl + } else { + schema.Tables = append(schema.Tables, &tbl) + } + + return nil +} diff --git a/internal/sql/format/format.go b/internal/sql/format/format.go new file mode 100644 index 0000000..b61b9cf --- /dev/null +++ b/internal/sql/format/format.go @@ -0,0 +1,23 @@ +package format + +// Dialect provides SQL dialect-specific formatting behavior +type Dialect interface { + // QuoteIdent returns a quoted identifier if it needs quoting + // (e.g., reserved words, mixed case identifiers) + QuoteIdent(s string) string + + // TypeName returns the SQL type name for the given namespace and name. + // This handles dialect-specific type name mappings (e.g., pg_catalog.int4 -> integer) + TypeName(ns, name string) string + + // Param returns the placeholder for the parameter with this number. + // numbered reports that the author wrote the number out (SQLite's ?2, + // where a bare ? takes the next index), so engines with both forms can + // keep the one that was written. + // PostgreSQL uses $1, $2, etc. MySQL uses ? + Param(n int, numbered bool) string + + // Cast formats a type cast expression. + // PostgreSQL uses expr::type, MySQL uses CAST(expr AS type) + Cast(arg, typeName string) string +} diff --git a/internal/sql/info/info.go b/internal/sql/info/info.go new file mode 100644 index 0000000..48484ef --- /dev/null +++ b/internal/sql/info/info.go @@ -0,0 +1,59 @@ +package info + +import ( + "github.com/sqlc-dev/sqlc/internal/sql/catalog" +) + +// Provide a read-only view into the catalog +func Newo(c *catalog.Catalog) InformationSchema { + return InformationSchema{c: c} +} + +type InformationSchema struct { + c *catalog.Catalog +} + +type Table struct { + Catalog string + Schema string + Name string +} + +// SELECT * FROM information_schema.tables; +func (i *InformationSchema) Tables() []Table { + var tables []Table + for _, s := range i.c.Schemas { + for _, t := range s.Tables { + tables = append(tables, Table{ + Catalog: i.c.Name, + Schema: s.Name, + Name: t.Rel.Name, + }) + } + } + return tables +} + +type Column struct { + Catalog string + Schema string + Table string + Name string + DataType string + IsNullable bool +} + +// SELECT * FROM information_schema.columns; +func (i *InformationSchema) Columns() []Column { + return []Column{} +} + +type Schema struct { + Catalog string + Name string +} + +// SELECT * FROM information_schema.schemata; +func (i *InformationSchema) Schemata() []Schema { + return []Schema{} +} diff --git a/internal/sql/lang/operator.go b/internal/sql/lang/operator.go new file mode 100644 index 0000000..c1ece1d --- /dev/null +++ b/internal/sql/lang/operator.go @@ -0,0 +1,63 @@ +package lang + +// TODO: This logic is PostgreSQL-specific and needs to be refactored to support MySQL + +func IsComparisonOperator(s string) bool { + switch s { + case ">": + case "<": + case "<=": + case ">=": + case "=": + case "==": + case "<>": + case "!=": + // Comparisons an engine spells as a keyword rather than as punctuation. + // They are written upper case, which is how SQLite's parser records + // them; PostgreSQL and MySQL use distinct node types or their own + // operator names for these, so the spellings do not overlap. + case "IS": + case "IS NOT": + case "IS DISTINCT FROM": + case "IS NOT DISTINCT FROM": + case "ISNULL": + case "NOTNULL": + case "NOT NULL": + case "LIKE": + case "NOT LIKE": + case "GLOB": + case "NOT GLOB": + case "REGEXP": + case "NOT REGEXP": + case "MATCH": + case "NOT MATCH": + default: + return false + } + return true +} + +func IsMathematicalOperator(s string) bool { + switch s { + case "+": + case "-": + case "*": + case "/": + case "%": + case "^": + case "|/": + case "||/": + case "!": + case "!!": + case "@": + case "&": + case "|": + case "#": + case "~": + case "<<": + case ">>": + default: + return false + } + return true +} diff --git a/internal/sql/named/CLAUDE.md b/internal/sql/named/CLAUDE.md new file mode 100644 index 0000000..b1f1cae --- /dev/null +++ b/internal/sql/named/CLAUDE.md @@ -0,0 +1,58 @@ +# Named Parameters Package - Claude Code Guide + +This package models a query's parameters: their names, their nullability and +whether they came from `sqlc.slice()`. + +It no longer knows anything about sqlc's *syntax*. `sqlc.arg()`, `sqlc.narg()`, +`sqlc.slice()` and `@name` are rewritten to native placeholders by +`internal/sql/preprocess` before any engine parser runs, and that package builds +the `ParamSet` while it rewrites. + +## Param + +A `Param` carries the user-facing name plus a nullability that combines what was +inferred from the schema with what the user asked for: + +- `NewParam(name)` — unspecified nullability, from `sqlc.arg()` or `@name` +- `NewUserNullableParam(name)` — from `sqlc.narg()`, always nullable +- `NewSqlcSlice(name)` — from `sqlc.slice()` +- `NewInferredParam(name, notNull)` — what the compiler inferred + +A user-specified nullability outranks an inferred one. `mergeParam` ORs the +nullability bits together, so the order the two sources arrive in does not +matter. + +## ParamSet + +`ParamSet` maps placeholder numbers to `Param` values for a single statement. + +```go +ps := named.NewParamSet(numbersAlreadyUsed, hasNamedSupport) +n := ps.Add(named.NewParam("author_id")) // returns the placeholder number +``` + +`hasNamedSupport` is false for dialects that send one argument per `?` +(MySQL, ClickHouse). There, every occurrence of a name gets its own number. For +`$1`/`?1`/`@name` dialects repeated uses of a name share a number. + +The compiler reads the set back with: + +- `NameFor(number)` — the user-facing name for a placeholder +- `FetchMerge(number, inferred)` — the merged param and whether it was named + +## MySQL @variable vs sqlc @param + +`@name` is only sqlc syntax where the preprocessor's dialect says it is. MySQL +sets `AtSign: false`, so `@user_id` there is a user variable and reaches the +parser untouched (converted to `ast.VariableExpr`). PostgreSQL, SQLite and +GoogleSQL treat `@name` as a named parameter. + +```sql +-- PostgreSQL with sqlc @param syntax: +SELECT * FROM users WHERE id = @user_id +-- Preprocessed to: SELECT * FROM users WHERE id = $1 + +-- MySQL with user variable: +SELECT * FROM users WHERE id != @user_id +-- Stays: SELECT * FROM users WHERE id != @user_id +``` diff --git a/internal/sql/named/param.go b/internal/sql/named/param.go new file mode 100644 index 0000000..42f9b85 --- /dev/null +++ b/internal/sql/named/param.go @@ -0,0 +1,129 @@ +package named + +// nullability represents the nullability of a named parameter. +// The nullability can be: +// 1. unspecified +// 2. inferred +// 3. user-defined +// A user-specified nullability carries a higher precedence than an inferred one +// +// The representation is such that you can bitwise OR together nullability types to +// combine them together. +type nullability int + +const ( + nullUnspecified nullability = 0b0000 + inferredNull nullability = 0b0001 + inferredNotNull nullability = 0b0010 + nullable nullability = 0b0100 + notNullable nullability = 0b1000 +) + +// String implements the Stringer interface +func (n nullability) String() string { + switch n { + case nullUnspecified: + return "NullUnspecified" + case inferredNull: + return "InferredNull" + case inferredNotNull: + return "InferredNotNull" + case nullable: + return "Nullable" + case notNullable: + return "NotNullable" + default: + return "NullInvalid" + } +} + +// Param represents a input argument to the query which can be specified using: +// - positional parameters $1 +// - named parameter operator @param +// - named parameter function calls sqlc.arg(param) +type Param struct { + name string + nullability nullability + isSqlcSlice bool +} + +// NewParam builds a new params with unspecified nullability +func NewParam(name string) Param { + return Param{name: name, nullability: nullUnspecified} +} + +// NewInferredParam builds a new params with inferred nullability +func NewInferredParam(name string, notNull bool) Param { + if notNull { + return Param{name: name, nullability: inferredNotNull} + } + + return Param{name: name, nullability: inferredNull} +} + +// NewUserNullableParam is a parameter that has been overridden +// by the user to be nullable. +func NewUserNullableParam(name string) Param { + return Param{name: name, nullability: nullable} +} + +// NewSqlcSlice is a sqlc.slice() parameter. +func NewSqlcSlice(name string) Param { + return Param{name: name, nullability: nullUnspecified, isSqlcSlice: true} +} + +// Name is the user defined name to use for this parameter +func (p Param) Name() string { + return p.name +} + +// is checks if this params object has the specified nullability bit set +func (p Param) is(n nullability) bool { + return (p.nullability & n) == n +} + +// NonNull determines whether this param should be "not null" in its current state +func (p Param) NotNull() bool { + const null = false + const notNull = true + + if p.is(notNullable) { + return notNull + } + + if p.is(nullable) { + return null + } + + if p.is(inferredNotNull) { + return notNull + } + + if p.is(inferredNull) { + return null + } + + // This param is unspecified, so by default we choose nullable + // which matches the default behavior of most databases + return null +} + +// IsSlice returns whether this param is a sqlc.slice() param. +func (p Param) IsSqlcSlice() bool { + return p.isSqlcSlice +} + +// mergeParam creates a new param from 2 partially specified params +// If the parameters have different names, the first is preferred +func mergeParam(a, b Param) Param { + name := a.name + if name == "" { + name = b.name + } + + return Param{ + name: name, + nullability: a.nullability | b.nullability, + isSqlcSlice: a.isSqlcSlice || b.isSqlcSlice, + } +} diff --git a/internal/sql/named/param_set.go b/internal/sql/named/param_set.go new file mode 100644 index 0000000..d47617a --- /dev/null +++ b/internal/sql/named/param_set.go @@ -0,0 +1,85 @@ +package named + +// ParamSet represents a set of parameters for a single query +type ParamSet struct { + // does this engine support named parameters? + hasNamedSupport bool + // the set of currently tracked named parameters + namedParams map[string]Param + // the locations of each of the named parameters + namedLocs map[string][]int + // a map of positions currently used + positionToName map[int]string + // argn keeps track of the last checked positional parameter used + argn int +} + +// Return the name for a given parameter number and a boolean indicating if it +// was found. +func (p *ParamSet) NameFor(idx int) (string, bool) { + name, ok := p.positionToName[idx] + return name, ok +} + +func (p *ParamSet) nextArgNum() int { + for { + if _, ok := p.positionToName[p.argn]; !ok { + return p.argn + } + + p.argn++ + } +} + +// Add adds a parameter to this set and returns the numbered location used for it +func (p *ParamSet) Add(param Param) int { + name := param.name + existing, ok := p.namedParams[name] + + p.namedParams[name] = mergeParam(existing, param) + if ok && p.hasNamedSupport { + return p.namedLocs[name][0] + } + + argn := p.nextArgNum() + p.positionToName[argn] = name + p.namedLocs[name] = append(p.namedLocs[name], argn) + return argn +} + +// FetchMerge fetches an indexed parameter, and merges `mergeP` into it +// Returns: the merged parameter and whether it was a named parameter +func (p *ParamSet) FetchMerge(idx int, mergeP Param) (param Param, isNamed bool) { + name, exists := p.positionToName[idx] + if !exists || name == "" { + return mergeP, false + } + + param, ok := p.namedParams[name] + if !ok { + return mergeP, false + } + + return mergeParam(param, mergeP), true +} + +// NewParamSet creates a set of parameters with the given list of already used positions +func NewParamSet(positionsUsed map[int]bool, hasNamedSupport bool) *ParamSet { + positionToName := make(map[int]string, len(positionsUsed)) + for index, used := range positionsUsed { + if !used { + continue + } + + // assume the previously used params have no name + positionToName[index] = "" + } + + return &ParamSet{ + argn: 1, + namedParams: make(map[string]Param), + namedLocs: make(map[string][]int), + hasNamedSupport: hasNamedSupport, + positionToName: positionToName, + } +} diff --git a/internal/sql/named/param_set_test.go b/internal/sql/named/param_set_test.go new file mode 100644 index 0000000..99b7ed0 --- /dev/null +++ b/internal/sql/named/param_set_test.go @@ -0,0 +1,58 @@ +package named + +import "testing" + +func TestParamSet_Add(t *testing.T) { + t.Parallel() + + type test struct { + pset *ParamSet + param Param + expected int + } + + named := NewParamSet(nil, true) + populatedNamed := NewParamSet(map[int]bool{1: true, 2: true, 4: true, 5: true, 6: true}, true) + populatedUnnamed := NewParamSet(map[int]bool{1: true, 2: true, 4: true, 5: true, 6: true}, false) + unnamed := NewParamSet(nil, false) + p1 := NewParam("hello") + p2 := NewParam("world") + + tests := []test{ + // First parameter should be 1 + {named, p1, 1}, + // Duplicate first parameters should be 1 + {named, p1, 1}, + // A new parameter receives a new parameter number + {named, p2, 2}, + // An additional new parameter does _not_ receive a new + {named, p2, 2}, + + // First parameter should be 1 + {unnamed, p1, 1}, + // Duplicate first parameters should increment argn + {unnamed, p1, 2}, + // A new parameter receives a new parameter number + {unnamed, p2, 3}, + // An additional new parameter still does receive a new argn + {unnamed, p2, 4}, + + // First parameter of a pre-populated should be 3 + {populatedNamed, p1, 3}, + {populatedNamed, p1, 3}, + {populatedNamed, p2, 7}, + {populatedNamed, p2, 7}, + + {populatedUnnamed, p1, 3}, + {populatedUnnamed, p1, 7}, + {populatedUnnamed, p2, 8}, + {populatedUnnamed, p2, 9}, + } + + for _, spec := range tests { + actual := spec.pset.Add(spec.param) + if actual != spec.expected { + t.Errorf("ParamSet.Add(%s) expected %v; got %v", spec.param.name, spec.expected, actual) + } + } +} diff --git a/internal/sql/named/param_test.go b/internal/sql/named/param_test.go new file mode 100644 index 0000000..2643f8b --- /dev/null +++ b/internal/sql/named/param_test.go @@ -0,0 +1,82 @@ +package named + +import "testing" + +func TestMergeParamNullability(t *testing.T) { + type test struct { + a Param + b Param + notNull bool + message string + } + + name := "name" + unspec := NewParam(name) + inferredNotNull := NewInferredParam(name, true) + inferredNull := NewInferredParam(name, false) + userDefNull := NewUserNullableParam(name) + + const notNull = true + const null = false + + tests := []test{ + // Unspecified nullability parameter works + {unspec, inferredNotNull, notNull, "Unspec + inferred(not null) = not null"}, + {unspec, inferredNull, null, "Unspec + inferred(not null) = null"}, + {unspec, userDefNull, null, "Unspec + userdef(null) = null"}, + + // Inferred nullability agreeing with user defined nullabilty + {inferredNull, userDefNull, null, "inferred(null) + userdef(null) = null"}, + + // Inferred nullability disagreeing with user defined nullabilty + {inferredNotNull, userDefNull, null, "inferred(not null) + userdef(null) = null"}, + } + + for _, spec := range tests { + a := spec.a + b := spec.b + actual := mergeParam(a, b).NotNull() + expected := spec.notNull + if actual != expected { + t.Errorf("Combine(%s,%s) expected %v; got %v", a.nullability, b.nullability, expected, actual) + } + + // We have already tried Combine(a, b) the same result should be true for Combine(b, a) + actual = mergeParam(b, a).NotNull() + if actual != expected { + t.Errorf("Combine(%s,%s) expected %v; got %v", b.nullability, a.nullability, expected, actual) + } + } +} + +func TestMergeParamName(t *testing.T) { + type test struct { + a Param + b Param + name string + } + + a := NewParam("a") + b := NewParam("b") + blank := NewParam("") + + tests := []test{ + // should prefer the first param's name if both specified + {a, b, "a"}, + {b, a, "b"}, + + // should prefer non-blank names + {a, blank, "a"}, + {blank, a, "a"}, + } + + for _, spec := range tests { + a := spec.a + b := spec.b + actual := mergeParam(a, b).Name() + expected := spec.name + if actual != expected { + t.Errorf("Combine(%s,%s) expected %v; got %v", a.name, b.name, expected, actual) + } + } +} diff --git a/internal/sql/preprocess/CLAUDE.md b/internal/sql/preprocess/CLAUDE.md new file mode 100644 index 0000000..a7f4d9a --- /dev/null +++ b/internal/sql/preprocess/CLAUDE.md @@ -0,0 +1,114 @@ +# SQL Preprocess Package - Claude Code Guide + +This package rewrites sqlc's query syntax into native SQL **before** any engine +parser sees a query. After it runs, no sqlc syntax remains in the text, so +parsers, converters and `astutils` traversals only ever deal with SQL. + +## What it rewrites + +| syntax | becomes | +| --- | --- | +| `sqlc.arg(name)` / `sqlc.narg(name)` | the dialect's native placeholder | +| `sqlc.slice(name)` | the placeholder wrapped in `/*SLICE:name*/` | +| `sqlc.embed(table)` | `table.*` | +| `@name` | the native placeholder, on dialects where `@` is sqlc syntax | + +Native placeholders by dialect: + +| engine | placeholder | `@name` | +| --- | --- | --- | +| postgresql | `$1` | sqlc syntax | +| mysql | `?` | user variable, left alone | +| sqlite | `?1` | sqlc syntax | + +GoogleSQL and ClickHouse are deliberately absent. They handle their own +parameter syntax, so `File` returns their source unchanged and sqlc syntax is +not available to them — `sqlc.arg()` reaches the parser as the function call it +looks like. + +## How it works + +`lexer` is a dialect-parameterized scanner. It does not parse SQL — it knows +only enough to skip the regions where sqlc syntax must not be rewritten: +comments (`--`, `/* */`, `#`), string literals, quoted identifiers, backticks +and PostgreSQL dollar-quoted strings. `Dialect` (dialect.go) is the single +place those lexical rules live. + +`File(engine, src)` looks up the dialect; an engine with no entry gets its +source back untouched. Otherwise it walks the whole file, splits it at +top-level semicolons and, for each statement: + +1. `scan` collects every sqlc construct **and** every native placeholder, in + source order. +2. `number` assigns placeholder numbers. Numbered dialects keep the numbers the + user wrote and fill in the gaps; `?` dialects renumber everything in source + order, because each `?` is its own argument. +3. The statement is rewritten into the output buffer and a `Statement` records + what changed. + +## The side table + +`Result.Statement(offset)` returns the `Statement` covering an offset in the +**rewritten** text: + +- `Params` — the `named.ParamSet` for the statement +- `Embeds` — each rewritten `table.*`, keyed by its location so the compiler can + tell it apart from a star reference the user wrote +- `Slices` — the location of each `sqlc.slice()` placeholder +- `Numbers` — location → parameter number, used by the compiler to override the + numbers an engine assigned in AST-conversion order +- `Dollar` / `ParamErr` — the placeholder-style validation that used to live in + `validate.ParamRef` +- `Err` — a sqlc syntax error (unknown `sqlc.*` function, wrong arity, an + argument that is not an identifier or string) + +`Result.Origin(offset)` maps an offset in the rewritten text back to the +original source, so errors point at what the user wrote. + +## Invariants + +- **A rewrite never adds a line.** Replacements are single-line, so a line + number taken from the rewritten text is never past the end of the original. It + can *lose* lines, when the sqlc call itself spanned several — map offsets + through `Origin` rather than trusting line numbers. +- **An invalid statement is copied through untouched.** The engine still parses + what the user wrote and the error is reported per statement, not per file. +- **Nothing inside a comment or literal is rewritten.** Query annotations like + `-- name: GetAuthor :one` are comments, so they are always safe. + +## Tests + +`testdata///` holds the input and the expected results: + +| file | contents | +| --- | --- | +| `input.sql` | the query file | +| `output.sql` | the rewritten SQL | +| `side_table.json` | everything the preprocessor recorded | +| `stderr.txt` | reported errors, only when the input is invalid | + +`TestRewrite` runs one subtest per directory. `side_table.json` is rendered by +reading the result back through the same API the compiler uses, so it covers +parameter names and nullability, embed and slice spans, placeholder numbering +and the offset map — a parameter's `location` is its offset in the rewritten +text and its `origin` is where it came from. + +Regenerate every golden with: + +```bash +go test ./internal/sql/preprocess -update +``` + +The cases cover every shape of sqlc syntax that appears in +`internal/endtoend`, per preprocessed engine — each function against a bare +reference, a string constant and a quoted identifier, the placeholder styles, +and the constructs that must be left alone (comments, literals, MySQL user +variables and `$1`, PostgreSQL's `@>` and `?` operators). When you add a shape +to the corpus, add it here too. + +## Adding a dialect + +Add an entry to `dialects` in dialect.go. Nothing else in the codebase needs to +change for `sqlc.arg`/`narg`/`slice`/`embed` to work for a new engine — but only +add one if the engine should support sqlc syntax at all. Leaving an engine out +is a deliberate choice, not an oversight. diff --git a/internal/sql/preprocess/dialect.go b/internal/sql/preprocess/dialect.go new file mode 100644 index 0000000..4d8d4ae --- /dev/null +++ b/internal/sql/preprocess/dialect.go @@ -0,0 +1,114 @@ +package preprocess + +import ( + "github.com/sqlc-dev/sqlc/internal/config" +) + +// Style is the native placeholder syntax a dialect uses for bind parameters. +type Style int + +const ( + // StyleDollar numbers parameters as $1, $2, ... (PostgreSQL) + StyleDollar Style = iota + // StyleQuestion uses an unnumbered ? for every parameter (MySQL) + StyleQuestion + // StyleOrdinal numbers parameters as ?1, ?2, ... (SQLite) + StyleOrdinal +) + +// Dialect describes the lexical rules the preprocessor needs to walk a query +// without parsing it: how the dialect quotes strings and identifiers, how it +// writes comments and which placeholder syntax it accepts. +// +// The preprocessor never interprets SQL. It only needs to know enough to skip +// the regions of a query where sqlc syntax must not be rewritten. +type Dialect struct { + // Style is the native placeholder syntax used for rewritten parameters. + Style Style + + // AtSign reports whether a bare "@name" is sqlc named-parameter syntax. + // It is false for MySQL, where "@name" is a user variable. + AtSign bool + + // DollarQuote reports whether $tag$ ... $tag$ string literals are valid. + DollarQuote bool + + // DollarNumber reports whether $1 is a bind parameter. + DollarNumber bool + + // Question reports whether ? is a bind parameter. + Question bool + + // Backtick reports whether `ident` is a quoted identifier. + Backtick bool + + // HashComment reports whether # starts a line comment. + HashComment bool + + // DoubleQuoteString reports whether "..." is a string literal rather than + // a quoted identifier. MySQL treats it as a string unless ANSI_QUOTES is + // enabled. + DoubleQuoteString bool + + // NestedBlockComment reports whether /* ... /* ... */ ... */ nests. + NestedBlockComment bool + + // Backslash reports whether a backslash escapes the next character inside + // a string literal. + Backslash bool + + // FoldIdentifier reports whether the dialect lowercases unquoted + // identifiers. It decides the case of a parameter named by a bare + // reference, e.g. sqlc.arg(FooBar). + FoldIdentifier bool +} + +var dialects = map[config.Engine]Dialect{ + config.EnginePostgreSQL: { + Style: StyleDollar, + AtSign: true, + DollarQuote: true, + DollarNumber: true, + NestedBlockComment: true, + FoldIdentifier: true, + }, + config.EngineMySQL: { + Style: StyleQuestion, + Question: true, + Backtick: true, + HashComment: true, + DoubleQuoteString: true, + Backslash: true, + FoldIdentifier: true, + }, + config.EngineSQLite: { + Style: StyleOrdinal, + AtSign: true, + Question: true, + Backtick: true, + Backslash: true, + }, + // ClickHouse binds with an unnumbered ?, like MySQL, and its identifiers + // keep their case. + config.EngineClickHouse: { + Style: StyleQuestion, + Question: true, + Backtick: true, + Backslash: true, + }, +} + +// DialectFor returns the lexical rules for an engine, and whether the engine is +// preprocessed at all. GoogleSQL is not: it handles its own parameter syntax, +// so its queries reach the parser unchanged. +func DialectFor(engine config.Engine) (Dialect, bool) { + d, ok := dialects[engine] + return d, ok +} + +// hasNamedSupport reports whether repeated uses of the same parameter name can +// share a single placeholder. MySQL sends an argument per "?", so every +// occurrence needs its own number. +func (d Dialect) hasNamedSupport() bool { + return d.Style != StyleQuestion +} diff --git a/internal/sql/preprocess/lexer.go b/internal/sql/preprocess/lexer.go new file mode 100644 index 0000000..d17d80b --- /dev/null +++ b/internal/sql/preprocess/lexer.go @@ -0,0 +1,284 @@ +package preprocess + +import ( + "strings" +) + +// lexer is a dialect-parameterized scanner over a SQL file. It does not parse +// SQL; it knows just enough about comments, string literals, quoted identifiers +// and dollar-quoted strings to walk a query without ever looking inside a +// region where sqlc syntax must be left alone. +type lexer struct { + d Dialect + src string +} + +func isIdentStart(c byte) bool { + return c == '_' || + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + c >= 0x80 +} + +func isIdentPart(c byte) bool { + return isIdentStart(c) || (c >= '0' && c <= '9') || c == '$' +} + +func isDigit(c byte) bool { + return c >= '0' && c <= '9' +} + +func isSpace(c byte) bool { + return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v' +} + +func (l *lexer) at(i int) byte { + if i < 0 || i >= len(l.src) { + return 0 + } + return l.src[i] +} + +// skip returns the offset just past the comment, string literal, quoted +// identifier or dollar-quoted string that starts at i. It returns -1 when no +// such token starts at i. +func (l *lexer) skip(i int) int { + switch c := l.at(i); c { + case '\'': + return l.skipQuoted(i, '\'', l.d.Backslash || l.isEscapeString(i)) + case '"': + return l.skipQuoted(i, '"', l.d.DoubleQuoteString && l.d.Backslash) + case '`': + if !l.d.Backtick { + return -1 + } + return l.skipQuoted(i, '`', false) + case '-': + if l.at(i+1) == '-' { + return l.skipLine(i) + } + case '#': + if l.d.HashComment { + return l.skipLine(i) + } + case '/': + if l.at(i+1) == '*' { + return l.skipBlockComment(i) + } + case '$': + if l.d.DollarQuote { + if end := l.skipDollarQuoted(i); end >= 0 { + return end + } + } + } + return -1 +} + +// isEscapeString reports whether the string literal starting at i is a +// PostgreSQL escape string constant, written E'...', where a backslash escapes +// the following character. +func (l *lexer) isEscapeString(i int) bool { + if !l.d.DollarQuote { // PostgreSQL-only syntax + return false + } + c := l.at(i - 1) + if c != 'e' && c != 'E' { + return false + } + // The E must not be the tail of a longer identifier. + return !isIdentPart(l.at(i - 2)) +} + +func (l *lexer) skipQuoted(i int, quote byte, backslash bool) int { + for j := i + 1; j < len(l.src); j++ { + switch l.src[j] { + case '\\': + if backslash { + j++ + } + case quote: + // A doubled quote is an escaped quote, not the end. + if l.at(j+1) == quote { + j++ + continue + } + return j + 1 + } + } + return len(l.src) +} + +func (l *lexer) skipLine(i int) int { + if idx := strings.IndexByte(l.src[i:], '\n'); idx >= 0 { + return i + idx + 1 + } + return len(l.src) +} + +func (l *lexer) skipBlockComment(i int) int { + depth := 0 + for j := i; j < len(l.src)-1; j++ { + if l.src[j] == '/' && l.src[j+1] == '*' { + depth++ + j++ + continue + } + if l.src[j] == '*' && l.src[j+1] == '/' { + depth-- + j++ + if depth == 0 || !l.d.NestedBlockComment { + return j + 1 + } + } + } + return len(l.src) +} + +// skipDollarQuoted handles PostgreSQL's $tag$ ... $tag$ string literals. It +// returns -1 when i does not start a dollar quote. +func (l *lexer) skipDollarQuoted(i int) int { + tag := l.dollarTag(i) + if tag == "" { + return -1 + } + if idx := strings.Index(l.src[i+len(tag):], tag); idx >= 0 { + return i + len(tag) + idx + len(tag) + } + return len(l.src) +} + +// dollarTag returns the full opening delimiter ("$$" or "$tag$") when one +// starts at i, and "" otherwise. +func (l *lexer) dollarTag(i int) string { + if l.at(i) != '$' { + return "" + } + j := i + 1 + for j < len(l.src) && l.src[j] != '$' { + c := l.src[j] + if isDigit(c) && j == i+1 { + return "" // $1 is a bind parameter, not a tag + } + if !isIdentPart(c) || c == '$' { + return "" + } + j++ + } + if j >= len(l.src) { + return "" + } + return l.src[i : j+1] +} + +// identEnd returns the offset just past the identifier that starts at i. +func (l *lexer) identEnd(i int) int { + j := i + for j < len(l.src) && isIdentPart(l.src[j]) { + j++ + } + return j +} + +// skipSpace advances past whitespace and comments. +func (l *lexer) skipSpace(i int) int { + for i < len(l.src) { + if isSpace(l.src[i]) { + i++ + continue + } + if l.src[i] == '-' && l.at(i+1) == '-' { + i = l.skipLine(i) + continue + } + if l.src[i] == '/' && l.at(i+1) == '*' { + i = l.skipBlockComment(i) + continue + } + if l.src[i] == '#' && l.d.HashComment { + i = l.skipLine(i) + continue + } + break + } + return i +} + +// statements splits the source into statement spans at top-level semicolons. +// The spans cover the whole source, so every byte belongs to exactly one +// statement. +func (l *lexer) statements() [][2]int { + var out [][2]int + start := 0 + for i := 0; i < len(l.src); { + if end := l.skip(i); end >= 0 { + i = end + continue + } + if l.src[i] == ';' { + out = append(out, [2]int{start, i + 1}) + start = i + 1 + } + i++ + } + if start < len(l.src) { + out = append(out, [2]int{start, len(l.src)}) + } + return out +} + +// matchParen returns the offset of the ")" that closes the "(" at i, or -1. +func (l *lexer) matchParen(i int) int { + depth := 0 + for j := i; j < len(l.src); { + if end := l.skip(j); end >= 0 { + j = end + continue + } + switch l.src[j] { + case '(': + depth++ + case ')': + depth-- + if depth == 0 { + return j + } + } + j++ + } + return -1 +} + +// splitArgs splits the text between parentheses on top-level commas. Empty or +// whitespace-only input yields no arguments. +func (l *lexer) splitArgs(start, end int) []string { + var args []string + depth := 0 + last := start + for j := start; j < end; { + if stop := l.skip(j); stop >= 0 { + if stop > end { + stop = end + } + j = stop + continue + } + switch l.src[j] { + case '(': + depth++ + case ')': + depth-- + case ',': + if depth == 0 { + args = append(args, l.src[last:j]) + last = j + 1 + } + } + j++ + } + tail := l.src[last:end] + if len(args) == 0 && strings.TrimSpace(tail) == "" { + return nil + } + return append(args, tail) +} diff --git a/internal/sql/preprocess/preprocess.go b/internal/sql/preprocess/preprocess.go new file mode 100644 index 0000000..ad25bc9 --- /dev/null +++ b/internal/sql/preprocess/preprocess.go @@ -0,0 +1,398 @@ +// Package preprocess rewrites sqlc's query syntax into native SQL before any +// engine parser sees a query. +// +// sqlc.arg(), sqlc.narg(), sqlc.slice(), sqlc.embed() and @name are sqlc +// syntax, not SQL. Historically they survived all the way through each engine's +// parser and were replaced by walking the resulting AST, which meant every +// engine had to round-trip a schema-qualified function call it did not +// understand. This package removes that requirement: it scans the query text +// with a dialect-parameterized lexer, replaces each construct with the engine's +// native placeholder, and records what it replaced. Engines then only ever see +// valid SQL. +package preprocess + +import ( + "errors" + "fmt" + "strings" + + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/named" + "github.com/sqlc-dev/sqlc/internal/sql/sqlerr" +) + +// Embed is a rewritten sqlc.embed(table) call. +type Embed struct { + Table *ast.TableName + + // Location is the offset of the rewritten "table.*" in the preprocessed + // text. The compiler uses it to tell a rewritten star reference apart from + // one the user wrote. + Location int + + param string +} + +// Orig returns the sqlc syntax this embed was rewritten from. +func (e Embed) Orig() string { + return fmt.Sprintf("sqlc.embed(%s)", e.param) +} + +// EmbedSet is the set of embeds in a single statement. +type EmbedSet []*Embed + +// Find returns the embed recorded at any of the given locations. Engines do not +// all populate the same location fields, so callers pass every location that +// could identify the node. +func (es EmbedSet) Find(locations ...int) (*Embed, bool) { + for _, e := range es { + for _, loc := range locations { + if loc == e.Location { + return e, true + } + } + } + return nil, false +} + +// Statement holds everything the preprocessor learned about a single statement. +type Statement struct { + // Start and End delimit the statement in the rewritten text. + Start, End int + + // Params maps each placeholder number to its sqlc metadata. + Params *named.ParamSet + + // Embeds records the sqlc.embed() calls that were rewritten to "table.*". + Embeds EmbedSet + + // Slices holds the offset, in the rewritten text, of every placeholder that + // came from sqlc.slice(), mapped to the parameter name. + Slices map[int]string + + // Numbers maps the offset of every placeholder in the rewritten text to the + // number assigned to it. Engines number bind parameters in whatever order + // they happen to convert the AST, so the compiler uses this to restore + // source order. + Numbers map[int]int + + // Dollar reports whether the statement's own placeholders are numbered. + Dollar bool + + // ParamErr is set when the placeholders the user wrote are inconsistent: + // numbered and unnumbered styles mixed, or a gap in the numbering. + ParamErr error + + // Err is a validation error found while rewriting. The statement text is + // left untouched when this is set, so the engine still sees the original + // query and the error can be reported against it. + Err error +} + +// Result is the outcome of preprocessing a SQL file. +type Result struct { + // Text is the rewritten SQL. It has the same number of statements and the + // same line structure as the input. + Text string + + stmts []*Statement + edits []edit +} + +// edit records one rewritten span, in both coordinate systems. +type edit struct { + oldStart, oldEnd int + newStart, newEnd int +} + +// Statements returns every statement in the rewritten text, in source order. +func (r *Result) Statements() []*Statement { + return r.stmts +} + +// Statement returns the preprocessing results for the statement covering the +// given offset in the rewritten text. It never returns nil. +func (r *Result) Statement(location int) *Statement { + for _, s := range r.stmts { + if location < s.End { + return s + } + } + return &Statement{Params: named.NewParamSet(nil, true)} +} + +// Origin maps an offset in the rewritten text back to the offset in the +// original source, so errors can be reported against what the user wrote. +func (r *Result) Origin(location int) int { + delta := 0 + for _, e := range r.edits { + if location < e.newStart { + break + } + if location < e.newEnd { + return e.oldStart + } + delta += (e.oldEnd - e.oldStart) - (e.newEnd - e.newStart) + } + return location + delta +} + +type kind int + +const ( + kindArg kind = iota + kindNarg + kindSlice + kindEmbed + kindNative +) + +// occurrence is one construct found in the query text. +type occurrence struct { + kind kind + start int // offset in the original source + end int + name string + // ident is the argument exactly as written, used to rebuild "table.*" for + // embeds so quoting is preserved. + ident string + // number is the placeholder number assigned to this occurrence. + number int + // explicit reports whether a native placeholder carried its own number. + explicit bool + err *sqlerr.Error +} + +// File rewrites every sqlc construct in src to native SQL for the given engine. +// +// An engine that is not preprocessed — GoogleSQL, which handles its own +// parameter syntax — gets the source back unchanged, with an empty side +// table. sqlc.arg() and friends are not rewritten for it, so they reach the +// parser as the function calls they look like. +func File(engine config.Engine, src string) *Result { + d, ok := DialectFor(engine) + if !ok { + return &Result{Text: src} + } + return Dialected(d, src) +} + +// Dialected rewrites src using an explicit dialect. +func Dialected(d Dialect, src string) *Result { + l := &lexer{d: d, src: src} + res := &Result{} + + var b strings.Builder + b.Grow(len(src)) + + spans := l.statements() + for i, span := range spans { + start, end := span[0], span[1] + + // Whatever trails the last semicolon is only whitespace in a + // well-formed file. It still belongs in the output, but it is not a + // statement. + if i == len(spans)-1 && strings.TrimSpace(src[start:end]) == "" { + b.WriteString(src[start:end]) + continue + } + + occs := l.scan(start, end) + stmt := &Statement{Start: b.Len()} + + // A statement that fails validation is copied through unchanged so the + // engine parses what the user actually wrote and the error keeps its + // original shape. + if err := firstError(occs); err != nil { + b.WriteString(src[start:end]) + stmt.End = b.Len() + err.Location = stmt.Start + (err.Location - start) + stmt.Err = err + stmt.Params = named.NewParamSet(nil, d.hasNamedSupport()) + stmt.Dollar = true + res.stmts = append(res.stmts, stmt) + continue + } + + stmt.Dollar, stmt.ParamErr = validatePlaceholders(occs) + stmt.Params = number(d, occs) + stmt.Numbers = map[int]int{} + + prev := start + for i := range occs { + occ := &occs[i] + b.WriteString(src[prev:occ.start]) + newStart := b.Len() + replacement := d.replacement(occ) + b.WriteString(replacement) + newEnd := b.Len() + prev = occ.end + + if replacement != src[occ.start:occ.end] { + res.edits = append(res.edits, edit{ + oldStart: occ.start, oldEnd: occ.end, + newStart: newStart, newEnd: newEnd, + }) + } + + if occ.kind != kindEmbed { + stmt.Numbers[newStart+sliceMarkerLen(d, occ)] = occ.number + } + + switch occ.kind { + case kindEmbed: + stmt.Embeds = append(stmt.Embeds, &Embed{ + Table: &ast.TableName{Name: occ.name}, + Location: newStart, + param: occ.ident, + }) + case kindSlice: + if stmt.Slices == nil { + stmt.Slices = map[int]string{} + } + // The placeholder follows the /*SLICE:name*/ marker, so record + // the offset the engine will report for the parameter node. + stmt.Slices[newStart+sliceMarkerLen(d, occ)] = occ.name + } + } + b.WriteString(src[prev:end]) + stmt.End = b.Len() + res.stmts = append(res.stmts, stmt) + } + + res.Text = b.String() + return res +} + +func firstError(occs []occurrence) *sqlerr.Error { + for _, occ := range occs { + if occ.err != nil { + return occ.err + } + } + return nil +} + +// sliceMarkerLen returns the length of the /*SLICE:name*/ prefix a slice +// placeholder is written with, or 0 when there is none. +func sliceMarkerLen(d Dialect, occ *occurrence) int { + if occ.kind != kindSlice || d.Style == StyleDollar { + return 0 + } + return len("/*SLICE:") + len(occ.name) + len("*/") +} + +// validatePlaceholders checks the placeholders the user wrote, reproducing the +// rules the AST-based validator applied before sqlc syntax was rewritten: a +// query may not mix numbered and unnumbered placeholders, and the numbers it +// does use may not have gaps. +func validatePlaceholders(occs []occurrence) (dollar bool, err error) { + var numbered, unnumbered bool + seen := map[int]bool{} + for _, occ := range occs { + if occ.kind != kindNative { + continue + } + if occ.explicit { + numbered = true + seen[occ.number] = true + } else { + unnumbered = true + } + } + if numbered && unnumbered { + return false, errors.New("can not mix $1 format with ? format") + } + for i := 1; i <= len(seen); i++ { + if !seen[i] { + return !unnumbered, &sqlerr.Error{ + Code: "42P18", + Message: fmt.Sprintf("could not determine data type of parameter $%d", i), + } + } + } + return !unnumbered, nil +} + +// number assigns a placeholder number to every occurrence and builds the +// parameter set for the statement. +func number(d Dialect, occs []occurrence) *named.ParamSet { + if d.Style == StyleQuestion { + // Every "?" is sent as its own argument, so existing and rewritten + // placeholders are numbered together in source order. + ps := named.NewParamSet(nil, false) + for i := range occs { + occ := &occs[i] + if occ.kind == kindEmbed { + continue + } + occ.number = ps.Add(param(occ)) + } + return ps + } + + // Numbered dialects keep the numbers the user wrote and fill in the gaps. + numbs := map[int]bool{} + count := 0 + for i := range occs { + occ := &occs[i] + if occ.kind != kindNative { + continue + } + count++ + if !occ.explicit { + occ.number = count + } + numbs[occ.number] = true + } + ps := named.NewParamSet(numbs, d.hasNamedSupport()) + for i := range occs { + occ := &occs[i] + if occ.kind == kindEmbed || occ.kind == kindNative { + continue + } + occ.number = ps.Add(param(occ)) + } + return ps +} + +func param(occ *occurrence) named.Param { + switch occ.kind { + case kindNarg: + return named.NewUserNullableParam(occ.name) + case kindSlice: + return named.NewSqlcSlice(occ.name) + default: + return named.NewParam(occ.name) + } +} + +// replacement returns the native SQL that stands in for an occurrence. +func (d Dialect) replacement(occ *occurrence) string { + switch occ.kind { + case kindEmbed: + return occ.ident + ".*" + case kindNative: + return occ.ident + } + switch d.Style { + case StyleDollar: + // PostgreSQL passes a slice as a single array parameter, so it needs no + // expansion marker. + return fmt.Sprintf("$%d", occ.number) + case StyleOrdinal: + if occ.kind == kindSlice { + // This sequence is also replicated in + // internal/codegen/golang.Field since it's needed during template + // generation for replacement. + return fmt.Sprintf("/*SLICE:%s*/?", occ.name) + } + return fmt.Sprintf("?%d", occ.number) + default: + if occ.kind == kindSlice { + return fmt.Sprintf("/*SLICE:%s*/?", occ.name) + } + return "?" + } +} diff --git a/internal/sql/preprocess/preprocess_test.go b/internal/sql/preprocess/preprocess_test.go new file mode 100644 index 0000000..5b0eb3e --- /dev/null +++ b/internal/sql/preprocess/preprocess_test.go @@ -0,0 +1,232 @@ +package preprocess_test + +import ( + "encoding/json" + "flag" + "fmt" + "os" + "path/filepath" + "sort" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/source" + "github.com/sqlc-dev/sqlc/internal/sql/named" + "github.com/sqlc-dev/sqlc/internal/sql/preprocess" + "github.com/sqlc-dev/sqlc/internal/sql/sqlerr" +) + +var update = flag.Bool("update", false, "update the testdata golden files") + +// TestRewrite runs every case under testdata. Each case is a directory holding +// the input and the expected results, grouped by engine: +// +// testdata///input.sql the query file +// testdata///output.sql the rewritten SQL +// testdata///side_table.json what the preprocessor recorded +// testdata///stderr.txt reported errors (only when invalid) +// +// Regenerate the golden files with `go test ./internal/sql/preprocess -update`. +func TestRewrite(t *testing.T) { + for _, dir := range cases(t) { + t.Run(filepath.ToSlash(dir), func(t *testing.T) { + path := filepath.Join("testdata", dir) + engine := config.Engine(filepath.Dir(dir)) + + input := readFile(t, filepath.Join(path, "input.sql")) + res := preprocess.File(engine, input) + + compare(t, filepath.Join(path, "output.sql"), res.Text) + compare(t, filepath.Join(path, "side_table.json"), sideTable(res)) + compare(t, filepath.Join(path, "stderr.txt"), errors(input, res)) + + // A rewrite only ever replaces text with something shorter or + // equal in lines, so a line number taken from the rewritten text is + // never past the end of the original. + if want, got := strings.Count(input, "\n"), strings.Count(res.Text, "\n"); got > want { + t.Errorf("rewrite added lines: got %d, want at most %d", got, want) + } + }) + } +} + +// The JSON shape of the side table the preprocessor records alongside the +// rewritten SQL. Locations are offsets into the rewritten text; origins are the +// offsets they map back to in the original source. +type statement struct { + Start int `json:"start"` + End int `json:"end"` + Dollar bool `json:"dollar"` + Params []parameter `json:"params,omitempty"` + Embeds []embed `json:"embeds,omitempty"` + Error string `json:"error,omitempty"` + ErrorAt int `json:"error_at,omitempty"` + ParamError string `json:"param_error,omitempty"` +} + +type parameter struct { + Number int `json:"number"` + Location int `json:"location"` + Origin int `json:"origin"` + Name string `json:"name,omitempty"` + // Named is false for a placeholder the user wrote themselves, which the + // preprocessor numbers but does not name. + Named bool `json:"named"` + // Nullable is true when sqlc.narg() forced the parameter nullable, even + // though the schema says it is NOT NULL. + Nullable bool `json:"nullable,omitempty"` + Slice bool `json:"slice,omitempty"` +} + +type embed struct { + Table string `json:"table"` + Location int `json:"location"` + Origin int `json:"origin"` + Orig string `json:"orig"` +} + +// sideTable renders everything the preprocessor recorded, reading it back +// through the same API the compiler uses. +func sideTable(res *preprocess.Result) string { + out := make([]statement, 0, len(res.Statements())) + for _, stmt := range res.Statements() { + s := statement{Start: stmt.Start, End: stmt.End, Dollar: stmt.Dollar} + if stmt.Err != nil { + s.Error = stmt.Err.Error() + if e, ok := stmt.Err.(*sqlerr.Error); ok { + s.ErrorAt = e.Location + } + } + if stmt.ParamErr != nil { + s.ParamError = stmt.ParamErr.Error() + } + + locations := make([]int, 0, len(stmt.Numbers)) + for loc := range stmt.Numbers { + locations = append(locations, loc) + } + sort.Ints(locations) + for _, loc := range locations { + number := stmt.Numbers[loc] + name, _ := stmt.Params.NameFor(number) + // Merging against a NOT NULL parameter is how the compiler asks + // whether the user overrode nullability with sqlc.narg(). + p, isNamed := stmt.Params.FetchMerge(number, named.NewInferredParam(name, true)) + _, isSlice := stmt.Slices[loc] + s.Params = append(s.Params, parameter{ + Number: number, + Location: loc, + Origin: res.Origin(loc), + Name: name, + Named: isNamed, + Nullable: isNamed && !p.NotNull(), + Slice: isSlice, + }) + } + + for _, e := range stmt.Embeds { + s.Embeds = append(s.Embeds, embed{ + Table: e.Table.Name, + Location: e.Location, + Origin: res.Origin(e.Location), + Orig: e.Orig(), + }) + } + out = append(out, s) + } + + blob, err := json.MarshalIndent(out, "", " ") + if err != nil { + panic(err) + } + return string(blob) + "\n" +} + +// errors renders every validation error the preprocessor recorded, one per +// line, as "line:column: message" against the original source. +func errors(input string, res *preprocess.Result) string { + var out []string + for _, stmt := range res.Statements() { + for _, err := range []error{stmt.Err, stmt.ParamErr} { + if err == nil { + continue + } + loc := stmt.Start + if e, ok := err.(*sqlerr.Error); ok && e.Location != 0 { + loc = e.Location + } + line, column := source.LineNumber(input, res.Origin(loc)) + out = append(out, fmt.Sprintf("%d:%d: %s", line, column, err)) + } + } + if len(out) == 0 { + return "" + } + return strings.Join(out, "\n") + "\n" +} + +// cases returns every testdata directory that holds an input.sql, relative to +// testdata and in a stable order. +func cases(t *testing.T) []string { + t.Helper() + var dirs []string + err := filepath.Walk("testdata", func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() || info.Name() != "input.sql" { + return nil + } + rel, err := filepath.Rel("testdata", filepath.Dir(path)) + if err != nil { + return err + } + dirs = append(dirs, rel) + return nil + }) + if err != nil { + t.Fatal(err) + } + if len(dirs) == 0 { + t.Fatal("no test cases found in testdata") + } + sort.Strings(dirs) + return dirs +} + +func readFile(t *testing.T, path string) string { + t.Helper() + blob, err := os.ReadFile(path) + if err != nil { + t.Fatal(err) + } + return string(blob) +} + +// compare checks actual against a golden file. An empty expectation means the +// file should not exist. +func compare(t *testing.T, path, actual string) { + t.Helper() + if *update { + if actual == "" { + os.Remove(path) + return + } + if err := os.WriteFile(path, []byte(actual), 0644); err != nil { + t.Fatal(err) + } + return + } + var expected string + if blob, err := os.ReadFile(path); err == nil { + expected = string(blob) + } else if !os.IsNotExist(err) { + t.Fatal(err) + } + if diff := cmp.Diff(expected, actual); diff != "" { + t.Errorf("%s differed (-want +got):\n%s", filepath.Base(path), diff) + } +} diff --git a/internal/sql/preprocess/scan.go b/internal/sql/preprocess/scan.go new file mode 100644 index 0000000..b2b4b1f --- /dev/null +++ b/internal/sql/preprocess/scan.go @@ -0,0 +1,209 @@ +package preprocess + +import ( + "fmt" + "strconv" + "strings" + + "github.com/sqlc-dev/sqlc/internal/sql/sqlerr" +) + +// scan walks a single statement and returns every sqlc construct and native +// placeholder it contains, in source order. +func (l *lexer) scan(start, end int) []occurrence { + var out []occurrence + for i := start; i < end; { + if stop := l.skip(i); stop >= 0 { + if stop <= i { + stop = i + 1 + } + i = stop + continue + } + c := l.src[i] + switch { + case isIdentStart(c): + j := l.identEnd(i) + if strings.EqualFold(l.src[i:j], "sqlc") { + if occ, next, ok := l.sqlcCall(i, j); ok { + out = append(out, occ) + i = next + continue + } + } + i = j + + case c == '@' && l.d.AtSign && isIdentStart(l.at(i+1)): + j := l.identEnd(i + 1) + out = append(out, occurrence{ + kind: kindArg, + start: i, + end: j, + name: l.src[i+1 : j], + ident: l.src[i:j], + }) + i = j + + case c == '$' && l.d.DollarNumber && isDigit(l.at(i+1)): + j := i + 1 + for j < len(l.src) && isDigit(l.src[j]) { + j++ + } + n, _ := strconv.Atoi(l.src[i+1 : j]) + out = append(out, occurrence{ + kind: kindNative, + start: i, + end: j, + number: n, + explicit: true, + ident: l.src[i:j], + }) + i = j + + case c == '?' && l.d.Question: + j := i + 1 + for j < len(l.src) && isDigit(l.src[j]) { + j++ + } + occ := occurrence{kind: kindNative, start: i, end: j, ident: l.src[i:j]} + if j > i+1 { + occ.number, _ = strconv.Atoi(l.src[i+1 : j]) + occ.explicit = true + } + out = append(out, occ) + i = j + + default: + i++ + } + } + return out +} + +// sqlcCall parses a "sqlc.()" call that starts at start, where +// afterSqlc is the offset just past the "sqlc" identifier. It reports false +// when the text is not a sqlc call at all, in which case scanning continues +// normally. +func (l *lexer) sqlcCall(start, afterSqlc int) (occurrence, int, bool) { + i := l.skipSpace(afterSqlc) + if l.at(i) != '.' { + return occurrence{}, 0, false + } + i = l.skipSpace(i + 1) + if !isIdentStart(l.at(i)) { + return occurrence{}, 0, false + } + nameEnd := l.identEnd(i) + fn := strings.ToLower(l.src[i:nameEnd]) + + open := l.skipSpace(nameEnd) + if l.at(open) != '(' { + return occurrence{}, 0, false + } + closing := l.matchParen(open) + if closing < 0 { + return occurrence{}, 0, false + } + + occ := occurrence{start: start, end: closing + 1} + switch fn { + case "arg": + occ.kind = kindArg + case "narg": + occ.kind = kindNarg + case "slice": + occ.kind = kindSlice + case "embed": + occ.kind = kindEmbed + default: + occ.err = sqlerr.FunctionNotFound("sqlc." + fn) + occ.err.Location = start + return occ, occ.end, true + } + + args := l.splitArgs(open+1, closing) + if len(args) != 1 { + occ.err = &sqlerr.Error{ + Message: fmt.Sprintf("expected 1 parameter to sqlc.%s; got %d", fn, len(args)), + Location: start, + } + return occ, occ.end, true + } + + name, ident, ok := argument(l.d, args[0]) + if !ok { + occ.err = &sqlerr.Error{ + Message: fmt.Sprintf("expected parameter to sqlc.%s to be string or reference; got %q", fn, strings.TrimSpace(args[0])), + Location: start, + } + return occ, occ.end, true + } + occ.name = name + occ.ident = ident + return occ, occ.end, true +} + +// argument interprets the single argument to a sqlc function. It returns the +// parameter name and the text to reuse when rebuilding a reference, which keeps +// any identifier quoting the user wrote. +func argument(d Dialect, arg string) (name, ident string, ok bool) { + arg = strings.TrimSpace(arg) + if arg == "" { + return "", "", false + } + switch arg[0] { + case '\'': + // A string constant names the parameter but is not a reference, so the + // rebuilt identifier drops the quotes. + s, ok := unquote(arg, '\'') + return s, s, ok + case '"': + s, ok := unquote(arg, '"') + if !ok { + return "", "", false + } + if d.DoubleQuoteString { + return s, s, true + } + return s, arg, true + case '`': + if !d.Backtick { + return "", "", false + } + s, ok := unquote(arg, '`') + if !ok { + return "", "", false + } + return s, arg, true + } + if !isIdentStart(arg[0]) { + return "", "", false + } + for i := 0; i < len(arg); i++ { + if !isIdentPart(arg[i]) && arg[i] != '.' { + return "", "", false + } + } + // A qualified reference flattens to a single name, matching how the AST + // rewrite joined the parts of a ColumnRef. + name = strings.ReplaceAll(arg, ".", "") + if d.FoldIdentifier { + name = strings.ToLower(name) + } + return name, arg, true +} + +func unquote(s string, quote byte) (string, bool) { + if len(s) < 2 || s[0] != quote || s[len(s)-1] != quote { + return "", false + } + inner := s[1 : len(s)-1] + if strings.IndexByte(inner, quote) >= 0 { + doubled := string([]byte{quote, quote}) + if strings.Contains(inner, doubled) { + return strings.ReplaceAll(inner, doubled, string(quote)), true + } + return "", false + } + return inner, true +} diff --git a/internal/sql/preprocess/testdata/mysql/arg/input.sql b/internal/sql/preprocess/testdata/mysql/arg/input.sql new file mode 100644 index 0000000..180ea26 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/arg/input.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE a = sqlc.arg(x) AND b = sqlc.arg(x); diff --git a/internal/sql/preprocess/testdata/mysql/arg/output.sql b/internal/sql/preprocess/testdata/mysql/arg/output.sql new file mode 100644 index 0000000..0091b6d --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/arg/output.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE a = ? AND b = ?; diff --git a/internal/sql/preprocess/testdata/mysql/arg/side_table.json b/internal/sql/preprocess/testdata/mysql/arg/side_table.json new file mode 100644 index 0000000..78b83b3 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/arg/side_table.json @@ -0,0 +1,23 @@ +[ + { + "start": 0, + "end": 43, + "dollar": true, + "params": [ + { + "number": 1, + "location": 31, + "origin": 31, + "name": "x", + "named": true + }, + { + "number": 2, + "location": 41, + "origin": 51, + "name": "x", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/mysql/dollar_number_is_not_a_placeholder/input.sql b/internal/sql/preprocess/testdata/mysql/dollar_number_is_not_a_placeholder/input.sql new file mode 100644 index 0000000..d933db8 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/dollar_number_is_not_a_placeholder/input.sql @@ -0,0 +1 @@ +SELECT * FROM second_view WHERE val2 = $1; diff --git a/internal/sql/preprocess/testdata/mysql/dollar_number_is_not_a_placeholder/output.sql b/internal/sql/preprocess/testdata/mysql/dollar_number_is_not_a_placeholder/output.sql new file mode 100644 index 0000000..d933db8 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/dollar_number_is_not_a_placeholder/output.sql @@ -0,0 +1 @@ +SELECT * FROM second_view WHERE val2 = $1; diff --git a/internal/sql/preprocess/testdata/mysql/dollar_number_is_not_a_placeholder/side_table.json b/internal/sql/preprocess/testdata/mysql/dollar_number_is_not_a_placeholder/side_table.json new file mode 100644 index 0000000..05701e1 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/dollar_number_is_not_a_placeholder/side_table.json @@ -0,0 +1,7 @@ +[ + { + "start": 0, + "end": 42, + "dollar": true + } +] diff --git a/internal/sql/preprocess/testdata/mysql/double_quoted_argument/input.sql b/internal/sql/preprocess/testdata/mysql/double_quoted_argument/input.sql new file mode 100644 index 0000000..37f4314 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/double_quoted_argument/input.sql @@ -0,0 +1,4 @@ +SELECT + (CASE WHEN sqlc.arg("Timezone") = "calendar" THEN cal.Timezone ELSE sqlc.arg("Timezone") END), + COALESCE(sqlc.narg("calName"), "") +FROM Calendar cal; diff --git a/internal/sql/preprocess/testdata/mysql/double_quoted_argument/output.sql b/internal/sql/preprocess/testdata/mysql/double_quoted_argument/output.sql new file mode 100644 index 0000000..201532c --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/double_quoted_argument/output.sql @@ -0,0 +1,4 @@ +SELECT + (CASE WHEN ? = "calendar" THEN cal.Timezone ELSE ? END), + COALESCE(?, "") +FROM Calendar cal; diff --git a/internal/sql/preprocess/testdata/mysql/double_quoted_argument/side_table.json b/internal/sql/preprocess/testdata/mysql/double_quoted_argument/side_table.json new file mode 100644 index 0000000..711a883 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/double_quoted_argument/side_table.json @@ -0,0 +1,31 @@ +[ + { + "start": 0, + "end": 106, + "dollar": true, + "params": [ + { + "number": 1, + "location": 22, + "origin": 22, + "name": "Timezone", + "named": true + }, + { + "number": 2, + "location": 60, + "origin": 79, + "name": "Timezone", + "named": true + }, + { + "number": 3, + "location": 81, + "origin": 119, + "name": "calName", + "named": true, + "nullable": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/mysql/embed/input.sql b/internal/sql/preprocess/testdata/mysql/embed/input.sql new file mode 100644 index 0000000..bb5188a --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/embed/input.sql @@ -0,0 +1 @@ +SELECT sqlc.embed(users) FROM users; diff --git a/internal/sql/preprocess/testdata/mysql/embed/output.sql b/internal/sql/preprocess/testdata/mysql/embed/output.sql new file mode 100644 index 0000000..e9d0968 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/embed/output.sql @@ -0,0 +1 @@ +SELECT users.* FROM users; diff --git a/internal/sql/preprocess/testdata/mysql/embed/side_table.json b/internal/sql/preprocess/testdata/mysql/embed/side_table.json new file mode 100644 index 0000000..840d08c --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/embed/side_table.json @@ -0,0 +1,15 @@ +[ + { + "start": 0, + "end": 26, + "dollar": true, + "embeds": [ + { + "table": "users", + "location": 7, + "origin": 7, + "orig": "sqlc.embed(users)" + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/mysql/error_invalid_calls/input.sql b/internal/sql/preprocess/testdata/mysql/error_invalid_calls/input.sql new file mode 100644 index 0000000..51f7ddb --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/error_invalid_calls/input.sql @@ -0,0 +1,11 @@ +-- name: WrongFunc :one +SELECT id FROM users WHERE id = sqlc.argh(target_id); + +-- name: TooManyArgs :one +SELECT id FROM users WHERE id = sqlc.arg('foo', 'bar'); + +-- name: TooFewArgs :one +SELECT id FROM users WHERE id = sqlc.arg(); + +-- name: InvalidArgPlaceholder :one +SELECT id FROM users WHERE id = sqlc.arg(?); diff --git a/internal/sql/preprocess/testdata/mysql/error_invalid_calls/output.sql b/internal/sql/preprocess/testdata/mysql/error_invalid_calls/output.sql new file mode 100644 index 0000000..51f7ddb --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/error_invalid_calls/output.sql @@ -0,0 +1,11 @@ +-- name: WrongFunc :one +SELECT id FROM users WHERE id = sqlc.argh(target_id); + +-- name: TooManyArgs :one +SELECT id FROM users WHERE id = sqlc.arg('foo', 'bar'); + +-- name: TooFewArgs :one +SELECT id FROM users WHERE id = sqlc.arg(); + +-- name: InvalidArgPlaceholder :one +SELECT id FROM users WHERE id = sqlc.arg(?); diff --git a/internal/sql/preprocess/testdata/mysql/error_invalid_calls/side_table.json b/internal/sql/preprocess/testdata/mysql/error_invalid_calls/side_table.json new file mode 100644 index 0000000..a36ba15 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/error_invalid_calls/side_table.json @@ -0,0 +1,30 @@ +[ + { + "start": 0, + "end": 77, + "dollar": true, + "error": "function \"sqlc.argh\" does not exist", + "error_at": 56 + }, + { + "start": 77, + "end": 160, + "dollar": true, + "error": "expected 1 parameter to sqlc.arg; got 2", + "error_at": 137 + }, + { + "start": 160, + "end": 230, + "dollar": true, + "error": "expected 1 parameter to sqlc.arg; got 0", + "error_at": 219 + }, + { + "start": 230, + "end": 312, + "dollar": true, + "error": "expected parameter to sqlc.arg to be string or reference; got \"?\"", + "error_at": 300 + } +] diff --git a/internal/sql/preprocess/testdata/mysql/error_invalid_calls/stderr.txt b/internal/sql/preprocess/testdata/mysql/error_invalid_calls/stderr.txt new file mode 100644 index 0000000..aae154e --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/error_invalid_calls/stderr.txt @@ -0,0 +1,4 @@ +2:33: function "sqlc.argh" does not exist +5:33: expected 1 parameter to sqlc.arg; got 2 +8:33: expected 1 parameter to sqlc.arg; got 0 +11:33: expected parameter to sqlc.arg to be string or reference; got "?" diff --git a/internal/sql/preprocess/testdata/mysql/existing_placeholders_are_numbered_together/input.sql b/internal/sql/preprocess/testdata/mysql/existing_placeholders_are_numbered_together/input.sql new file mode 100644 index 0000000..9b9c756 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/existing_placeholders_are_numbered_together/input.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE a = ? AND b = sqlc.arg(x) AND c = ?; diff --git a/internal/sql/preprocess/testdata/mysql/existing_placeholders_are_numbered_together/output.sql b/internal/sql/preprocess/testdata/mysql/existing_placeholders_are_numbered_together/output.sql new file mode 100644 index 0000000..8f52c1a --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/existing_placeholders_are_numbered_together/output.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE a = ? AND b = ? AND c = ?; diff --git a/internal/sql/preprocess/testdata/mysql/existing_placeholders_are_numbered_together/side_table.json b/internal/sql/preprocess/testdata/mysql/existing_placeholders_are_numbered_together/side_table.json new file mode 100644 index 0000000..2f8a512 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/existing_placeholders_are_numbered_together/side_table.json @@ -0,0 +1,28 @@ +[ + { + "start": 0, + "end": 53, + "dollar": false, + "params": [ + { + "number": 1, + "location": 31, + "origin": 31, + "named": false + }, + { + "number": 2, + "location": 41, + "origin": 41, + "name": "x", + "named": true + }, + { + "number": 3, + "location": 51, + "origin": 61, + "named": false + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/mysql/narg_identifier/input.sql b/internal/sql/preprocess/testdata/mysql/narg_identifier/input.sql new file mode 100644 index 0000000..c36f3d6 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/narg_identifier/input.sql @@ -0,0 +1 @@ +SELECT * FROM users WHERE name = sqlc.narg(name); diff --git a/internal/sql/preprocess/testdata/mysql/narg_identifier/output.sql b/internal/sql/preprocess/testdata/mysql/narg_identifier/output.sql new file mode 100644 index 0000000..e48f330 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/narg_identifier/output.sql @@ -0,0 +1 @@ +SELECT * FROM users WHERE name = ?; diff --git a/internal/sql/preprocess/testdata/mysql/narg_identifier/side_table.json b/internal/sql/preprocess/testdata/mysql/narg_identifier/side_table.json new file mode 100644 index 0000000..c3b25fb --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/narg_identifier/side_table.json @@ -0,0 +1,17 @@ +[ + { + "start": 0, + "end": 35, + "dollar": true, + "params": [ + { + "number": 1, + "location": 33, + "origin": 33, + "name": "name", + "named": true, + "nullable": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/mysql/on_duplicate_key_update/input.sql b/internal/sql/preprocess/testdata/mysql/on_duplicate_key_update/input.sql new file mode 100644 index 0000000..4da5824 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/on_duplicate_key_update/input.sql @@ -0,0 +1,2 @@ +INSERT INTO t (a) VALUES (sqlc.arg(val)) +ON DUPLICATE KEY UPDATE a = sqlc.arg(new_val); diff --git a/internal/sql/preprocess/testdata/mysql/on_duplicate_key_update/output.sql b/internal/sql/preprocess/testdata/mysql/on_duplicate_key_update/output.sql new file mode 100644 index 0000000..9681976 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/on_duplicate_key_update/output.sql @@ -0,0 +1,2 @@ +INSERT INTO t (a) VALUES (?) +ON DUPLICATE KEY UPDATE a = ?; diff --git a/internal/sql/preprocess/testdata/mysql/on_duplicate_key_update/side_table.json b/internal/sql/preprocess/testdata/mysql/on_duplicate_key_update/side_table.json new file mode 100644 index 0000000..6b4e506 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/on_duplicate_key_update/side_table.json @@ -0,0 +1,23 @@ +[ + { + "start": 0, + "end": 59, + "dollar": true, + "params": [ + { + "number": 1, + "location": 26, + "origin": 26, + "name": "val", + "named": true + }, + { + "number": 2, + "location": 57, + "origin": 69, + "name": "new_val", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/mysql/skip_backslash_escape/input.sql b/internal/sql/preprocess/testdata/mysql/skip_backslash_escape/input.sql new file mode 100644 index 0000000..ae9b08c --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/skip_backslash_escape/input.sql @@ -0,0 +1 @@ +SELECT 'a\' sqlc.arg(nope)'; diff --git a/internal/sql/preprocess/testdata/mysql/skip_backslash_escape/output.sql b/internal/sql/preprocess/testdata/mysql/skip_backslash_escape/output.sql new file mode 100644 index 0000000..ae9b08c --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/skip_backslash_escape/output.sql @@ -0,0 +1 @@ +SELECT 'a\' sqlc.arg(nope)'; diff --git a/internal/sql/preprocess/testdata/mysql/skip_backslash_escape/side_table.json b/internal/sql/preprocess/testdata/mysql/skip_backslash_escape/side_table.json new file mode 100644 index 0000000..7ab9eae --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/skip_backslash_escape/side_table.json @@ -0,0 +1,7 @@ +[ + { + "start": 0, + "end": 28, + "dollar": true + } +] diff --git a/internal/sql/preprocess/testdata/mysql/skip_backtick_identifier/input.sql b/internal/sql/preprocess/testdata/mysql/skip_backtick_identifier/input.sql new file mode 100644 index 0000000..124b3d3 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/skip_backtick_identifier/input.sql @@ -0,0 +1 @@ +SELECT `sqlc.arg(nope)` FROM t; diff --git a/internal/sql/preprocess/testdata/mysql/skip_backtick_identifier/output.sql b/internal/sql/preprocess/testdata/mysql/skip_backtick_identifier/output.sql new file mode 100644 index 0000000..124b3d3 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/skip_backtick_identifier/output.sql @@ -0,0 +1 @@ +SELECT `sqlc.arg(nope)` FROM t; diff --git a/internal/sql/preprocess/testdata/mysql/skip_backtick_identifier/side_table.json b/internal/sql/preprocess/testdata/mysql/skip_backtick_identifier/side_table.json new file mode 100644 index 0000000..cdde9a6 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/skip_backtick_identifier/side_table.json @@ -0,0 +1,7 @@ +[ + { + "start": 0, + "end": 31, + "dollar": true + } +] diff --git a/internal/sql/preprocess/testdata/mysql/skip_double_quoted_string/input.sql b/internal/sql/preprocess/testdata/mysql/skip_double_quoted_string/input.sql new file mode 100644 index 0000000..3fb2557 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/skip_double_quoted_string/input.sql @@ -0,0 +1 @@ +SELECT "sqlc.arg(nope)" FROM t; diff --git a/internal/sql/preprocess/testdata/mysql/skip_double_quoted_string/output.sql b/internal/sql/preprocess/testdata/mysql/skip_double_quoted_string/output.sql new file mode 100644 index 0000000..3fb2557 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/skip_double_quoted_string/output.sql @@ -0,0 +1 @@ +SELECT "sqlc.arg(nope)" FROM t; diff --git a/internal/sql/preprocess/testdata/mysql/skip_double_quoted_string/side_table.json b/internal/sql/preprocess/testdata/mysql/skip_double_quoted_string/side_table.json new file mode 100644 index 0000000..cdde9a6 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/skip_double_quoted_string/side_table.json @@ -0,0 +1,7 @@ +[ + { + "start": 0, + "end": 31, + "dollar": true + } +] diff --git a/internal/sql/preprocess/testdata/mysql/skip_hash_comment/input.sql b/internal/sql/preprocess/testdata/mysql/skip_hash_comment/input.sql new file mode 100644 index 0000000..755efa7 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/skip_hash_comment/input.sql @@ -0,0 +1,2 @@ +# sqlc.arg(nope) +SELECT 1; diff --git a/internal/sql/preprocess/testdata/mysql/skip_hash_comment/output.sql b/internal/sql/preprocess/testdata/mysql/skip_hash_comment/output.sql new file mode 100644 index 0000000..755efa7 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/skip_hash_comment/output.sql @@ -0,0 +1,2 @@ +# sqlc.arg(nope) +SELECT 1; diff --git a/internal/sql/preprocess/testdata/mysql/skip_hash_comment/side_table.json b/internal/sql/preprocess/testdata/mysql/skip_hash_comment/side_table.json new file mode 100644 index 0000000..667e960 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/skip_hash_comment/side_table.json @@ -0,0 +1,7 @@ +[ + { + "start": 0, + "end": 26, + "dollar": true + } +] diff --git a/internal/sql/preprocess/testdata/mysql/slice/input.sql b/internal/sql/preprocess/testdata/mysql/slice/input.sql new file mode 100644 index 0000000..f5d8964 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/slice/input.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE id IN (sqlc.slice(ids)); diff --git a/internal/sql/preprocess/testdata/mysql/slice/output.sql b/internal/sql/preprocess/testdata/mysql/slice/output.sql new file mode 100644 index 0000000..5422151 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/slice/output.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE id IN (/*SLICE:ids*/?); diff --git a/internal/sql/preprocess/testdata/mysql/slice/side_table.json b/internal/sql/preprocess/testdata/mysql/slice/side_table.json new file mode 100644 index 0000000..4b16794 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/slice/side_table.json @@ -0,0 +1,17 @@ +[ + { + "start": 0, + "end": 50, + "dollar": true, + "params": [ + { + "number": 1, + "location": 47, + "origin": 34, + "name": "ids", + "named": true, + "slice": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/mysql/slice_folds_identifier/input.sql b/internal/sql/preprocess/testdata/mysql/slice_folds_identifier/input.sql new file mode 100644 index 0000000..3fdbab3 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/slice_folds_identifier/input.sql @@ -0,0 +1 @@ +SELECT * FROM foo WHERE retyped IN (sqlc.slice(paramName)); diff --git a/internal/sql/preprocess/testdata/mysql/slice_folds_identifier/output.sql b/internal/sql/preprocess/testdata/mysql/slice_folds_identifier/output.sql new file mode 100644 index 0000000..451d50c --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/slice_folds_identifier/output.sql @@ -0,0 +1 @@ +SELECT * FROM foo WHERE retyped IN (/*SLICE:paramname*/?); diff --git a/internal/sql/preprocess/testdata/mysql/slice_folds_identifier/side_table.json b/internal/sql/preprocess/testdata/mysql/slice_folds_identifier/side_table.json new file mode 100644 index 0000000..43154fe --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/slice_folds_identifier/side_table.json @@ -0,0 +1,17 @@ +[ + { + "start": 0, + "end": 58, + "dollar": true, + "params": [ + { + "number": 1, + "location": 55, + "origin": 36, + "name": "paramname", + "named": true, + "slice": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/mysql/string_constant/input.sql b/internal/sql/preprocess/testdata/mysql/string_constant/input.sql new file mode 100644 index 0000000..21f5701 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/string_constant/input.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE a = sqlc.arg('x') AND b = sqlc.narg('y') AND c IN (sqlc.slice('ids')); diff --git a/internal/sql/preprocess/testdata/mysql/string_constant/output.sql b/internal/sql/preprocess/testdata/mysql/string_constant/output.sql new file mode 100644 index 0000000..7dd7adc --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/string_constant/output.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE a = ? AND b = ? AND c IN (/*SLICE:ids*/?); diff --git a/internal/sql/preprocess/testdata/mysql/string_constant/side_table.json b/internal/sql/preprocess/testdata/mysql/string_constant/side_table.json new file mode 100644 index 0000000..45ffcd2 --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/string_constant/side_table.json @@ -0,0 +1,32 @@ +[ + { + "start": 0, + "end": 69, + "dollar": true, + "params": [ + { + "number": 1, + "location": 31, + "origin": 31, + "name": "x", + "named": true + }, + { + "number": 2, + "location": 41, + "origin": 53, + "name": "y", + "named": true, + "nullable": true + }, + { + "number": 3, + "location": 66, + "origin": 78, + "name": "ids", + "named": true, + "slice": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/mysql/string_constant_keeps_case/input.sql b/internal/sql/preprocess/testdata/mysql/string_constant_keeps_case/input.sql new file mode 100644 index 0000000..beec84e --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/string_constant_keeps_case/input.sql @@ -0,0 +1 @@ +SELECT sqlc.arg('MixedCase'), sqlc.arg(MixedCase); diff --git a/internal/sql/preprocess/testdata/mysql/string_constant_keeps_case/output.sql b/internal/sql/preprocess/testdata/mysql/string_constant_keeps_case/output.sql new file mode 100644 index 0000000..99dcdde --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/string_constant_keeps_case/output.sql @@ -0,0 +1 @@ +SELECT ?, ?; diff --git a/internal/sql/preprocess/testdata/mysql/string_constant_keeps_case/side_table.json b/internal/sql/preprocess/testdata/mysql/string_constant_keeps_case/side_table.json new file mode 100644 index 0000000..16a138b --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/string_constant_keeps_case/side_table.json @@ -0,0 +1,23 @@ +[ + { + "start": 0, + "end": 12, + "dollar": true, + "params": [ + { + "number": 1, + "location": 7, + "origin": 7, + "name": "MixedCase", + "named": true + }, + { + "number": 2, + "location": 10, + "origin": 30, + "name": "mixedcase", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/mysql/user_variables_are_not_parameters/input.sql b/internal/sql/preprocess/testdata/mysql/user_variables_are_not_parameters/input.sql new file mode 100644 index 0000000..ce518fc --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/user_variables_are_not_parameters/input.sql @@ -0,0 +1 @@ +SELECT @row := @row + 1 FROM users WHERE id = sqlc.arg(id); diff --git a/internal/sql/preprocess/testdata/mysql/user_variables_are_not_parameters/output.sql b/internal/sql/preprocess/testdata/mysql/user_variables_are_not_parameters/output.sql new file mode 100644 index 0000000..4db8a1b --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/user_variables_are_not_parameters/output.sql @@ -0,0 +1 @@ +SELECT @row := @row + 1 FROM users WHERE id = ?; diff --git a/internal/sql/preprocess/testdata/mysql/user_variables_are_not_parameters/side_table.json b/internal/sql/preprocess/testdata/mysql/user_variables_are_not_parameters/side_table.json new file mode 100644 index 0000000..ccf1ada --- /dev/null +++ b/internal/sql/preprocess/testdata/mysql/user_variables_are_not_parameters/side_table.json @@ -0,0 +1,16 @@ +[ + { + "start": 0, + "end": 48, + "dollar": true, + "params": [ + { + "number": 1, + "location": 46, + "origin": 46, + "name": "id", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/arg/input.sql b/internal/sql/preprocess/testdata/postgresql/arg/input.sql new file mode 100644 index 0000000..4f78775 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/arg/input.sql @@ -0,0 +1,2 @@ +-- name: GetUser :one +SELECT id FROM users WHERE name = sqlc.arg(name); diff --git a/internal/sql/preprocess/testdata/postgresql/arg/output.sql b/internal/sql/preprocess/testdata/postgresql/arg/output.sql new file mode 100644 index 0000000..e6d2e2e --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/arg/output.sql @@ -0,0 +1,2 @@ +-- name: GetUser :one +SELECT id FROM users WHERE name = $1; diff --git a/internal/sql/preprocess/testdata/postgresql/arg/side_table.json b/internal/sql/preprocess/testdata/postgresql/arg/side_table.json new file mode 100644 index 0000000..d01162f --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/arg/side_table.json @@ -0,0 +1,16 @@ +[ + { + "start": 0, + "end": 59, + "dollar": true, + "params": [ + { + "number": 1, + "location": 56, + "origin": 56, + "name": "name", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/at_sign/input.sql b/internal/sql/preprocess/testdata/postgresql/at_sign/input.sql new file mode 100644 index 0000000..57c7883 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/at_sign/input.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE name = @name AND age = @age; diff --git a/internal/sql/preprocess/testdata/postgresql/at_sign/output.sql b/internal/sql/preprocess/testdata/postgresql/at_sign/output.sql new file mode 100644 index 0000000..90875ab --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/at_sign/output.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE name = $1 AND age = $2; diff --git a/internal/sql/preprocess/testdata/postgresql/at_sign/side_table.json b/internal/sql/preprocess/testdata/postgresql/at_sign/side_table.json new file mode 100644 index 0000000..bebc9a1 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/at_sign/side_table.json @@ -0,0 +1,23 @@ +[ + { + "start": 0, + "end": 50, + "dollar": true, + "params": [ + { + "number": 1, + "location": 34, + "origin": 34, + "name": "name", + "named": true + }, + { + "number": 2, + "location": 47, + "origin": 50, + "name": "age", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/at_sign_cast/input.sql b/internal/sql/preprocess/testdata/postgresql/at_sign_cast/input.sql new file mode 100644 index 0000000..a167ed5 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/at_sign_cast/input.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE ok = @flag::bool; diff --git a/internal/sql/preprocess/testdata/postgresql/at_sign_cast/output.sql b/internal/sql/preprocess/testdata/postgresql/at_sign_cast/output.sql new file mode 100644 index 0000000..28cdd95 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/at_sign_cast/output.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE ok = $1::bool; diff --git a/internal/sql/preprocess/testdata/postgresql/at_sign_cast/side_table.json b/internal/sql/preprocess/testdata/postgresql/at_sign_cast/side_table.json new file mode 100644 index 0000000..02ec768 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/at_sign_cast/side_table.json @@ -0,0 +1,16 @@ +[ + { + "start": 0, + "end": 41, + "dollar": true, + "params": [ + { + "number": 1, + "location": 32, + "origin": 32, + "name": "flag", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/at_sign_in_vet_directive/input.sql b/internal/sql/preprocess/testdata/postgresql/at_sign_in_vet_directive/input.sql new file mode 100644 index 0000000..d06af4e --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/at_sign_in_vet_directive/input.sql @@ -0,0 +1,3 @@ +-- name: SkipVetAll :exec +-- @sqlc-vet-disable always-fail no-exec +SELECT true FROM users WHERE id = sqlc.arg(id); diff --git a/internal/sql/preprocess/testdata/postgresql/at_sign_in_vet_directive/output.sql b/internal/sql/preprocess/testdata/postgresql/at_sign_in_vet_directive/output.sql new file mode 100644 index 0000000..5bbca3d --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/at_sign_in_vet_directive/output.sql @@ -0,0 +1,3 @@ +-- name: SkipVetAll :exec +-- @sqlc-vet-disable always-fail no-exec +SELECT true FROM users WHERE id = $1; diff --git a/internal/sql/preprocess/testdata/postgresql/at_sign_in_vet_directive/side_table.json b/internal/sql/preprocess/testdata/postgresql/at_sign_in_vet_directive/side_table.json new file mode 100644 index 0000000..3430150 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/at_sign_in_vet_directive/side_table.json @@ -0,0 +1,16 @@ +[ + { + "start": 0, + "end": 104, + "dollar": true, + "params": [ + { + "number": 1, + "location": 101, + "origin": 101, + "name": "id", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/comment_inside_call/input.sql b/internal/sql/preprocess/testdata/postgresql/comment_inside_call/input.sql new file mode 100644 index 0000000..58bb27f --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/comment_inside_call/input.sql @@ -0,0 +1 @@ +SELECT sqlc.arg/* here */(name); diff --git a/internal/sql/preprocess/testdata/postgresql/comment_inside_call/output.sql b/internal/sql/preprocess/testdata/postgresql/comment_inside_call/output.sql new file mode 100644 index 0000000..37699f7 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/comment_inside_call/output.sql @@ -0,0 +1 @@ +SELECT $1; diff --git a/internal/sql/preprocess/testdata/postgresql/comment_inside_call/side_table.json b/internal/sql/preprocess/testdata/postgresql/comment_inside_call/side_table.json new file mode 100644 index 0000000..80979ab --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/comment_inside_call/side_table.json @@ -0,0 +1,16 @@ +[ + { + "start": 0, + "end": 10, + "dollar": true, + "params": [ + { + "number": 1, + "location": 7, + "origin": 7, + "name": "name", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/embed/input.sql b/internal/sql/preprocess/testdata/postgresql/embed/input.sql new file mode 100644 index 0000000..5516074 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/embed/input.sql @@ -0,0 +1 @@ +SELECT sqlc.embed(users), sqlc.embed(pets) FROM users JOIN pets ON true; diff --git a/internal/sql/preprocess/testdata/postgresql/embed/output.sql b/internal/sql/preprocess/testdata/postgresql/embed/output.sql new file mode 100644 index 0000000..59d0cab --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/embed/output.sql @@ -0,0 +1 @@ +SELECT users.*, pets.* FROM users JOIN pets ON true; diff --git a/internal/sql/preprocess/testdata/postgresql/embed/side_table.json b/internal/sql/preprocess/testdata/postgresql/embed/side_table.json new file mode 100644 index 0000000..ed71a0d --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/embed/side_table.json @@ -0,0 +1,21 @@ +[ + { + "start": 0, + "end": 52, + "dollar": true, + "embeds": [ + { + "table": "users", + "location": 7, + "origin": 7, + "orig": "sqlc.embed(users)" + }, + { + "table": "pets", + "location": 16, + "origin": 26, + "orig": "sqlc.embed(pets)" + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/embed_and_user_star/input.sql b/internal/sql/preprocess/testdata/postgresql/embed_and_user_star/input.sql new file mode 100644 index 0000000..bec1807 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/embed_and_user_star/input.sql @@ -0,0 +1 @@ +SELECT sqlc.embed(a), b.* FROM a, b; diff --git a/internal/sql/preprocess/testdata/postgresql/embed_and_user_star/output.sql b/internal/sql/preprocess/testdata/postgresql/embed_and_user_star/output.sql new file mode 100644 index 0000000..e3ea7ed --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/embed_and_user_star/output.sql @@ -0,0 +1 @@ +SELECT a.*, b.* FROM a, b; diff --git a/internal/sql/preprocess/testdata/postgresql/embed_and_user_star/side_table.json b/internal/sql/preprocess/testdata/postgresql/embed_and_user_star/side_table.json new file mode 100644 index 0000000..d30b005 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/embed_and_user_star/side_table.json @@ -0,0 +1,15 @@ +[ + { + "start": 0, + "end": 26, + "dollar": true, + "embeds": [ + { + "table": "a", + "location": 7, + "origin": 7, + "orig": "sqlc.embed(a)" + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/embed_quoted_identifier/input.sql b/internal/sql/preprocess/testdata/postgresql/embed_quoted_identifier/input.sql new file mode 100644 index 0000000..86af411 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/embed_quoted_identifier/input.sql @@ -0,0 +1 @@ +SELECT sqlc.embed("Users") FROM "Users"; diff --git a/internal/sql/preprocess/testdata/postgresql/embed_quoted_identifier/output.sql b/internal/sql/preprocess/testdata/postgresql/embed_quoted_identifier/output.sql new file mode 100644 index 0000000..3909362 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/embed_quoted_identifier/output.sql @@ -0,0 +1 @@ +SELECT "Users".* FROM "Users"; diff --git a/internal/sql/preprocess/testdata/postgresql/embed_quoted_identifier/side_table.json b/internal/sql/preprocess/testdata/postgresql/embed_quoted_identifier/side_table.json new file mode 100644 index 0000000..02f9e3d --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/embed_quoted_identifier/side_table.json @@ -0,0 +1,15 @@ +[ + { + "start": 0, + "end": 30, + "dollar": true, + "embeds": [ + { + "table": "Users", + "location": 7, + "origin": 7, + "orig": "sqlc.embed(\"Users\")" + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/embed_string_constant/input.sql b/internal/sql/preprocess/testdata/postgresql/embed_string_constant/input.sql new file mode 100644 index 0000000..77203a9 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/embed_string_constant/input.sql @@ -0,0 +1 @@ +SELECT sqlc.embed('t') FROM t; diff --git a/internal/sql/preprocess/testdata/postgresql/embed_string_constant/output.sql b/internal/sql/preprocess/testdata/postgresql/embed_string_constant/output.sql new file mode 100644 index 0000000..269c8bb --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/embed_string_constant/output.sql @@ -0,0 +1 @@ +SELECT t.* FROM t; diff --git a/internal/sql/preprocess/testdata/postgresql/embed_string_constant/side_table.json b/internal/sql/preprocess/testdata/postgresql/embed_string_constant/side_table.json new file mode 100644 index 0000000..b7b97cf --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/embed_string_constant/side_table.json @@ -0,0 +1,15 @@ +[ + { + "start": 0, + "end": 18, + "dollar": true, + "embeds": [ + { + "table": "t", + "location": 7, + "origin": 7, + "orig": "sqlc.embed(t)" + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/embed_with_args/input.sql b/internal/sql/preprocess/testdata/postgresql/embed_with_args/input.sql new file mode 100644 index 0000000..68b9efb --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/embed_with_args/input.sql @@ -0,0 +1 @@ +SELECT sqlc.embed(a), b.name FROM a JOIN b ON b.id = a.b_id WHERE a.id = sqlc.arg(id); diff --git a/internal/sql/preprocess/testdata/postgresql/embed_with_args/output.sql b/internal/sql/preprocess/testdata/postgresql/embed_with_args/output.sql new file mode 100644 index 0000000..aaa0860 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/embed_with_args/output.sql @@ -0,0 +1 @@ +SELECT a.*, b.name FROM a JOIN b ON b.id = a.b_id WHERE a.id = $1; diff --git a/internal/sql/preprocess/testdata/postgresql/embed_with_args/side_table.json b/internal/sql/preprocess/testdata/postgresql/embed_with_args/side_table.json new file mode 100644 index 0000000..93a6a0f --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/embed_with_args/side_table.json @@ -0,0 +1,24 @@ +[ + { + "start": 0, + "end": 66, + "dollar": true, + "params": [ + { + "number": 1, + "location": 63, + "origin": 73, + "name": "id", + "named": true + } + ], + "embeds": [ + { + "table": "a", + "location": 7, + "origin": 7, + "orig": "sqlc.embed(a)" + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/error_is_per_statement/input.sql b/internal/sql/preprocess/testdata/postgresql/error_is_per_statement/input.sql new file mode 100644 index 0000000..f1f94d0 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_is_per_statement/input.sql @@ -0,0 +1,2 @@ +SELECT sqlc.argh(a); +SELECT sqlc.arg(b); diff --git a/internal/sql/preprocess/testdata/postgresql/error_is_per_statement/output.sql b/internal/sql/preprocess/testdata/postgresql/error_is_per_statement/output.sql new file mode 100644 index 0000000..43f9262 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_is_per_statement/output.sql @@ -0,0 +1,2 @@ +SELECT sqlc.argh(a); +SELECT $1; diff --git a/internal/sql/preprocess/testdata/postgresql/error_is_per_statement/side_table.json b/internal/sql/preprocess/testdata/postgresql/error_is_per_statement/side_table.json new file mode 100644 index 0000000..e4c5d10 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_is_per_statement/side_table.json @@ -0,0 +1,23 @@ +[ + { + "start": 0, + "end": 20, + "dollar": true, + "error": "function \"sqlc.argh\" does not exist", + "error_at": 7 + }, + { + "start": 20, + "end": 31, + "dollar": true, + "params": [ + { + "number": 1, + "location": 28, + "origin": 28, + "name": "b", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/error_is_per_statement/stderr.txt b/internal/sql/preprocess/testdata/postgresql/error_is_per_statement/stderr.txt new file mode 100644 index 0000000..c55d986 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_is_per_statement/stderr.txt @@ -0,0 +1 @@ +1:8: function "sqlc.argh" does not exist diff --git a/internal/sql/preprocess/testdata/postgresql/error_nested_call/input.sql b/internal/sql/preprocess/testdata/postgresql/error_nested_call/input.sql new file mode 100644 index 0000000..e8d7485 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_nested_call/input.sql @@ -0,0 +1 @@ +SELECT sqlc.arg(sqlc.arg(a)); diff --git a/internal/sql/preprocess/testdata/postgresql/error_nested_call/output.sql b/internal/sql/preprocess/testdata/postgresql/error_nested_call/output.sql new file mode 100644 index 0000000..e8d7485 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_nested_call/output.sql @@ -0,0 +1 @@ +SELECT sqlc.arg(sqlc.arg(a)); diff --git a/internal/sql/preprocess/testdata/postgresql/error_nested_call/side_table.json b/internal/sql/preprocess/testdata/postgresql/error_nested_call/side_table.json new file mode 100644 index 0000000..988c57a --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_nested_call/side_table.json @@ -0,0 +1,9 @@ +[ + { + "start": 0, + "end": 29, + "dollar": true, + "error": "expected parameter to sqlc.arg to be string or reference; got \"sqlc.arg(a)\"", + "error_at": 7 + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/error_nested_call/stderr.txt b/internal/sql/preprocess/testdata/postgresql/error_nested_call/stderr.txt new file mode 100644 index 0000000..7faabf7 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_nested_call/stderr.txt @@ -0,0 +1 @@ +1:8: expected parameter to sqlc.arg to be string or reference; got "sqlc.arg(a)" diff --git a/internal/sql/preprocess/testdata/postgresql/error_no_arguments/input.sql b/internal/sql/preprocess/testdata/postgresql/error_no_arguments/input.sql new file mode 100644 index 0000000..540bfb1 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_no_arguments/input.sql @@ -0,0 +1 @@ +SELECT sqlc.arg(); diff --git a/internal/sql/preprocess/testdata/postgresql/error_no_arguments/output.sql b/internal/sql/preprocess/testdata/postgresql/error_no_arguments/output.sql new file mode 100644 index 0000000..540bfb1 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_no_arguments/output.sql @@ -0,0 +1 @@ +SELECT sqlc.arg(); diff --git a/internal/sql/preprocess/testdata/postgresql/error_no_arguments/side_table.json b/internal/sql/preprocess/testdata/postgresql/error_no_arguments/side_table.json new file mode 100644 index 0000000..3f37493 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_no_arguments/side_table.json @@ -0,0 +1,9 @@ +[ + { + "start": 0, + "end": 18, + "dollar": true, + "error": "expected 1 parameter to sqlc.arg; got 0", + "error_at": 7 + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/error_no_arguments/stderr.txt b/internal/sql/preprocess/testdata/postgresql/error_no_arguments/stderr.txt new file mode 100644 index 0000000..46c7fcd --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_no_arguments/stderr.txt @@ -0,0 +1 @@ +1:8: expected 1 parameter to sqlc.arg; got 0 diff --git a/internal/sql/preprocess/testdata/postgresql/error_numbering_gap/input.sql b/internal/sql/preprocess/testdata/postgresql/error_numbering_gap/input.sql new file mode 100644 index 0000000..5a0ead0 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_numbering_gap/input.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE a = $2 AND b = $3; diff --git a/internal/sql/preprocess/testdata/postgresql/error_numbering_gap/output.sql b/internal/sql/preprocess/testdata/postgresql/error_numbering_gap/output.sql new file mode 100644 index 0000000..5a0ead0 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_numbering_gap/output.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE a = $2 AND b = $3; diff --git a/internal/sql/preprocess/testdata/postgresql/error_numbering_gap/side_table.json b/internal/sql/preprocess/testdata/postgresql/error_numbering_gap/side_table.json new file mode 100644 index 0000000..18933ca --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_numbering_gap/side_table.json @@ -0,0 +1,22 @@ +[ + { + "start": 0, + "end": 45, + "dollar": true, + "params": [ + { + "number": 2, + "location": 31, + "origin": 31, + "named": false + }, + { + "number": 3, + "location": 42, + "origin": 42, + "named": false + } + ], + "param_error": "could not determine data type of parameter $1" + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/error_numbering_gap/stderr.txt b/internal/sql/preprocess/testdata/postgresql/error_numbering_gap/stderr.txt new file mode 100644 index 0000000..a9cbefb --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_numbering_gap/stderr.txt @@ -0,0 +1 @@ +1:1: could not determine data type of parameter $1 diff --git a/internal/sql/preprocess/testdata/postgresql/error_placeholder_argument/input.sql b/internal/sql/preprocess/testdata/postgresql/error_placeholder_argument/input.sql new file mode 100644 index 0000000..3589b18 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_placeholder_argument/input.sql @@ -0,0 +1 @@ +SELECT sqlc.arg($1); diff --git a/internal/sql/preprocess/testdata/postgresql/error_placeholder_argument/output.sql b/internal/sql/preprocess/testdata/postgresql/error_placeholder_argument/output.sql new file mode 100644 index 0000000..3589b18 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_placeholder_argument/output.sql @@ -0,0 +1 @@ +SELECT sqlc.arg($1); diff --git a/internal/sql/preprocess/testdata/postgresql/error_placeholder_argument/side_table.json b/internal/sql/preprocess/testdata/postgresql/error_placeholder_argument/side_table.json new file mode 100644 index 0000000..918be18 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_placeholder_argument/side_table.json @@ -0,0 +1,9 @@ +[ + { + "start": 0, + "end": 20, + "dollar": true, + "error": "expected parameter to sqlc.arg to be string or reference; got \"$1\"", + "error_at": 7 + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/error_placeholder_argument/stderr.txt b/internal/sql/preprocess/testdata/postgresql/error_placeholder_argument/stderr.txt new file mode 100644 index 0000000..16d54e9 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_placeholder_argument/stderr.txt @@ -0,0 +1 @@ +1:8: expected parameter to sqlc.arg to be string or reference; got "$1" diff --git a/internal/sql/preprocess/testdata/postgresql/error_too_many_arguments/input.sql b/internal/sql/preprocess/testdata/postgresql/error_too_many_arguments/input.sql new file mode 100644 index 0000000..d5e1c62 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_too_many_arguments/input.sql @@ -0,0 +1 @@ +SELECT sqlc.arg('a', 'b'); diff --git a/internal/sql/preprocess/testdata/postgresql/error_too_many_arguments/output.sql b/internal/sql/preprocess/testdata/postgresql/error_too_many_arguments/output.sql new file mode 100644 index 0000000..d5e1c62 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_too_many_arguments/output.sql @@ -0,0 +1 @@ +SELECT sqlc.arg('a', 'b'); diff --git a/internal/sql/preprocess/testdata/postgresql/error_too_many_arguments/side_table.json b/internal/sql/preprocess/testdata/postgresql/error_too_many_arguments/side_table.json new file mode 100644 index 0000000..501e713 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_too_many_arguments/side_table.json @@ -0,0 +1,9 @@ +[ + { + "start": 0, + "end": 26, + "dollar": true, + "error": "expected 1 parameter to sqlc.arg; got 2", + "error_at": 7 + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/error_too_many_arguments/stderr.txt b/internal/sql/preprocess/testdata/postgresql/error_too_many_arguments/stderr.txt new file mode 100644 index 0000000..92e71bd --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_too_many_arguments/stderr.txt @@ -0,0 +1 @@ +1:8: expected 1 parameter to sqlc.arg; got 2 diff --git a/internal/sql/preprocess/testdata/postgresql/error_unknown_function/input.sql b/internal/sql/preprocess/testdata/postgresql/error_unknown_function/input.sql new file mode 100644 index 0000000..5a344b1 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_unknown_function/input.sql @@ -0,0 +1 @@ +SELECT sqlc.argh(a); diff --git a/internal/sql/preprocess/testdata/postgresql/error_unknown_function/output.sql b/internal/sql/preprocess/testdata/postgresql/error_unknown_function/output.sql new file mode 100644 index 0000000..5a344b1 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_unknown_function/output.sql @@ -0,0 +1 @@ +SELECT sqlc.argh(a); diff --git a/internal/sql/preprocess/testdata/postgresql/error_unknown_function/side_table.json b/internal/sql/preprocess/testdata/postgresql/error_unknown_function/side_table.json new file mode 100644 index 0000000..99e103e --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_unknown_function/side_table.json @@ -0,0 +1,9 @@ +[ + { + "start": 0, + "end": 20, + "dollar": true, + "error": "function \"sqlc.argh\" does not exist", + "error_at": 7 + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/error_unknown_function/stderr.txt b/internal/sql/preprocess/testdata/postgresql/error_unknown_function/stderr.txt new file mode 100644 index 0000000..c55d986 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/error_unknown_function/stderr.txt @@ -0,0 +1 @@ +1:8: function "sqlc.argh" does not exist diff --git a/internal/sql/preprocess/testdata/postgresql/existing_placeholder/input.sql b/internal/sql/preprocess/testdata/postgresql/existing_placeholder/input.sql new file mode 100644 index 0000000..1d7497a --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/existing_placeholder/input.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE a = $1 AND b = sqlc.arg(x); diff --git a/internal/sql/preprocess/testdata/postgresql/existing_placeholder/output.sql b/internal/sql/preprocess/testdata/postgresql/existing_placeholder/output.sql new file mode 100644 index 0000000..1742cc3 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/existing_placeholder/output.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE a = $1 AND b = $2; diff --git a/internal/sql/preprocess/testdata/postgresql/existing_placeholder/side_table.json b/internal/sql/preprocess/testdata/postgresql/existing_placeholder/side_table.json new file mode 100644 index 0000000..8f09746 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/existing_placeholder/side_table.json @@ -0,0 +1,22 @@ +[ + { + "start": 0, + "end": 45, + "dollar": true, + "params": [ + { + "number": 1, + "location": 31, + "origin": 31, + "named": false + }, + { + "number": 2, + "location": 42, + "origin": 42, + "name": "x", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/extra_whitespace/input.sql b/internal/sql/preprocess/testdata/postgresql/extra_whitespace/input.sql new file mode 100644 index 0000000..1ddb921 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/extra_whitespace/input.sql @@ -0,0 +1 @@ +SELECT sqlc.arg ( name ), sqlc . arg(other); diff --git a/internal/sql/preprocess/testdata/postgresql/extra_whitespace/output.sql b/internal/sql/preprocess/testdata/postgresql/extra_whitespace/output.sql new file mode 100644 index 0000000..ca9e542 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/extra_whitespace/output.sql @@ -0,0 +1 @@ +SELECT $1, $2; diff --git a/internal/sql/preprocess/testdata/postgresql/extra_whitespace/side_table.json b/internal/sql/preprocess/testdata/postgresql/extra_whitespace/side_table.json new file mode 100644 index 0000000..58dc58d --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/extra_whitespace/side_table.json @@ -0,0 +1,23 @@ +[ + { + "start": 0, + "end": 14, + "dollar": true, + "params": [ + { + "number": 1, + "location": 7, + "origin": 7, + "name": "name", + "named": true + }, + { + "number": 2, + "location": 11, + "origin": 28, + "name": "other", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/jsonb_operator_and_path_string/input.sql b/internal/sql/preprocess/testdata/postgresql/jsonb_operator_and_path_string/input.sql new file mode 100644 index 0000000..523e2d7 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/jsonb_operator_and_path_string/input.sql @@ -0,0 +1,2 @@ +SELECT * FROM transactions +WHERE jsonb_extract_path(transactions.data, '$.transaction.signatures[0]') @> to_jsonb(sqlc.arg('data')::text); diff --git a/internal/sql/preprocess/testdata/postgresql/jsonb_operator_and_path_string/output.sql b/internal/sql/preprocess/testdata/postgresql/jsonb_operator_and_path_string/output.sql new file mode 100644 index 0000000..acc0a99 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/jsonb_operator_and_path_string/output.sql @@ -0,0 +1,2 @@ +SELECT * FROM transactions +WHERE jsonb_extract_path(transactions.data, '$.transaction.signatures[0]') @> to_jsonb($1::text); diff --git a/internal/sql/preprocess/testdata/postgresql/jsonb_operator_and_path_string/side_table.json b/internal/sql/preprocess/testdata/postgresql/jsonb_operator_and_path_string/side_table.json new file mode 100644 index 0000000..36f37fe --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/jsonb_operator_and_path_string/side_table.json @@ -0,0 +1,16 @@ +[ + { + "start": 0, + "end": 124, + "dollar": true, + "params": [ + { + "number": 1, + "location": 114, + "origin": 114, + "name": "data", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/multiline_call/input.sql b/internal/sql/preprocess/testdata/postgresql/multiline_call/input.sql new file mode 100644 index 0000000..d377f42 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/multiline_call/input.sql @@ -0,0 +1,3 @@ +SELECT sqlc.arg( + name +); diff --git a/internal/sql/preprocess/testdata/postgresql/multiline_call/output.sql b/internal/sql/preprocess/testdata/postgresql/multiline_call/output.sql new file mode 100644 index 0000000..37699f7 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/multiline_call/output.sql @@ -0,0 +1 @@ +SELECT $1; diff --git a/internal/sql/preprocess/testdata/postgresql/multiline_call/side_table.json b/internal/sql/preprocess/testdata/postgresql/multiline_call/side_table.json new file mode 100644 index 0000000..80979ab --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/multiline_call/side_table.json @@ -0,0 +1,16 @@ +[ + { + "start": 0, + "end": 10, + "dollar": true, + "params": [ + { + "number": 1, + "location": 7, + "origin": 7, + "name": "name", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/narg/input.sql b/internal/sql/preprocess/testdata/postgresql/narg/input.sql new file mode 100644 index 0000000..7e5109a --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/narg/input.sql @@ -0,0 +1,2 @@ +-- name: GetUser :one +SELECT id FROM users WHERE name = sqlc.narg(name); diff --git a/internal/sql/preprocess/testdata/postgresql/narg/output.sql b/internal/sql/preprocess/testdata/postgresql/narg/output.sql new file mode 100644 index 0000000..e6d2e2e --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/narg/output.sql @@ -0,0 +1,2 @@ +-- name: GetUser :one +SELECT id FROM users WHERE name = $1; diff --git a/internal/sql/preprocess/testdata/postgresql/narg/side_table.json b/internal/sql/preprocess/testdata/postgresql/narg/side_table.json new file mode 100644 index 0000000..7d31758 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/narg/side_table.json @@ -0,0 +1,17 @@ +[ + { + "start": 0, + "end": 59, + "dollar": true, + "params": [ + { + "number": 1, + "location": 56, + "origin": 56, + "name": "name", + "named": true, + "nullable": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/narg_string_constant/input.sql b/internal/sql/preprocess/testdata/postgresql/narg_string_constant/input.sql new file mode 100644 index 0000000..1563e71 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/narg_string_constant/input.sql @@ -0,0 +1 @@ +SELECT * FROM users WHERE name = COALESCE(sqlc.narg('name'), name); diff --git a/internal/sql/preprocess/testdata/postgresql/narg_string_constant/output.sql b/internal/sql/preprocess/testdata/postgresql/narg_string_constant/output.sql new file mode 100644 index 0000000..50612d0 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/narg_string_constant/output.sql @@ -0,0 +1 @@ +SELECT * FROM users WHERE name = COALESCE($1, name); diff --git a/internal/sql/preprocess/testdata/postgresql/narg_string_constant/side_table.json b/internal/sql/preprocess/testdata/postgresql/narg_string_constant/side_table.json new file mode 100644 index 0000000..a076148 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/narg_string_constant/side_table.json @@ -0,0 +1,17 @@ +[ + { + "start": 0, + "end": 52, + "dollar": true, + "params": [ + { + "number": 1, + "location": 42, + "origin": 42, + "name": "name", + "named": true, + "nullable": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/numbering_restarts_per_statement/input.sql b/internal/sql/preprocess/testdata/postgresql/numbering_restarts_per_statement/input.sql new file mode 100644 index 0000000..80e729d --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/numbering_restarts_per_statement/input.sql @@ -0,0 +1,2 @@ +SELECT sqlc.arg(a); +SELECT sqlc.arg(b); diff --git a/internal/sql/preprocess/testdata/postgresql/numbering_restarts_per_statement/output.sql b/internal/sql/preprocess/testdata/postgresql/numbering_restarts_per_statement/output.sql new file mode 100644 index 0000000..aa0274e --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/numbering_restarts_per_statement/output.sql @@ -0,0 +1,2 @@ +SELECT $1; +SELECT $1; diff --git a/internal/sql/preprocess/testdata/postgresql/numbering_restarts_per_statement/side_table.json b/internal/sql/preprocess/testdata/postgresql/numbering_restarts_per_statement/side_table.json new file mode 100644 index 0000000..2921bcb --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/numbering_restarts_per_statement/side_table.json @@ -0,0 +1,30 @@ +[ + { + "start": 0, + "end": 10, + "dollar": true, + "params": [ + { + "number": 1, + "location": 7, + "origin": 7, + "name": "a", + "named": true + } + ] + }, + { + "start": 10, + "end": 21, + "dollar": true, + "params": [ + { + "number": 1, + "location": 18, + "origin": 27, + "name": "b", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/quoted_names/input.sql b/internal/sql/preprocess/testdata/postgresql/quoted_names/input.sql new file mode 100644 index 0000000..155e2f5 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/quoted_names/input.sql @@ -0,0 +1 @@ +SELECT sqlc.arg('a'), sqlc.arg("b"); diff --git a/internal/sql/preprocess/testdata/postgresql/quoted_names/output.sql b/internal/sql/preprocess/testdata/postgresql/quoted_names/output.sql new file mode 100644 index 0000000..ca9e542 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/quoted_names/output.sql @@ -0,0 +1 @@ +SELECT $1, $2; diff --git a/internal/sql/preprocess/testdata/postgresql/quoted_names/side_table.json b/internal/sql/preprocess/testdata/postgresql/quoted_names/side_table.json new file mode 100644 index 0000000..c6fedbd --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/quoted_names/side_table.json @@ -0,0 +1,23 @@ +[ + { + "start": 0, + "end": 14, + "dollar": true, + "params": [ + { + "number": 1, + "location": 7, + "origin": 7, + "name": "a", + "named": true + }, + { + "number": 2, + "location": 11, + "origin": 22, + "name": "b", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/repeated_name/input.sql b/internal/sql/preprocess/testdata/postgresql/repeated_name/input.sql new file mode 100644 index 0000000..1f6121a --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/repeated_name/input.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE a = sqlc.arg(x) OR b = sqlc.arg(x) OR c = sqlc.arg(y); diff --git a/internal/sql/preprocess/testdata/postgresql/repeated_name/output.sql b/internal/sql/preprocess/testdata/postgresql/repeated_name/output.sql new file mode 100644 index 0000000..b138d6c --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/repeated_name/output.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE a = $1 OR b = $1 OR c = $2; diff --git a/internal/sql/preprocess/testdata/postgresql/repeated_name/side_table.json b/internal/sql/preprocess/testdata/postgresql/repeated_name/side_table.json new file mode 100644 index 0000000..4203a72 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/repeated_name/side_table.json @@ -0,0 +1,30 @@ +[ + { + "start": 0, + "end": 54, + "dollar": true, + "params": [ + { + "number": 1, + "location": 31, + "origin": 31, + "name": "x", + "named": true + }, + { + "number": 1, + "location": 41, + "origin": 50, + "name": "x", + "named": true + }, + { + "number": 2, + "location": 51, + "origin": 69, + "name": "y", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/skip_block_comment/input.sql b/internal/sql/preprocess/testdata/postgresql/skip_block_comment/input.sql new file mode 100644 index 0000000..eb0245e --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_block_comment/input.sql @@ -0,0 +1,3 @@ +/* sqlc.arg(nope) + @nope */ +SELECT 1; diff --git a/internal/sql/preprocess/testdata/postgresql/skip_block_comment/output.sql b/internal/sql/preprocess/testdata/postgresql/skip_block_comment/output.sql new file mode 100644 index 0000000..eb0245e --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_block_comment/output.sql @@ -0,0 +1,3 @@ +/* sqlc.arg(nope) + @nope */ +SELECT 1; diff --git a/internal/sql/preprocess/testdata/postgresql/skip_block_comment/side_table.json b/internal/sql/preprocess/testdata/postgresql/skip_block_comment/side_table.json new file mode 100644 index 0000000..33fdd7c --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_block_comment/side_table.json @@ -0,0 +1,7 @@ +[ + { + "start": 0, + "end": 39, + "dollar": true + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/skip_dollar_quoted/input.sql b/internal/sql/preprocess/testdata/postgresql/skip_dollar_quoted/input.sql new file mode 100644 index 0000000..448b6ae --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_dollar_quoted/input.sql @@ -0,0 +1 @@ +CREATE FUNCTION f() RETURNS int AS $$ SELECT sqlc.arg(nope); $$ LANGUAGE sql; diff --git a/internal/sql/preprocess/testdata/postgresql/skip_dollar_quoted/output.sql b/internal/sql/preprocess/testdata/postgresql/skip_dollar_quoted/output.sql new file mode 100644 index 0000000..448b6ae --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_dollar_quoted/output.sql @@ -0,0 +1 @@ +CREATE FUNCTION f() RETURNS int AS $$ SELECT sqlc.arg(nope); $$ LANGUAGE sql; diff --git a/internal/sql/preprocess/testdata/postgresql/skip_dollar_quoted/side_table.json b/internal/sql/preprocess/testdata/postgresql/skip_dollar_quoted/side_table.json new file mode 100644 index 0000000..d67323c --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_dollar_quoted/side_table.json @@ -0,0 +1,7 @@ +[ + { + "start": 0, + "end": 77, + "dollar": true + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/skip_escape_string/input.sql b/internal/sql/preprocess/testdata/postgresql/skip_escape_string/input.sql new file mode 100644 index 0000000..800fd62 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_escape_string/input.sql @@ -0,0 +1 @@ +SELECT E'\' sqlc.arg(nope)'; diff --git a/internal/sql/preprocess/testdata/postgresql/skip_escape_string/output.sql b/internal/sql/preprocess/testdata/postgresql/skip_escape_string/output.sql new file mode 100644 index 0000000..800fd62 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_escape_string/output.sql @@ -0,0 +1 @@ +SELECT E'\' sqlc.arg(nope)'; diff --git a/internal/sql/preprocess/testdata/postgresql/skip_escape_string/side_table.json b/internal/sql/preprocess/testdata/postgresql/skip_escape_string/side_table.json new file mode 100644 index 0000000..7ab9eae --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_escape_string/side_table.json @@ -0,0 +1,7 @@ +[ + { + "start": 0, + "end": 28, + "dollar": true + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/skip_jsonb_operators/input.sql b/internal/sql/preprocess/testdata/postgresql/skip_jsonb_operators/input.sql new file mode 100644 index 0000000..a41da47 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_jsonb_operators/input.sql @@ -0,0 +1 @@ +SELECT 1 FROM t WHERE a @> b AND j ? 'a'; diff --git a/internal/sql/preprocess/testdata/postgresql/skip_jsonb_operators/output.sql b/internal/sql/preprocess/testdata/postgresql/skip_jsonb_operators/output.sql new file mode 100644 index 0000000..a41da47 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_jsonb_operators/output.sql @@ -0,0 +1 @@ +SELECT 1 FROM t WHERE a @> b AND j ? 'a'; diff --git a/internal/sql/preprocess/testdata/postgresql/skip_jsonb_operators/side_table.json b/internal/sql/preprocess/testdata/postgresql/skip_jsonb_operators/side_table.json new file mode 100644 index 0000000..85b41b8 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_jsonb_operators/side_table.json @@ -0,0 +1,7 @@ +[ + { + "start": 0, + "end": 41, + "dollar": true + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/skip_line_comment/input.sql b/internal/sql/preprocess/testdata/postgresql/skip_line_comment/input.sql new file mode 100644 index 0000000..b718e04 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_line_comment/input.sql @@ -0,0 +1,2 @@ +-- name: Get :one -- sqlc.arg(nope) @nope +SELECT 1; diff --git a/internal/sql/preprocess/testdata/postgresql/skip_line_comment/output.sql b/internal/sql/preprocess/testdata/postgresql/skip_line_comment/output.sql new file mode 100644 index 0000000..b718e04 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_line_comment/output.sql @@ -0,0 +1,2 @@ +-- name: Get :one -- sqlc.arg(nope) @nope +SELECT 1; diff --git a/internal/sql/preprocess/testdata/postgresql/skip_line_comment/side_table.json b/internal/sql/preprocess/testdata/postgresql/skip_line_comment/side_table.json new file mode 100644 index 0000000..93bd6b4 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_line_comment/side_table.json @@ -0,0 +1,7 @@ +[ + { + "start": 0, + "end": 51, + "dollar": true + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/skip_nested_block_comment/input.sql b/internal/sql/preprocess/testdata/postgresql/skip_nested_block_comment/input.sql new file mode 100644 index 0000000..46ac007 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_nested_block_comment/input.sql @@ -0,0 +1 @@ +/* /* sqlc.arg(nope) */ @nope */ SELECT 1; diff --git a/internal/sql/preprocess/testdata/postgresql/skip_nested_block_comment/output.sql b/internal/sql/preprocess/testdata/postgresql/skip_nested_block_comment/output.sql new file mode 100644 index 0000000..46ac007 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_nested_block_comment/output.sql @@ -0,0 +1 @@ +/* /* sqlc.arg(nope) */ @nope */ SELECT 1; diff --git a/internal/sql/preprocess/testdata/postgresql/skip_nested_block_comment/side_table.json b/internal/sql/preprocess/testdata/postgresql/skip_nested_block_comment/side_table.json new file mode 100644 index 0000000..05701e1 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_nested_block_comment/side_table.json @@ -0,0 +1,7 @@ +[ + { + "start": 0, + "end": 42, + "dollar": true + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/skip_other_schemas/input.sql b/internal/sql/preprocess/testdata/postgresql/skip_other_schemas/input.sql new file mode 100644 index 0000000..07cf2dc --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_other_schemas/input.sql @@ -0,0 +1 @@ +SELECT sqlcx.arg(a), other.embed(b); diff --git a/internal/sql/preprocess/testdata/postgresql/skip_other_schemas/output.sql b/internal/sql/preprocess/testdata/postgresql/skip_other_schemas/output.sql new file mode 100644 index 0000000..07cf2dc --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_other_schemas/output.sql @@ -0,0 +1 @@ +SELECT sqlcx.arg(a), other.embed(b); diff --git a/internal/sql/preprocess/testdata/postgresql/skip_other_schemas/side_table.json b/internal/sql/preprocess/testdata/postgresql/skip_other_schemas/side_table.json new file mode 100644 index 0000000..c279f2b --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_other_schemas/side_table.json @@ -0,0 +1,7 @@ +[ + { + "start": 0, + "end": 36, + "dollar": true + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/skip_quoted_identifier/input.sql b/internal/sql/preprocess/testdata/postgresql/skip_quoted_identifier/input.sql new file mode 100644 index 0000000..3fb2557 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_quoted_identifier/input.sql @@ -0,0 +1 @@ +SELECT "sqlc.arg(nope)" FROM t; diff --git a/internal/sql/preprocess/testdata/postgresql/skip_quoted_identifier/output.sql b/internal/sql/preprocess/testdata/postgresql/skip_quoted_identifier/output.sql new file mode 100644 index 0000000..3fb2557 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_quoted_identifier/output.sql @@ -0,0 +1 @@ +SELECT "sqlc.arg(nope)" FROM t; diff --git a/internal/sql/preprocess/testdata/postgresql/skip_quoted_identifier/side_table.json b/internal/sql/preprocess/testdata/postgresql/skip_quoted_identifier/side_table.json new file mode 100644 index 0000000..cdde9a6 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_quoted_identifier/side_table.json @@ -0,0 +1,7 @@ +[ + { + "start": 0, + "end": 31, + "dollar": true + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/skip_string_literal/input.sql b/internal/sql/preprocess/testdata/postgresql/skip_string_literal/input.sql new file mode 100644 index 0000000..4e5ef9f --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_string_literal/input.sql @@ -0,0 +1 @@ +SELECT 'sqlc.arg(nope) @nope'; diff --git a/internal/sql/preprocess/testdata/postgresql/skip_string_literal/output.sql b/internal/sql/preprocess/testdata/postgresql/skip_string_literal/output.sql new file mode 100644 index 0000000..4e5ef9f --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_string_literal/output.sql @@ -0,0 +1 @@ +SELECT 'sqlc.arg(nope) @nope'; diff --git a/internal/sql/preprocess/testdata/postgresql/skip_string_literal/side_table.json b/internal/sql/preprocess/testdata/postgresql/skip_string_literal/side_table.json new file mode 100644 index 0000000..06317d8 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_string_literal/side_table.json @@ -0,0 +1,7 @@ +[ + { + "start": 0, + "end": 30, + "dollar": true + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/skip_tagged_dollar_quoted/input.sql b/internal/sql/preprocess/testdata/postgresql/skip_tagged_dollar_quoted/input.sql new file mode 100644 index 0000000..8b4be6f --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_tagged_dollar_quoted/input.sql @@ -0,0 +1 @@ +SELECT $tag$ sqlc.arg(nope) @nope $tag$; diff --git a/internal/sql/preprocess/testdata/postgresql/skip_tagged_dollar_quoted/output.sql b/internal/sql/preprocess/testdata/postgresql/skip_tagged_dollar_quoted/output.sql new file mode 100644 index 0000000..8b4be6f --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_tagged_dollar_quoted/output.sql @@ -0,0 +1 @@ +SELECT $tag$ sqlc.arg(nope) @nope $tag$; diff --git a/internal/sql/preprocess/testdata/postgresql/skip_tagged_dollar_quoted/side_table.json b/internal/sql/preprocess/testdata/postgresql/skip_tagged_dollar_quoted/side_table.json new file mode 100644 index 0000000..3bd689e --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/skip_tagged_dollar_quoted/side_table.json @@ -0,0 +1,7 @@ +[ + { + "start": 0, + "end": 40, + "dollar": true + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/slice_is_an_array/input.sql b/internal/sql/preprocess/testdata/postgresql/slice_is_an_array/input.sql new file mode 100644 index 0000000..0c69e21 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/slice_is_an_array/input.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE id = ANY(sqlc.slice(ids)); diff --git a/internal/sql/preprocess/testdata/postgresql/slice_is_an_array/output.sql b/internal/sql/preprocess/testdata/postgresql/slice_is_an_array/output.sql new file mode 100644 index 0000000..06bb997 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/slice_is_an_array/output.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE id = ANY($1); diff --git a/internal/sql/preprocess/testdata/postgresql/slice_is_an_array/side_table.json b/internal/sql/preprocess/testdata/postgresql/slice_is_an_array/side_table.json new file mode 100644 index 0000000..f9350ea --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/slice_is_an_array/side_table.json @@ -0,0 +1,17 @@ +[ + { + "start": 0, + "end": 40, + "dollar": true, + "params": [ + { + "number": 1, + "location": 36, + "origin": 36, + "name": "ids", + "named": true, + "slice": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/slice_string_constant/input.sql b/internal/sql/preprocess/testdata/postgresql/slice_string_constant/input.sql new file mode 100644 index 0000000..3132a9f --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/slice_string_constant/input.sql @@ -0,0 +1 @@ +SELECT * FROM users WHERE id = ANY(sqlc.slice('ids')); diff --git a/internal/sql/preprocess/testdata/postgresql/slice_string_constant/output.sql b/internal/sql/preprocess/testdata/postgresql/slice_string_constant/output.sql new file mode 100644 index 0000000..bd7ba1f --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/slice_string_constant/output.sql @@ -0,0 +1 @@ +SELECT * FROM users WHERE id = ANY($1); diff --git a/internal/sql/preprocess/testdata/postgresql/slice_string_constant/side_table.json b/internal/sql/preprocess/testdata/postgresql/slice_string_constant/side_table.json new file mode 100644 index 0000000..d7f67ee --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/slice_string_constant/side_table.json @@ -0,0 +1,17 @@ +[ + { + "start": 0, + "end": 39, + "dollar": true, + "params": [ + { + "number": 1, + "location": 35, + "origin": 35, + "name": "ids", + "named": true, + "slice": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/statement_terminator_in_string/input.sql b/internal/sql/preprocess/testdata/postgresql/statement_terminator_in_string/input.sql new file mode 100644 index 0000000..1d254ec --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/statement_terminator_in_string/input.sql @@ -0,0 +1,2 @@ +SELECT ';', sqlc.arg(a); +SELECT sqlc.arg(b); diff --git a/internal/sql/preprocess/testdata/postgresql/statement_terminator_in_string/output.sql b/internal/sql/preprocess/testdata/postgresql/statement_terminator_in_string/output.sql new file mode 100644 index 0000000..f5baebf --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/statement_terminator_in_string/output.sql @@ -0,0 +1,2 @@ +SELECT ';', $1; +SELECT $1; diff --git a/internal/sql/preprocess/testdata/postgresql/statement_terminator_in_string/side_table.json b/internal/sql/preprocess/testdata/postgresql/statement_terminator_in_string/side_table.json new file mode 100644 index 0000000..a3e7e05 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/statement_terminator_in_string/side_table.json @@ -0,0 +1,30 @@ +[ + { + "start": 0, + "end": 15, + "dollar": true, + "params": [ + { + "number": 1, + "location": 12, + "origin": 12, + "name": "a", + "named": true + } + ] + }, + { + "start": 15, + "end": 26, + "dollar": true, + "params": [ + { + "number": 1, + "location": 23, + "origin": 32, + "name": "b", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/string_constant_escaped_quote/input.sql b/internal/sql/preprocess/testdata/postgresql/string_constant_escaped_quote/input.sql new file mode 100644 index 0000000..1643d37 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/string_constant_escaped_quote/input.sql @@ -0,0 +1 @@ +SELECT sqlc.arg('it''s'); diff --git a/internal/sql/preprocess/testdata/postgresql/string_constant_escaped_quote/output.sql b/internal/sql/preprocess/testdata/postgresql/string_constant_escaped_quote/output.sql new file mode 100644 index 0000000..37699f7 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/string_constant_escaped_quote/output.sql @@ -0,0 +1 @@ +SELECT $1; diff --git a/internal/sql/preprocess/testdata/postgresql/string_constant_escaped_quote/side_table.json b/internal/sql/preprocess/testdata/postgresql/string_constant_escaped_quote/side_table.json new file mode 100644 index 0000000..5c78707 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/string_constant_escaped_quote/side_table.json @@ -0,0 +1,16 @@ +[ + { + "start": 0, + "end": 10, + "dollar": true, + "params": [ + { + "number": 1, + "location": 7, + "origin": 7, + "name": "it's", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/string_constant_keeps_case/input.sql b/internal/sql/preprocess/testdata/postgresql/string_constant_keeps_case/input.sql new file mode 100644 index 0000000..beec84e --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/string_constant_keeps_case/input.sql @@ -0,0 +1 @@ +SELECT sqlc.arg('MixedCase'), sqlc.arg(MixedCase); diff --git a/internal/sql/preprocess/testdata/postgresql/string_constant_keeps_case/output.sql b/internal/sql/preprocess/testdata/postgresql/string_constant_keeps_case/output.sql new file mode 100644 index 0000000..ca9e542 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/string_constant_keeps_case/output.sql @@ -0,0 +1 @@ +SELECT $1, $2; diff --git a/internal/sql/preprocess/testdata/postgresql/string_constant_keeps_case/side_table.json b/internal/sql/preprocess/testdata/postgresql/string_constant_keeps_case/side_table.json new file mode 100644 index 0000000..48ccbea --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/string_constant_keeps_case/side_table.json @@ -0,0 +1,23 @@ +[ + { + "start": 0, + "end": 14, + "dollar": true, + "params": [ + { + "number": 1, + "location": 7, + "origin": 7, + "name": "MixedCase", + "named": true + }, + { + "number": 2, + "location": 11, + "origin": 30, + "name": "mixedcase", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/postgresql/uppercase/input.sql b/internal/sql/preprocess/testdata/postgresql/uppercase/input.sql new file mode 100644 index 0000000..4931f59 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/uppercase/input.sql @@ -0,0 +1 @@ +SELECT SQLC.ARG(name); diff --git a/internal/sql/preprocess/testdata/postgresql/uppercase/output.sql b/internal/sql/preprocess/testdata/postgresql/uppercase/output.sql new file mode 100644 index 0000000..37699f7 --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/uppercase/output.sql @@ -0,0 +1 @@ +SELECT $1; diff --git a/internal/sql/preprocess/testdata/postgresql/uppercase/side_table.json b/internal/sql/preprocess/testdata/postgresql/uppercase/side_table.json new file mode 100644 index 0000000..80979ab --- /dev/null +++ b/internal/sql/preprocess/testdata/postgresql/uppercase/side_table.json @@ -0,0 +1,16 @@ +[ + { + "start": 0, + "end": 10, + "dollar": true, + "params": [ + { + "number": 1, + "location": 7, + "origin": 7, + "name": "name", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/sqlite/arg/input.sql b/internal/sql/preprocess/testdata/sqlite/arg/input.sql new file mode 100644 index 0000000..238d2d1 --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/arg/input.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE a = sqlc.arg(x) AND b = sqlc.arg(y); diff --git a/internal/sql/preprocess/testdata/sqlite/arg/output.sql b/internal/sql/preprocess/testdata/sqlite/arg/output.sql new file mode 100644 index 0000000..8d719f8 --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/arg/output.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE a = ?1 AND b = ?2; diff --git a/internal/sql/preprocess/testdata/sqlite/arg/side_table.json b/internal/sql/preprocess/testdata/sqlite/arg/side_table.json new file mode 100644 index 0000000..1e68787 --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/arg/side_table.json @@ -0,0 +1,23 @@ +[ + { + "start": 0, + "end": 45, + "dollar": true, + "params": [ + { + "number": 1, + "location": 31, + "origin": 31, + "name": "x", + "named": true + }, + { + "number": 2, + "location": 42, + "origin": 51, + "name": "y", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/sqlite/at_sign/input.sql b/internal/sql/preprocess/testdata/sqlite/at_sign/input.sql new file mode 100644 index 0000000..00688da --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/at_sign/input.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE name = @name; diff --git a/internal/sql/preprocess/testdata/sqlite/at_sign/output.sql b/internal/sql/preprocess/testdata/sqlite/at_sign/output.sql new file mode 100644 index 0000000..e232a5b --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/at_sign/output.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE name = ?1; diff --git a/internal/sql/preprocess/testdata/sqlite/at_sign/side_table.json b/internal/sql/preprocess/testdata/sqlite/at_sign/side_table.json new file mode 100644 index 0000000..5b95487 --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/at_sign/side_table.json @@ -0,0 +1,16 @@ +[ + { + "start": 0, + "end": 37, + "dollar": true, + "params": [ + { + "number": 1, + "location": 34, + "origin": 34, + "name": "name", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/sqlite/embed/input.sql b/internal/sql/preprocess/testdata/sqlite/embed/input.sql new file mode 100644 index 0000000..2c00b3b --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/embed/input.sql @@ -0,0 +1 @@ +SELECT sqlc.embed(users) FROM users WHERE id = sqlc.arg(id); diff --git a/internal/sql/preprocess/testdata/sqlite/embed/output.sql b/internal/sql/preprocess/testdata/sqlite/embed/output.sql new file mode 100644 index 0000000..022b992 --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/embed/output.sql @@ -0,0 +1 @@ +SELECT users.* FROM users WHERE id = ?1; diff --git a/internal/sql/preprocess/testdata/sqlite/embed/side_table.json b/internal/sql/preprocess/testdata/sqlite/embed/side_table.json new file mode 100644 index 0000000..2a2c4fc --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/embed/side_table.json @@ -0,0 +1,24 @@ +[ + { + "start": 0, + "end": 40, + "dollar": true, + "params": [ + { + "number": 1, + "location": 37, + "origin": 47, + "name": "id", + "named": true + } + ], + "embeds": [ + { + "table": "users", + "location": 7, + "origin": 7, + "orig": "sqlc.embed(users)" + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/sqlite/error_invalid_calls/input.sql b/internal/sql/preprocess/testdata/sqlite/error_invalid_calls/input.sql new file mode 100644 index 0000000..51f7ddb --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/error_invalid_calls/input.sql @@ -0,0 +1,11 @@ +-- name: WrongFunc :one +SELECT id FROM users WHERE id = sqlc.argh(target_id); + +-- name: TooManyArgs :one +SELECT id FROM users WHERE id = sqlc.arg('foo', 'bar'); + +-- name: TooFewArgs :one +SELECT id FROM users WHERE id = sqlc.arg(); + +-- name: InvalidArgPlaceholder :one +SELECT id FROM users WHERE id = sqlc.arg(?); diff --git a/internal/sql/preprocess/testdata/sqlite/error_invalid_calls/output.sql b/internal/sql/preprocess/testdata/sqlite/error_invalid_calls/output.sql new file mode 100644 index 0000000..51f7ddb --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/error_invalid_calls/output.sql @@ -0,0 +1,11 @@ +-- name: WrongFunc :one +SELECT id FROM users WHERE id = sqlc.argh(target_id); + +-- name: TooManyArgs :one +SELECT id FROM users WHERE id = sqlc.arg('foo', 'bar'); + +-- name: TooFewArgs :one +SELECT id FROM users WHERE id = sqlc.arg(); + +-- name: InvalidArgPlaceholder :one +SELECT id FROM users WHERE id = sqlc.arg(?); diff --git a/internal/sql/preprocess/testdata/sqlite/error_invalid_calls/side_table.json b/internal/sql/preprocess/testdata/sqlite/error_invalid_calls/side_table.json new file mode 100644 index 0000000..a36ba15 --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/error_invalid_calls/side_table.json @@ -0,0 +1,30 @@ +[ + { + "start": 0, + "end": 77, + "dollar": true, + "error": "function \"sqlc.argh\" does not exist", + "error_at": 56 + }, + { + "start": 77, + "end": 160, + "dollar": true, + "error": "expected 1 parameter to sqlc.arg; got 2", + "error_at": 137 + }, + { + "start": 160, + "end": 230, + "dollar": true, + "error": "expected 1 parameter to sqlc.arg; got 0", + "error_at": 219 + }, + { + "start": 230, + "end": 312, + "dollar": true, + "error": "expected parameter to sqlc.arg to be string or reference; got \"?\"", + "error_at": 300 + } +] diff --git a/internal/sql/preprocess/testdata/sqlite/error_invalid_calls/stderr.txt b/internal/sql/preprocess/testdata/sqlite/error_invalid_calls/stderr.txt new file mode 100644 index 0000000..aae154e --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/error_invalid_calls/stderr.txt @@ -0,0 +1,4 @@ +2:33: function "sqlc.argh" does not exist +5:33: expected 1 parameter to sqlc.arg; got 2 +8:33: expected 1 parameter to sqlc.arg; got 0 +11:33: expected parameter to sqlc.arg to be string or reference; got "?" diff --git a/internal/sql/preprocess/testdata/sqlite/error_mixed_placeholder_styles/input.sql b/internal/sql/preprocess/testdata/sqlite/error_mixed_placeholder_styles/input.sql new file mode 100644 index 0000000..0c98f3e --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/error_mixed_placeholder_styles/input.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE a = ?1 AND b = ?; diff --git a/internal/sql/preprocess/testdata/sqlite/error_mixed_placeholder_styles/output.sql b/internal/sql/preprocess/testdata/sqlite/error_mixed_placeholder_styles/output.sql new file mode 100644 index 0000000..0c98f3e --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/error_mixed_placeholder_styles/output.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE a = ?1 AND b = ?; diff --git a/internal/sql/preprocess/testdata/sqlite/error_mixed_placeholder_styles/side_table.json b/internal/sql/preprocess/testdata/sqlite/error_mixed_placeholder_styles/side_table.json new file mode 100644 index 0000000..ae8f878 --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/error_mixed_placeholder_styles/side_table.json @@ -0,0 +1,22 @@ +[ + { + "start": 0, + "end": 44, + "dollar": false, + "params": [ + { + "number": 1, + "location": 31, + "origin": 31, + "named": false + }, + { + "number": 2, + "location": 42, + "origin": 42, + "named": false + } + ], + "param_error": "can not mix $1 format with ? format" + } +] diff --git a/internal/sql/preprocess/testdata/sqlite/error_mixed_placeholder_styles/stderr.txt b/internal/sql/preprocess/testdata/sqlite/error_mixed_placeholder_styles/stderr.txt new file mode 100644 index 0000000..9d90398 --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/error_mixed_placeholder_styles/stderr.txt @@ -0,0 +1 @@ +1:1: can not mix $1 format with ? format diff --git a/internal/sql/preprocess/testdata/sqlite/existing_numbered_placeholder/input.sql b/internal/sql/preprocess/testdata/sqlite/existing_numbered_placeholder/input.sql new file mode 100644 index 0000000..838caa5 --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/existing_numbered_placeholder/input.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE a = ?1 AND b = sqlc.arg(x); diff --git a/internal/sql/preprocess/testdata/sqlite/existing_numbered_placeholder/output.sql b/internal/sql/preprocess/testdata/sqlite/existing_numbered_placeholder/output.sql new file mode 100644 index 0000000..8d719f8 --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/existing_numbered_placeholder/output.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE a = ?1 AND b = ?2; diff --git a/internal/sql/preprocess/testdata/sqlite/existing_numbered_placeholder/side_table.json b/internal/sql/preprocess/testdata/sqlite/existing_numbered_placeholder/side_table.json new file mode 100644 index 0000000..8f09746 --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/existing_numbered_placeholder/side_table.json @@ -0,0 +1,22 @@ +[ + { + "start": 0, + "end": 45, + "dollar": true, + "params": [ + { + "number": 1, + "location": 31, + "origin": 31, + "named": false + }, + { + "number": 2, + "location": 42, + "origin": 42, + "name": "x", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/sqlite/narg_identifier/input.sql b/internal/sql/preprocess/testdata/sqlite/narg_identifier/input.sql new file mode 100644 index 0000000..c36f3d6 --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/narg_identifier/input.sql @@ -0,0 +1 @@ +SELECT * FROM users WHERE name = sqlc.narg(name); diff --git a/internal/sql/preprocess/testdata/sqlite/narg_identifier/output.sql b/internal/sql/preprocess/testdata/sqlite/narg_identifier/output.sql new file mode 100644 index 0000000..58a07d1 --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/narg_identifier/output.sql @@ -0,0 +1 @@ +SELECT * FROM users WHERE name = ?1; diff --git a/internal/sql/preprocess/testdata/sqlite/narg_identifier/side_table.json b/internal/sql/preprocess/testdata/sqlite/narg_identifier/side_table.json new file mode 100644 index 0000000..dfa9deb --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/narg_identifier/side_table.json @@ -0,0 +1,17 @@ +[ + { + "start": 0, + "end": 36, + "dollar": true, + "params": [ + { + "number": 1, + "location": 33, + "origin": 33, + "name": "name", + "named": true, + "nullable": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/sqlite/repeated_name/input.sql b/internal/sql/preprocess/testdata/sqlite/repeated_name/input.sql new file mode 100644 index 0000000..180ea26 --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/repeated_name/input.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE a = sqlc.arg(x) AND b = sqlc.arg(x); diff --git a/internal/sql/preprocess/testdata/sqlite/repeated_name/output.sql b/internal/sql/preprocess/testdata/sqlite/repeated_name/output.sql new file mode 100644 index 0000000..143e91e --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/repeated_name/output.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE a = ?1 AND b = ?1; diff --git a/internal/sql/preprocess/testdata/sqlite/repeated_name/side_table.json b/internal/sql/preprocess/testdata/sqlite/repeated_name/side_table.json new file mode 100644 index 0000000..490774d --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/repeated_name/side_table.json @@ -0,0 +1,23 @@ +[ + { + "start": 0, + "end": 45, + "dollar": true, + "params": [ + { + "number": 1, + "location": 31, + "origin": 31, + "name": "x", + "named": true + }, + { + "number": 1, + "location": 42, + "origin": 51, + "name": "x", + "named": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/sqlite/slice/input.sql b/internal/sql/preprocess/testdata/sqlite/slice/input.sql new file mode 100644 index 0000000..f5d8964 --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/slice/input.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE id IN (sqlc.slice(ids)); diff --git a/internal/sql/preprocess/testdata/sqlite/slice/output.sql b/internal/sql/preprocess/testdata/sqlite/slice/output.sql new file mode 100644 index 0000000..5422151 --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/slice/output.sql @@ -0,0 +1 @@ +SELECT id FROM users WHERE id IN (/*SLICE:ids*/?); diff --git a/internal/sql/preprocess/testdata/sqlite/slice/side_table.json b/internal/sql/preprocess/testdata/sqlite/slice/side_table.json new file mode 100644 index 0000000..4b16794 --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/slice/side_table.json @@ -0,0 +1,17 @@ +[ + { + "start": 0, + "end": 50, + "dollar": true, + "params": [ + { + "number": 1, + "location": 47, + "origin": 34, + "name": "ids", + "named": true, + "slice": true + } + ] + } +] diff --git a/internal/sql/preprocess/testdata/sqlite/string_constant/input.sql b/internal/sql/preprocess/testdata/sqlite/string_constant/input.sql new file mode 100644 index 0000000..3efd6a9 --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/string_constant/input.sql @@ -0,0 +1 @@ +SELECT * FROM users WHERE a = sqlc.arg('x') AND b = sqlc.narg('y') AND c IN (sqlc.slice('ids')); diff --git a/internal/sql/preprocess/testdata/sqlite/string_constant/output.sql b/internal/sql/preprocess/testdata/sqlite/string_constant/output.sql new file mode 100644 index 0000000..ea33ad3 --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/string_constant/output.sql @@ -0,0 +1 @@ +SELECT * FROM users WHERE a = ?1 AND b = ?2 AND c IN (/*SLICE:ids*/?); diff --git a/internal/sql/preprocess/testdata/sqlite/string_constant/side_table.json b/internal/sql/preprocess/testdata/sqlite/string_constant/side_table.json new file mode 100644 index 0000000..f48044c --- /dev/null +++ b/internal/sql/preprocess/testdata/sqlite/string_constant/side_table.json @@ -0,0 +1,32 @@ +[ + { + "start": 0, + "end": 70, + "dollar": true, + "params": [ + { + "number": 1, + "location": 30, + "origin": 30, + "name": "x", + "named": true + }, + { + "number": 2, + "location": 41, + "origin": 52, + "name": "y", + "named": true, + "nullable": true + }, + { + "number": 3, + "location": 67, + "origin": 77, + "name": "ids", + "named": true, + "slice": true + } + ] + } +] diff --git a/internal/sql/sqlerr/errors.go b/internal/sql/sqlerr/errors.go new file mode 100644 index 0000000..c9cf58d --- /dev/null +++ b/internal/sql/sqlerr/errors.go @@ -0,0 +1,111 @@ +package sqlerr + +import ( + "errors" + "fmt" +) + +var Exists = errors.New("already exists") +var NotFound = errors.New("does not exist") +var NotUnique = errors.New("is not unique") + +type Error struct { + Err error + Code string + Message string + Location int + Line int + Column int + // Hint string +} + +func (e *Error) Unwrap() error { + return e.Err +} + +func (e *Error) Error() string { + if e.Err != nil { + return fmt.Sprintf("%s %s", e.Message, e.Err.Error()) + } else { + return e.Message + } +} + +func ColumnExists(rel, col string) *Error { + return &Error{ + Err: Exists, + Code: "42701", + Message: fmt.Sprintf("column %q of relation %q", col, rel), + } +} + +func ColumnNotFound(rel, col string) *Error { + return &Error{ + Err: NotFound, + Code: "42703", + Message: fmt.Sprintf("column %q of relation %q", col, rel), + } +} + +func RelationExists(rel string) *Error { + return &Error{ + Err: Exists, + Code: "42P07", + Message: fmt.Sprintf("relation %q", rel), + } +} + +func RelationNotFound(rel string) *Error { + return &Error{ + Err: NotFound, + Code: "42P01", + Message: fmt.Sprintf("relation %q", rel), + } +} + +func SchemaExists(name string) *Error { + return &Error{ + Err: Exists, + Code: "42P06", + Message: fmt.Sprintf("schema %q", name), + } +} + +func SchemaNotFound(sch string) *Error { + return &Error{ + Err: NotFound, + Code: "3F000", + Message: fmt.Sprintf("schema %q", sch), + } +} + +func TypeExists(typ string) *Error { + return &Error{ + Err: Exists, + Code: "42710", + Message: fmt.Sprintf("type %q", typ), + } +} + +func TypeNotFound(typ string) *Error { + return &Error{ + Err: NotFound, + Code: "42704", + Message: fmt.Sprintf("type %q", typ), + } +} + +func FunctionNotFound(fun string) *Error { + return &Error{ + Err: NotFound, + Code: "42704", + Message: fmt.Sprintf("function %q", fun), + } +} + +func FunctionNotUnique(fn string) *Error { + return &Error{ + Err: NotUnique, + Message: fmt.Sprintf("function name %q", fn), + } +} diff --git a/internal/sql/sqlfile/split.go b/internal/sql/sqlfile/split.go new file mode 100644 index 0000000..b54dc87 --- /dev/null +++ b/internal/sql/sqlfile/split.go @@ -0,0 +1,241 @@ +package sqlfile + +import ( + "bufio" + "context" + "io" + "strings" +) + +// Split reads SQL queries from an io.Reader and returns them as a slice of strings. +// Each SQL query is delimited by a semicolon (;). +// The function handles: +// - Single-line comments (-- comment) +// - Multi-line comments (/* comment */) +// - Single-quoted strings ('string') +// - Double-quoted identifiers ("identifier") +// - Dollar-quoted strings ($$string$$ or $tag$string$tag$) +func Split(ctx context.Context, r io.Reader) ([]string, error) { + scanner := bufio.NewScanner(r) + var queries []string + var currentQuery strings.Builder + var inSingleQuote bool + var inDoubleQuote bool + var inDollarQuote bool + var dollarTag string + var inMultiLineComment bool + + for scanner.Scan() { + // Check context cancellation + select { + case <-ctx.Done(): + return nil, ctx.Err() + default: + } + + line := scanner.Text() + i := 0 + lineLen := len(line) + + for i < lineLen { + ch := line[i] + + // Handle multi-line comments + if inMultiLineComment { + if i+1 < lineLen && ch == '*' && line[i+1] == '/' { + inMultiLineComment = false + currentQuery.WriteString("*/") + i += 2 + continue + } + currentQuery.WriteByte(ch) + i++ + continue + } + + // Handle dollar-quoted strings (PostgreSQL) + if inDollarQuote { + if ch == '$' { + // Try to match the closing tag + endTag := extractDollarTag(line[i:]) + if endTag == dollarTag { + inDollarQuote = false + currentQuery.WriteString(endTag) + i += len(endTag) + continue + } + } + currentQuery.WriteByte(ch) + i++ + continue + } + + // Handle single-quoted strings + if inSingleQuote { + currentQuery.WriteByte(ch) + if ch == '\'' { + // Check for escaped quote '' + if i+1 < lineLen && line[i+1] == '\'' { + currentQuery.WriteByte('\'') + i += 2 + continue + } + inSingleQuote = false + } + i++ + continue + } + + // Handle double-quoted identifiers + if inDoubleQuote { + currentQuery.WriteByte(ch) + if ch == '"' { + // Check for escaped quote "" + if i+1 < lineLen && line[i+1] == '"' { + currentQuery.WriteByte('"') + i += 2 + continue + } + inDoubleQuote = false + } + i++ + continue + } + + // Check for single-line comment + if i+1 < lineLen && ch == '-' && line[i+1] == '-' { + // Rest of line is a comment + currentQuery.WriteString(line[i:]) + break + } + + // Check for multi-line comment start + if i+1 < lineLen && ch == '/' && line[i+1] == '*' { + inMultiLineComment = true + currentQuery.WriteString("/*") + i += 2 + continue + } + + // Check for dollar quote start + if ch == '$' { + tag := extractDollarTag(line[i:]) + if tag != "" { + inDollarQuote = true + dollarTag = tag + currentQuery.WriteString(tag) + i += len(tag) + continue + } + } + + // Check for single quote + if ch == '\'' { + inSingleQuote = true + currentQuery.WriteByte(ch) + i++ + continue + } + + // Check for double quote + if ch == '"' { + inDoubleQuote = true + currentQuery.WriteByte(ch) + i++ + continue + } + + // Check for semicolon (statement terminator) + if ch == ';' { + currentQuery.WriteByte(ch) + // Check if there's a comment after the semicolon on the same line + i++ + if i < lineLen { + // Skip whitespace + for i < lineLen && (line[i] == ' ' || line[i] == '\t') { + currentQuery.WriteByte(line[i]) + i++ + } + // If there's a comment, include it + if i+1 < lineLen && line[i] == '-' && line[i+1] == '-' { + currentQuery.WriteString(line[i:]) + } + } + query := strings.TrimSpace(currentQuery.String()) + if query != "" && query != ";" { + queries = append(queries, query) + } + currentQuery.Reset() + break // Move to next line + } + + // Regular character + currentQuery.WriteByte(ch) + i++ + } + + // Add newline if we're building a query + if currentQuery.Len() > 0 { + currentQuery.WriteByte('\n') + } + } + + if err := scanner.Err(); err != nil { + return nil, err + } + + // Handle any remaining query + query := strings.TrimSpace(currentQuery.String()) + if query != "" && query != ";" { + queries = append(queries, query) + } + + return queries, nil +} + +// extractDollarTag extracts a dollar-quoted string tag from the beginning of s. +// Returns empty string if no valid dollar tag is found. +// Valid tags: $$ or $identifier$ where identifier contains only alphanumeric and underscore. +func extractDollarTag(s string) string { + if len(s) == 0 || s[0] != '$' { + return "" + } + + // Find the closing $ + for i := 1; i < len(s); i++ { + if s[i] == '$' { + tag := s[:i+1] + // Validate tag content (only alphanumeric and underscore allowed between $) + tagContent := tag[1 : len(tag)-1] + if isValidDollarTagContent(tagContent) { + return tag + } + return "" + } + // If we hit a character that's not allowed in a tag, it's not a dollar quote + if !isValidDollarTagChar(s[i]) { + return "" + } + } + + return "" +} + +// isValidDollarTagContent returns true if s contains only valid characters for a dollar tag. +func isValidDollarTagContent(s string) bool { + if s == "" { + return true // $$ is valid + } + for _, ch := range s { + if !isValidDollarTagChar(byte(ch)) { + return false + } + } + return true +} + +// isValidDollarTagChar returns true if ch is a valid character in a dollar tag. +// Valid characters are alphanumeric and underscore. +func isValidDollarTagChar(ch byte) bool { + return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '_' +} diff --git a/internal/sql/sqlfile/split_test.go b/internal/sql/sqlfile/split_test.go new file mode 100644 index 0000000..749b0a9 --- /dev/null +++ b/internal/sql/sqlfile/split_test.go @@ -0,0 +1,149 @@ +package sqlfile + +import ( + "context" + "fmt" + "os" + "path/filepath" + "strings" + "testing" +) + +func TestSplit(t *testing.T) { + testdataDir := "testdata" + + entries, err := os.ReadDir(testdataDir) + if err != nil { + t.Fatalf("Failed to read testdata directory: %v", err) + } + + for _, entry := range entries { + if !entry.IsDir() { + continue + } + + testName := entry.Name() + t.Run(testName, func(t *testing.T) { + testDir := filepath.Join(testdataDir, testName) + + // Read input file + inputPath := filepath.Join(testDir, "input.sql") + inputData, err := os.ReadFile(inputPath) + if err != nil { + t.Fatalf("Failed to read input file: %v", err) + } + + // Read expected output files + var expected []string + for i := 1; ; i++ { + outputPath := filepath.Join(testDir, fmt.Sprintf("output_%d.sql", i)) + data, err := os.ReadFile(outputPath) + if err != nil { + if os.IsNotExist(err) { + break + } + t.Fatalf("Failed to read output file %s: %v", outputPath, err) + } + expected = append(expected, string(data)) + } + + // Run Split + ctx := context.Background() + reader := strings.NewReader(string(inputData)) + + got, err := Split(ctx, reader) + if err != nil { + t.Fatalf("Split() error = %v", err) + } + + // Compare results + if len(got) != len(expected) { + t.Errorf("Split() got %d queries, expected %d", len(got), len(expected)) + t.Logf("Got: %v", got) + t.Logf("Expected: %v", expected) + return + } + + for i := range got { + if got[i] != expected[i] { + t.Errorf("Query %d:\ngot: %q\nexpected: %q", i, got[i], expected[i]) + } + } + }) + } +} + +func TestSplitContextCancellation(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() // Cancel immediately + + reader := strings.NewReader("SELECT * FROM users;") + _, err := Split(ctx, reader) + + if err != context.Canceled { + t.Errorf("Expected context.Canceled error, got %v", err) + } +} + +func TestExtractDollarTag(t *testing.T) { + tests := []struct { + name string + input string + expected string + }{ + { + name: "empty dollar quote", + input: "$$", + expected: "$$", + }, + { + name: "simple tag", + input: "$tag$", + expected: "$tag$", + }, + { + name: "tag with numbers", + input: "$tag123$", + expected: "$tag123$", + }, + { + name: "tag with underscore", + input: "$my_tag$", + expected: "$my_tag$", + }, + { + name: "not a dollar quote (no closing)", + input: "$tag", + expected: "", + }, + { + name: "not a dollar quote (invalid char)", + input: "$tag-name$", + expected: "", + }, + { + name: "empty string", + input: "", + expected: "", + }, + { + name: "no dollar sign", + input: "tag", + expected: "", + }, + { + name: "tag with extra content", + input: "$tag$rest of string", + expected: "$tag$", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := extractDollarTag(tt.input) + if got != tt.expected { + t.Errorf("extractDollarTag(%q) = %q, expected %q", tt.input, got, tt.expected) + } + }) + } +} diff --git a/internal/sql/sqlfile/testdata/complex_query/input.sql b/internal/sql/sqlfile/testdata/complex_query/input.sql new file mode 100644 index 0000000..a4c0adc --- /dev/null +++ b/internal/sql/sqlfile/testdata/complex_query/input.sql @@ -0,0 +1,13 @@ +-- Create a user +INSERT INTO users (name, email) VALUES ('John''s', 'john@example.com'); -- comment; + +/* Multi-line + comment with ; */ +CREATE FUNCTION test() RETURNS text AS $$ +BEGIN + -- Internal comment + RETURN 'test;value'; +END; +$$ LANGUAGE plpgsql; + +SELECT "weird;column" FROM users WHERE name = 'test;value'; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/complex_query/output_1.sql b/internal/sql/sqlfile/testdata/complex_query/output_1.sql new file mode 100644 index 0000000..ce779a9 --- /dev/null +++ b/internal/sql/sqlfile/testdata/complex_query/output_1.sql @@ -0,0 +1,2 @@ +-- Create a user +INSERT INTO users (name, email) VALUES ('John''s', 'john@example.com'); -- comment; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/complex_query/output_2.sql b/internal/sql/sqlfile/testdata/complex_query/output_2.sql new file mode 100644 index 0000000..a40e997 --- /dev/null +++ b/internal/sql/sqlfile/testdata/complex_query/output_2.sql @@ -0,0 +1,8 @@ +/* Multi-line + comment with ; */ +CREATE FUNCTION test() RETURNS text AS $$ +BEGIN + -- Internal comment + RETURN 'test;value'; +END; +$$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/complex_query/output_3.sql b/internal/sql/sqlfile/testdata/complex_query/output_3.sql new file mode 100644 index 0000000..0f12201 --- /dev/null +++ b/internal/sql/sqlfile/testdata/complex_query/output_3.sql @@ -0,0 +1 @@ +SELECT "weird;column" FROM users WHERE name = 'test;value'; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/dollar_quote_with_newlines/input.sql b/internal/sql/sqlfile/testdata/dollar_quote_with_newlines/input.sql new file mode 100644 index 0000000..29c5601 --- /dev/null +++ b/internal/sql/sqlfile/testdata/dollar_quote_with_newlines/input.sql @@ -0,0 +1,3 @@ +SELECT $$Line 1 +Line 2; with semicolon +Line 3$$; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/dollar_quote_with_newlines/output_1.sql b/internal/sql/sqlfile/testdata/dollar_quote_with_newlines/output_1.sql new file mode 100644 index 0000000..29c5601 --- /dev/null +++ b/internal/sql/sqlfile/testdata/dollar_quote_with_newlines/output_1.sql @@ -0,0 +1,3 @@ +SELECT $$Line 1 +Line 2; with semicolon +Line 3$$; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/dollar_quoted_function/input.sql b/internal/sql/sqlfile/testdata/dollar_quoted_function/input.sql new file mode 100644 index 0000000..1e8bcf4 --- /dev/null +++ b/internal/sql/sqlfile/testdata/dollar_quoted_function/input.sql @@ -0,0 +1,5 @@ +CREATE FUNCTION foo() RETURNS text AS $$ +BEGIN + RETURN 'test;'; +END; +$$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/dollar_quoted_function/output_1.sql b/internal/sql/sqlfile/testdata/dollar_quoted_function/output_1.sql new file mode 100644 index 0000000..1e8bcf4 --- /dev/null +++ b/internal/sql/sqlfile/testdata/dollar_quoted_function/output_1.sql @@ -0,0 +1,5 @@ +CREATE FUNCTION foo() RETURNS text AS $$ +BEGIN + RETURN 'test;'; +END; +$$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/dollar_quoted_string/input.sql b/internal/sql/sqlfile/testdata/dollar_quoted_string/input.sql new file mode 100644 index 0000000..f6b17df --- /dev/null +++ b/internal/sql/sqlfile/testdata/dollar_quoted_string/input.sql @@ -0,0 +1 @@ +SELECT $$This has a ; semicolon$$; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/dollar_quoted_string/output_1.sql b/internal/sql/sqlfile/testdata/dollar_quoted_string/output_1.sql new file mode 100644 index 0000000..f6b17df --- /dev/null +++ b/internal/sql/sqlfile/testdata/dollar_quoted_string/output_1.sql @@ -0,0 +1 @@ +SELECT $$This has a ; semicolon$$; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/double_quoted_identifier/input.sql b/internal/sql/sqlfile/testdata/double_quoted_identifier/input.sql new file mode 100644 index 0000000..ec10c4a --- /dev/null +++ b/internal/sql/sqlfile/testdata/double_quoted_identifier/input.sql @@ -0,0 +1 @@ +SELECT "column;name" FROM "table;name"; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/double_quoted_identifier/output_1.sql b/internal/sql/sqlfile/testdata/double_quoted_identifier/output_1.sql new file mode 100644 index 0000000..ec10c4a --- /dev/null +++ b/internal/sql/sqlfile/testdata/double_quoted_identifier/output_1.sql @@ -0,0 +1 @@ +SELECT "column;name" FROM "table;name"; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/empty_input/input.sql b/internal/sql/sqlfile/testdata/empty_input/input.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/sql/sqlfile/testdata/escaped_double_quotes/input.sql b/internal/sql/sqlfile/testdata/escaped_double_quotes/input.sql new file mode 100644 index 0000000..b76ac62 --- /dev/null +++ b/internal/sql/sqlfile/testdata/escaped_double_quotes/input.sql @@ -0,0 +1 @@ +SELECT "column""name" FROM users; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/escaped_double_quotes/output_1.sql b/internal/sql/sqlfile/testdata/escaped_double_quotes/output_1.sql new file mode 100644 index 0000000..b76ac62 --- /dev/null +++ b/internal/sql/sqlfile/testdata/escaped_double_quotes/output_1.sql @@ -0,0 +1 @@ +SELECT "column""name" FROM users; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/escaped_quotes/input.sql b/internal/sql/sqlfile/testdata/escaped_quotes/input.sql new file mode 100644 index 0000000..adbed97 --- /dev/null +++ b/internal/sql/sqlfile/testdata/escaped_quotes/input.sql @@ -0,0 +1 @@ +INSERT INTO users (name) VALUES ('It''s a test'); \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/escaped_quotes/output_1.sql b/internal/sql/sqlfile/testdata/escaped_quotes/output_1.sql new file mode 100644 index 0000000..adbed97 --- /dev/null +++ b/internal/sql/sqlfile/testdata/escaped_quotes/output_1.sql @@ -0,0 +1 @@ +INSERT INTO users (name) VALUES ('It''s a test'); \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/last_query_no_semicolon/input.sql b/internal/sql/sqlfile/testdata/last_query_no_semicolon/input.sql new file mode 100644 index 0000000..327c60a --- /dev/null +++ b/internal/sql/sqlfile/testdata/last_query_no_semicolon/input.sql @@ -0,0 +1,2 @@ +SELECT * FROM users; +INSERT INTO posts (title) VALUES ('Test') \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/last_query_no_semicolon/output_1.sql b/internal/sql/sqlfile/testdata/last_query_no_semicolon/output_1.sql new file mode 100644 index 0000000..b28910e --- /dev/null +++ b/internal/sql/sqlfile/testdata/last_query_no_semicolon/output_1.sql @@ -0,0 +1 @@ +SELECT * FROM users; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/last_query_no_semicolon/output_2.sql b/internal/sql/sqlfile/testdata/last_query_no_semicolon/output_2.sql new file mode 100644 index 0000000..0a99795 --- /dev/null +++ b/internal/sql/sqlfile/testdata/last_query_no_semicolon/output_2.sql @@ -0,0 +1 @@ +INSERT INTO posts (title) VALUES ('Test') \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/multi_line_comment/input.sql b/internal/sql/sqlfile/testdata/multi_line_comment/input.sql new file mode 100644 index 0000000..9a5e75a --- /dev/null +++ b/internal/sql/sqlfile/testdata/multi_line_comment/input.sql @@ -0,0 +1,3 @@ +SELECT * FROM users /* this is +a multi-line comment */; +SELECT * FROM posts; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/multi_line_comment/output_1.sql b/internal/sql/sqlfile/testdata/multi_line_comment/output_1.sql new file mode 100644 index 0000000..22792d2 --- /dev/null +++ b/internal/sql/sqlfile/testdata/multi_line_comment/output_1.sql @@ -0,0 +1,2 @@ +SELECT * FROM users /* this is +a multi-line comment */; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/multi_line_comment/output_2.sql b/internal/sql/sqlfile/testdata/multi_line_comment/output_2.sql new file mode 100644 index 0000000..7707478 --- /dev/null +++ b/internal/sql/sqlfile/testdata/multi_line_comment/output_2.sql @@ -0,0 +1 @@ +SELECT * FROM posts; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/multi_line_comment_with_semicolon/input.sql b/internal/sql/sqlfile/testdata/multi_line_comment_with_semicolon/input.sql new file mode 100644 index 0000000..2b89a4a --- /dev/null +++ b/internal/sql/sqlfile/testdata/multi_line_comment_with_semicolon/input.sql @@ -0,0 +1,2 @@ +SELECT * FROM users /* this has ; in it */; +SELECT * FROM posts; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/multi_line_comment_with_semicolon/output_1.sql b/internal/sql/sqlfile/testdata/multi_line_comment_with_semicolon/output_1.sql new file mode 100644 index 0000000..22da00e --- /dev/null +++ b/internal/sql/sqlfile/testdata/multi_line_comment_with_semicolon/output_1.sql @@ -0,0 +1 @@ +SELECT * FROM users /* this has ; in it */; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/multi_line_comment_with_semicolon/output_2.sql b/internal/sql/sqlfile/testdata/multi_line_comment_with_semicolon/output_2.sql new file mode 100644 index 0000000..7707478 --- /dev/null +++ b/internal/sql/sqlfile/testdata/multi_line_comment_with_semicolon/output_2.sql @@ -0,0 +1 @@ +SELECT * FROM posts; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/multiple_queries/input.sql b/internal/sql/sqlfile/testdata/multiple_queries/input.sql new file mode 100644 index 0000000..fccb5d3 --- /dev/null +++ b/internal/sql/sqlfile/testdata/multiple_queries/input.sql @@ -0,0 +1,3 @@ +SELECT * FROM users; +INSERT INTO users (name) VALUES ('John'); +DELETE FROM users WHERE id = 1; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/multiple_queries/output_1.sql b/internal/sql/sqlfile/testdata/multiple_queries/output_1.sql new file mode 100644 index 0000000..b28910e --- /dev/null +++ b/internal/sql/sqlfile/testdata/multiple_queries/output_1.sql @@ -0,0 +1 @@ +SELECT * FROM users; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/multiple_queries/output_2.sql b/internal/sql/sqlfile/testdata/multiple_queries/output_2.sql new file mode 100644 index 0000000..0ec06c3 --- /dev/null +++ b/internal/sql/sqlfile/testdata/multiple_queries/output_2.sql @@ -0,0 +1 @@ +INSERT INTO users (name) VALUES ('John'); \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/multiple_queries/output_3.sql b/internal/sql/sqlfile/testdata/multiple_queries/output_3.sql new file mode 100644 index 0000000..cad242d --- /dev/null +++ b/internal/sql/sqlfile/testdata/multiple_queries/output_3.sql @@ -0,0 +1 @@ +DELETE FROM users WHERE id = 1; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/nested_dollar_quotes/input.sql b/internal/sql/sqlfile/testdata/nested_dollar_quotes/input.sql new file mode 100644 index 0000000..e1c9b52 --- /dev/null +++ b/internal/sql/sqlfile/testdata/nested_dollar_quotes/input.sql @@ -0,0 +1 @@ +SELECT $outer$This contains $inner$nested; quote$inner$;$outer$; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/nested_dollar_quotes/output_1.sql b/internal/sql/sqlfile/testdata/nested_dollar_quotes/output_1.sql new file mode 100644 index 0000000..e1c9b52 --- /dev/null +++ b/internal/sql/sqlfile/testdata/nested_dollar_quotes/output_1.sql @@ -0,0 +1 @@ +SELECT $outer$This contains $inner$nested; quote$inner$;$outer$; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/no_trailing_semicolon/input.sql b/internal/sql/sqlfile/testdata/no_trailing_semicolon/input.sql new file mode 100644 index 0000000..e9e19fa --- /dev/null +++ b/internal/sql/sqlfile/testdata/no_trailing_semicolon/input.sql @@ -0,0 +1 @@ +SELECT * FROM users \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/no_trailing_semicolon/output_1.sql b/internal/sql/sqlfile/testdata/no_trailing_semicolon/output_1.sql new file mode 100644 index 0000000..e9e19fa --- /dev/null +++ b/internal/sql/sqlfile/testdata/no_trailing_semicolon/output_1.sql @@ -0,0 +1 @@ +SELECT * FROM users \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/only_semicolons/input.sql b/internal/sql/sqlfile/testdata/only_semicolons/input.sql new file mode 100644 index 0000000..3e62726 --- /dev/null +++ b/internal/sql/sqlfile/testdata/only_semicolons/input.sql @@ -0,0 +1 @@ +;;; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/semicolon_in_string/input.sql b/internal/sql/sqlfile/testdata/semicolon_in_string/input.sql new file mode 100644 index 0000000..ad364a7 --- /dev/null +++ b/internal/sql/sqlfile/testdata/semicolon_in_string/input.sql @@ -0,0 +1 @@ +INSERT INTO users (name) VALUES ('John; DROP TABLE users;'); \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/semicolon_in_string/output_1.sql b/internal/sql/sqlfile/testdata/semicolon_in_string/output_1.sql new file mode 100644 index 0000000..ad364a7 --- /dev/null +++ b/internal/sql/sqlfile/testdata/semicolon_in_string/output_1.sql @@ -0,0 +1 @@ +INSERT INTO users (name) VALUES ('John; DROP TABLE users;'); \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/single_line_comment/input.sql b/internal/sql/sqlfile/testdata/single_line_comment/input.sql new file mode 100644 index 0000000..ba996d6 --- /dev/null +++ b/internal/sql/sqlfile/testdata/single_line_comment/input.sql @@ -0,0 +1,2 @@ +SELECT * FROM users; -- this is a comment +SELECT * FROM posts; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/single_line_comment/output_1.sql b/internal/sql/sqlfile/testdata/single_line_comment/output_1.sql new file mode 100644 index 0000000..d6dd4dc --- /dev/null +++ b/internal/sql/sqlfile/testdata/single_line_comment/output_1.sql @@ -0,0 +1 @@ +SELECT * FROM users; -- this is a comment \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/single_line_comment/output_2.sql b/internal/sql/sqlfile/testdata/single_line_comment/output_2.sql new file mode 100644 index 0000000..7707478 --- /dev/null +++ b/internal/sql/sqlfile/testdata/single_line_comment/output_2.sql @@ -0,0 +1 @@ +SELECT * FROM posts; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/single_line_comment_with_semicolon/input.sql b/internal/sql/sqlfile/testdata/single_line_comment_with_semicolon/input.sql new file mode 100644 index 0000000..1c86be9 --- /dev/null +++ b/internal/sql/sqlfile/testdata/single_line_comment_with_semicolon/input.sql @@ -0,0 +1,2 @@ +SELECT * FROM users; -- this has a ; in it +SELECT * FROM posts; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/single_line_comment_with_semicolon/output_1.sql b/internal/sql/sqlfile/testdata/single_line_comment_with_semicolon/output_1.sql new file mode 100644 index 0000000..1c252df --- /dev/null +++ b/internal/sql/sqlfile/testdata/single_line_comment_with_semicolon/output_1.sql @@ -0,0 +1 @@ +SELECT * FROM users; -- this has a ; in it \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/single_line_comment_with_semicolon/output_2.sql b/internal/sql/sqlfile/testdata/single_line_comment_with_semicolon/output_2.sql new file mode 100644 index 0000000..7707478 --- /dev/null +++ b/internal/sql/sqlfile/testdata/single_line_comment_with_semicolon/output_2.sql @@ -0,0 +1 @@ +SELECT * FROM posts; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/single_query/input.sql b/internal/sql/sqlfile/testdata/single_query/input.sql new file mode 100644 index 0000000..b28910e --- /dev/null +++ b/internal/sql/sqlfile/testdata/single_query/input.sql @@ -0,0 +1 @@ +SELECT * FROM users; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/single_query/output_1.sql b/internal/sql/sqlfile/testdata/single_query/output_1.sql new file mode 100644 index 0000000..b28910e --- /dev/null +++ b/internal/sql/sqlfile/testdata/single_query/output_1.sql @@ -0,0 +1 @@ +SELECT * FROM users; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/tagged_dollar_quoted_string/input.sql b/internal/sql/sqlfile/testdata/tagged_dollar_quoted_string/input.sql new file mode 100644 index 0000000..65ffbae --- /dev/null +++ b/internal/sql/sqlfile/testdata/tagged_dollar_quoted_string/input.sql @@ -0,0 +1 @@ +SELECT $tag$This has a ; semicolon$tag$; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/tagged_dollar_quoted_string/output_1.sql b/internal/sql/sqlfile/testdata/tagged_dollar_quoted_string/output_1.sql new file mode 100644 index 0000000..65ffbae --- /dev/null +++ b/internal/sql/sqlfile/testdata/tagged_dollar_quoted_string/output_1.sql @@ -0,0 +1 @@ +SELECT $tag$This has a ; semicolon$tag$; \ No newline at end of file diff --git a/internal/sql/sqlfile/testdata/whitespace_only/input.sql b/internal/sql/sqlfile/testdata/whitespace_only/input.sql new file mode 100644 index 0000000..139597f --- /dev/null +++ b/internal/sql/sqlfile/testdata/whitespace_only/input.sql @@ -0,0 +1,2 @@ + + diff --git a/internal/sql/sqlpath/read.go b/internal/sql/sqlpath/read.go new file mode 100644 index 0000000..278ebf3 --- /dev/null +++ b/internal/sql/sqlpath/read.go @@ -0,0 +1,66 @@ +package sqlpath + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/sqlc-dev/sqlc/internal/migrations" +) + +// Return a list of SQL files in the listed paths. +// +// Only includes files ending in .sql. Omits hidden files, directories, and +// down migrations. + +// If a path contains *, ?, [, or ], treat the path as a pattern and expand it +// filepath.Glob. +func Glob(patterns []string) ([]string, error) { + var files, paths []string + for _, pattern := range patterns { + if strings.ContainsAny(pattern, "*?[]") { + matches, err := filepath.Glob(pattern) + if err != nil { + return nil, err + } + // if len(matches) == 0 { + // slog.Warn("zero files matched", "pattern", pattern) + // } + paths = append(paths, matches...) + } else { + paths = append(paths, pattern) + } + } + for _, path := range paths { + f, err := os.Stat(path) + if err != nil { + return nil, fmt.Errorf("path error: %w", err) + } + if f.IsDir() { + listing, err := os.ReadDir(path) + if err != nil { + return nil, err + } + for _, f := range listing { + files = append(files, filepath.Join(path, f.Name())) + } + } else { + files = append(files, filepath.Clean(path)) + } + } + var sqlFiles []string + for _, file := range files { + if !strings.HasSuffix(file, ".sql") { + continue + } + if strings.HasPrefix(filepath.Base(file), ".") { + continue + } + if migrations.IsDown(filepath.Base(file)) { + continue + } + sqlFiles = append(sqlFiles, file) + } + return sqlFiles, nil +} diff --git a/internal/sql/sqlpath/read_test.go b/internal/sql/sqlpath/read_test.go new file mode 100644 index 0000000..e4d9590 --- /dev/null +++ b/internal/sql/sqlpath/read_test.go @@ -0,0 +1,243 @@ +package sqlpath + +import ( + "fmt" + "path/filepath" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" +) + +// Returns a list of SQL files from given paths. +func TestReturnsListOfSQLFiles(t *testing.T) { + // Arrange + paths := []string{"testdata/file1.sql", "testdata/file2.sql"} + + // Act + result, err := Glob(paths) + + // Assert + expected := []string{filepath.Join("testdata", "file1.sql"), filepath.Join("testdata", "file2.sql")} + if !cmp.Equal(result, expected) { + t.Errorf("Expected %v, but got %v, %v", expected, result, cmp.Diff(expected, result)) + } + if err != nil { + t.Errorf("Expected no error, but got %v", err) + } +} + +func TestReturnsNilListWhenNoSQLFilesFound(t *testing.T) { + // Arrange + paths := []string{"testdata/extra.txt"} + + // Act + result, err := Glob(paths) + // Assert + var expected []string + if !cmp.Equal(result, expected) { + t.Errorf("Expected %v, but got %v, %v", expected, result, cmp.Diff(expected, result)) + } + if err != nil { + t.Errorf("Expected no error, but got %v", err) + } +} + +func TestIgnoresHiddenFilesWhenSearchingForSQLFiles(t *testing.T) { + // Arrange + paths := []string{"testdata/.hidden.sql"} + + // Act + result, err := Glob(paths) + + // Assert + var expected []string + if !cmp.Equal(result, expected) { + t.Errorf("Expected %v, but got %v", expected, result) + } + if err != nil { + t.Errorf("Expected no error, but got %v", err) + } +} + +func TestIgnoresNonSQLFilesWhenSearchingForSQLFiles(t *testing.T) { + // Arrange + paths := []string{"testdata/extra.txt"} + + // Act + result, err := Glob(paths) + + // Assert + var expected []string + if !cmp.Equal(result, expected) { + t.Errorf("Expected %v, but got %v", expected, result) + } + if err != nil { + t.Errorf("Expected no error, but got %v", err) + } +} + +func TestExcludesSQLFilesEndingWithDownSQLWhenSearchingForSQLFiles(t *testing.T) { + // Arrange + paths := []string{"testdata/file1.sql", "testdata/file3.down.sql"} + + // Act + result, err := Glob(paths) + + // Assert + expected := []string{filepath.Join("testdata", "file1.sql")} + if !cmp.Equal(result, expected) { + t.Errorf("Expected %v, but got %v", expected, result) + } + if err != nil { + t.Errorf("Expected no error, but got %v", err) + } +} + +func TestReturnsErrorWhenPathDoesNotExist(t *testing.T) { + // Arrange + paths := []string{"non_existent_path"} + + // Act + result, err := Glob(paths) + + // Assert + var expected []string + if !cmp.Equal(result, expected) { + t.Errorf("Expected %v, but got %v", expected, result) + } + if err == nil { + t.Errorf("Expected an error, but got nil") + } else { + expectedError := fmt.Errorf("path error:") + if !strings.HasPrefix(err.Error(), expectedError.Error()) { + t.Errorf("Expected error %v, but got %v", expectedError, err) + } + } +} + +func TestReturnsErrorWhenDirectoryCannotBeRead(t *testing.T) { + // Arrange + paths := []string{"testdata/unreadable"} + + // Act + result, err := Glob(paths) + + // Assert + var expected []string + if !cmp.Equal(result, expected) { + t.Errorf("Expected %v, but got %v", expected, result) + } + if err == nil { + t.Errorf("Expected an error, but got nil") + } else { + expectedError := fmt.Errorf("path error:") + if !strings.HasPrefix(err.Error(), expectedError.Error()) { + t.Errorf("Expected error %v, but got %v", expectedError, err) + } + } +} + +func TestDoesNotIncludesSQLFilesWithUppercaseExtension(t *testing.T) { + // Arrange + paths := []string{"testdata/file4.SQL"} + + // Act + result, err := Glob(paths) + + // Assert + var expected []string + if !cmp.Equal(result, expected) { + t.Errorf("Expected %v, but got %v", expected, result) + } + if err != nil { + t.Errorf("Expected no error, but got %v", err) + } +} + +func TestNotIncludesHiddenFilesAnyPath(t *testing.T) { + // Arrange + paths := []string{ + "./testdata/.hiddendir/file1.sql", // pass + "./testdata/.hidden.sql", // skip + } + + // Act + result, err := Glob(paths) + + // Assert + expected := []string{filepath.Join("testdata", ".hiddendir", "file1.sql")} + if !cmp.Equal(result, expected) { + t.Errorf("Expected %v, but got %v", expected, result) + } + if err != nil { + t.Errorf("Expected no error, but got %v", err) + } +} + +func TestFollowSymlinks(t *testing.T) { + // Arrange + paths := []string{"testdata/symlink", "testdata/file1.symlink.sql"} + + // Act + result, err := Glob(paths) + + // Assert + expected := []string{ + filepath.Join("testdata", "symlink", "file1.sql"), + filepath.Join("testdata", "symlink", "file1.symlink.sql"), + filepath.Join("testdata", "symlink", "file2.sql"), + filepath.Join("testdata", "file1.symlink.sql"), + } + if !cmp.Equal(result, expected) { + t.Errorf("Expected %v, but got %v", expected, result) + } + if err != nil { + t.Errorf("Expected no error, but got %v", err) + } +} + +func TestGlobPattern(t *testing.T) { + // Arrange + tests := []struct { + pattern string + expected []string + }{ + { + pattern: "testdata/glob/*/queries", + expected: []string{ + filepath.Join("testdata", "glob", "sub1", "queries", "file1.sql"), + filepath.Join("testdata", "glob", "sub2", "queries", "file2.sql"), + filepath.Join("testdata", "glob", "sub3", "queries", "file3.sql"), + filepath.Join("testdata", "glob", "sub3", "queries", "file4.sql"), + }, + }, + { + pattern: "testdata/glob/sub3/queries/file?.sql", + expected: []string{ + filepath.Join("testdata", "glob", "sub3", "queries", "file3.sql"), + filepath.Join("testdata", "glob", "sub3", "queries", "file4.sql"), + }, + }, + { + pattern: "testdata/glob/sub3/queries/file[1-5].sql", + expected: []string{ + filepath.Join("testdata", "glob", "sub3", "queries", "file3.sql"), + filepath.Join("testdata", "glob", "sub3", "queries", "file4.sql"), + }, + }, + } + + for _, test := range tests { + // Act + result, err := Glob([]string{test.pattern}) + + // Assert + if !cmp.Equal(result, test.expected) { + t.Errorf("Pattern %v: Expected %v, but got %v", test.pattern, test.expected, result) + } + if err != nil { + t.Errorf("Pattern %v: Expected no error, but got %v", test.pattern, err) + } + } +} diff --git a/internal/sql/sqlpath/testdata/.hidden.sql b/internal/sql/sqlpath/testdata/.hidden.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/sql/sqlpath/testdata/.hiddendir/file1.sql b/internal/sql/sqlpath/testdata/.hiddendir/file1.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/sql/sqlpath/testdata/extra.txt b/internal/sql/sqlpath/testdata/extra.txt new file mode 100644 index 0000000..e69de29 diff --git a/internal/sql/sqlpath/testdata/file1.sql b/internal/sql/sqlpath/testdata/file1.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/sql/sqlpath/testdata/file1.symlink.sql b/internal/sql/sqlpath/testdata/file1.symlink.sql new file mode 120000 index 0000000..7c823b3 --- /dev/null +++ b/internal/sql/sqlpath/testdata/file1.symlink.sql @@ -0,0 +1 @@ +./file1.sql \ No newline at end of file diff --git a/internal/sql/sqlpath/testdata/file2.sql b/internal/sql/sqlpath/testdata/file2.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/sql/sqlpath/testdata/file3.down.sql b/internal/sql/sqlpath/testdata/file3.down.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/sql/sqlpath/testdata/file4.SQL b/internal/sql/sqlpath/testdata/file4.SQL new file mode 100644 index 0000000..e69de29 diff --git a/internal/sql/sqlpath/testdata/glob/sub1/queries/file1.sql b/internal/sql/sqlpath/testdata/glob/sub1/queries/file1.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/sql/sqlpath/testdata/glob/sub2/queries/file2.sql b/internal/sql/sqlpath/testdata/glob/sub2/queries/file2.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/sql/sqlpath/testdata/glob/sub3/queries/file3.sql b/internal/sql/sqlpath/testdata/glob/sub3/queries/file3.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/sql/sqlpath/testdata/glob/sub3/queries/file4.sql b/internal/sql/sqlpath/testdata/glob/sub3/queries/file4.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/sql/sqlpath/testdata/subdir/file2.sql b/internal/sql/sqlpath/testdata/subdir/file2.sql new file mode 100644 index 0000000..e69de29 diff --git a/internal/sql/sqlpath/testdata/symlink b/internal/sql/sqlpath/testdata/symlink new file mode 120000 index 0000000..945c9b4 --- /dev/null +++ b/internal/sql/sqlpath/testdata/symlink @@ -0,0 +1 @@ +. \ No newline at end of file diff --git a/internal/sql/validate/cmd.go b/internal/sql/validate/cmd.go new file mode 100644 index 0000000..e9d9dd0 --- /dev/null +++ b/internal/sql/validate/cmd.go @@ -0,0 +1,88 @@ +package validate + +import ( + "errors" + "fmt" + + "github.com/sqlc-dev/sqlc/internal/metadata" + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/astutils" +) + +func validateCopyfrom(n ast.Node) error { + stmt, ok := n.(*ast.InsertStmt) + if !ok { + return errors.New(":copyfrom requires an INSERT INTO statement") + } + if stmt.OnConflictClause != nil { + return errors.New(":copyfrom is not compatible with ON CONFLICT") + } + if stmt.WithClause != nil { + return errors.New(":copyfrom is not compatible with WITH clauses") + } + if stmt.ReturningList != nil && len(stmt.ReturningList.Items) > 0 { + return errors.New(":copyfrom is not compatible with RETURNING") + } + sel, ok := stmt.SelectStmt.(*ast.SelectStmt) + if !ok { + return nil + } + if len(sel.FromClause.Items) > 0 { + return errors.New(":copyfrom is not compatible with INSERT INTO ... SELECT") + } + if sel.ValuesLists == nil || len(sel.ValuesLists.Items) != 1 { + return errors.New(":copyfrom requires exactly one example row to be inserted") + } + sublist, ok := sel.ValuesLists.Items[0].(*ast.List) + if !ok { + return nil + } + for _, v := range sublist.Items { + if _, ok := v.(*ast.ParamRef); !ok { + return errors.New(":copyfrom doesn't support non-parameter values") + } + } + return nil +} + +func validateBatch(n ast.Node) error { + args := astutils.Search(n, func(n ast.Node) bool { + _, ok := n.(*ast.ParamRef) + return ok + }) + if len(args.Items) == 0 { + return errors.New(":batch* commands require parameters") + } + return nil +} + +func Cmd(n ast.Node, name, cmd string) error { + if cmd == metadata.CmdCopyFrom { + return validateCopyfrom(n) + } + if (cmd == metadata.CmdBatchExec || cmd == metadata.CmdBatchMany) || cmd == metadata.CmdBatchOne { + if err := validateBatch(n); err != nil { + return err + } + } + if !(cmd == metadata.CmdMany || cmd == metadata.CmdOne || cmd == metadata.CmdBatchMany || cmd == metadata.CmdBatchOne) { + return nil + } + var list *ast.List + switch stmt := n.(type) { + case *ast.SelectStmt: + return nil + case *ast.DeleteStmt: + list = stmt.ReturningList + case *ast.InsertStmt: + list = stmt.ReturningList + case *ast.UpdateStmt: + list = stmt.ReturningList + default: + return nil + } + if list == nil || len(list.Items) == 0 { + return fmt.Errorf("query %q specifies parameter %q without containing a RETURNING clause", name, cmd) + } + return nil +} diff --git a/internal/sql/validate/func_call.go b/internal/sql/validate/func_call.go new file mode 100644 index 0000000..c60cbaa --- /dev/null +++ b/internal/sql/validate/func_call.go @@ -0,0 +1,48 @@ +package validate + +import ( + "errors" + + "github.com/sqlc-dev/sqlc/internal/config" + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/astutils" + "github.com/sqlc-dev/sqlc/internal/sql/catalog" + "github.com/sqlc-dev/sqlc/internal/sql/sqlerr" +) + +type funcCallVisitor struct { + catalog *catalog.Catalog + settings config.CombinedSettings + err error +} + +func (v *funcCallVisitor) Visit(node ast.Node) astutils.Visitor { + if v.err != nil { + return nil + } + + call, ok := node.(*ast.FuncCall) + if !ok { + return v + } + fn := call.Func + if fn == nil { + return v + } + + fun, err := v.catalog.ResolveFuncCall(call) + if fun != nil { + return v + } + if errors.Is(err, sqlerr.NotFound) && !v.settings.Package.StrictFunctionChecks { + return v + } + v.err = err + return nil +} + +func FuncCall(c *catalog.Catalog, cs config.CombinedSettings, n ast.Node) error { + visitor := funcCallVisitor{catalog: c, settings: cs} + astutils.Walk(&visitor, n) + return visitor.err +} diff --git a/internal/sql/validate/insert_stmt.go b/internal/sql/validate/insert_stmt.go new file mode 100644 index 0000000..236ddbf --- /dev/null +++ b/internal/sql/validate/insert_stmt.go @@ -0,0 +1,141 @@ +package validate + +import ( + "strings" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/catalog" + "github.com/sqlc-dev/sqlc/internal/sql/sqlerr" +) + +const excludedTable = "EXCLUDED" + +func InsertStmt(c *catalog.Catalog, fqn *ast.TableName, stmt *ast.InsertStmt) error { + sel, ok := stmt.SelectStmt.(*ast.SelectStmt) + if !ok { + return nil + } + if sel.ValuesLists == nil { + return nil + } + if len(sel.ValuesLists.Items) != 1 { + return nil + } + sublist, ok := sel.ValuesLists.Items[0].(*ast.List) + if !ok { + return nil + } + + colsLen := len(stmt.Cols.Items) + valsLen := len(sublist.Items) + switch { + case colsLen > valsLen: + return &sqlerr.Error{ + Code: "42601", + Message: "INSERT has more target columns than expressions", + } + case colsLen < valsLen: + return &sqlerr.Error{ + Code: "42601", + Message: "INSERT has more expressions than target columns", + } + } + + return onConflictClause(c, fqn, stmt) +} + +// onConflictClause validates an ON CONFLICT DO UPDATE clause against the target +// table. It checks: +// - ON CONFLICT (col, ...) conflict target columns exist +// - DO UPDATE SET col = ... assignment target columns exist +// - EXCLUDED.col references exist +func onConflictClause(c *catalog.Catalog, fqn *ast.TableName, n *ast.InsertStmt) error { + if fqn == nil || n.OnConflictClause == nil || n.OnConflictClause.Action != ast.OnConflictActionUpdate { + return nil + } + + table, err := c.GetTable(fqn) + if err != nil { + return err + } + + // Build set of column names for existence checks. + colNames := make(map[string]struct{}, len(table.Columns)) + for _, col := range table.Columns { + colNames[col.Name] = struct{}{} + } + + // DO UPDATE requires a conflict target: ON CONFLICT (col) or ON CONFLICT ON CONSTRAINT name. + if n.OnConflictClause.Infer == nil { + return &sqlerr.Error{ + Code: "42601", + Message: "ON CONFLICT DO UPDATE requires inference specification or constraint name", + } + } + + // Validate ON CONFLICT (col, ...) conflict target columns. + if n.OnConflictClause.Infer.IndexElems != nil { + for _, item := range n.OnConflictClause.Infer.IndexElems.Items { + elem, ok := item.(*ast.IndexElem) + if !ok || elem.Name == nil { + continue + } + + if _, exists := colNames[*elem.Name]; !exists { + e := sqlerr.ColumnNotFound(table.Rel.Name, *elem.Name) + e.Location = n.OnConflictClause.Infer.Location + return e + } + } + } + + // Validate DO UPDATE SET col = ... assignment target columns and EXCLUDED.col references. + if n.OnConflictClause.TargetList == nil { + return nil + } + + for _, item := range n.OnConflictClause.TargetList.Items { + target, ok := item.(*ast.ResTarget) + if !ok || target.Name == nil { + continue + } + + if _, exists := colNames[*target.Name]; !exists { + e := sqlerr.ColumnNotFound(table.Rel.Name, *target.Name) + e.Location = target.Location + return e + } + + if ref, ok := target.Val.(*ast.ColumnRef); ok { + if excludedCol, ok := excludedColumnRef(ref); ok { + if _, exists := colNames[excludedCol]; !exists { + e := sqlerr.ColumnNotFound(excludedTable, excludedCol) + e.Location = ref.Location + return e + } + } + } + } + + return nil +} + +// excludedColumnRef returns the column name if the ColumnRef is an EXCLUDED.col +// reference, and ok=true. Returns "", false otherwise. +func excludedColumnRef(ref *ast.ColumnRef) (string, bool) { + if ref.Fields == nil || len(ref.Fields.Items) != 2 { + return "", false + } + + first, ok := ref.Fields.Items[0].(*ast.String) + if !ok || !strings.EqualFold(first.Str, excludedTable) { + return "", false + } + + second, ok := ref.Fields.Items[1].(*ast.String) + if !ok { + return "", false + } + + return second.Str, true +} diff --git a/internal/sql/validate/slice.go b/internal/sql/validate/slice.go new file mode 100644 index 0000000..cbd45ed --- /dev/null +++ b/internal/sql/validate/slice.go @@ -0,0 +1,70 @@ +package validate + +import ( + "fmt" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/astutils" + "github.com/sqlc-dev/sqlc/internal/sql/sqlerr" +) + +type sliceVisitor struct { + // slices maps the location of a placeholder in the query text to the name + // of the sqlc.slice() parameter it was rewritten from. + slices map[int]string + err error +} + +func (v *sliceVisitor) Visit(node ast.Node) astutils.Visitor { + if v.err != nil { + return nil + } + + in, ok := node.(*ast.In) + if !ok { + return v + } + + // A slice expands to a comma-separated list at query time, so it has to be + // the only element of the IN expression: + // id IN (sqlc.slice("ids")) -- GOOD + // id in (0, 1, sqlc.slice("ids")) -- BAD + if len(in.List) <= 1 { + return v + } + + for _, n := range in.List { + ref, ok := n.(*ast.ParamRef) + if !ok { + continue + } + name, ok := v.slices[ref.Location] + if !ok { + continue + } + + inExpr := "..." + if col, ok := in.Expr.(*ast.ColumnRef); ok { + inExpr = col.Name + } + v.err = &sqlerr.Error{ + Message: fmt.Sprintf("expected '%s IN' expr to consist only of sqlc.slice(%s); eg ", inExpr, name), + Location: ref.Location, + } + return nil + } + + return v +} + +// Slice reports whether every sqlc.slice() parameter is the only element of the +// IN expression that contains it. The slices map is keyed by the location the +// preprocessor recorded for each rewritten slice placeholder. +func Slice(n ast.Node, slices map[int]string) error { + if len(slices) == 0 { + return nil + } + visitor := sliceVisitor{slices: slices} + astutils.Walk(&visitor, n) + return visitor.err +} diff --git a/internal/sqlcdebug/sqlcdebug.go b/internal/sqlcdebug/sqlcdebug.go new file mode 100644 index 0000000..2f5eef0 --- /dev/null +++ b/internal/sqlcdebug/sqlcdebug.go @@ -0,0 +1,182 @@ +// Package sqlcdebug parses the SQLCDEBUG environment variable and exposes +// its key=value settings to the rest of the codebase. +// +// The SQLCDEBUG variable is a comma-separated list of name=value pairs: +// +// SQLCDEBUG=dumpast=1,trace=trace.out +// +// Settings are looked up at the call site by declaring a package-level +// variable: +// +// var dumpAST = sqlcdebug.New("dumpast") +// +// func parse() { +// if dumpAST.Value() == "1" { ... } +// } +// +// New panics if name is not registered in [Settings] below. Adding a new +// setting therefore requires extending the [Settings] table so that all +// known keys are documented in one place. +// +// This package is modeled after Go's internal/godebug. Unlike Go, sqlc is +// short-lived, so settings are parsed once at process startup; the +// [Update] hook exists for tests that need to reparse mid-run. +package sqlcdebug + +import ( + "os" + "strings" + "sync" + "sync/atomic" +) + +// Info documents a single SQLCDEBUG setting. +type Info struct { + // Name is the SQLCDEBUG key, e.g. "dumpast". + Name string + // Description is a short human-readable description. + Description string + // Default is the value returned by [Setting.Value] when the key is + // not present in SQLCDEBUG. + Default string +} + +// Settings is the master table of all known SQLCDEBUG keys. New keys must +// be added here before they can be looked up via [New]. +var Settings = []Info{ + {Name: "dumpast", Description: "print the AST of every SQL statement"}, + {Name: "dumpcatalog", Description: "print the parsed database schema"}, + {Name: "trace", Description: "write a runtime trace to the named file (1 means trace.out)"}, + {Name: "processplugins", Description: "set to 0 to disable process-based plugins", Default: "1"}, + {Name: "databases", Description: "set to 'managed' to disable database connections via URI"}, + {Name: "dumpvetenv", Description: "print the variables available to a vet rule during evaluation"}, + {Name: "dumpexplain", Description: "print the JSON-formatted output from EXPLAIN during vet evaluation"}, +} + +func info(name string) (Info, bool) { + for _, s := range Settings { + if s.Name == name { + return s, true + } + } + return Info{}, false +} + +// Setting is a single SQLCDEBUG key. Obtain one with [New]; reading it +// with [Setting.Value] returns the value parsed from the SQLCDEBUG +// environment variable, or the registered default. +type Setting struct { + info Info + set atomic.Bool + value atomic.Pointer[string] +} + +var ( + registryMu sync.Mutex + registry = map[string]*Setting{} +) + +// New returns the Setting for name. The same pointer is returned for +// repeated calls. New panics if name is not present in [Settings]. +func New(name string) *Setting { + registryMu.Lock() + defer registryMu.Unlock() + if s, ok := registry[name]; ok { + return s + } + i, ok := info(name) + if !ok { + panic("sqlcdebug: unknown setting " + name) + } + s := &Setting{info: i} + registry[name] = s + apply(s, parsedEnv()) + return s +} + +// Name returns the setting's key. +func (s *Setting) Name() string { return s.info.Name } + +// Default returns the value used when the key is absent from SQLCDEBUG. +func (s *Setting) Default() string { return s.info.Default } + +// Value returns the parsed value of the SQLCDEBUG setting, falling back +// to the registered default. +func (s *Setting) Value() string { + if v := s.value.Load(); v != nil { + return *v + } + return s.info.Default +} + +// IsSet reports whether the key was present in SQLCDEBUG. +func (s *Setting) IsSet() bool { return s.set.Load() } + +// Any reports whether SQLCDEBUG contained any recognized key=value pair. +// It mirrors the legacy "is debug active?" check. +func Any() bool { + for _, s := range registry { + if s.IsSet() { + return true + } + } + return parsedEnvHasAny() +} + +var ( + envOnce sync.Once + envMap map[string]string +) + +func parsedEnv() map[string]string { + envOnce.Do(func() { + envMap = parse(os.Getenv("SQLCDEBUG")) + }) + return envMap +} + +func parsedEnvHasAny() bool { + return len(parsedEnv()) > 0 +} + +func parse(raw string) map[string]string { + out := map[string]string{} + if raw == "" { + return out + } + for pair := range strings.SplitSeq(raw, ",") { + pair = strings.TrimSpace(pair) + if pair == "" { + continue + } + k, v, ok := strings.Cut(pair, "=") + if !ok { + continue + } + out[k] = v + } + return out +} + +func apply(s *Setting, env map[string]string) { + if v, ok := env[s.info.Name]; ok { + s.value.Store(&v) + s.set.Store(true) + } else { + s.value.Store(nil) + s.set.Store(false) + } +} + +// Update reparses the given SQLCDEBUG-formatted string and refreshes +// every registered setting. Intended for tests; production code should +// rely on the value parsed at startup. +func Update(raw string) { + registryMu.Lock() + defer registryMu.Unlock() + envMap = parse(raw) + envOnce.Do(func() {}) // mark as parsed so future New() calls see envMap. + for _, s := range registry { + apply(s, envMap) + } +} diff --git a/internal/sqlcdebug/sqlcdebug_test.go b/internal/sqlcdebug/sqlcdebug_test.go new file mode 100644 index 0000000..6fbd118 --- /dev/null +++ b/internal/sqlcdebug/sqlcdebug_test.go @@ -0,0 +1,107 @@ +package sqlcdebug + +import ( + "sync" + "testing" +) + +func resetForTest(t *testing.T) { + t.Helper() + registryMu.Lock() + registry = map[string]*Setting{} + envMap = nil + envOnce = sync.Once{} + registryMu.Unlock() +} + +func TestParse(t *testing.T) { + tests := []struct { + input string + want map[string]string + }{ + {"", map[string]string{}}, + {"dumpast=1", map[string]string{"dumpast": "1"}}, + {"dumpast=1,trace=trace.out", map[string]string{"dumpast": "1", "trace": "trace.out"}}, + {" dumpast=1 , processplugins=0 ", map[string]string{"dumpast": "1", "processplugins": "0"}}, + {"trace=", map[string]string{"trace": ""}}, + {"bare", map[string]string{}}, + } + for _, tt := range tests { + got := parse(tt.input) + if len(got) != len(tt.want) { + t.Errorf("parse(%q): got %v, want %v", tt.input, got, tt.want) + continue + } + for k, v := range tt.want { + if got[k] != v { + t.Errorf("parse(%q)[%q] = %q, want %q", tt.input, k, got[k], v) + } + } + } +} + +func TestSettingValue(t *testing.T) { + resetForTest(t) + Update("dumpast=1,trace=foo.out") + + if v := New("dumpast").Value(); v != "1" { + t.Errorf("dumpast = %q, want %q", v, "1") + } + if v := New("trace").Value(); v != "foo.out" { + t.Errorf("trace = %q, want %q", v, "foo.out") + } + if !New("dumpast").IsSet() { + t.Errorf("IsSet(dumpast) = false, want true") + } + + // Unset key returns its registered default. + if v := New("processplugins").Value(); v != "1" { + t.Errorf("processplugins default = %q, want %q", v, "1") + } + if New("processplugins").IsSet() { + t.Errorf("IsSet(processplugins) = true, want false") + } +} + +func TestUpdateRefreshesExistingSettings(t *testing.T) { + resetForTest(t) + dumpAST := New("dumpast") + + if v := dumpAST.Value(); v != "" { + t.Errorf("initial dumpast = %q, want empty", v) + } + + Update("dumpast=1") + if v := dumpAST.Value(); v != "1" { + t.Errorf("after Update dumpast = %q, want %q", v, "1") + } + + Update("") + if v := dumpAST.Value(); v != "" { + t.Errorf("after reset dumpast = %q, want empty", v) + } + if dumpAST.IsSet() { + t.Errorf("after reset IsSet = true, want false") + } +} + +func TestAny(t *testing.T) { + resetForTest(t) + if Any() { + t.Errorf("Any() = true, want false on empty env") + } + Update("trace=1") + if !Any() { + t.Errorf("Any() = false, want true after Update") + } +} + +func TestNewPanicsOnUnknown(t *testing.T) { + resetForTest(t) + defer func() { + if r := recover(); r == nil { + t.Errorf("New(\"bogus\") did not panic") + } + }() + New("bogus") +} diff --git a/internal/sqlite3ext/sqlite3ext.go b/internal/sqlite3ext/sqlite3ext.go new file mode 100644 index 0000000..b3382e4 --- /dev/null +++ b/internal/sqlite3ext/sqlite3ext.go @@ -0,0 +1,21 @@ +// Package sqlite3ext registers the SQLite extensions sqlc relies on with +// github.com/ncruces/go-sqlite3. +// +// As of go-sqlite3 v0.35.0 the FTS5 and R*Tree/Geopoly extensions are compiled +// separately and are no longer part of the default build. Registering them as +// auto extensions makes them available on every connection, matching the +// behavior of earlier releases. +// +// Import this package for side effects wherever a SQLite connection is opened. +package sqlite3ext + +import ( + "github.com/ncruces/go-sqlite3" + "github.com/ncruces/go-sqlite3/ext/fts5" + "github.com/ncruces/go-sqlite3/ext/rtree" +) + +func init() { + sqlite3.AutoExtension(fts5.Register) + sqlite3.AutoExtension(rtree.Register) +} diff --git a/internal/sqltest/docker/enabled.go b/internal/sqltest/docker/enabled.go new file mode 100644 index 0000000..251ae1f --- /dev/null +++ b/internal/sqltest/docker/enabled.go @@ -0,0 +1,23 @@ +package docker + +import ( + "fmt" + "os/exec" + + "golang.org/x/sync/singleflight" +) + +var flight singleflight.Group + +func Installed() error { + if _, err := exec.LookPath("docker"); err != nil { + return fmt.Errorf("docker not found: %w", err) + } + // Verify the Docker daemon is actually running and accessible. + // Without this check, tests will try Docker, fail on docker pull, + // and t.Fatal instead of falling back to native database support. + if out, err := exec.Command("docker", "info").CombinedOutput(); err != nil { + return fmt.Errorf("docker daemon not available: %w\n%s", err, out) + } + return nil +} diff --git a/internal/sqltest/docker/mysql.go b/internal/sqltest/docker/mysql.go new file mode 100644 index 0000000..2079b7c --- /dev/null +++ b/internal/sqltest/docker/mysql.go @@ -0,0 +1,104 @@ +package docker + +import ( + "context" + "database/sql" + "fmt" + "os/exec" + "strings" + "time" + + _ "github.com/go-sql-driver/mysql" +) + +var mysqlHost string + +func StartMySQLServer(c context.Context) (string, error) { + if err := Installed(); err != nil { + return "", err + } + if mysqlHost != "" { + return mysqlHost, nil + } + value, err, _ := flight.Do("mysql", func() (any, error) { + host, err := startMySQLServer(c) + if err != nil { + return "", err + } + mysqlHost = host + return host, nil + }) + if err != nil { + return "", err + } + data, ok := value.(string) + if !ok { + return "", fmt.Errorf("returned value was not a string") + } + return data, nil +} + +func startMySQLServer(c context.Context) (string, error) { + { + _, err := exec.Command("docker", "pull", "mysql:9").CombinedOutput() + if err != nil { + return "", fmt.Errorf("docker pull: mysql:9 %w", err) + } + } + + var exists bool + { + cmd := exec.Command("docker", "container", "inspect", "sqlc_sqltest_docker_mysql") + // This means we've already started the container + exists = cmd.Run() == nil + } + + if !exists { + cmd := exec.Command("docker", "run", + "--name", "sqlc_sqltest_docker_mysql", + "-e", "MYSQL_ROOT_PASSWORD=mysecretpassword", + "-e", "MYSQL_DATABASE=dinotest", + "-p", "3306:3306", + "-d", + "mysql:9", + ) + + output, err := cmd.CombinedOutput() + fmt.Println(string(output)) + + msg := `Conflict. The container name "/sqlc_sqltest_docker_mysql" is already in use by container` + if !strings.Contains(string(output), msg) && err != nil { + return "", err + } + } + + ctx, cancel := context.WithTimeout(c, 10*time.Second) + defer cancel() + + // Create a ticker that fires every 10ms + ticker := time.NewTicker(10 * time.Millisecond) + defer ticker.Stop() + + uri := "root:mysecretpassword@/dinotest?multiStatements=true&parseTime=true" + + db, err := sql.Open("mysql", uri) + if err != nil { + return "", fmt.Errorf("sql.Open: %w", err) + } + + defer db.Close() + + for { + select { + case <-ctx.Done(): + return "", fmt.Errorf("timeout reached: %w", ctx.Err()) + + case <-ticker.C: + // Run your function here + if err := db.PingContext(ctx); err != nil { + continue + } + return uri, nil + } + } +} diff --git a/internal/sqltest/docker/postgres.go b/internal/sqltest/docker/postgres.go new file mode 100644 index 0000000..243a53b --- /dev/null +++ b/internal/sqltest/docker/postgres.go @@ -0,0 +1,105 @@ +package docker + +import ( + "context" + "fmt" + "log/slog" + "os/exec" + "strings" + "time" + + "github.com/jackc/pgx/v5" +) + +var postgresHost string + +func StartPostgreSQLServer(c context.Context) (string, error) { + if err := Installed(); err != nil { + return "", err + } + if postgresHost != "" { + return postgresHost, nil + } + value, err, _ := flight.Do("postgresql", func() (any, error) { + host, err := startPostgreSQLServer(c) + if err != nil { + return "", err + } + postgresHost = host + return host, err + }) + if err != nil { + return "", err + } + data, ok := value.(string) + if !ok { + return "", fmt.Errorf("returned value was not a string") + } + return data, nil +} + +func startPostgreSQLServer(c context.Context) (string, error) { + { + _, err := exec.Command("docker", "pull", "postgres:16").CombinedOutput() + if err != nil { + return "", fmt.Errorf("docker pull: postgres:16 %w", err) + } + } + + uri := "postgres://postgres:mysecretpassword@localhost:5432/postgres?sslmode=disable" + + var exists bool + { + cmd := exec.Command("docker", "container", "inspect", "sqlc_sqltest_docker_postgres") + // This means we've already started the container + exists = cmd.Run() == nil + } + + if !exists { + cmd := exec.Command("docker", "run", + "--name", "sqlc_sqltest_docker_postgres", + "-e", "POSTGRES_PASSWORD=mysecretpassword", + "-e", "POSTGRES_USER=postgres", + "-p", "5432:5432", + "-d", + "postgres:16", + "-c", "max_connections=200", + ) + + output, err := cmd.CombinedOutput() + fmt.Println(string(output)) + + msg := `Conflict. The container name "/sqlc_sqltest_docker_postgres" is already in use by container` + if !strings.Contains(string(output), msg) && err != nil { + return "", err + } + } + + ctx, cancel := context.WithTimeout(c, 5*time.Second) + defer cancel() + + // Create a ticker that fires every 10ms + ticker := time.NewTicker(10 * time.Millisecond) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return "", fmt.Errorf("timeout reached: %w", ctx.Err()) + + case <-ticker.C: + // Run your function here + conn, err := pgx.Connect(ctx, uri) + if err != nil { + slog.Debug("sqltest", "connect", err) + continue + } + defer conn.Close(ctx) + if err := conn.Ping(ctx); err != nil { + slog.Error("sqltest", "ping", err) + continue + } + return uri, nil + } + } +} diff --git a/internal/sqltest/local/id.go b/internal/sqltest/local/id.go new file mode 100644 index 0000000..919e2dc --- /dev/null +++ b/internal/sqltest/local/id.go @@ -0,0 +1,13 @@ +package local + +import "math/rand" + +var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") + +func id() string { + b := make([]rune, 10) + for i := range b { + b[i] = letterRunes[rand.Intn(len(letterRunes))] + } + return string(b) +} diff --git a/internal/sqltest/local/mysql.go b/internal/sqltest/local/mysql.go new file mode 100644 index 0000000..05733f6 --- /dev/null +++ b/internal/sqltest/local/mysql.go @@ -0,0 +1,109 @@ +package local + +import ( + "context" + "database/sql" + "fmt" + "os" + "strings" + "sync" + "testing" + + "github.com/go-sql-driver/mysql" + + migrate "github.com/sqlc-dev/sqlc/internal/migrations" + "github.com/sqlc-dev/sqlc/internal/sql/sqlpath" + "github.com/sqlc-dev/sqlc/internal/sqltest/docker" + "github.com/sqlc-dev/sqlc/internal/sqltest/native" +) + +var mysqlSync sync.Once +var mysqlPool *sql.DB + +func MySQL(t *testing.T, migrations []string) string { + ctx := context.Background() + t.Helper() + + dburi := os.Getenv("MYSQL_SERVER_URI") + if dburi == "" { + if ierr := docker.Installed(); ierr == nil { + u, err := docker.StartMySQLServer(ctx) + if err != nil { + t.Fatal(err) + } + dburi = u + } else if ierr := native.Supported(); ierr == nil { + // Fall back to native installation when Docker is not available + u, err := native.StartMySQLServer(ctx) + if err != nil { + t.Fatal(err) + } + dburi = u + } else { + t.Skip("MYSQL_SERVER_URI is empty and neither Docker nor native installation is available") + } + } + + mysqlSync.Do(func() { + db, err := sql.Open("mysql", dburi) + if err != nil { + t.Fatal(err) + } + mysqlPool = db + }) + + if mysqlPool == nil { + t.Fatalf("MySQL pool creation failed") + } + + var seed []string + files, err := sqlpath.Glob(migrations) + if err != nil { + t.Fatal(err) + } + for _, f := range files { + blob, err := os.ReadFile(f) + if err != nil { + t.Fatal(err) + } + seed = append(seed, migrate.RemoveRollbackStatements(string(blob))) + } + + cfg, err := mysql.ParseDSN(dburi) + if err != nil { + t.Fatal(err) + } + + name := fmt.Sprintf("sqlc_test_%s", id()) + + if _, err := mysqlPool.ExecContext(ctx, fmt.Sprintf("CREATE DATABASE `%s`", name)); err != nil { + t.Fatal(err) + } + + cfg.DBName = name + + dropQuery := fmt.Sprintf("DROP DATABASE `%s`", name) + + t.Cleanup(func() { + if _, err := mysqlPool.ExecContext(ctx, dropQuery); err != nil { + t.Fatal(err) + } + }) + + db, err := sql.Open("mysql", cfg.FormatDSN()) + if err != nil { + t.Fatalf("connect %s: %s", name, err) + } + defer db.Close() + + for _, q := range seed { + if len(strings.TrimSpace(q)) == 0 { + continue + } + if _, err := db.ExecContext(ctx, q); err != nil { + t.Fatalf("%s: %s", q, err) + } + } + + return cfg.FormatDSN() +} diff --git a/internal/sqltest/local/postgres.go b/internal/sqltest/local/postgres.go new file mode 100644 index 0000000..7b5a848 --- /dev/null +++ b/internal/sqltest/local/postgres.go @@ -0,0 +1,136 @@ +package local + +import ( + "context" + "fmt" + "hash/fnv" + "net/url" + "os" + "strings" + "testing" + + "github.com/jackc/pgx/v5" + "golang.org/x/sync/singleflight" + + migrate "github.com/sqlc-dev/sqlc/internal/migrations" + "github.com/sqlc-dev/sqlc/internal/pgx/poolcache" + "github.com/sqlc-dev/sqlc/internal/sql/sqlpath" + "github.com/sqlc-dev/sqlc/internal/sqltest/docker" + "github.com/sqlc-dev/sqlc/internal/sqltest/native" +) + +var flight singleflight.Group +var cache = poolcache.New() + +func PostgreSQL(t *testing.T, migrations []string) string { + return postgreSQL(t, migrations, true) +} + +func ReadOnlyPostgreSQL(t *testing.T, migrations []string) string { + return postgreSQL(t, migrations, false) +} + +func postgreSQL(t *testing.T, migrations []string, rw bool) string { + ctx := context.Background() + t.Helper() + + dburi := os.Getenv("POSTGRESQL_SERVER_URI") + if dburi == "" { + if ierr := docker.Installed(); ierr == nil { + u, err := docker.StartPostgreSQLServer(ctx) + if err != nil { + t.Fatal(err) + } + dburi = u + } else if ierr := native.Supported(); ierr == nil { + // Fall back to native installation when Docker is not available + u, err := native.StartPostgreSQLServer(ctx) + if err != nil { + t.Fatal(err) + } + dburi = u + } else { + t.Skip("POSTGRESQL_SERVER_URI is empty and neither Docker nor native installation is available") + } + } + + postgresPool, err := cache.Open(ctx, dburi) + if err != nil { + t.Fatalf("PostgreSQL pool creation failed: %s", err) + } + + var seed []string + files, err := sqlpath.Glob(migrations) + if err != nil { + t.Fatal(err) + } + + h := fnv.New64() + for _, f := range files { + blob, err := os.ReadFile(f) + if err != nil { + t.Fatal(err) + } + h.Write(blob) + seed = append(seed, migrate.RemoveRollbackStatements(string(blob))) + } + + var name string + if rw { + name = fmt.Sprintf("sqlc_test_%s", id()) + } else { + name = fmt.Sprintf("sqlc_test_%x", h.Sum(nil)) + } + + uri, err := url.Parse(dburi) + if err != nil { + t.Fatal(err) + } + uri.Path = name + dropQuery := fmt.Sprintf(`DROP DATABASE IF EXISTS "%s" WITH (FORCE)`, name) + + key := uri.String() + + _, err, _ = flight.Do(key, func() (any, error) { + row := postgresPool.QueryRow(ctx, + fmt.Sprintf(`SELECT datname FROM pg_database WHERE datname = '%s'`, name)) + + var datname string + if err := row.Scan(&datname); err == nil { + t.Logf("database exists: %s", name) + return nil, nil + } + + t.Logf("creating database: %s", name) + if _, err := postgresPool.Exec(ctx, fmt.Sprintf(`CREATE DATABASE "%s"`, name)); err != nil { + return nil, err + } + + conn, err := pgx.Connect(ctx, uri.String()) + if err != nil { + return nil, fmt.Errorf("connect %s: %s", name, err) + } + defer conn.Close(ctx) + + for _, q := range seed { + if len(strings.TrimSpace(q)) == 0 { + continue + } + if _, err := conn.Exec(ctx, q); err != nil { + return nil, fmt.Errorf("%s: %s", q, err) + } + } + return nil, nil + }) + if rw || err != nil { + t.Cleanup(func() { + if _, err := postgresPool.Exec(ctx, dropQuery); err != nil { + t.Fatalf("failed cleaning up: %s", err) + } + }) + } + if err != nil { + t.Fatalf("create db: %s", err) + } + return key +} diff --git a/internal/sqltest/mysql.go b/internal/sqltest/mysql.go new file mode 100644 index 0000000..cdeb8b8 --- /dev/null +++ b/internal/sqltest/mysql.go @@ -0,0 +1,104 @@ +package sqltest + +import ( + "database/sql" + "fmt" + "math/rand" + "os" + "path/filepath" + "testing" + "time" + + _ "github.com/go-sql-driver/mysql" + + "github.com/sqlc-dev/sqlc/internal/sql/sqlpath" +) + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") + +func id() string { + b := make([]rune, 10) + for i := range b { + b[i] = letterRunes[rand.Intn(len(letterRunes))] + } + return string(b) +} + +func MySQL(t *testing.T, migrations []string) (*sql.DB, func()) { + // For each test, pick a new database name at random. + name := "sqltest_mysql_" + id() + return CreateMySQLDatabase(t, name, migrations) +} + +func CreateMySQLDatabase(t *testing.T, name string, migrations []string) (*sql.DB, func()) { + t.Helper() + + data := os.Getenv("MYSQL_DATABASE") + host := os.Getenv("MYSQL_HOST") + pass := os.Getenv("MYSQL_ROOT_PASSWORD") + port := os.Getenv("MYSQL_PORT") + user := os.Getenv("MYSQL_USER") + + if user == "" { + user = "root" + } + + if pass == "" { + pass = "mysecretpassword" + } + + if port == "" { + port = "3306" + } + + if host == "" { + host = "127.0.0.1" + } + + if data == "" { + data = "dinotest" + } + + source := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?multiStatements=true&parseTime=true", user, pass, host, port, data) + t.Logf("db: %s", source) + + db, err := sql.Open("mysql", source) + if err != nil { + t.Fatal(err) + } + + if _, err := db.Exec("CREATE DATABASE " + name); err != nil { + t.Fatal(err) + } + + source = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?multiStatements=true&parseTime=true", user, pass, host, port, name) + sdb, err := sql.Open("mysql", source) + if err != nil { + t.Fatal(err) + } + + files, err := sqlpath.Glob(migrations) + if err != nil { + t.Fatal(err) + } + for _, f := range files { + blob, err := os.ReadFile(f) + if err != nil { + t.Fatal(err) + } + if _, err := sdb.Exec(string(blob)); err != nil { + t.Fatalf("%s: %s", filepath.Base(f), err) + } + } + + return sdb, func() { + // Drop the test db after test runs + if _, err := db.Exec("DROP DATABASE " + name); err != nil { + t.Fatal(err) + } + } +} diff --git a/internal/sqltest/native/enabled.go b/internal/sqltest/native/enabled.go new file mode 100644 index 0000000..e5e12cc --- /dev/null +++ b/internal/sqltest/native/enabled.go @@ -0,0 +1,20 @@ +package native + +import ( + "fmt" + "os/exec" + "runtime" +) + +// Supported returns nil if native database installation is supported on this platform. +// Currently only Linux (Ubuntu/Debian) is supported. +func Supported() error { + if runtime.GOOS != "linux" { + return fmt.Errorf("native database installation only supported on linux, got %s", runtime.GOOS) + } + // Check if apt-get is available (Debian/Ubuntu) + if _, err := exec.LookPath("apt-get"); err != nil { + return fmt.Errorf("apt-get not found: %w", err) + } + return nil +} diff --git a/internal/sqltest/native/mysql.go b/internal/sqltest/native/mysql.go new file mode 100644 index 0000000..924e23b --- /dev/null +++ b/internal/sqltest/native/mysql.go @@ -0,0 +1,203 @@ +package native + +import ( + "context" + "database/sql" + "fmt" + "log/slog" + "os/exec" + "time" + + _ "github.com/go-sql-driver/mysql" + "golang.org/x/sync/singleflight" +) + +var mysqlFlight singleflight.Group +var mysqlURI string + +// StartMySQLServer starts an existing MySQL installation natively (without Docker). +func StartMySQLServer(ctx context.Context) (string, error) { + if err := Supported(); err != nil { + return "", err + } + if mysqlURI != "" { + return mysqlURI, nil + } + value, err, _ := mysqlFlight.Do("mysql", func() (any, error) { + uri, err := startMySQLServer(ctx) + if err != nil { + return "", err + } + mysqlURI = uri + return uri, nil + }) + if err != nil { + return "", err + } + data, ok := value.(string) + if !ok { + return "", fmt.Errorf("returned value was not a string") + } + return data, nil +} + +func startMySQLServer(ctx context.Context) (string, error) { + // Standard URI for test MySQL + uri := "root:mysecretpassword@tcp(localhost:3306)/mysql?multiStatements=true&parseTime=true" + + // Try to connect first - it might already be running + if err := waitForMySQL(ctx, uri, 500*time.Millisecond); err == nil { + slog.Info("native/mysql", "status", "already running") + return uri, nil + } + + // Also try without password (default MySQL installation) + uriNoPassword := "root@tcp(localhost:3306)/mysql?multiStatements=true&parseTime=true" + if err := waitForMySQL(ctx, uriNoPassword, 500*time.Millisecond); err == nil { + slog.Info("native/mysql", "status", "already running (no password)") + // MySQL is running without password, try to set one + if err := setMySQLPassword(ctx); err != nil { + slog.Debug("native/mysql", "set-password-error", err) + // Return without password if we can't set one + return uriNoPassword, nil + } + // Try again with password + if err := waitForMySQL(ctx, uri, 1*time.Second); err == nil { + return uri, nil + } + // If password didn't work, use no password + return uriNoPassword, nil + } + + // Try to start existing MySQL service (might be installed but not running) + if _, err := exec.LookPath("mysqld"); err == nil { + slog.Info("native/mysql", "status", "starting existing service") + if err := startMySQLService(); err != nil { + slog.Debug("native/mysql", "start-error", err) + } else { + // Wait for MySQL to be ready + waitCtx, cancel := context.WithTimeout(ctx, 30*time.Second) + defer cancel() + + // Try with password first + if err := waitForMySQL(waitCtx, uri, 15*time.Second); err == nil { + return uri, nil + } + + // Try without password + if err := waitForMySQL(waitCtx, uriNoPassword, 15*time.Second); err == nil { + if err := setMySQLPassword(ctx); err != nil { + slog.Debug("native/mysql", "set-password-error", err) + return uriNoPassword, nil + } + if err := waitForMySQL(ctx, uri, 1*time.Second); err == nil { + return uri, nil + } + return uriNoPassword, nil + } + } + } + + return "", fmt.Errorf("MySQL is not installed or could not be started") +} + +func startMySQLService() error { + // Try systemctl first + cmd := exec.Command("sudo", "systemctl", "start", "mysql") + if err := cmd.Run(); err == nil { + // Give MySQL time to fully initialize + time.Sleep(2 * time.Second) + return nil + } + + // Try mysqld + cmd = exec.Command("sudo", "systemctl", "start", "mysqld") + if err := cmd.Run(); err == nil { + time.Sleep(2 * time.Second) + return nil + } + + // Try service command + cmd = exec.Command("sudo", "service", "mysql", "start") + if err := cmd.Run(); err == nil { + time.Sleep(2 * time.Second) + return nil + } + + cmd = exec.Command("sudo", "service", "mysqld", "start") + if err := cmd.Run(); err == nil { + time.Sleep(2 * time.Second) + return nil + } + + return fmt.Errorf("could not start MySQL service") +} + +func setMySQLPassword(ctx context.Context) error { + // Connect without password + db, err := sql.Open("mysql", "root@tcp(localhost:3306)/mysql") + if err != nil { + return err + } + defer db.Close() + + // Set root password using mysql_native_password for broader compatibility + _, err = db.ExecContext(ctx, "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'mysecretpassword';") + if err != nil { + // Try without specifying auth plugin + _, err = db.ExecContext(ctx, "ALTER USER 'root'@'localhost' IDENTIFIED BY 'mysecretpassword';") + if err != nil { + // Try older MySQL syntax + _, err = db.ExecContext(ctx, "SET PASSWORD FOR 'root'@'localhost' = PASSWORD('mysecretpassword');") + if err != nil { + return fmt.Errorf("could not set MySQL password: %w", err) + } + } + } + + // Flush privileges + _, _ = db.ExecContext(ctx, "FLUSH PRIVILEGES;") + + return nil +} + +func waitForMySQL(ctx context.Context, uri string, timeout time.Duration) error { + deadline := time.Now().Add(timeout) + ticker := time.NewTicker(500 * time.Millisecond) + defer ticker.Stop() + + // Make an immediate first attempt before waiting for the ticker + if err := tryMySQLConnection(ctx, uri); err == nil { + return nil + } + + var lastErr error + for { + select { + case <-ctx.Done(): + return fmt.Errorf("context cancelled: %w (last error: %v)", ctx.Err(), lastErr) + case <-ticker.C: + if time.Now().After(deadline) { + return fmt.Errorf("timeout waiting for MySQL (last error: %v)", lastErr) + } + if err := tryMySQLConnection(ctx, uri); err != nil { + lastErr = err + continue + } + return nil + } + } +} + +func tryMySQLConnection(ctx context.Context, uri string) error { + db, err := sql.Open("mysql", uri) + if err != nil { + slog.Debug("native/mysql", "open-attempt", err) + return err + } + defer db.Close() + // Use a short timeout for ping to avoid hanging + pingCtx, cancel := context.WithTimeout(ctx, 2*time.Second) + defer cancel() + return db.PingContext(pingCtx) +} diff --git a/internal/sqltest/native/postgres.go b/internal/sqltest/native/postgres.go new file mode 100644 index 0000000..91b7f56 --- /dev/null +++ b/internal/sqltest/native/postgres.go @@ -0,0 +1,221 @@ +package native + +import ( + "context" + "fmt" + "log/slog" + "os/exec" + "strings" + "time" + + "github.com/jackc/pgx/v5" + "golang.org/x/sync/singleflight" +) + +var postgresFlight singleflight.Group +var postgresURI string + +// StartPostgreSQLServer starts an existing PostgreSQL installation natively (without Docker). +func StartPostgreSQLServer(ctx context.Context) (string, error) { + if err := Supported(); err != nil { + return "", err + } + if postgresURI != "" { + return postgresURI, nil + } + value, err, _ := postgresFlight.Do("postgresql", func() (any, error) { + uri, err := startPostgreSQLServer(ctx) + if err != nil { + return "", err + } + postgresURI = uri + return uri, nil + }) + if err != nil { + return "", err + } + data, ok := value.(string) + if !ok { + return "", fmt.Errorf("returned value was not a string") + } + return data, nil +} + +func startPostgreSQLServer(ctx context.Context) (string, error) { + // Standard URI for test PostgreSQL + uri := "postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable" + + // Try to connect first - it might already be running + if err := waitForPostgres(ctx, uri, 500*time.Millisecond); err == nil { + slog.Info("native/postgres", "status", "already running") + return uri, nil + } + + // Check if PostgreSQL is installed + if _, err := exec.LookPath("psql"); err != nil { + return "", fmt.Errorf("PostgreSQL is not installed (psql not found)") + } + + // Start PostgreSQL service + slog.Info("native/postgres", "status", "starting service") + + // Try systemctl first, fall back to pg_ctlcluster + if err := startPostgresService(); err != nil { + return "", fmt.Errorf("failed to start PostgreSQL: %w", err) + } + + // Configure PostgreSQL for password authentication + if err := configurePostgres(); err != nil { + return "", fmt.Errorf("failed to configure PostgreSQL: %w", err) + } + + // Wait for PostgreSQL to be ready + waitCtx, cancel := context.WithTimeout(ctx, 30*time.Second) + defer cancel() + + if err := waitForPostgres(waitCtx, uri, 30*time.Second); err != nil { + return "", fmt.Errorf("timeout waiting for PostgreSQL: %w", err) + } + + return uri, nil +} + +func startPostgresService() error { + // Try systemctl first + cmd := exec.Command("sudo", "systemctl", "start", "postgresql") + if err := cmd.Run(); err == nil { + return nil + } + + // Try service command + cmd = exec.Command("sudo", "service", "postgresql", "start") + if err := cmd.Run(); err == nil { + return nil + } + + // Try pg_ctlcluster (Debian/Ubuntu specific) + // Find the installed PostgreSQL version + output, err := exec.Command("ls", "/etc/postgresql/").CombinedOutput() + if err != nil { + return fmt.Errorf("could not find PostgreSQL version: %w", err) + } + + versions := strings.Fields(string(output)) + if len(versions) == 0 { + return fmt.Errorf("no PostgreSQL version found in /etc/postgresql/") + } + + version := versions[0] + cmd = exec.Command("sudo", "pg_ctlcluster", version, "main", "start") + if output, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("pg_ctlcluster start failed: %w\n%s", err, output) + } + + return nil +} + +func configurePostgres() error { + // Set password for postgres user using sudo -u postgres + cmd := exec.Command("sudo", "-u", "postgres", "psql", "-c", "ALTER USER postgres PASSWORD 'postgres';") + if output, err := cmd.CombinedOutput(); err != nil { + // This might fail if password is already set, which is fine + slog.Debug("native/postgres", "set-password", string(output)) + } + + // Update pg_hba.conf to allow password authentication + // First, find the pg_hba.conf file + output, err := exec.Command("sudo", "-u", "postgres", "psql", "-t", "-c", "SHOW hba_file;").CombinedOutput() + if err != nil { + return fmt.Errorf("could not find hba_file: %w", err) + } + + hbaFile := strings.TrimSpace(string(output)) + if hbaFile == "" { + return fmt.Errorf("empty hba_file path") + } + + // Check if we need to update pg_hba.conf + catOutput, err := exec.Command("sudo", "cat", hbaFile).CombinedOutput() + if err != nil { + return fmt.Errorf("could not read %s: %w", hbaFile, err) + } + + // If md5 or scram-sha-256 auth is not configured for local connections, add it + content := string(catOutput) + if !strings.Contains(content, "host all all 127.0.0.1/32 md5") && + !strings.Contains(content, "host all all 127.0.0.1/32 scram-sha-256") { + + // Prepend a rule for localhost password authentication + newRule := "host all all 127.0.0.1/32 md5\n" + + // Use sed to add the rule at the beginning (after comments) + cmd := exec.Command("sudo", "bash", "-c", + fmt.Sprintf(`echo '%s' | cat - %s > /tmp/pg_hba.conf.new && sudo mv /tmp/pg_hba.conf.new %s`, + newRule, hbaFile, hbaFile)) + if output, err := cmd.CombinedOutput(); err != nil { + slog.Debug("native/postgres", "update-hba-error", string(output)) + } + + // Reload PostgreSQL to apply changes + if err := reloadPostgres(); err != nil { + slog.Debug("native/postgres", "reload-error", err) + } + } + + return nil +} + +func reloadPostgres() error { + // Try systemctl reload + cmd := exec.Command("sudo", "systemctl", "reload", "postgresql") + if err := cmd.Run(); err == nil { + return nil + } + + // Try service reload + cmd = exec.Command("sudo", "service", "postgresql", "reload") + if err := cmd.Run(); err == nil { + return nil + } + + // Try pg_ctlcluster reload + output, _ := exec.Command("ls", "/etc/postgresql/").CombinedOutput() + versions := strings.Fields(string(output)) + if len(versions) > 0 { + cmd = exec.Command("sudo", "pg_ctlcluster", versions[0], "main", "reload") + return cmd.Run() + } + + return fmt.Errorf("could not reload PostgreSQL") +} + +func waitForPostgres(ctx context.Context, uri string, timeout time.Duration) error { + deadline := time.Now().Add(timeout) + ticker := time.NewTicker(100 * time.Millisecond) + defer ticker.Stop() + + var lastErr error + for { + select { + case <-ctx.Done(): + return fmt.Errorf("context cancelled: %w (last error: %v)", ctx.Err(), lastErr) + case <-ticker.C: + if time.Now().After(deadline) { + return fmt.Errorf("timeout waiting for PostgreSQL (last error: %v)", lastErr) + } + conn, err := pgx.Connect(ctx, uri) + if err != nil { + lastErr = err + slog.Debug("native/postgres", "connect-attempt", err) + continue + } + if err := conn.Ping(ctx); err != nil { + lastErr = err + conn.Close(ctx) + continue + } + conn.Close(ctx) + return nil + } + } +} diff --git a/internal/sqltest/sqlite.go b/internal/sqltest/sqlite.go new file mode 100644 index 0000000..b102fc9 --- /dev/null +++ b/internal/sqltest/sqlite.go @@ -0,0 +1,56 @@ +package sqltest + +import ( + "database/sql" + "os" + "path/filepath" + "testing" + + _ "github.com/ncruces/go-sqlite3/driver" + + "github.com/sqlc-dev/sqlc/internal/sql/sqlpath" + _ "github.com/sqlc-dev/sqlc/internal/sqlite3ext" +) + +func SQLite(t *testing.T, migrations []string) (*sql.DB, func()) { + t.Helper() + // For each test, pick a new database name at random. + source, err := os.CreateTemp("", "sqltest_sqlite_") + if err != nil { + t.Fatal(err) + } + if err := source.Close(); err != nil { + t.Fatal(err) + } + return CreateSQLiteDatabase(t, source.Name(), migrations) +} + +func CreateSQLiteDatabase(t *testing.T, path string, migrations []string) (*sql.DB, func()) { + t.Helper() + + t.Logf("open %s\n", path) + sdb, err := sql.Open("sqlite3", path) + if err != nil { + t.Fatal(err) + } + + files, err := sqlpath.Glob(migrations) + if err != nil { + t.Fatal(err) + } + for _, f := range files { + blob, err := os.ReadFile(f) + if err != nil { + t.Fatal(err) + } + if _, err := sdb.Exec(string(blob)); err != nil { + t.Fatalf("%s: %s", filepath.Base(f), err) + } + } + + return sdb, func() { + if _, err := os.Stat(path); err == nil { + os.Remove(path) + } + } +} diff --git a/internal/tracer/trace.go b/internal/tracer/trace.go new file mode 100644 index 0000000..ececc4b --- /dev/null +++ b/internal/tracer/trace.go @@ -0,0 +1,44 @@ +package tracer + +import ( + "context" + "fmt" + "os" + "runtime/trace" + + "github.com/sqlc-dev/sqlc/internal/sqlcdebug" +) + +var debugTrace = sqlcdebug.New("trace") + +// Path returns the file to which Go's runtime tracer should write its +// output, derived from SQLCDEBUG=trace=... +func Path() string { + v := debugTrace.Value() + if v == "1" { + return "trace.out" + } + return v +} + +// Start starts Go's runtime tracing facility. Traces are written to the +// path returned by [Path]. It also starts a new [*trace.Task] that will +// be stopped when the cleanup is called. +func Start(base context.Context) (_ context.Context, cleanup func(), _ error) { + f, err := os.Create(Path()) + if err != nil { + return base, cleanup, fmt.Errorf("failed to create trace output file: %v", err) + } + + if err := trace.Start(f); err != nil { + return base, cleanup, fmt.Errorf("failed to start trace: %v", err) + } + + ctx, task := trace.NewTask(base, "sqlc") + + return ctx, func() { + defer f.Close() + defer trace.Stop() + defer task.End() + }, nil +} diff --git a/internal/vet/vet.pb.go b/internal/vet/vet.pb.go new file mode 100644 index 0000000..b40f109 --- /dev/null +++ b/internal/vet/vet.pb.go @@ -0,0 +1,1649 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.30.0 +// protoc (unknown) +// source: vet/vet.proto + +package vet + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Parameter struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Number int32 `protobuf:"varint,1,opt,name=number,proto3" json:"number,omitempty"` +} + +func (x *Parameter) Reset() { + *x = Parameter{} + if protoimpl.UnsafeEnabled { + mi := &file_vet_vet_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Parameter) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Parameter) ProtoMessage() {} + +func (x *Parameter) ProtoReflect() protoreflect.Message { + mi := &file_vet_vet_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Parameter.ProtoReflect.Descriptor instead. +func (*Parameter) Descriptor() ([]byte, []int) { + return file_vet_vet_proto_rawDescGZIP(), []int{0} +} + +func (x *Parameter) GetNumber() int32 { + if x != nil { + return x.Number + } + return 0 +} + +type Config struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` + Engine string `protobuf:"bytes,2,opt,name=engine,proto3" json:"engine,omitempty"` + Schema []string `protobuf:"bytes,3,rep,name=schema,proto3" json:"schema,omitempty"` + Queries []string `protobuf:"bytes,4,rep,name=queries,proto3" json:"queries,omitempty"` +} + +func (x *Config) Reset() { + *x = Config{} + if protoimpl.UnsafeEnabled { + mi := &file_vet_vet_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Config) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Config) ProtoMessage() {} + +func (x *Config) ProtoReflect() protoreflect.Message { + mi := &file_vet_vet_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Config.ProtoReflect.Descriptor instead. +func (*Config) Descriptor() ([]byte, []int) { + return file_vet_vet_proto_rawDescGZIP(), []int{1} +} + +func (x *Config) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *Config) GetEngine() string { + if x != nil { + return x.Engine + } + return "" +} + +func (x *Config) GetSchema() []string { + if x != nil { + return x.Schema + } + return nil +} + +func (x *Config) GetQueries() []string { + if x != nil { + return x.Queries + } + return nil +} + +type Query struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Sql string `protobuf:"bytes,1,opt,name=sql,proto3" json:"sql,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Cmd string `protobuf:"bytes,3,opt,name=cmd,proto3" json:"cmd,omitempty"` + Params []*Parameter `protobuf:"bytes,4,rep,name=params,json=parameters,proto3" json:"params,omitempty"` +} + +func (x *Query) Reset() { + *x = Query{} + if protoimpl.UnsafeEnabled { + mi := &file_vet_vet_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Query) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Query) ProtoMessage() {} + +func (x *Query) ProtoReflect() protoreflect.Message { + mi := &file_vet_vet_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Query.ProtoReflect.Descriptor instead. +func (*Query) Descriptor() ([]byte, []int) { + return file_vet_vet_proto_rawDescGZIP(), []int{2} +} + +func (x *Query) GetSql() string { + if x != nil { + return x.Sql + } + return "" +} + +func (x *Query) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Query) GetCmd() string { + if x != nil { + return x.Cmd + } + return "" +} + +func (x *Query) GetParams() []*Parameter { + if x != nil { + return x.Params + } + return nil +} + +type PostgreSQL struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Explain *PostgreSQLExplain `protobuf:"bytes,1,opt,name=explain,proto3" json:"explain,omitempty"` +} + +func (x *PostgreSQL) Reset() { + *x = PostgreSQL{} + if protoimpl.UnsafeEnabled { + mi := &file_vet_vet_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PostgreSQL) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PostgreSQL) ProtoMessage() {} + +func (x *PostgreSQL) ProtoReflect() protoreflect.Message { + mi := &file_vet_vet_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PostgreSQL.ProtoReflect.Descriptor instead. +func (*PostgreSQL) Descriptor() ([]byte, []int) { + return file_vet_vet_proto_rawDescGZIP(), []int{3} +} + +func (x *PostgreSQL) GetExplain() *PostgreSQLExplain { + if x != nil { + return x.Explain + } + return nil +} + +type PostgreSQLExplain struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Plan *PostgreSQLExplain_Plan `protobuf:"bytes,1,opt,name=plan,json=Plan,proto3" json:"plan,omitempty"` + Settings map[string]string `protobuf:"bytes,2,rep,name=settings,json=Settings,proto3" json:"settings,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Planning *PostgreSQLExplain_Planning `protobuf:"bytes,3,opt,name=planning,json=Planning,proto3" json:"planning,omitempty"` +} + +func (x *PostgreSQLExplain) Reset() { + *x = PostgreSQLExplain{} + if protoimpl.UnsafeEnabled { + mi := &file_vet_vet_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PostgreSQLExplain) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PostgreSQLExplain) ProtoMessage() {} + +func (x *PostgreSQLExplain) ProtoReflect() protoreflect.Message { + mi := &file_vet_vet_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PostgreSQLExplain.ProtoReflect.Descriptor instead. +func (*PostgreSQLExplain) Descriptor() ([]byte, []int) { + return file_vet_vet_proto_rawDescGZIP(), []int{4} +} + +func (x *PostgreSQLExplain) GetPlan() *PostgreSQLExplain_Plan { + if x != nil { + return x.Plan + } + return nil +} + +func (x *PostgreSQLExplain) GetSettings() map[string]string { + if x != nil { + return x.Settings + } + return nil +} + +func (x *PostgreSQLExplain) GetPlanning() *PostgreSQLExplain_Planning { + if x != nil { + return x.Planning + } + return nil +} + +type MySQL struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Explain *MySQLExplain `protobuf:"bytes,1,opt,name=explain,proto3" json:"explain,omitempty"` +} + +func (x *MySQL) Reset() { + *x = MySQL{} + if protoimpl.UnsafeEnabled { + mi := &file_vet_vet_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MySQL) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MySQL) ProtoMessage() {} + +func (x *MySQL) ProtoReflect() protoreflect.Message { + mi := &file_vet_vet_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MySQL.ProtoReflect.Descriptor instead. +func (*MySQL) Descriptor() ([]byte, []int) { + return file_vet_vet_proto_rawDescGZIP(), []int{5} +} + +func (x *MySQL) GetExplain() *MySQLExplain { + if x != nil { + return x.Explain + } + return nil +} + +type MySQLExplain struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + QueryBlock *MySQLExplain_QueryBlock `protobuf:"bytes,1,opt,name=query_block,json=queryBlock,proto3" json:"query_block,omitempty"` +} + +func (x *MySQLExplain) Reset() { + *x = MySQLExplain{} + if protoimpl.UnsafeEnabled { + mi := &file_vet_vet_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MySQLExplain) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MySQLExplain) ProtoMessage() {} + +func (x *MySQLExplain) ProtoReflect() protoreflect.Message { + mi := &file_vet_vet_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MySQLExplain.ProtoReflect.Descriptor instead. +func (*MySQLExplain) Descriptor() ([]byte, []int) { + return file_vet_vet_proto_rawDescGZIP(), []int{6} +} + +func (x *MySQLExplain) GetQueryBlock() *MySQLExplain_QueryBlock { + if x != nil { + return x.QueryBlock + } + return nil +} + +type PostgreSQLExplain_Plan struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + NodeType string `protobuf:"bytes,1,opt,name=node_type,json=Node Type,proto3" json:"node_type,omitempty"` + ParentRelationship string `protobuf:"bytes,2,opt,name=parent_relationship,json=Parent Relationship,proto3" json:"parent_relationship,omitempty"` + RelationName string `protobuf:"bytes,3,opt,name=relation_name,json=Relation Name,proto3" json:"relation_name,omitempty"` + Schema string `protobuf:"bytes,4,opt,name=schema,json=Schema,proto3" json:"schema,omitempty"` + Alias string `protobuf:"bytes,5,opt,name=alias,json=Alias,proto3" json:"alias,omitempty"` + ParallelAware bool `protobuf:"varint,6,opt,name=parallel_aware,json=Parallel Aware,proto3" json:"parallel_aware,omitempty"` + AsyncCapable bool `protobuf:"varint,7,opt,name=async_capable,json=Async Capable,proto3" json:"async_capable,omitempty"` + StartupCost float32 `protobuf:"fixed32,8,opt,name=startup_cost,json=Startup Cost,proto3" json:"startup_cost,omitempty"` + TotalCost float32 `protobuf:"fixed32,9,opt,name=total_cost,json=Total Cost,proto3" json:"total_cost,omitempty"` + PlanRows uint64 `protobuf:"varint,10,opt,name=plan_rows,json=Plan Rows,proto3" json:"plan_rows,omitempty"` + PlanWidth uint64 `protobuf:"varint,11,opt,name=plan_width,json=Plan Width,proto3" json:"plan_width,omitempty"` + Output []string `protobuf:"bytes,12,rep,name=output,json=Output,proto3" json:"output,omitempty"` + Plans []*PostgreSQLExplain_Plan `protobuf:"bytes,13,rep,name=plans,json=Plans,proto3" json:"plans,omitempty"` + // Embedded "Blocks" fields + SharedHitBlocks uint64 `protobuf:"varint,14,opt,name=shared_hit_blocks,json=Shared Hit Blocks,proto3" json:"shared_hit_blocks,omitempty"` + SharedReadBlocks uint64 `protobuf:"varint,15,opt,name=shared_read_blocks,json=Shared Read Blocks,proto3" json:"shared_read_blocks,omitempty"` + SharedDirtiedBlocks uint64 `protobuf:"varint,16,opt,name=shared_dirtied_blocks,json=Shared Dirtied Blocks,proto3" json:"shared_dirtied_blocks,omitempty"` + SharedWrittenBlocks uint64 `protobuf:"varint,17,opt,name=shared_written_blocks,json=Shared Written Blocks,proto3" json:"shared_written_blocks,omitempty"` + LocalHitBlocks uint64 `protobuf:"varint,18,opt,name=local_hit_blocks,json=Local Hit Blocks,proto3" json:"local_hit_blocks,omitempty"` + LocalReadBlocks uint64 `protobuf:"varint,19,opt,name=local_read_blocks,json=Local Read Blocks,proto3" json:"local_read_blocks,omitempty"` + LocalDirtiedBlocks uint64 `protobuf:"varint,20,opt,name=local_dirtied_blocks,json=Local Dirtied Blocks,proto3" json:"local_dirtied_blocks,omitempty"` + LocalWrittenBlocks uint64 `protobuf:"varint,21,opt,name=local_written_blocks,json=Local Written Blocks,proto3" json:"local_written_blocks,omitempty"` + TempReadBlocks uint64 `protobuf:"varint,22,opt,name=temp_read_blocks,json=Temp Read Blocks,proto3" json:"temp_read_blocks,omitempty"` + TempWrittenBlocks uint64 `protobuf:"varint,23,opt,name=temp_written_blocks,json=Temp Written Blocks,proto3" json:"temp_written_blocks,omitempty"` + // "Node Type": "Sort" fields + SortKey []string `protobuf:"bytes,24,rep,name=sort_key,json=Sort Key,proto3" json:"sort_key,omitempty"` + // "Node Type": "Hash Join" fields + JoinType string `protobuf:"bytes,25,opt,name=join_type,json=Join Type,proto3" json:"join_type,omitempty"` + InnerUnique bool `protobuf:"varint,26,opt,name=inner_unique,json=Inner Unique,proto3" json:"inner_unique,omitempty"` + HashCond string `protobuf:"bytes,27,opt,name=hash_cond,json=Hash Cond,proto3" json:"hash_cond,omitempty"` + // "Node Type": "Index Scan" fields + IndexName string `protobuf:"bytes,28,opt,name=index_name,json=Index Name,proto3" json:"index_name,omitempty"` + ScanDirection string `protobuf:"bytes,29,opt,name=scan_direction,json=Scan Direction,proto3" json:"scan_direction,omitempty"` + IndexCond string `protobuf:"bytes,30,opt,name=index_cond,json=Index Cond,proto3" json:"index_cond,omitempty"` +} + +func (x *PostgreSQLExplain_Plan) Reset() { + *x = PostgreSQLExplain_Plan{} + if protoimpl.UnsafeEnabled { + mi := &file_vet_vet_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PostgreSQLExplain_Plan) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PostgreSQLExplain_Plan) ProtoMessage() {} + +func (x *PostgreSQLExplain_Plan) ProtoReflect() protoreflect.Message { + mi := &file_vet_vet_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PostgreSQLExplain_Plan.ProtoReflect.Descriptor instead. +func (*PostgreSQLExplain_Plan) Descriptor() ([]byte, []int) { + return file_vet_vet_proto_rawDescGZIP(), []int{4, 1} +} + +func (x *PostgreSQLExplain_Plan) GetNodeType() string { + if x != nil { + return x.NodeType + } + return "" +} + +func (x *PostgreSQLExplain_Plan) GetParentRelationship() string { + if x != nil { + return x.ParentRelationship + } + return "" +} + +func (x *PostgreSQLExplain_Plan) GetRelationName() string { + if x != nil { + return x.RelationName + } + return "" +} + +func (x *PostgreSQLExplain_Plan) GetSchema() string { + if x != nil { + return x.Schema + } + return "" +} + +func (x *PostgreSQLExplain_Plan) GetAlias() string { + if x != nil { + return x.Alias + } + return "" +} + +func (x *PostgreSQLExplain_Plan) GetParallelAware() bool { + if x != nil { + return x.ParallelAware + } + return false +} + +func (x *PostgreSQLExplain_Plan) GetAsyncCapable() bool { + if x != nil { + return x.AsyncCapable + } + return false +} + +func (x *PostgreSQLExplain_Plan) GetStartupCost() float32 { + if x != nil { + return x.StartupCost + } + return 0 +} + +func (x *PostgreSQLExplain_Plan) GetTotalCost() float32 { + if x != nil { + return x.TotalCost + } + return 0 +} + +func (x *PostgreSQLExplain_Plan) GetPlanRows() uint64 { + if x != nil { + return x.PlanRows + } + return 0 +} + +func (x *PostgreSQLExplain_Plan) GetPlanWidth() uint64 { + if x != nil { + return x.PlanWidth + } + return 0 +} + +func (x *PostgreSQLExplain_Plan) GetOutput() []string { + if x != nil { + return x.Output + } + return nil +} + +func (x *PostgreSQLExplain_Plan) GetPlans() []*PostgreSQLExplain_Plan { + if x != nil { + return x.Plans + } + return nil +} + +func (x *PostgreSQLExplain_Plan) GetSharedHitBlocks() uint64 { + if x != nil { + return x.SharedHitBlocks + } + return 0 +} + +func (x *PostgreSQLExplain_Plan) GetSharedReadBlocks() uint64 { + if x != nil { + return x.SharedReadBlocks + } + return 0 +} + +func (x *PostgreSQLExplain_Plan) GetSharedDirtiedBlocks() uint64 { + if x != nil { + return x.SharedDirtiedBlocks + } + return 0 +} + +func (x *PostgreSQLExplain_Plan) GetSharedWrittenBlocks() uint64 { + if x != nil { + return x.SharedWrittenBlocks + } + return 0 +} + +func (x *PostgreSQLExplain_Plan) GetLocalHitBlocks() uint64 { + if x != nil { + return x.LocalHitBlocks + } + return 0 +} + +func (x *PostgreSQLExplain_Plan) GetLocalReadBlocks() uint64 { + if x != nil { + return x.LocalReadBlocks + } + return 0 +} + +func (x *PostgreSQLExplain_Plan) GetLocalDirtiedBlocks() uint64 { + if x != nil { + return x.LocalDirtiedBlocks + } + return 0 +} + +func (x *PostgreSQLExplain_Plan) GetLocalWrittenBlocks() uint64 { + if x != nil { + return x.LocalWrittenBlocks + } + return 0 +} + +func (x *PostgreSQLExplain_Plan) GetTempReadBlocks() uint64 { + if x != nil { + return x.TempReadBlocks + } + return 0 +} + +func (x *PostgreSQLExplain_Plan) GetTempWrittenBlocks() uint64 { + if x != nil { + return x.TempWrittenBlocks + } + return 0 +} + +func (x *PostgreSQLExplain_Plan) GetSortKey() []string { + if x != nil { + return x.SortKey + } + return nil +} + +func (x *PostgreSQLExplain_Plan) GetJoinType() string { + if x != nil { + return x.JoinType + } + return "" +} + +func (x *PostgreSQLExplain_Plan) GetInnerUnique() bool { + if x != nil { + return x.InnerUnique + } + return false +} + +func (x *PostgreSQLExplain_Plan) GetHashCond() string { + if x != nil { + return x.HashCond + } + return "" +} + +func (x *PostgreSQLExplain_Plan) GetIndexName() string { + if x != nil { + return x.IndexName + } + return "" +} + +func (x *PostgreSQLExplain_Plan) GetScanDirection() string { + if x != nil { + return x.ScanDirection + } + return "" +} + +func (x *PostgreSQLExplain_Plan) GetIndexCond() string { + if x != nil { + return x.IndexCond + } + return "" +} + +type PostgreSQLExplain_Planning struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SharedHitBlocks uint64 `protobuf:"varint,1,opt,name=shared_hit_blocks,json=Shared Hit Blocks,proto3" json:"shared_hit_blocks,omitempty"` + SharedReadBlocks uint64 `protobuf:"varint,2,opt,name=shared_read_blocks,json=Shared Read Blocks,proto3" json:"shared_read_blocks,omitempty"` + SharedDirtiedBlocks uint64 `protobuf:"varint,3,opt,name=shared_dirtied_blocks,json=Shared Dirtied Blocks,proto3" json:"shared_dirtied_blocks,omitempty"` + SharedWrittenBlocks uint64 `protobuf:"varint,4,opt,name=shared_written_blocks,json=Shared Written Blocks,proto3" json:"shared_written_blocks,omitempty"` + LocalHitBlocks uint64 `protobuf:"varint,5,opt,name=local_hit_blocks,json=Local Hit Blocks,proto3" json:"local_hit_blocks,omitempty"` + LocalReadBlocks uint64 `protobuf:"varint,6,opt,name=local_read_blocks,json=Local Read Blocks,proto3" json:"local_read_blocks,omitempty"` + LocalDirtiedBlocks uint64 `protobuf:"varint,7,opt,name=local_dirtied_blocks,json=Local Dirtied Blocks,proto3" json:"local_dirtied_blocks,omitempty"` + LocalWrittenBlocks uint64 `protobuf:"varint,8,opt,name=local_written_blocks,json=Local Written Blocks,proto3" json:"local_written_blocks,omitempty"` + TempReadBlocks uint64 `protobuf:"varint,9,opt,name=temp_read_blocks,json=Temp Read Blocks,proto3" json:"temp_read_blocks,omitempty"` + TempWrittenBlocks uint64 `protobuf:"varint,10,opt,name=temp_written_blocks,json=Temp Written Blocks,proto3" json:"temp_written_blocks,omitempty"` +} + +func (x *PostgreSQLExplain_Planning) Reset() { + *x = PostgreSQLExplain_Planning{} + if protoimpl.UnsafeEnabled { + mi := &file_vet_vet_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PostgreSQLExplain_Planning) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PostgreSQLExplain_Planning) ProtoMessage() {} + +func (x *PostgreSQLExplain_Planning) ProtoReflect() protoreflect.Message { + mi := &file_vet_vet_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PostgreSQLExplain_Planning.ProtoReflect.Descriptor instead. +func (*PostgreSQLExplain_Planning) Descriptor() ([]byte, []int) { + return file_vet_vet_proto_rawDescGZIP(), []int{4, 2} +} + +func (x *PostgreSQLExplain_Planning) GetSharedHitBlocks() uint64 { + if x != nil { + return x.SharedHitBlocks + } + return 0 +} + +func (x *PostgreSQLExplain_Planning) GetSharedReadBlocks() uint64 { + if x != nil { + return x.SharedReadBlocks + } + return 0 +} + +func (x *PostgreSQLExplain_Planning) GetSharedDirtiedBlocks() uint64 { + if x != nil { + return x.SharedDirtiedBlocks + } + return 0 +} + +func (x *PostgreSQLExplain_Planning) GetSharedWrittenBlocks() uint64 { + if x != nil { + return x.SharedWrittenBlocks + } + return 0 +} + +func (x *PostgreSQLExplain_Planning) GetLocalHitBlocks() uint64 { + if x != nil { + return x.LocalHitBlocks + } + return 0 +} + +func (x *PostgreSQLExplain_Planning) GetLocalReadBlocks() uint64 { + if x != nil { + return x.LocalReadBlocks + } + return 0 +} + +func (x *PostgreSQLExplain_Planning) GetLocalDirtiedBlocks() uint64 { + if x != nil { + return x.LocalDirtiedBlocks + } + return 0 +} + +func (x *PostgreSQLExplain_Planning) GetLocalWrittenBlocks() uint64 { + if x != nil { + return x.LocalWrittenBlocks + } + return 0 +} + +func (x *PostgreSQLExplain_Planning) GetTempReadBlocks() uint64 { + if x != nil { + return x.TempReadBlocks + } + return 0 +} + +func (x *PostgreSQLExplain_Planning) GetTempWrittenBlocks() uint64 { + if x != nil { + return x.TempWrittenBlocks + } + return 0 +} + +type MySQLExplain_QueryBlock struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SelectId uint64 `protobuf:"varint,1,opt,name=select_id,json=selectId,proto3" json:"select_id,omitempty"` + Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` + CostInfo map[string]string `protobuf:"bytes,3,rep,name=cost_info,json=costInfo,proto3" json:"cost_info,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Table *MySQLExplain_Table `protobuf:"bytes,4,opt,name=table,proto3" json:"table,omitempty"` + OrderingOperation *MySQLExplain_OrderingOperation `protobuf:"bytes,5,opt,name=ordering_operation,json=orderingOperation,proto3" json:"ordering_operation,omitempty"` + NestedLoop []*MySQLExplain_NestedLoopObj `protobuf:"bytes,6,rep,name=nested_loop,json=nestedLoop,proto3" json:"nested_loop,omitempty"` +} + +func (x *MySQLExplain_QueryBlock) Reset() { + *x = MySQLExplain_QueryBlock{} + if protoimpl.UnsafeEnabled { + mi := &file_vet_vet_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MySQLExplain_QueryBlock) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MySQLExplain_QueryBlock) ProtoMessage() {} + +func (x *MySQLExplain_QueryBlock) ProtoReflect() protoreflect.Message { + mi := &file_vet_vet_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MySQLExplain_QueryBlock.ProtoReflect.Descriptor instead. +func (*MySQLExplain_QueryBlock) Descriptor() ([]byte, []int) { + return file_vet_vet_proto_rawDescGZIP(), []int{6, 0} +} + +func (x *MySQLExplain_QueryBlock) GetSelectId() uint64 { + if x != nil { + return x.SelectId + } + return 0 +} + +func (x *MySQLExplain_QueryBlock) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *MySQLExplain_QueryBlock) GetCostInfo() map[string]string { + if x != nil { + return x.CostInfo + } + return nil +} + +func (x *MySQLExplain_QueryBlock) GetTable() *MySQLExplain_Table { + if x != nil { + return x.Table + } + return nil +} + +func (x *MySQLExplain_QueryBlock) GetOrderingOperation() *MySQLExplain_OrderingOperation { + if x != nil { + return x.OrderingOperation + } + return nil +} + +func (x *MySQLExplain_QueryBlock) GetNestedLoop() []*MySQLExplain_NestedLoopObj { + if x != nil { + return x.NestedLoop + } + return nil +} + +type MySQLExplain_Table struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TableName string `protobuf:"bytes,1,opt,name=table_name,json=tableName,proto3" json:"table_name,omitempty"` + AccessType string `protobuf:"bytes,2,opt,name=access_type,json=accessType,proto3" json:"access_type,omitempty"` + RowsExaminedPerScan uint64 `protobuf:"varint,3,opt,name=rows_examined_per_scan,json=rowsExaminedPerScan,proto3" json:"rows_examined_per_scan,omitempty"` + RowsProducedPerJoin uint64 `protobuf:"varint,4,opt,name=rows_produced_per_join,json=rowsProducedPerJoin,proto3" json:"rows_produced_per_join,omitempty"` + Filtered string `protobuf:"bytes,5,opt,name=filtered,proto3" json:"filtered,omitempty"` + CostInfo map[string]string `protobuf:"bytes,6,rep,name=cost_info,json=costInfo,proto3" json:"cost_info,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + UsedColumns []string `protobuf:"bytes,7,rep,name=used_columns,json=usedColumns,proto3" json:"used_columns,omitempty"` + Insert bool `protobuf:"varint,8,opt,name=insert,proto3" json:"insert,omitempty"` + PossibleKeys []string `protobuf:"bytes,9,rep,name=possible_keys,json=possibleKeys,proto3" json:"possible_keys,omitempty"` + Key string `protobuf:"bytes,10,opt,name=key,proto3" json:"key,omitempty"` + UsedKeyParts []string `protobuf:"bytes,11,rep,name=used_key_parts,json=usedKeyParts,proto3" json:"used_key_parts,omitempty"` + KeyLength string `protobuf:"bytes,12,opt,name=key_length,json=keyLength,proto3" json:"key_length,omitempty"` + Ref []string `protobuf:"bytes,13,rep,name=ref,proto3" json:"ref,omitempty"` +} + +func (x *MySQLExplain_Table) Reset() { + *x = MySQLExplain_Table{} + if protoimpl.UnsafeEnabled { + mi := &file_vet_vet_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MySQLExplain_Table) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MySQLExplain_Table) ProtoMessage() {} + +func (x *MySQLExplain_Table) ProtoReflect() protoreflect.Message { + mi := &file_vet_vet_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MySQLExplain_Table.ProtoReflect.Descriptor instead. +func (*MySQLExplain_Table) Descriptor() ([]byte, []int) { + return file_vet_vet_proto_rawDescGZIP(), []int{6, 1} +} + +func (x *MySQLExplain_Table) GetTableName() string { + if x != nil { + return x.TableName + } + return "" +} + +func (x *MySQLExplain_Table) GetAccessType() string { + if x != nil { + return x.AccessType + } + return "" +} + +func (x *MySQLExplain_Table) GetRowsExaminedPerScan() uint64 { + if x != nil { + return x.RowsExaminedPerScan + } + return 0 +} + +func (x *MySQLExplain_Table) GetRowsProducedPerJoin() uint64 { + if x != nil { + return x.RowsProducedPerJoin + } + return 0 +} + +func (x *MySQLExplain_Table) GetFiltered() string { + if x != nil { + return x.Filtered + } + return "" +} + +func (x *MySQLExplain_Table) GetCostInfo() map[string]string { + if x != nil { + return x.CostInfo + } + return nil +} + +func (x *MySQLExplain_Table) GetUsedColumns() []string { + if x != nil { + return x.UsedColumns + } + return nil +} + +func (x *MySQLExplain_Table) GetInsert() bool { + if x != nil { + return x.Insert + } + return false +} + +func (x *MySQLExplain_Table) GetPossibleKeys() []string { + if x != nil { + return x.PossibleKeys + } + return nil +} + +func (x *MySQLExplain_Table) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *MySQLExplain_Table) GetUsedKeyParts() []string { + if x != nil { + return x.UsedKeyParts + } + return nil +} + +func (x *MySQLExplain_Table) GetKeyLength() string { + if x != nil { + return x.KeyLength + } + return "" +} + +func (x *MySQLExplain_Table) GetRef() []string { + if x != nil { + return x.Ref + } + return nil +} + +type MySQLExplain_NestedLoopObj struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Table *MySQLExplain_Table `protobuf:"bytes,1,opt,name=table,proto3" json:"table,omitempty"` +} + +func (x *MySQLExplain_NestedLoopObj) Reset() { + *x = MySQLExplain_NestedLoopObj{} + if protoimpl.UnsafeEnabled { + mi := &file_vet_vet_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MySQLExplain_NestedLoopObj) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MySQLExplain_NestedLoopObj) ProtoMessage() {} + +func (x *MySQLExplain_NestedLoopObj) ProtoReflect() protoreflect.Message { + mi := &file_vet_vet_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MySQLExplain_NestedLoopObj.ProtoReflect.Descriptor instead. +func (*MySQLExplain_NestedLoopObj) Descriptor() ([]byte, []int) { + return file_vet_vet_proto_rawDescGZIP(), []int{6, 2} +} + +func (x *MySQLExplain_NestedLoopObj) GetTable() *MySQLExplain_Table { + if x != nil { + return x.Table + } + return nil +} + +type MySQLExplain_OrderingOperation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UsingFilesort bool `protobuf:"varint,1,opt,name=using_filesort,json=usingFilesort,proto3" json:"using_filesort,omitempty"` + CostInfo map[string]string `protobuf:"bytes,2,rep,name=cost_info,json=costInfo,proto3" json:"cost_info,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Table *MySQLExplain_Table `protobuf:"bytes,3,opt,name=table,proto3" json:"table,omitempty"` + NestedLoop []*MySQLExplain_NestedLoopObj `protobuf:"bytes,4,rep,name=nested_loop,json=nestedLoop,proto3" json:"nested_loop,omitempty"` +} + +func (x *MySQLExplain_OrderingOperation) Reset() { + *x = MySQLExplain_OrderingOperation{} + if protoimpl.UnsafeEnabled { + mi := &file_vet_vet_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MySQLExplain_OrderingOperation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MySQLExplain_OrderingOperation) ProtoMessage() {} + +func (x *MySQLExplain_OrderingOperation) ProtoReflect() protoreflect.Message { + mi := &file_vet_vet_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MySQLExplain_OrderingOperation.ProtoReflect.Descriptor instead. +func (*MySQLExplain_OrderingOperation) Descriptor() ([]byte, []int) { + return file_vet_vet_proto_rawDescGZIP(), []int{6, 3} +} + +func (x *MySQLExplain_OrderingOperation) GetUsingFilesort() bool { + if x != nil { + return x.UsingFilesort + } + return false +} + +func (x *MySQLExplain_OrderingOperation) GetCostInfo() map[string]string { + if x != nil { + return x.CostInfo + } + return nil +} + +func (x *MySQLExplain_OrderingOperation) GetTable() *MySQLExplain_Table { + if x != nil { + return x.Table + } + return nil +} + +func (x *MySQLExplain_OrderingOperation) GetNestedLoop() []*MySQLExplain_NestedLoopObj { + if x != nil { + return x.NestedLoop + } + return nil +} + +var File_vet_vet_proto protoreflect.FileDescriptor + +var file_vet_vet_proto_rawDesc = []byte{ + 0x0a, 0x0d, 0x76, 0x65, 0x74, 0x2f, 0x76, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x03, 0x76, 0x65, 0x74, 0x22, 0x23, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, + 0x72, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x6c, 0x0a, 0x06, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, + 0x06, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, + 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x18, 0x0a, + 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, + 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x22, 0x6b, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x73, 0x71, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, + 0x71, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x6d, 0x64, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, 0x6d, 0x64, 0x12, 0x2a, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, + 0x6d, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x76, 0x65, 0x74, 0x2e, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, + 0x74, 0x65, 0x72, 0x73, 0x22, 0x3e, 0x0a, 0x0a, 0x50, 0x6f, 0x73, 0x74, 0x67, 0x72, 0x65, 0x53, + 0x51, 0x4c, 0x12, 0x30, 0x0a, 0x07, 0x65, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x76, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x67, 0x72, + 0x65, 0x53, 0x51, 0x4c, 0x45, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x52, 0x07, 0x65, 0x78, 0x70, + 0x6c, 0x61, 0x69, 0x6e, 0x22, 0x8d, 0x0f, 0x0a, 0x11, 0x50, 0x6f, 0x73, 0x74, 0x67, 0x72, 0x65, + 0x53, 0x51, 0x4c, 0x45, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x12, 0x2f, 0x0a, 0x04, 0x70, 0x6c, + 0x61, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x76, 0x65, 0x74, 0x2e, 0x50, + 0x6f, 0x73, 0x74, 0x67, 0x72, 0x65, 0x53, 0x51, 0x4c, 0x45, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, + 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x52, 0x04, 0x50, 0x6c, 0x61, 0x6e, 0x12, 0x40, 0x0a, 0x08, 0x73, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, + 0x76, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x67, 0x72, 0x65, 0x53, 0x51, 0x4c, 0x45, 0x78, + 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x08, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3b, 0x0a, + 0x08, 0x70, 0x6c, 0x61, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1f, 0x2e, 0x76, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x67, 0x72, 0x65, 0x53, 0x51, 0x4c, + 0x45, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x6e, 0x69, 0x6e, 0x67, + 0x52, 0x08, 0x50, 0x6c, 0x61, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x1a, 0x3b, 0x0a, 0x0d, 0x53, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x93, 0x09, 0x0a, 0x04, 0x50, 0x6c, 0x61, 0x6e, + 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x54, 0x79, 0x70, 0x65, 0x12, 0x30, + 0x0a, 0x13, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x68, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x50, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x20, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x68, 0x69, 0x70, + 0x12, 0x24, 0x0a, 0x0d, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x14, + 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x41, + 0x6c, 0x69, 0x61, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, + 0x5f, 0x61, 0x77, 0x61, 0x72, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x50, 0x61, + 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x20, 0x41, 0x77, 0x61, 0x72, 0x65, 0x12, 0x24, 0x0a, 0x0d, + 0x61, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x63, 0x61, 0x70, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0d, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x20, 0x43, 0x61, 0x70, 0x61, 0x62, + 0x6c, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x5f, 0x63, 0x6f, + 0x73, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0c, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, + 0x70, 0x20, 0x43, 0x6f, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, + 0x63, 0x6f, 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0a, 0x54, 0x6f, 0x74, 0x61, + 0x6c, 0x20, 0x43, 0x6f, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x6c, 0x61, 0x6e, 0x5f, 0x72, + 0x6f, 0x77, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x50, 0x6c, 0x61, 0x6e, 0x20, + 0x52, 0x6f, 0x77, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x6c, 0x61, 0x6e, 0x5f, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x50, 0x6c, 0x61, 0x6e, 0x20, 0x57, + 0x69, 0x64, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x0c, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x31, 0x0a, 0x05, + 0x70, 0x6c, 0x61, 0x6e, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x76, 0x65, + 0x74, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x67, 0x72, 0x65, 0x53, 0x51, 0x4c, 0x45, 0x78, 0x70, 0x6c, + 0x61, 0x69, 0x6e, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x52, 0x05, 0x50, 0x6c, 0x61, 0x6e, 0x73, 0x12, + 0x2c, 0x0a, 0x11, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f, 0x68, 0x69, 0x74, 0x5f, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x53, 0x68, 0x61, 0x72, + 0x65, 0x64, 0x20, 0x48, 0x69, 0x74, 0x20, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x2e, 0x0a, + 0x12, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x04, 0x52, 0x12, 0x53, 0x68, 0x61, 0x72, 0x65, + 0x64, 0x20, 0x52, 0x65, 0x61, 0x64, 0x20, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x34, 0x0a, + 0x15, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f, 0x64, 0x69, 0x72, 0x74, 0x69, 0x65, 0x64, 0x5f, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x15, 0x53, 0x68, + 0x61, 0x72, 0x65, 0x64, 0x20, 0x44, 0x69, 0x72, 0x74, 0x69, 0x65, 0x64, 0x20, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x73, 0x12, 0x34, 0x0a, 0x15, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f, 0x77, 0x72, + 0x69, 0x74, 0x74, 0x65, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x11, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x15, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x20, 0x57, 0x72, 0x69, 0x74, 0x74, + 0x65, 0x6e, 0x20, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x6f, 0x63, + 0x61, 0x6c, 0x5f, 0x68, 0x69, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x12, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x10, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x48, 0x69, 0x74, 0x20, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x72, + 0x65, 0x61, 0x64, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x13, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x11, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x52, 0x65, 0x61, 0x64, 0x20, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x64, 0x69, 0x72, + 0x74, 0x69, 0x65, 0x64, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x14, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x44, 0x69, 0x72, 0x74, 0x69, 0x65, 0x64, + 0x20, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x6c, 0x6f, 0x63, 0x61, 0x6c, + 0x5f, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, + 0x15, 0x20, 0x01, 0x28, 0x04, 0x52, 0x14, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x57, 0x72, 0x69, + 0x74, 0x74, 0x65, 0x6e, 0x20, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x74, + 0x65, 0x6d, 0x70, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, + 0x16, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x54, 0x65, 0x6d, 0x70, 0x20, 0x52, 0x65, 0x61, 0x64, + 0x20, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x30, 0x0a, 0x13, 0x74, 0x65, 0x6d, 0x70, 0x5f, + 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x17, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x54, 0x65, 0x6d, 0x70, 0x20, 0x57, 0x72, 0x69, 0x74, 0x74, + 0x65, 0x6e, 0x20, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x6f, 0x72, + 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x18, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x53, 0x6f, 0x72, + 0x74, 0x20, 0x4b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x19, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x4a, 0x6f, 0x69, 0x6e, 0x20, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x5f, 0x75, 0x6e, 0x69, + 0x71, 0x75, 0x65, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x49, 0x6e, 0x6e, 0x65, 0x72, + 0x20, 0x55, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x68, 0x61, 0x73, 0x68, 0x5f, + 0x63, 0x6f, 0x6e, 0x64, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x48, 0x61, 0x73, 0x68, + 0x20, 0x43, 0x6f, 0x6e, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x20, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x73, 0x63, 0x61, 0x6e, 0x5f, 0x64, 0x69, + 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x53, + 0x63, 0x61, 0x6e, 0x20, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, + 0x0a, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x18, 0x1e, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x43, 0x6f, 0x6e, 0x64, 0x1a, 0xf4, 0x03, + 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x2c, 0x0a, 0x11, 0x73, 0x68, + 0x61, 0x72, 0x65, 0x64, 0x5f, 0x68, 0x69, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x20, 0x48, 0x69, + 0x74, 0x20, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x73, 0x68, 0x61, 0x72, + 0x65, 0x64, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x12, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x20, 0x52, 0x65, 0x61, + 0x64, 0x20, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x34, 0x0a, 0x15, 0x73, 0x68, 0x61, 0x72, + 0x65, 0x64, 0x5f, 0x64, 0x69, 0x72, 0x74, 0x69, 0x65, 0x64, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x15, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x20, + 0x44, 0x69, 0x72, 0x74, 0x69, 0x65, 0x64, 0x20, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x34, + 0x0a, 0x15, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, + 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x15, 0x53, + 0x68, 0x61, 0x72, 0x65, 0x64, 0x20, 0x57, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x68, 0x69, + 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, + 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x48, 0x69, 0x74, 0x20, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, + 0x12, 0x2c, 0x0a, 0x11, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x4c, 0x6f, 0x63, + 0x61, 0x6c, 0x20, 0x52, 0x65, 0x61, 0x64, 0x20, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x32, + 0x0a, 0x14, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x64, 0x69, 0x72, 0x74, 0x69, 0x65, 0x64, 0x5f, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x14, 0x4c, 0x6f, + 0x63, 0x61, 0x6c, 0x20, 0x44, 0x69, 0x72, 0x74, 0x69, 0x65, 0x64, 0x20, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x77, 0x72, 0x69, 0x74, + 0x74, 0x65, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x14, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x57, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x74, 0x65, 0x6d, 0x70, 0x5f, 0x72, + 0x65, 0x61, 0x64, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x10, 0x54, 0x65, 0x6d, 0x70, 0x20, 0x52, 0x65, 0x61, 0x64, 0x20, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x73, 0x12, 0x30, 0x0a, 0x13, 0x74, 0x65, 0x6d, 0x70, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x74, + 0x65, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x13, 0x54, 0x65, 0x6d, 0x70, 0x20, 0x57, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x73, 0x22, 0x34, 0x0a, 0x05, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x12, 0x2b, 0x0a, + 0x07, 0x65, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, + 0x2e, 0x76, 0x65, 0x74, 0x2e, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x45, 0x78, 0x70, 0x6c, 0x61, 0x69, + 0x6e, 0x52, 0x07, 0x65, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x22, 0xf3, 0x0a, 0x0a, 0x0c, 0x4d, + 0x79, 0x53, 0x51, 0x4c, 0x45, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x12, 0x3d, 0x0a, 0x0b, 0x71, + 0x75, 0x65, 0x72, 0x79, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1c, 0x2e, 0x76, 0x65, 0x74, 0x2e, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x45, 0x78, 0x70, 0x6c, + 0x61, 0x69, 0x6e, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x0a, + 0x71, 0x75, 0x65, 0x72, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x1a, 0x8e, 0x03, 0x0a, 0x0a, 0x51, + 0x75, 0x65, 0x72, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x47, 0x0a, 0x09, 0x63, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x76, 0x65, 0x74, 0x2e, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x45, + 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x2e, 0x43, 0x6f, 0x73, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x08, 0x63, 0x6f, 0x73, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2d, 0x0a, 0x05, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x76, 0x65, 0x74, 0x2e, 0x4d, + 0x79, 0x53, 0x51, 0x4c, 0x45, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x2e, 0x54, 0x61, 0x62, 0x6c, + 0x65, 0x52, 0x05, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x52, 0x0a, 0x12, 0x6f, 0x72, 0x64, 0x65, + 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x76, 0x65, 0x74, 0x2e, 0x4d, 0x79, 0x53, 0x51, 0x4c, + 0x45, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x69, 0x6e, 0x67, + 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x11, 0x6f, 0x72, 0x64, 0x65, 0x72, + 0x69, 0x6e, 0x67, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x0b, + 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x6c, 0x6f, 0x6f, 0x70, 0x18, 0x06, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x65, 0x74, 0x2e, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x45, 0x78, 0x70, + 0x6c, 0x61, 0x69, 0x6e, 0x2e, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, + 0x62, 0x6a, 0x52, 0x0a, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4c, 0x6f, 0x6f, 0x70, 0x1a, 0x3b, + 0x0a, 0x0d, 0x43, 0x6f, 0x73, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x97, 0x04, 0x0a, 0x05, + 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x33, 0x0a, 0x16, 0x72, 0x6f, 0x77, 0x73, 0x5f, 0x65, 0x78, + 0x61, 0x6d, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x73, 0x63, 0x61, 0x6e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x72, 0x6f, 0x77, 0x73, 0x45, 0x78, 0x61, 0x6d, 0x69, + 0x6e, 0x65, 0x64, 0x50, 0x65, 0x72, 0x53, 0x63, 0x61, 0x6e, 0x12, 0x33, 0x0a, 0x16, 0x72, 0x6f, + 0x77, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x64, 0x5f, 0x70, 0x65, 0x72, 0x5f, + 0x6a, 0x6f, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x72, 0x6f, 0x77, 0x73, + 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x64, 0x50, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x12, + 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x12, 0x42, 0x0a, 0x09, 0x63, + 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, + 0x2e, 0x76, 0x65, 0x74, 0x2e, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x45, 0x78, 0x70, 0x6c, 0x61, 0x69, + 0x6e, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x43, 0x6f, 0x73, 0x74, 0x49, 0x6e, 0x66, 0x6f, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x63, 0x6f, 0x73, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, + 0x21, 0x0a, 0x0c, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, + 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x75, 0x73, 0x65, 0x64, 0x43, 0x6f, 0x6c, 0x75, 0x6d, + 0x6e, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x06, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x6f, + 0x73, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0c, 0x70, 0x6f, 0x73, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x24, 0x0a, 0x0e, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, + 0x72, 0x74, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x75, 0x73, 0x65, 0x64, 0x4b, + 0x65, 0x79, 0x50, 0x61, 0x72, 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6b, 0x65, 0x79, 0x5f, 0x6c, + 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6b, 0x65, 0x79, + 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x66, 0x18, 0x0d, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65, 0x66, 0x1a, 0x3b, 0x0a, 0x0d, 0x43, 0x6f, 0x73, 0x74, + 0x49, 0x6e, 0x66, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3e, 0x0a, 0x0d, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4c, + 0x6f, 0x6f, 0x70, 0x4f, 0x62, 0x6a, 0x12, 0x2d, 0x0a, 0x05, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x76, 0x65, 0x74, 0x2e, 0x4d, 0x79, 0x53, 0x51, + 0x4c, 0x45, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x05, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x1a, 0xb8, 0x02, 0x0a, 0x11, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x69, + 0x6e, 0x67, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x75, + 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0d, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x6f, + 0x72, 0x74, 0x12, 0x4e, 0x0a, 0x09, 0x63, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x76, 0x65, 0x74, 0x2e, 0x4d, 0x79, 0x53, 0x51, + 0x4c, 0x45, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x69, 0x6e, + 0x67, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x73, 0x74, 0x49, + 0x6e, 0x66, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x63, 0x6f, 0x73, 0x74, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x2d, 0x0a, 0x05, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x17, 0x2e, 0x76, 0x65, 0x74, 0x2e, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x45, 0x78, 0x70, + 0x6c, 0x61, 0x69, 0x6e, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x05, 0x74, 0x61, 0x62, 0x6c, + 0x65, 0x12, 0x40, 0x0a, 0x0b, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x6c, 0x6f, 0x6f, 0x70, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x65, 0x74, 0x2e, 0x4d, 0x79, 0x53, + 0x51, 0x4c, 0x45, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x2e, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, + 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x62, 0x6a, 0x52, 0x0a, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4c, + 0x6f, 0x6f, 0x70, 0x1a, 0x3b, 0x0a, 0x0d, 0x43, 0x6f, 0x73, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x42, 0x66, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x65, 0x74, 0x42, 0x08, 0x56, 0x65, 0x74, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x71, 0x6c, 0x63, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x73, 0x71, 0x6c, + 0x63, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x76, 0x65, 0x74, 0xa2, 0x02, + 0x03, 0x56, 0x58, 0x58, 0xaa, 0x02, 0x03, 0x56, 0x65, 0x74, 0xca, 0x02, 0x03, 0x56, 0x65, 0x74, + 0xe2, 0x02, 0x0f, 0x56, 0x65, 0x74, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0xea, 0x02, 0x03, 0x56, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_vet_vet_proto_rawDescOnce sync.Once + file_vet_vet_proto_rawDescData = file_vet_vet_proto_rawDesc +) + +func file_vet_vet_proto_rawDescGZIP() []byte { + file_vet_vet_proto_rawDescOnce.Do(func() { + file_vet_vet_proto_rawDescData = protoimpl.X.CompressGZIP(file_vet_vet_proto_rawDescData) + }) + return file_vet_vet_proto_rawDescData +} + +var file_vet_vet_proto_msgTypes = make([]protoimpl.MessageInfo, 17) +var file_vet_vet_proto_goTypes = []interface{}{ + (*Parameter)(nil), // 0: vet.Parameter + (*Config)(nil), // 1: vet.Config + (*Query)(nil), // 2: vet.Query + (*PostgreSQL)(nil), // 3: vet.PostgreSQL + (*PostgreSQLExplain)(nil), // 4: vet.PostgreSQLExplain + (*MySQL)(nil), // 5: vet.MySQL + (*MySQLExplain)(nil), // 6: vet.MySQLExplain + nil, // 7: vet.PostgreSQLExplain.SettingsEntry + (*PostgreSQLExplain_Plan)(nil), // 8: vet.PostgreSQLExplain.Plan + (*PostgreSQLExplain_Planning)(nil), // 9: vet.PostgreSQLExplain.Planning + (*MySQLExplain_QueryBlock)(nil), // 10: vet.MySQLExplain.QueryBlock + (*MySQLExplain_Table)(nil), // 11: vet.MySQLExplain.Table + (*MySQLExplain_NestedLoopObj)(nil), // 12: vet.MySQLExplain.NestedLoopObj + (*MySQLExplain_OrderingOperation)(nil), // 13: vet.MySQLExplain.OrderingOperation + nil, // 14: vet.MySQLExplain.QueryBlock.CostInfoEntry + nil, // 15: vet.MySQLExplain.Table.CostInfoEntry + nil, // 16: vet.MySQLExplain.OrderingOperation.CostInfoEntry +} +var file_vet_vet_proto_depIdxs = []int32{ + 0, // 0: vet.Query.params:type_name -> vet.Parameter + 4, // 1: vet.PostgreSQL.explain:type_name -> vet.PostgreSQLExplain + 8, // 2: vet.PostgreSQLExplain.plan:type_name -> vet.PostgreSQLExplain.Plan + 7, // 3: vet.PostgreSQLExplain.settings:type_name -> vet.PostgreSQLExplain.SettingsEntry + 9, // 4: vet.PostgreSQLExplain.planning:type_name -> vet.PostgreSQLExplain.Planning + 6, // 5: vet.MySQL.explain:type_name -> vet.MySQLExplain + 10, // 6: vet.MySQLExplain.query_block:type_name -> vet.MySQLExplain.QueryBlock + 8, // 7: vet.PostgreSQLExplain.Plan.plans:type_name -> vet.PostgreSQLExplain.Plan + 14, // 8: vet.MySQLExplain.QueryBlock.cost_info:type_name -> vet.MySQLExplain.QueryBlock.CostInfoEntry + 11, // 9: vet.MySQLExplain.QueryBlock.table:type_name -> vet.MySQLExplain.Table + 13, // 10: vet.MySQLExplain.QueryBlock.ordering_operation:type_name -> vet.MySQLExplain.OrderingOperation + 12, // 11: vet.MySQLExplain.QueryBlock.nested_loop:type_name -> vet.MySQLExplain.NestedLoopObj + 15, // 12: vet.MySQLExplain.Table.cost_info:type_name -> vet.MySQLExplain.Table.CostInfoEntry + 11, // 13: vet.MySQLExplain.NestedLoopObj.table:type_name -> vet.MySQLExplain.Table + 16, // 14: vet.MySQLExplain.OrderingOperation.cost_info:type_name -> vet.MySQLExplain.OrderingOperation.CostInfoEntry + 11, // 15: vet.MySQLExplain.OrderingOperation.table:type_name -> vet.MySQLExplain.Table + 12, // 16: vet.MySQLExplain.OrderingOperation.nested_loop:type_name -> vet.MySQLExplain.NestedLoopObj + 17, // [17:17] is the sub-list for method output_type + 17, // [17:17] is the sub-list for method input_type + 17, // [17:17] is the sub-list for extension type_name + 17, // [17:17] is the sub-list for extension extendee + 0, // [0:17] is the sub-list for field type_name +} + +func init() { file_vet_vet_proto_init() } +func file_vet_vet_proto_init() { + if File_vet_vet_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_vet_vet_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Parameter); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_vet_vet_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Config); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_vet_vet_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Query); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_vet_vet_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PostgreSQL); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_vet_vet_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PostgreSQLExplain); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_vet_vet_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MySQL); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_vet_vet_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MySQLExplain); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_vet_vet_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PostgreSQLExplain_Plan); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_vet_vet_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PostgreSQLExplain_Planning); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_vet_vet_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MySQLExplain_QueryBlock); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_vet_vet_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MySQLExplain_Table); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_vet_vet_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MySQLExplain_NestedLoopObj); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_vet_vet_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MySQLExplain_OrderingOperation); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_vet_vet_proto_rawDesc, + NumEnums: 0, + NumMessages: 17, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_vet_vet_proto_goTypes, + DependencyIndexes: file_vet_vet_proto_depIdxs, + MessageInfos: file_vet_vet_proto_msgTypes, + }.Build() + File_vet_vet_proto = out.File + file_vet_vet_proto_rawDesc = nil + file_vet_vet_proto_goTypes = nil + file_vet_vet_proto_depIdxs = nil +} diff --git a/internal/x/expander/expander.go b/internal/x/expander/expander.go new file mode 100644 index 0000000..af0cab2 --- /dev/null +++ b/internal/x/expander/expander.go @@ -0,0 +1,507 @@ +package expander + +import ( + "context" + "fmt" + "io" + "strings" + + "github.com/sqlc-dev/sqlc/internal/sql/ast" + "github.com/sqlc-dev/sqlc/internal/sql/astutils" + "github.com/sqlc-dev/sqlc/internal/sql/format" +) + +// Parser is an interface for SQL parsers that can parse SQL into AST statements. +type Parser interface { + Parse(r io.Reader) ([]ast.Statement, error) +} + +// ColumnGetter retrieves column names for a query by preparing it against a database. +type ColumnGetter interface { + GetColumnNames(ctx context.Context, query string) ([]string, error) +} + +// Expander expands SELECT * and RETURNING * queries by replacing * with explicit column names +// obtained from preparing the query against a database. +type Expander struct { + colGetter ColumnGetter + parser Parser + dialect format.Dialect +} + +// New creates a new Expander with the given column getter, parser, and dialect. +func New(colGetter ColumnGetter, parser Parser, dialect format.Dialect) *Expander { + return &Expander{ + colGetter: colGetter, + parser: parser, + dialect: dialect, + } +} + +// Expand takes a SQL query, and if it contains * in SELECT or RETURNING clause, +// expands it to use explicit column names. Returns the expanded query string. +func (e *Expander) Expand(ctx context.Context, query string) (string, error) { + // Parse the query + stmts, err := e.parser.Parse(strings.NewReader(query)) + if err != nil { + return "", fmt.Errorf("failed to parse query: %w", err) + } + + if len(stmts) == 0 { + return query, nil + } + + stmt := stmts[0].Raw.Stmt + + // Check if there's any star in the statement (including CTEs, subqueries, etc.) + if !hasStarAnywhere(stmt) { + return query, nil + } + + // Expand all stars in the statement recursively + if err := e.expandNode(ctx, stmt); err != nil { + return "", err + } + + // Format the modified AST back to SQL + expanded := ast.Format(stmts[0].Raw, e.dialect) + + return expanded, nil +} + +// expandNode recursively expands * in all parts of the statement +func (e *Expander) expandNode(ctx context.Context, node ast.Node) error { + if node == nil { + return nil + } + + switch n := node.(type) { + case *ast.SelectStmt: + return e.expandSelectStmt(ctx, n) + case *ast.InsertStmt: + return e.expandInsertStmt(ctx, n) + case *ast.UpdateStmt: + return e.expandUpdateStmt(ctx, n) + case *ast.DeleteStmt: + return e.expandDeleteStmt(ctx, n) + case *ast.CommonTableExpr: + return e.expandNode(ctx, n.Ctequery) + } + return nil +} + +// expandSelectStmt expands * in a SELECT statement including CTEs and subqueries +func (e *Expander) expandSelectStmt(ctx context.Context, stmt *ast.SelectStmt) error { + // First expand any CTEs - must be done in order since later CTEs may depend on earlier ones + if stmt.WithClause != nil && stmt.WithClause.Ctes != nil { + for _, cteNode := range stmt.WithClause.Ctes.Items { + cte, ok := cteNode.(*ast.CommonTableExpr) + if !ok { + continue + } + cteSelect, ok := cte.Ctequery.(*ast.SelectStmt) + if !ok { + continue + } + if hasStarInList(cteSelect.TargetList) { + // Get column names for this CTE + columns, err := e.getCTEColumnNames(ctx, stmt, cte) + if err != nil { + return err + } + cteSelect.TargetList = rewriteTargetList(cteSelect.TargetList, columns) + } + // Recursively handle nested CTEs/subqueries in this CTE + if err := e.expandSelectStmtInner(ctx, cteSelect); err != nil { + return err + } + } + } + + // Expand subqueries in FROM clause + if stmt.FromClause != nil { + for _, fromItem := range stmt.FromClause.Items { + if err := e.expandFromClause(ctx, fromItem); err != nil { + return err + } + } + } + + // Expand the target list if it has stars + if hasStarInList(stmt.TargetList) { + // Format the current state to get columns + tempRaw := &ast.RawStmt{Stmt: stmt} + tempQuery := ast.Format(tempRaw, e.dialect) + columns, err := e.getColumnNames(ctx, tempQuery) + if err != nil { + return fmt.Errorf("failed to get column names: %w", err) + } + stmt.TargetList = rewriteTargetList(stmt.TargetList, columns) + } + + return nil +} + +// expandSelectStmtInner expands nested structures without re-processing the target list +func (e *Expander) expandSelectStmtInner(ctx context.Context, stmt *ast.SelectStmt) error { + // Expand subqueries in FROM clause + if stmt.FromClause != nil { + for _, fromItem := range stmt.FromClause.Items { + if err := e.expandFromClause(ctx, fromItem); err != nil { + return err + } + } + } + return nil +} + +// getCTEColumnNames gets the column names for a CTE by constructing a query with proper context +func (e *Expander) getCTEColumnNames(ctx context.Context, stmt *ast.SelectStmt, targetCTE *ast.CommonTableExpr) ([]string, error) { + // Build a temporary query: WITH SELECT * FROM + var ctesToInclude []ast.Node + for _, cteNode := range stmt.WithClause.Ctes.Items { + ctesToInclude = append(ctesToInclude, cteNode) + cte, ok := cteNode.(*ast.CommonTableExpr) + if ok && cte.Ctename != nil && targetCTE.Ctename != nil && *cte.Ctename == *targetCTE.Ctename { + break + } + } + + // Create a SELECT * FROM with the relevant CTEs + cteName := "" + if targetCTE.Ctename != nil { + cteName = *targetCTE.Ctename + } + + tempStmt := &ast.SelectStmt{ + WithClause: &ast.WithClause{ + Ctes: &ast.List{Items: ctesToInclude}, + Recursive: stmt.WithClause.Recursive, + }, + TargetList: &ast.List{ + Items: []ast.Node{ + &ast.ResTarget{ + Val: &ast.ColumnRef{ + Fields: &ast.List{ + Items: []ast.Node{&ast.A_Star{}}, + }, + }, + }, + }, + }, + FromClause: &ast.List{ + Items: []ast.Node{ + &ast.RangeVar{ + Relname: &cteName, + }, + }, + }, + } + + tempRaw := &ast.RawStmt{Stmt: tempStmt} + tempQuery := ast.Format(tempRaw, e.dialect) + + return e.getColumnNames(ctx, tempQuery) +} + +// expandInsertStmt expands * in an INSERT statement's RETURNING clause +func (e *Expander) expandInsertStmt(ctx context.Context, stmt *ast.InsertStmt) error { + // Expand CTEs first + if stmt.WithClause != nil && stmt.WithClause.Ctes != nil { + for _, cte := range stmt.WithClause.Ctes.Items { + if err := e.expandNode(ctx, cte); err != nil { + return err + } + } + } + + // Expand the SELECT part if present + if stmt.SelectStmt != nil { + if err := e.expandNode(ctx, stmt.SelectStmt); err != nil { + return err + } + } + + // Expand RETURNING clause + if hasStarInList(stmt.ReturningList) { + tempRaw := &ast.RawStmt{Stmt: stmt} + tempQuery := ast.Format(tempRaw, e.dialect) + columns, err := e.getColumnNames(ctx, tempQuery) + if err != nil { + return fmt.Errorf("failed to get column names: %w", err) + } + stmt.ReturningList = rewriteTargetList(stmt.ReturningList, columns) + } + + return nil +} + +// expandUpdateStmt expands * in an UPDATE statement's RETURNING clause +func (e *Expander) expandUpdateStmt(ctx context.Context, stmt *ast.UpdateStmt) error { + // Expand CTEs first + if stmt.WithClause != nil && stmt.WithClause.Ctes != nil { + for _, cte := range stmt.WithClause.Ctes.Items { + if err := e.expandNode(ctx, cte); err != nil { + return err + } + } + } + + // Expand RETURNING clause + if hasStarInList(stmt.ReturningList) { + tempRaw := &ast.RawStmt{Stmt: stmt} + tempQuery := ast.Format(tempRaw, e.dialect) + columns, err := e.getColumnNames(ctx, tempQuery) + if err != nil { + return fmt.Errorf("failed to get column names: %w", err) + } + stmt.ReturningList = rewriteTargetList(stmt.ReturningList, columns) + } + + return nil +} + +// expandDeleteStmt expands * in a DELETE statement's RETURNING clause +func (e *Expander) expandDeleteStmt(ctx context.Context, stmt *ast.DeleteStmt) error { + // Expand CTEs first + if stmt.WithClause != nil && stmt.WithClause.Ctes != nil { + for _, cte := range stmt.WithClause.Ctes.Items { + if err := e.expandNode(ctx, cte); err != nil { + return err + } + } + } + + // Expand RETURNING clause + if hasStarInList(stmt.ReturningList) { + tempRaw := &ast.RawStmt{Stmt: stmt} + tempQuery := ast.Format(tempRaw, e.dialect) + columns, err := e.getColumnNames(ctx, tempQuery) + if err != nil { + return fmt.Errorf("failed to get column names: %w", err) + } + stmt.ReturningList = rewriteTargetList(stmt.ReturningList, columns) + } + + return nil +} + +// expandFromClause expands * in subqueries within FROM clause +func (e *Expander) expandFromClause(ctx context.Context, node ast.Node) error { + if node == nil { + return nil + } + + switch n := node.(type) { + case *ast.RangeSubselect: + if n.Subquery != nil { + return e.expandNode(ctx, n.Subquery) + } + case *ast.JoinExpr: + if err := e.expandFromClause(ctx, n.Larg); err != nil { + return err + } + if err := e.expandFromClause(ctx, n.Rarg); err != nil { + return err + } + } + return nil +} + +// hasStarAnywhere checks if there's a * anywhere in the statement using astutils.Search +func hasStarAnywhere(node ast.Node) bool { + if node == nil { + return false + } + // Use astutils.Search to find any A_Star node in the AST + stars := astutils.Search(node, func(n ast.Node) bool { + _, ok := n.(*ast.A_Star) + return ok + }) + return len(stars.Items) > 0 +} + +// hasStarInList checks if a target list contains a * expression using astutils.Search +func hasStarInList(targets *ast.List) bool { + if targets == nil { + return false + } + // Use astutils.Search to find any A_Star node in the target list + stars := astutils.Search(targets, func(n ast.Node) bool { + _, ok := n.(*ast.A_Star) + return ok + }) + return len(stars.Items) > 0 +} + +// getColumnNames prepares the query and returns the column names from the result +func (e *Expander) getColumnNames(ctx context.Context, query string) ([]string, error) { + return e.colGetter.GetColumnNames(ctx, query) +} + +// countStarsInList counts the number of * expressions in a target list +func countStarsInList(targets *ast.List) int { + if targets == nil { + return 0 + } + count := 0 + for _, target := range targets.Items { + resTarget, ok := target.(*ast.ResTarget) + if !ok { + continue + } + if resTarget.Val == nil { + continue + } + colRef, ok := resTarget.Val.(*ast.ColumnRef) + if !ok { + continue + } + if colRef.Fields == nil { + continue + } + for _, field := range colRef.Fields.Items { + if _, ok := field.(*ast.A_Star); ok { + count++ + break + } + } + } + return count +} + +// countNonStarsInList counts the number of non-* expressions in a target list +func countNonStarsInList(targets *ast.List) int { + if targets == nil { + return 0 + } + count := 0 + for _, target := range targets.Items { + resTarget, ok := target.(*ast.ResTarget) + if !ok { + count++ + continue + } + if resTarget.Val == nil { + count++ + continue + } + colRef, ok := resTarget.Val.(*ast.ColumnRef) + if !ok { + count++ + continue + } + if colRef.Fields == nil { + count++ + continue + } + isStar := false + for _, field := range colRef.Fields.Items { + if _, ok := field.(*ast.A_Star); ok { + isStar = true + break + } + } + if !isStar { + count++ + } + } + return count +} + +// rewriteTargetList replaces * in a target list with explicit column references +func rewriteTargetList(targets *ast.List, columns []string) *ast.List { + if targets == nil { + return nil + } + + starCount := countStarsInList(targets) + nonStarCount := countNonStarsInList(targets) + + // Calculate how many columns each * expands to + // Total columns = (columns per star * number of stars) + non-star columns + // So: columns per star = (total - non-star) / stars + columnsPerStar := 0 + if starCount > 0 { + columnsPerStar = (len(columns) - nonStarCount) / starCount + } + + newItems := make([]ast.Node, 0, len(columns)) + colIndex := 0 + + for _, target := range targets.Items { + resTarget, ok := target.(*ast.ResTarget) + if !ok { + newItems = append(newItems, target) + colIndex++ + continue + } + + if resTarget.Val == nil { + newItems = append(newItems, target) + colIndex++ + continue + } + + colRef, ok := resTarget.Val.(*ast.ColumnRef) + if !ok { + newItems = append(newItems, target) + colIndex++ + continue + } + + if colRef.Fields == nil { + newItems = append(newItems, target) + colIndex++ + continue + } + + // Check if this is a * (with or without table qualifier) + // and extract any table prefix + isStar := false + var tablePrefix []string + for _, field := range colRef.Fields.Items { + if _, ok := field.(*ast.A_Star); ok { + isStar = true + break + } + // Collect prefix parts (schema, table name) + if str, ok := field.(*ast.String); ok { + tablePrefix = append(tablePrefix, str.Str) + } + } + + if !isStar { + newItems = append(newItems, target) + colIndex++ + continue + } + + // Replace * with explicit column references + for i := 0; i < columnsPerStar && colIndex < len(columns); i++ { + newItems = append(newItems, makeColumnTargetWithPrefix(columns[colIndex], tablePrefix)) + colIndex++ + } + } + + return &ast.List{Items: newItems} +} + +// makeColumnTargetWithPrefix creates a ResTarget node for a column reference with optional table prefix +func makeColumnTargetWithPrefix(colName string, prefix []string) ast.Node { + fields := make([]ast.Node, 0, len(prefix)+1) + + // Add prefix parts (schema, table name) + for _, p := range prefix { + fields = append(fields, &ast.String{Str: p}) + } + + // Add column name + fields = append(fields, &ast.String{Str: colName}) + + return &ast.ResTarget{ + Val: &ast.ColumnRef{ + Fields: &ast.List{Items: fields}, + }, + } +} diff --git a/internal/x/expander/expander_test.go b/internal/x/expander/expander_test.go new file mode 100644 index 0000000..07092ff --- /dev/null +++ b/internal/x/expander/expander_test.go @@ -0,0 +1,435 @@ +package expander + +import ( + "context" + "database/sql" + "os" + "testing" + + _ "github.com/go-sql-driver/mysql" + "github.com/jackc/pgx/v5/pgxpool" + "github.com/ncruces/go-sqlite3" + + "github.com/sqlc-dev/sqlc/internal/engine/dolphin" + "github.com/sqlc-dev/sqlc/internal/engine/postgresql" + "github.com/sqlc-dev/sqlc/internal/engine/sqlite" + "github.com/sqlc-dev/sqlc/internal/sqltest/docker" + "github.com/sqlc-dev/sqlc/internal/sqltest/native" +) + +// PostgreSQLColumnGetter implements ColumnGetter for PostgreSQL using pgxpool. +type PostgreSQLColumnGetter struct { + pool *pgxpool.Pool +} + +func (g *PostgreSQLColumnGetter) GetColumnNames(ctx context.Context, query string) ([]string, error) { + conn, err := g.pool.Acquire(ctx) + if err != nil { + return nil, err + } + defer conn.Release() + + desc, err := conn.Conn().Prepare(ctx, "", query) + if err != nil { + return nil, err + } + + columns := make([]string, len(desc.Fields)) + for i, field := range desc.Fields { + columns[i] = field.Name + } + + return columns, nil +} + +// MySQLColumnGetter implements ColumnGetter for MySQL. Column names are read +// from the result set metadata returned by executing the query; the test +// tables are empty, so no real rows are transferred. +// +// An earlier implementation pulled column metadata straight out of a prepared +// statement via a forked mysql driver exposing StmtMetadata. That fork +// required a `replace` directive in go.mod, which broke `go install +// github.com/sqlc-dev/sqlc/cmd/sqlc@latest` (see +// https://github.com/sqlc-dev/sqlc/issues/4397). Reading columns from sql.Rows +// works with the upstream driver and keeps the test covering the same +// behavior. +type MySQLColumnGetter struct { + db *sql.DB +} + +func (g *MySQLColumnGetter) GetColumnNames(ctx context.Context, query string) ([]string, error) { + rows, err := g.db.QueryContext(ctx, query) + if err != nil { + return nil, err + } + defer rows.Close() + return rows.Columns() +} + +// SQLiteColumnGetter implements ColumnGetter for SQLite using the native ncruces/go-sqlite3 API. +type SQLiteColumnGetter struct { + conn *sqlite3.Conn +} + +func (g *SQLiteColumnGetter) GetColumnNames(ctx context.Context, query string) ([]string, error) { + // Prepare the statement - this gives us column metadata without executing + stmt, _, err := g.conn.Prepare(query) + if err != nil { + return nil, err + } + defer stmt.Close() + + // Get column names from the prepared statement + count := stmt.ColumnCount() + columns := make([]string, count) + for i := range count { + columns[i] = stmt.ColumnName(i) + } + + return columns, nil +} + +func TestExpandPostgreSQL(t *testing.T) { + ctx := context.Background() + + uri := os.Getenv("POSTGRESQL_SERVER_URI") + if uri == "" { + if err := docker.Installed(); err == nil { + u, err := docker.StartPostgreSQLServer(ctx) + if err != nil { + t.Fatal(err) + } + uri = u + } else if err := native.Supported(); err == nil { + u, err := native.StartPostgreSQLServer(ctx) + if err != nil { + t.Fatal(err) + } + uri = u + } else { + t.Skip("POSTGRESQL_SERVER_URI is empty and neither Docker nor native installation is available") + } + } + + pool, err := pgxpool.New(ctx, uri) + if err != nil { + t.Skipf("could not connect to database: %v", err) + } + defer pool.Close() + + // Create a test table + _, err = pool.Exec(ctx, ` + DROP TABLE IF EXISTS authors; + CREATE TABLE authors ( + id SERIAL PRIMARY KEY, + name TEXT NOT NULL, + bio TEXT + ); + `) + if err != nil { + t.Fatalf("failed to create test table: %v", err) + } + defer pool.Exec(ctx, "DROP TABLE IF EXISTS authors") + + // Create the parser which also implements format.Dialect + parser := postgresql.NewParser() + + // Create the expander + colGetter := &PostgreSQLColumnGetter{pool: pool} + exp := New(colGetter, parser, parser) + + tests := []struct { + name string + query string + expected string + }{ + { + name: "simple select star", + query: "SELECT * FROM authors", + expected: "SELECT id, name, bio FROM authors;", + }, + { + name: "select with no star", + query: "SELECT id, name FROM authors", + expected: "SELECT id, name FROM authors", // No change, returns original + }, + { + name: "select star with where clause", + query: "SELECT * FROM authors WHERE id = 1", + expected: "SELECT id, name, bio FROM authors WHERE id = 1;", + }, + { + name: "double star", + query: "SELECT *, * FROM authors", + expected: "SELECT id, name, bio, id, name, bio FROM authors;", + }, + { + name: "table qualified star", + query: "SELECT authors.* FROM authors", + expected: "SELECT authors.id, authors.name, authors.bio FROM authors;", + }, + { + name: "star in middle of columns", + query: "SELECT id, *, name FROM authors", + expected: "SELECT id, id, name, bio, name FROM authors;", + }, + { + name: "insert returning star", + query: "INSERT INTO authors (name, bio) VALUES ('John', 'A writer') RETURNING *", + expected: "INSERT INTO authors (name, bio) VALUES ('John', 'A writer') RETURNING id, name, bio;", + }, + { + name: "insert returning mixed", + query: "INSERT INTO authors (name, bio) VALUES ('John', 'A writer') RETURNING id, *", + expected: "INSERT INTO authors (name, bio) VALUES ('John', 'A writer') RETURNING id, id, name, bio;", + }, + { + name: "update returning star", + query: "UPDATE authors SET name = 'Jane' WHERE id = 1 RETURNING *", + expected: "UPDATE authors SET name = 'Jane' WHERE id = 1 RETURNING id, name, bio;", + }, + { + name: "delete returning star", + query: "DELETE FROM authors WHERE id = 1 RETURNING *", + expected: "DELETE FROM authors WHERE id = 1 RETURNING id, name, bio;", + }, + { + name: "cte with select star", + query: "WITH a AS (SELECT * FROM authors) SELECT * FROM a", + expected: "WITH a AS (SELECT id, name, bio FROM authors) SELECT id, name, bio FROM a;", + }, + { + name: "multiple ctes with dependency", + query: "WITH a AS (SELECT * FROM authors), b AS (SELECT * FROM a) SELECT * FROM b", + expected: "WITH a AS (SELECT id, name, bio FROM authors), b AS (SELECT id, name, bio FROM a) SELECT id, name, bio FROM b;", + }, + { + name: "count star not expanded", + query: "SELECT COUNT(*) FROM authors", + expected: "SELECT COUNT(*) FROM authors", // No change - COUNT(*) should not be expanded + }, + { + name: "count star with other columns", + query: "SELECT COUNT(*), name FROM authors GROUP BY name", + expected: "SELECT COUNT(*), name FROM authors GROUP BY name", // No change + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + result, err := exp.Expand(ctx, tc.query) + if err != nil { + t.Fatalf("Expand failed: %v", err) + } + if result != tc.expected { + t.Errorf("expected %q, got %q", tc.expected, result) + } + }) + } +} + +func TestExpandMySQL(t *testing.T) { + ctx := context.Background() + + source := os.Getenv("MYSQL_SERVER_URI") + if source == "" { + if err := docker.Installed(); err == nil { + u, err := docker.StartMySQLServer(ctx) + if err != nil { + t.Fatal(err) + } + source = u + } else if err := native.Supported(); err == nil { + u, err := native.StartMySQLServer(ctx) + if err != nil { + t.Fatal(err) + } + source = u + } else { + t.Skip("MYSQL_SERVER_URI is empty and neither Docker nor native installation is available") + } + } + + db, err := sql.Open("mysql", source) + if err != nil { + t.Skipf("could not connect to MySQL: %v", err) + } + defer db.Close() + + // Verify connection + if err := db.Ping(); err != nil { + t.Skipf("could not ping MySQL: %v", err) + } + + // Create a test table + _, err = db.ExecContext(ctx, `DROP TABLE IF EXISTS authors`) + if err != nil { + t.Fatalf("failed to drop test table: %v", err) + } + _, err = db.ExecContext(ctx, ` + CREATE TABLE authors ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + bio TEXT + ) + `) + if err != nil { + t.Fatalf("failed to create test table: %v", err) + } + defer db.ExecContext(ctx, "DROP TABLE IF EXISTS authors") + + // Create the parser which also implements format.Dialect + parser := dolphin.NewParser() + + // Create the expander + colGetter := &MySQLColumnGetter{db: db} + exp := New(colGetter, parser, parser) + + tests := []struct { + name string + query string + expected string + }{ + { + name: "simple select star", + query: "SELECT * FROM authors", + expected: "SELECT id, name, bio FROM authors;", + }, + { + name: "select with no star", + query: "SELECT id, name FROM authors", + expected: "SELECT id, name FROM authors", // No change, returns original + }, + { + name: "select star with where clause", + query: "SELECT * FROM authors WHERE id = 1", + expected: "SELECT id, name, bio FROM authors WHERE id = 1;", + }, + { + name: "table qualified star", + query: "SELECT authors.* FROM authors", + expected: "SELECT authors.id, authors.name, authors.bio FROM authors;", + }, + { + name: "double table qualified star", + query: "SELECT authors.*, authors.* FROM authors", + expected: "SELECT authors.id, authors.name, authors.bio, authors.id, authors.name, authors.bio FROM authors;", + }, + { + name: "star in middle of columns table qualified", + query: "SELECT id, authors.*, name FROM authors", + expected: "SELECT id, authors.id, authors.name, authors.bio, name FROM authors;", + }, + { + name: "count star not expanded", + query: "SELECT COUNT(*) FROM authors", + expected: "SELECT COUNT(*) FROM authors", // No change - COUNT(*) should not be expanded + }, + { + name: "count star with other columns", + query: "SELECT COUNT(*), name FROM authors GROUP BY name", + expected: "SELECT COUNT(*), name FROM authors GROUP BY name", // No change + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + result, err := exp.Expand(ctx, tc.query) + if err != nil { + t.Fatalf("Expand failed: %v", err) + } + if result != tc.expected { + t.Errorf("expected %q, got %q", tc.expected, result) + } + }) + } +} + +func TestExpandSQLite(t *testing.T) { + ctx := context.Background() + + // Create an in-memory SQLite database using native API + conn, err := sqlite3.Open(":memory:") + if err != nil { + t.Fatalf("could not open SQLite: %v", err) + } + defer conn.Close() + + // Create a test table + err = conn.Exec(` + CREATE TABLE authors ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + bio TEXT + ) + `) + if err != nil { + t.Fatalf("failed to create test table: %v", err) + } + + // Create the parser which also implements format.Dialect + parser := sqlite.NewParser() + + // Create the expander using native SQLite column getter + colGetter := &SQLiteColumnGetter{conn: conn} + exp := New(colGetter, parser, parser) + + tests := []struct { + name string + query string + expected string + }{ + { + name: "simple select star", + query: "SELECT * FROM authors", + expected: "SELECT id, name, bio FROM authors;", + }, + { + name: "select with no star", + query: "SELECT id, name FROM authors", + expected: "SELECT id, name FROM authors", // No change, returns original + }, + { + name: "select star with where clause", + query: "SELECT * FROM authors WHERE id = 1", + expected: "SELECT id, name, bio FROM authors WHERE id = 1;", + }, + { + name: "double star", + query: "SELECT *, * FROM authors", + expected: "SELECT id, name, bio, id, name, bio FROM authors;", + }, + { + name: "table qualified star", + query: "SELECT authors.* FROM authors", + expected: "SELECT authors.id, authors.name, authors.bio FROM authors;", + }, + { + name: "star in middle of columns", + query: "SELECT id, *, name FROM authors", + expected: "SELECT id, id, name, bio, name FROM authors;", + }, + { + name: "count star not expanded", + query: "SELECT COUNT(*) FROM authors", + expected: "SELECT COUNT(*) FROM authors", // No change - COUNT(*) should not be expanded + }, + { + name: "count star with other columns", + query: "SELECT COUNT(*), name FROM authors GROUP BY name", + expected: "SELECT COUNT(*), name FROM authors GROUP BY name", // No change + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + result, err := exp.Expand(ctx, tc.query) + if err != nil { + t.Fatalf("Expand failed: %v", err) + } + if result != tc.expected { + t.Errorf("expected %q, got %q", tc.expected, result) + } + }) + } +} diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go new file mode 100644 index 0000000..c83b699 --- /dev/null +++ b/pkg/cli/cli.go @@ -0,0 +1,30 @@ +// package cli exposes the command-line interface for sqlc. It can be used to +// run sqlc from Go without the overhead of creating a child process. +// +// Example usage: +// +// package main +// +// import ( +// "os" +// +// sqlc "github.com/sqlc-dev/sqlc/pkg/cli" +// ) +// +// func main() { +// os.Exit(sqlc.Run(os.Args[1:])) +// } +package cli + +import ( + "os" + + "github.com/sqlc-dev/sqlc/internal/cmd" +) + +// Run the sqlc CLI. It takes an array of command-line arguments +// (excluding the executable argument itself) and returns an exit +// code. +func Run(args []string) int { + return cmd.Do(args, os.Stdin, os.Stdout, os.Stderr) +} diff --git a/placeholder.go b/placeholder.go new file mode 100644 index 0000000..c53616c --- /dev/null +++ b/placeholder.go @@ -0,0 +1,6 @@ +package sqlc + +// This is a dummy file that allows SQLC to be "installed" as a module and locked using +// go.mod and then run using "go run github.com/sqlc-dev/sqlc" + +type Placeholder struct{} diff --git a/protos/analysis/analysis.proto b/protos/analysis/analysis.proto new file mode 100644 index 0000000..60e53b5 --- /dev/null +++ b/protos/analysis/analysis.proto @@ -0,0 +1,39 @@ +syntax = "proto3"; + +package analysis; + +message Identifier { + string catalog = 1; + string schema = 2; + string name = 3; +} + +message Column { + string name = 1; + string original_name = 2; + string data_type = 3; + bool not_null = 4; + bool unsigned = 5; + bool is_array = 6; + int32 array_dims = 7; + string comment = 8; + int32 length = 9; // *int + bool is_named_param = 10; + bool is_func_call = 11; + string scope = 12; + Identifier table = 13; + string table_alias = 14; + Identifier type = 15; + Identifier embed_table = 16; + bool is_sqlc_slice = 17; +} + +message Parameter { + int32 number = 1; + Column column = 2; +} + +message Analysis { + repeated Column columns = 1; + repeated Parameter params = 2; +} diff --git a/protos/buf.yaml b/protos/buf.yaml new file mode 100644 index 0000000..998cf11 --- /dev/null +++ b/protos/buf.yaml @@ -0,0 +1,8 @@ +version: v1 +name: buf.build/sqlc/sqlc +breaking: +lint: + use: + - DEFAULT + except: + - PACKAGE_VERSION_SUFFIX diff --git a/protos/plugin/codegen.proto b/protos/plugin/codegen.proto new file mode 100644 index 0000000..e6faf19 --- /dev/null +++ b/protos/plugin/codegen.proto @@ -0,0 +1,132 @@ +syntax = "proto3"; + +package plugin; + +service CodegenService { + rpc Generate (GenerateRequest) returns (GenerateResponse); +} + +message File { + string name = 1 [json_name = "name"]; + bytes contents = 2 [json_name = "contents"]; +} + +message Settings { + // Rename message was field 5 + // Overides message was field 6 + // PythonCode message was field 8 + // KotlinCode message was field 9 + // GoCode message was field 10; + // JSONCode message was field 11; + reserved 5, 8, 9, 10, 11; + + string version = 1 [json_name = "version"]; + string engine = 2 [json_name = "engine"]; + repeated string schema = 3 [json_name = "schema"]; + repeated string queries = 4 [json_name = "queries"]; + Codegen codegen = 12 [json_name = "codegen"]; +} + +message Codegen { + message Process { + string cmd = 1; + } + message WASM { + string url = 1; + string sha256 = 2; + } + string out = 1 [json_name = "out"]; + string plugin = 2 [json_name = "plugin"]; + bytes options = 3 [json_name = "options"]; + repeated string env = 4 [json_name = "env"]; + Process process = 5 [json_name = "process"]; + WASM wasm = 6 [json_name = "wasm"]; +} + +message Catalog { + string comment = 1; + string default_schema = 2; + string name = 3; + repeated Schema schemas = 4; +} + +message Schema { + string comment = 1; + string name = 2; + repeated Table tables = 3; + repeated Enum enums = 4; + repeated CompositeType composite_types = 5; +} + +message CompositeType { + string name = 1; + string comment = 2; +} + +message Enum { + string name = 1; + repeated string vals = 2; + string comment = 3; +} + +message Table { + Identifier rel = 1; + repeated Column columns = 2; + string comment = 3; +} + +message Identifier { + string catalog = 1; + string schema = 2; + string name = 3; +} + +message Column { + string name = 1; + bool not_null = 3; + bool is_array = 4; + string comment = 5; + int32 length = 6; + bool is_named_param = 7; + bool is_func_call = 8; + + // XXX: Figure out what PostgreSQL calls `foo.id` + string scope = 9; + Identifier table = 10; + string table_alias = 11; + Identifier type = 12; + bool is_sqlc_slice = 13; + Identifier embed_table = 14; + string original_name = 15; + bool unsigned = 16; + int32 array_dims = 17; +} + +message Query { + string text = 1 [json_name = "text"]; + string name = 2 [json_name = "name"]; + string cmd = 3 [json_name = "cmd"]; + repeated Column columns = 4 [json_name = "columns"]; + repeated Parameter params = 5 [json_name = "parameters"]; + repeated string comments = 6 [json_name = "comments"]; + string filename = 7 [json_name = "filename"]; + Identifier insert_into_table = 8 [json_name = "insert_into_table"]; +} + +message Parameter { + int32 number = 1 [json_name = "number"]; + Column column = 2 [json_name = "column"]; +} + +message GenerateRequest { + Settings settings = 1 [json_name = "settings"]; + Catalog catalog = 2 [json_name = "catalog"]; + repeated Query queries = 3 [json_name = "queries"]; + string sqlc_version = 4 [json_name = "sqlc_version"]; + bytes plugin_options = 5 [json_name = "plugin_options"]; + bytes global_options = 6 [json_name = "global_options"]; +} + +message GenerateResponse { + repeated File files = 1 [json_name = "files"]; +} diff --git a/protos/vet/vet.proto b/protos/vet/vet.proto new file mode 100644 index 0000000..9a5ded6 --- /dev/null +++ b/protos/vet/vet.proto @@ -0,0 +1,129 @@ +syntax = "proto3"; + +package vet; + +message Parameter { + int32 number = 1 [json_name = "number"]; +} + +message Config { + string version = 1 [json_name = "version"]; + string engine = 2 [json_name = "engine"]; + repeated string schema = 3 [json_name = "schema"]; + repeated string queries = 4 [json_name = "queries"]; +} + +message Query { + string sql = 1 [json_name = "sql"]; + string name = 2 [json_name = "name"]; + string cmd = 3 [json_name = "cmd"]; + repeated Parameter params = 4 [json_name = "parameters"]; +} + +message PostgreSQL { + PostgreSQLExplain explain = 1; +} + +message PostgreSQLExplain { + Plan plan = 1 [json_name = "Plan"]; + map settings = 2 [json_name = "Settings"]; + Planning planning = 3 [json_name = "Planning"]; + + message Plan { + string node_type = 1 [json_name = "Node Type"]; + string parent_relationship = 2 [json_name = "Parent Relationship"]; + string relation_name = 3 [json_name = "Relation Name"]; + string schema = 4 [json_name = "Schema"]; + string alias = 5 [json_name = "Alias"]; + bool parallel_aware = 6 [json_name = "Parallel Aware"]; + bool async_capable = 7 [json_name = "Async Capable"]; + float startup_cost = 8 [json_name = "Startup Cost"]; + float total_cost = 9 [json_name = "Total Cost"]; + uint64 plan_rows = 10 [json_name = "Plan Rows"]; + uint64 plan_width = 11 [json_name = "Plan Width"]; + repeated string output = 12 [json_name = "Output"]; + repeated Plan plans = 13 [json_name = "Plans"]; + + // Embedded "Blocks" fields + uint64 shared_hit_blocks = 14 [json_name = "Shared Hit Blocks"]; + uint64 shared_read_blocks = 15 [json_name = "Shared Read Blocks"]; + uint64 shared_dirtied_blocks = 16 [json_name = "Shared Dirtied Blocks"]; + uint64 shared_written_blocks = 17 [json_name = "Shared Written Blocks"]; + uint64 local_hit_blocks = 18 [json_name = "Local Hit Blocks"]; + uint64 local_read_blocks = 19 [json_name = "Local Read Blocks"]; + uint64 local_dirtied_blocks = 20 [json_name = "Local Dirtied Blocks"]; + uint64 local_written_blocks = 21 [json_name = "Local Written Blocks"]; + uint64 temp_read_blocks = 22 [json_name = "Temp Read Blocks"]; + uint64 temp_written_blocks = 23 [json_name = "Temp Written Blocks"]; + + // "Node Type": "Sort" fields + repeated string sort_key = 24 [json_name = "Sort Key"]; + + // "Node Type": "Hash Join" fields + string join_type = 25 [json_name = "Join Type"]; + bool inner_unique = 26 [json_name = "Inner Unique"]; + string hash_cond = 27 [json_name = "Hash Cond"]; + + // "Node Type": "Index Scan" fields + string index_name = 28 [json_name = "Index Name"]; + string scan_direction = 29 [json_name = "Scan Direction"]; + string index_cond = 30 [json_name = "Index Cond"]; + } + + message Planning { + uint64 shared_hit_blocks = 1 [json_name = "Shared Hit Blocks"]; + uint64 shared_read_blocks = 2 [json_name = "Shared Read Blocks"]; + uint64 shared_dirtied_blocks = 3 [json_name = "Shared Dirtied Blocks"]; + uint64 shared_written_blocks = 4 [json_name = "Shared Written Blocks"]; + uint64 local_hit_blocks = 5 [json_name = "Local Hit Blocks"]; + uint64 local_read_blocks = 6 [json_name = "Local Read Blocks"]; + uint64 local_dirtied_blocks = 7 [json_name = "Local Dirtied Blocks"]; + uint64 local_written_blocks = 8 [json_name = "Local Written Blocks"]; + uint64 temp_read_blocks = 9 [json_name = "Temp Read Blocks"]; + uint64 temp_written_blocks = 10 [json_name = "Temp Written Blocks"]; + } +} + +message MySQL { + MySQLExplain explain = 1; +} + +message MySQLExplain { + QueryBlock query_block = 1; + + message QueryBlock { + uint64 select_id = 1; + string message = 2; + map cost_info = 3; + Table table = 4; + OrderingOperation ordering_operation = 5; + repeated NestedLoopObj nested_loop = 6; + } + + message Table { + string table_name = 1; + string access_type = 2; + uint64 rows_examined_per_scan = 3; + uint64 rows_produced_per_join = 4; + string filtered = 5; + map cost_info = 6; + repeated string used_columns = 7; + bool insert = 8; + repeated string possible_keys = 9; + string key = 10; + repeated string used_key_parts = 11; + string key_length = 12; + repeated string ref = 13; + } + + message NestedLoopObj { + Table table = 1; + } + + message OrderingOperation { + bool using_filesort = 1; + map cost_info = 2; + Table table = 3; + repeated NestedLoopObj nested_loop = 4; + } +} diff --git a/scripts/build/main.go b/scripts/build/main.go new file mode 100755 index 0000000..6841c52 --- /dev/null +++ b/scripts/build/main.go @@ -0,0 +1,45 @@ +package main + +import ( + "fmt" + "log" + "os" + "os/exec" + "strings" +) + +func main() { + version := os.Getenv("VERSION") + sha := os.Getenv("GITHUB_SHA") + + if version == "" { + cmd := exec.Command("git", "show", "--no-patch", "--no-notes", "--pretty=%ci", sha) + out, err := cmd.CombinedOutput() + if err != nil { + log.Println(strings.TrimSpace(string(out))) + log.Fatal(err) + } + var date string + parts := strings.Split(string(out), " ") + date = strings.Replace(parts[0]+parts[1], "-", "", -1) + date = strings.Replace(date, ":", "", -1) + version = fmt.Sprintf("v0.0.0-%s-%s", date, sha[:12]) + } + + fmt.Printf("::set-output name=version::%s\n", version) + + x := "-X github.com/sqlc-dev/sqlc/internal/cmd.version=" + version + args := []string{ + "build", + "-ldflags", x, + "-o", "./sqlc", + "./cmd/sqlc", + } + cmd := exec.Command("go", args...) + cmd.Env = os.Environ() + out, err := cmd.CombinedOutput() + if err != nil { + log.Println(strings.TrimSpace(string(out))) + log.Fatal(err) + } +} diff --git a/scripts/bump-version/main.go b/scripts/bump-version/main.go new file mode 100644 index 0000000..aaf3f58 --- /dev/null +++ b/scripts/bump-version/main.go @@ -0,0 +1,150 @@ +package main + +import ( + "flag" + "fmt" + "io/fs" + "log" + "os" + "path/filepath" + "strings" + + "github.com/google/go-cmp/cmp" +) + +func main() { + curr := flag.String("c", "", "current version") + next := flag.String("n", "", "next version") + write := flag.Bool("w", false, "write out changes") + flag.Parse() + if err := run(*curr, *next, *write); err != nil { + log.Fatal(err) + } +} + +func run(current, next string, realmode bool) error { + write := func(path, old, new string) error { + if realmode { + if err := os.WriteFile(path, []byte(new), 0644); err != nil { + return fmt.Errorf("write error: %s: %w", path, err) + } + } else { + if diff := cmp.Diff(old, new); diff != "" { + log.Printf("%s: %s\n", path, diff) + } + } + return nil + } + + { + path := filepath.Join(".github", "ISSUE_TEMPLATE", "BUG_REPORT.yml") + c, err := os.ReadFile(path) + if err != nil { + return err + } + old := string(c) + if !strings.Contains(old, "- "+next) { + item := "- " + current + new := strings.ReplaceAll(old, item, "- "+next+"\n "+item) + if err := write(path, old, new); err != nil { + return err + } + } + } + + { + path := filepath.Join("docs", "overview", "install.md") + c, err := os.ReadFile(path) + if err != nil { + return err + } + old := string(c) + new := strings.ReplaceAll(old, "v"+current, "v"+next) + new = strings.ReplaceAll(new, "sqlc_"+current, "sqlc_"+next) + if err := write(path, old, new); err != nil { + return err + } + } + + { + path := filepath.Join("internal", "info", "facts.go") + c, err := os.ReadFile(path) + if err != nil { + return err + } + old := string(c) + new := strings.ReplaceAll(old, "v"+current, "v"+next) + if err := write(path, old, new); err != nil { + return err + } + } + + { + path := filepath.Join("docs", "conf.py") + c, err := os.ReadFile(path) + if err != nil { + return err + } + old := string(c) + new := strings.ReplaceAll(old, "release = '"+current, "release = '"+next) + if err := write(path, old, new); err != nil { + return err + } + } + + walker := func(path string, info fs.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + return nil + } + switch filepath.Ext(path) { + case ".go", ".kt", ".py", ".json", ".md": + c, err := os.ReadFile(path) + if err != nil { + return err + } + old := string(c) + new := strings.ReplaceAll(old, + `"sqlc_version": "v`+current, + `"sqlc_version": "v`+next) + new = strings.ReplaceAll(new, + `sqlc-version: "`+current, + `sqlc-version: "`+next) + new = strings.ReplaceAll(new, + `sqlc-version: '`+current, + `sqlc-version: '`+next) + new = strings.ReplaceAll(new, "sqlc v"+current, "sqlc v"+next) + new = strings.ReplaceAll(new, "SQLC_VERSION=v"+current, "SQLC_VERSION=v"+next) + if err := write(path, old, new); err != nil { + return err + } + default: + } + return nil + } + + { + p := filepath.Join("internal", "endtoend", "testdata") + if err := filepath.Walk(p, walker); err != nil { + return err + } + } + + { + p := filepath.Join("examples") + if err := filepath.Walk(p, walker); err != nil { + return err + } + } + + { + p := filepath.Join("docs") + if err := filepath.Walk(p, walker); err != nil { + return err + } + } + + return nil +} diff --git a/scripts/cleanup-test-dbs/main.go b/scripts/cleanup-test-dbs/main.go new file mode 100644 index 0000000..51093db --- /dev/null +++ b/scripts/cleanup-test-dbs/main.go @@ -0,0 +1,55 @@ +package main + +import ( + "context" + "fmt" + "log" + "os" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgxpool" +) + +func main() { + if err := run(); err != nil { + log.Fatal(err) + } +} + +const query = ` +SELECT datname +FROM pg_database +WHERE datname LIKE 'sqlc_test_%' +` + +func run() error { + ctx := context.Background() + dburi := os.Getenv("POSTGRESQL_SERVER_URI") + if dburi == "" { + return fmt.Errorf("POSTGRESQL_SERVER_URI is empty") + } + pool, err := pgxpool.New(ctx, dburi) + if err != nil { + return err + } + + rows, err := pool.Query(ctx, query) + if err != nil { + return err + } + + names, err := pgx.CollectRows(rows, pgx.RowTo[string]) + if err != nil { + return err + } + + for _, name := range names { + drop := fmt.Sprintf(`DROP DATABASE IF EXISTS "%s" WITH (FORCE)`, name) + if _, err := pool.Exec(ctx, drop); err != nil { + return err + } + log.Println("dropping database", name) + } + + return nil +} diff --git a/scripts/mirror-go-plugin/main.go b/scripts/mirror-go-plugin/main.go new file mode 100644 index 0000000..48277dc --- /dev/null +++ b/scripts/mirror-go-plugin/main.go @@ -0,0 +1,88 @@ +package main + +import ( + "bytes" + "flag" + "fmt" + "io/fs" + "log" + "os" + "path/filepath" + "strings" +) + +func main() { + flag.Parse() + // Assume it exists + loc := flag.Arg(0) + + dir := filepath.Join("internal", "codegen", "golang") + err := filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + return nil + } + contents, err := os.ReadFile(path) + if err != nil { + return err + } + + newdir := filepath.Join(loc, "internal") + newpath := strings.Replace(path, dir, newdir, 1) + + os.MkdirAll(filepath.Dir(newpath), 0755) + + contents = bytes.ReplaceAll(contents, + []byte(`"github.com/sqlc-dev/sqlc/internal/codegen/golang/opts"`), + []byte(`"github.com/sqlc-dev/sqlc-gen-go/internal/opts"`)) + + contents = bytes.ReplaceAll(contents, + []byte(`"github.com/sqlc-dev/sqlc/internal/plugin"`), + []byte(`"github.com/sqlc-dev/plugin-sdk-go/plugin"`)) + + contents = bytes.ReplaceAll(contents, + []byte(`"github.com/sqlc-dev/sqlc/internal/codegen/sdk"`), + []byte(`"github.com/sqlc-dev/plugin-sdk-go/sdk"`)) + + contents = bytes.ReplaceAll(contents, + []byte(`"github.com/sqlc-dev/sqlc/internal/metadata"`), + []byte(`"github.com/sqlc-dev/plugin-sdk-go/metadata"`)) + + contents = bytes.ReplaceAll(contents, + []byte(`"github.com/sqlc-dev/sqlc/internal/pattern"`), + []byte(`"github.com/sqlc-dev/plugin-sdk-go/pattern"`)) + + contents = bytes.ReplaceAll(contents, + []byte(`"github.com/sqlc-dev/sqlc/internal/debug"`), + []byte(`"github.com/sqlc-dev/sqlc-gen-go/internal/debug"`)) + + contents = bytes.ReplaceAll(contents, + []byte(`"github.com/sqlc-dev/sqlc/internal/inflection"`), + []byte(`"github.com/sqlc-dev/sqlc-gen-go/internal/inflection"`)) + + if err := os.WriteFile(newpath, contents, 0644); err != nil { + return err + } + return nil + }) + + if err != nil { + fmt.Printf("error walking the path: %v\n", err) + return + } + + { + path := filepath.Join("internal", "inflection", "singular.go") + contents, err := os.ReadFile(path) + if err != nil { + log.Fatal(err) + } + newpath := filepath.Join(loc, "internal", "inflection", "singular.go") + if err := os.WriteFile(newpath, contents, 0644); err != nil { + log.Fatal(err) + } + } + +} diff --git a/scripts/release.go b/scripts/release.go new file mode 100755 index 0000000..a8651a6 --- /dev/null +++ b/scripts/release.go @@ -0,0 +1,59 @@ +package main + +import ( + "flag" + "fmt" + "log" + "os" + "os/exec" + "strings" +) + +func main() { + docker := flag.Bool("docker", false, "create a docker release") + flag.Parse() + + version := os.Getenv("VERSION") + sha := os.Getenv("GITHUB_SHA") + + if version == "" { + cmd := exec.Command("git", "show", "--no-patch", "--no-notes", "--pretty=%ci", sha) + out, err := cmd.CombinedOutput() + if err != nil { + log.Println(strings.TrimSpace(string(out))) + log.Fatal(err) + } + + var date string + parts := strings.Split(string(out), " ") + date = strings.Replace(parts[0]+parts[1], "-", "", -1) + date = strings.Replace(date, ":", "", -1) + version = fmt.Sprintf("v0.0.0-%s-%s", date, sha[:12]) + } + + if *docker { + x := "-extldflags \"-static\" -X github.com/sqlc-dev/sqlc/internal/cmd.version=" + version + args := []string{ + "build", + "-a", + "-ldflags", x, + "-o", "/workspace/sqlc", + "./cmd/sqlc", + } + cmd := exec.Command("go", args...) + cmd.Env = os.Environ() + out, err := cmd.CombinedOutput() + if err != nil { + log.Println(strings.TrimSpace(string(out))) + log.Fatal(err) + } + return + } + + arch := flag.Arg(0) + if arch == "" { + log.Fatalf("missing platform_arch argument") + } + + log.Fatal("publishing to Equinox has been disabled") +} diff --git a/scripts/report.sh b/scripts/report.sh new file mode 100755 index 0000000..31302f4 --- /dev/null +++ b/scripts/report.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +curl \ + -X POST \ + --fail-with-body \ + -H "Authorization: Token token=\"$BUILDKITE_ANALYTICS_TOKEN\"" \ + -F "data=@junit.xml" \ + -F "format=junit" \ + -F "run_env[CI]=buildkite" \ + -F "run_env[key]=$GITHUB_RUN_ID" \ + -F "run_env[number]=$GITHUB_RUN_NUMBER-$GITHUB_RUN_ATTEMPT" \ + -F "run_env[job_id]=$GITHUB_RUN_ID" \ + -F "run_env[branch]=$GITHUB_REF" \ + -F "run_env[commit_sha]=$GITHUB_SHA" \ + -F "run_env[message]=Foo" \ + -F "run_env[url]=$GITHUB_SERVER_URL" \ + https://analytics-api.buildkite.com/v1/uploads diff --git a/scripts/test-json-process-plugin/main.go b/scripts/test-json-process-plugin/main.go new file mode 100644 index 0000000..471e020 --- /dev/null +++ b/scripts/test-json-process-plugin/main.go @@ -0,0 +1,39 @@ +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "os" +) + +type Out struct { + Files []File `json:"files"` +} + +type File struct { + Name string `json:"name"` + Contents []byte `json:"contents"` +} + +func main() { + in := make(map[string]any) + decoder := json.NewDecoder(os.Stdin) + err := decoder.Decode(&in) + if err != nil { + fmt.Fprintf(os.Stderr, "error generating JSON: %s", err) + os.Exit(2) + } + + buf := bytes.NewBuffer(nil) + queries := in["queries"].([]any) + for _, q := range queries { + text := q.(map[string]any)["text"].(string) + buf.WriteString(text) + buf.WriteString("\n") + } + + e := json.NewEncoder(os.Stdout) + e.SetIndent("", " ") + e.Encode(&Out{Files: []File{{Name: "hello.txt", Contents: buf.Bytes()}}}) +}